Skip to content

Commit

Permalink
Merge tag 'v6.6-rc7.vfs.fixes' of git://git.kernel.org/pub/scm/linux/…
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
Linus Torvalds committed Oct 19, 2023
2 parents f69d00d + 03adc61 commit ea1cc20
Show file tree
Hide file tree
Showing 3 changed files with 10 additions and 9 deletions.
9 changes: 5 additions & 4 deletions fs/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand All @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion include/linux/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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[];
};
Expand Down
8 changes: 4 additions & 4 deletions kernel/auditsc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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);
}
}

Expand Down

0 comments on commit ea1cc20

Please sign in to comment.