On Mon 02-11-26 15:21:31, Christian Brauner wrote:
> __xlate_proc_name() walks the components of a name like "a/b/c" and
> takes whatever it finds for "a" and "b" as the directory to go on in.
> It never checks that they actually are directories. So
> proc_create("file/x") hangs x into the subdir tree of the regular file
> "file". Nobody can look x up there, but remove_proc_subtree() on the
> file removes and frees x along with it, behind the back of whoever
> registered x.
>
> pktgen passes the name the writer of "add_device" picks to
> proc_create_data(), and only the part in front of the '@' has to name
> a network device:
>
> echo "add_device lo@" > /proc/net/pktgen/kpktgend_0
> echo "add_device lo@/x" > /proc/net/pktgen/kpktgend_1
> echo "rem_device_all" > /proc/net/pktgen/kpktgend_0
> echo "rem_device_all" > /proc/net/pktgen/kpktgend_1
>
> The third write frees both entries and the fourth one makes kpktgend_1
> call proc_remove() on the freed second one:
>
> BUG: KASAN: slab-use-after-free in proc_remove+0x8f/0xa0
> Read of size 8 at addr ff110001134c8e70 by task kpktgend_1/243
> Call Trace:
> proc_remove+0x8f/0xa0
> pktgen_remove_device.isra.0+0x118/0x500
> pktgen_rem_all_ifs+0xeb/0x1a0
> pktgen_thread_worker+0x1b42/0x7280
>
> The files of a network namespace belong to the root of its user
> namespace and these writes don't require a capability. So once pktgen
> is loaded an unprivileged user can do this in namespaces of its own.
>
> Treat a component that isn't a directory like one that doesn't exist.
> All names with a '/' that the tree passes in as literals only walk
> through directories. pktgen is fixed separately to not pass such names
> in the first place.
>
> Reported-by: Chris Mason <[email protected]>
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Cc: [email protected]
> Signed-off-by: Christian Brauner (Amutable) <[email protected]>
Looks good. Feel free to add:
Reviewed-by: Jan Kara <[email protected]>
Honza
> ---
> fs/proc/generic.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/fs/proc/generic.c b/fs/proc/generic.c
> index 2b1971da4a85..c560c96a64eb 100644
> --- a/fs/proc/generic.c
> +++ b/fs/proc/generic.c
> @@ -170,7 +170,7 @@ static int __xlate_proc_name(const char *name, struct
> proc_dir_entry **ret,
> de = *ret ?: &proc_root;
> while ((next = strchr(cp, '/')) != NULL) {
> de = pde_subdir_find(de, cp, next - cp);
> - if (!de) {
> + if (!de || !S_ISDIR(de->mode)) {
> WARN(1, "name '%s'\n", name);
> return -ENOENT;
> }
>
> --
> 2.53.0
>
--
Jan Kara <[email protected]>
SUSE Labs, CR