lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251103044553.GF2441659@ZenIV>
Date: Mon, 3 Nov 2025 04:45:53 +0000
From: Al Viro <viro@...iv.linux.org.uk>
To: Mateusz Guzik <mjguzik@...il.com>
Cc: brauner@...nel.org, jack@...e.cz, linux-kernel@...r.kernel.org,
	linux-fsdevel@...r.kernel.org
Subject: Re: [PATCH] fs: touch up predicts in putname()

On Sun, Nov 02, 2025 at 11:42:03PM +0100, Mateusz Guzik wrote:

> Even ignoring the fact that there is a refcount and people may be
> inclined to refname(name) + take_filename(name), the following already
> breaks:

Er...  refname() doesn't need to be seen for anyone other than auditsc.c
and core part of filename handling in fs/namei.c (I'd like to move it
to fs/filename.c someday)...

> foo() {
>     name = getname(...);
>     if (!IS_ERR_OR_NULL(name))
>         bar(name);
>     putname(name);
> }
> 
> bar(struct filename *name)
> {
>     baz(take_filename(&name));
> }
> 
> While the code as proposed in the branch does not do it, it is a
> matter of time before something which can be distilled to the above
> shows up.

Breaks in which case, exactly?  If baz() consumes its argument, we are
fine, if it does we have a leak...

I agree that 'take_filename' is inviting wrong connotations, though.

Hell knows - it might be worth thinking of that as claiming ownership.
Or, perhaps, transformation of the original object, if we separate
the notion of 'active filename' (absolutely tied to one thread, not
allowed to be reachable from any data structures shared with other
threads, etc.) from 'embryonic filename' (no refcounting whatsoever,
no copying of references, etc., consumed on transformation into
'active filename').  Then getname_alien() would create an embryo,
to be consumed before doing actual work.  That could be expressed
in C type system...  Need to think about that.

One possibility would be something like

struct alien_filename {
	struct filename *__dont_touch_that;
};

int getname_alien(struct alien_filename *v, const char __user *string)
{
	struct filename *res;
	if (WARN_ON(v->__dont_touch_that))
		return -EINVAL;
	res = getname_flags(string, GETNAME_NOAUDIT);
	if (IS_ERR(res))
		return PTR_ERR(res);
	v->__done_touch_that = res;
	return 0;
}

void destroy_alien_filename(struct alient_filename *v)
{
	putname(no_free_ptr(v->__dont_touch_that));
}

struct filename *claim_filename(struct alien_filename *v)
{
	struct filename *res = no_free_ptr(v->__dont_touch_that);
	if (!IS_ERR(res))
		audit_getname(res);
	return res;
}

and e.g.

struct io_rename {
        struct file                     *file;
	int                             old_dfd;
	int                             new_dfd;
	struct alien_filename           oldpath;
	struct alien_filename           newpath;
	int                             flags;
};

...
	err = getname_alien(&ren->oldpath);
	if (unlikely(err))
		return err;
	err = getname_alien(&ren->newpath);
	if (unlikely(err)) {
		destroy_alien_filename(&ren->oldpath);
		return err;
	}

...
	/* note that do_renameat2() consumes filename references */
        ret = do_renameat2(ren->old_dfd, claim_filename(&ren->oldpath),
			   ren->new_dfd, claim_filename(&ren->newpath),
			   ren->flags);
...

void io_renameat_cleanup(struct io_kiocb *req)
{
        struct io_rename *ren = io_kiocb_to_cmd(req, struct io_rename);
	 
	destroy_alien_filename(&ren->oldpath);
	destroy_alien_filename(&ren->newpath);
}

Might work...  Anyone found adding any instances of __dont_touch_that anywhere in
the kernel would be obviously doing something fishy (and if they are playing silly
buggers with obfuscating that, s/doing something fishy/malicious/), so C typechecking
+ git grep once in a while should suffice for safety.

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ