Commit ea1cc20c authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'v6.6-rc7.vfs.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs

Pull vfs fix from Christian Brauner:
 "An openat() call from io_uring triggering an audit call can apparently
  cause the refcount of struct filename to be incremented from multiple
  threads concurrently during async execution, triggering a refcount
  underflow and hitting a BUG_ON(). That bug has been lurking around
  since at least v5.16 apparently.

  Switch to an atomic counter to fix that. The underflow check is
  downgraded from a BUG_ON() to a WARN_ON_ONCE() but we could easily
  remove that check altogether tbh"

* tag 'v6.6-rc7.vfs.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs:
  audit,io_uring: io_uring openat triggers audit reference count underflow
parents f69d00d1 03adc61e
Loading
Loading
Loading
Loading
+5 −4
Original line number Diff line number Diff line
@@ -188,7 +188,7 @@ getname_flags(const char __user *filename, int flags, int *empty)
		}
	}

	result->refcnt = 1;
	atomic_set(&result->refcnt, 1);
	/* The empty path is special. */
	if (unlikely(!len)) {
		if (empty)
@@ -249,7 +249,7 @@ getname_kernel(const char * filename)
	memcpy((char *)result->name, filename, len);
	result->uptr = NULL;
	result->aname = NULL;
	result->refcnt = 1;
	atomic_set(&result->refcnt, 1);
	audit_getname(result);

	return result;
@@ -261,9 +261,10 @@ void putname(struct filename *name)
	if (IS_ERR(name))
		return;

	BUG_ON(name->refcnt <= 0);
	if (WARN_ON_ONCE(!atomic_read(&name->refcnt)))
		return;

	if (--name->refcnt > 0)
	if (!atomic_dec_and_test(&name->refcnt))
		return;

	if (name->name != name->iname) {
+1 −1
Original line number Diff line number Diff line
@@ -2403,7 +2403,7 @@ struct audit_names;
struct filename {
	const char		*name;	/* pointer to actual string */
	const __user char	*uptr;	/* original userland pointer */
	int			refcnt;
	atomic_t		refcnt;
	struct audit_names	*aname;
	const char		iname[];
};
+4 −4
Original line number Diff line number Diff line
@@ -2212,7 +2212,7 @@ __audit_reusename(const __user char *uptr)
		if (!n->name)
			continue;
		if (n->name->uptr == uptr) {
			n->name->refcnt++;
			atomic_inc(&n->name->refcnt);
			return n->name;
		}
	}
@@ -2241,7 +2241,7 @@ void __audit_getname(struct filename *name)
	n->name = name;
	n->name_len = AUDIT_NAME_FULL;
	name->aname = n;
	name->refcnt++;
	atomic_inc(&name->refcnt);
}

static inline int audit_copy_fcaps(struct audit_names *name,
@@ -2373,7 +2373,7 @@ void __audit_inode(struct filename *name, const struct dentry *dentry,
		return;
	if (name) {
		n->name = name;
		name->refcnt++;
		atomic_inc(&name->refcnt);
	}

out:
@@ -2500,7 +2500,7 @@ void __audit_inode_child(struct inode *parent,
		if (found_parent) {
			found_child->name = found_parent->name;
			found_child->name_len = AUDIT_NAME_FULL;
			found_child->name->refcnt++;
			atomic_inc(&found_child->name->refcnt);
		}
	}