v6.6-rc7.vfs.fixes

-----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQRAhzRXHqcMeLMyaSiRxhvAZXjcogUCZTD6IQAKCRCRxhvAZXjc
 opXLAQC9X+ECnGUAOy/kvOrEBkBb7G4BuZ8XsrnL976riVNp0gEA85LaJV9Ow7Xk
 51k/1ujhYkglQbCsa0zo+mI4ueE3wAQ=
 =Dqrj
 -----END PGP SIGNATURE-----

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
This commit is contained in:
Linus Torvalds 2023-10-19 09:37:41 -07:00
commit ea1cc20cd4
3 changed files with 10 additions and 9 deletions

View file

@ -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) {

View file

@ -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[];
};

View file

@ -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);
}
}