Commit ea1cc20c authored by Linus Torvalds's avatar Linus Torvalds

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
...@@ -188,7 +188,7 @@ getname_flags(const char __user *filename, int flags, int *empty) ...@@ -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. */ /* The empty path is special. */
if (unlikely(!len)) { if (unlikely(!len)) {
if (empty) if (empty)
...@@ -249,7 +249,7 @@ getname_kernel(const char * filename) ...@@ -249,7 +249,7 @@ getname_kernel(const char * filename)
memcpy((char *)result->name, filename, len); memcpy((char *)result->name, filename, len);
result->uptr = NULL; result->uptr = NULL;
result->aname = NULL; result->aname = NULL;
result->refcnt = 1; atomic_set(&result->refcnt, 1);
audit_getname(result); audit_getname(result);
return result; return result;
...@@ -261,9 +261,10 @@ void putname(struct filename *name) ...@@ -261,9 +261,10 @@ void putname(struct filename *name)
if (IS_ERR(name)) if (IS_ERR(name))
return; 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; return;
if (name->name != name->iname) { if (name->name != name->iname) {
......
...@@ -2403,7 +2403,7 @@ struct audit_names; ...@@ -2403,7 +2403,7 @@ struct audit_names;
struct filename { struct filename {
const char *name; /* pointer to actual string */ const char *name; /* pointer to actual string */
const __user char *uptr; /* original userland pointer */ const __user char *uptr; /* original userland pointer */
int refcnt; atomic_t refcnt;
struct audit_names *aname; struct audit_names *aname;
const char iname[]; const char iname[];
}; };
......
...@@ -2212,7 +2212,7 @@ __audit_reusename(const __user char *uptr) ...@@ -2212,7 +2212,7 @@ __audit_reusename(const __user char *uptr)
if (!n->name) if (!n->name)
continue; continue;
if (n->name->uptr == uptr) { if (n->name->uptr == uptr) {
n->name->refcnt++; atomic_inc(&n->name->refcnt);
return n->name; return n->name;
} }
} }
...@@ -2241,7 +2241,7 @@ void __audit_getname(struct filename *name) ...@@ -2241,7 +2241,7 @@ void __audit_getname(struct filename *name)
n->name = name; n->name = name;
n->name_len = AUDIT_NAME_FULL; n->name_len = AUDIT_NAME_FULL;
name->aname = n; name->aname = n;
name->refcnt++; atomic_inc(&name->refcnt);
} }
static inline int audit_copy_fcaps(struct audit_names *name, static inline int audit_copy_fcaps(struct audit_names *name,
...@@ -2373,7 +2373,7 @@ void __audit_inode(struct filename *name, const struct dentry *dentry, ...@@ -2373,7 +2373,7 @@ void __audit_inode(struct filename *name, const struct dentry *dentry,
return; return;
if (name) { if (name) {
n->name = name; n->name = name;
name->refcnt++; atomic_inc(&name->refcnt);
} }
out: out:
...@@ -2500,7 +2500,7 @@ void __audit_inode_child(struct inode *parent, ...@@ -2500,7 +2500,7 @@ void __audit_inode_child(struct inode *parent,
if (found_parent) { if (found_parent) {
found_child->name = found_parent->name; found_child->name = found_parent->name;
found_child->name_len = AUDIT_NAME_FULL; found_child->name_len = AUDIT_NAME_FULL;
found_child->name->refcnt++; atomic_inc(&found_child->name->refcnt);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment