On Mon, Apr 14, 2025 at 01:01:53PM +0200, Christian Brauner wrote: > > diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c > > index 7f358740e958..367eaf2c78b7 100644 > > --- a/kernel/audit_watch.c > > +++ b/kernel/audit_watch.c > > @@ -350,11 +350,10 @@ static int audit_get_nd(struct audit_watch *watch, struct path *parent) > > struct dentry *d = kern_path_locked(watch->path, parent); > > if (IS_ERR(d)) > > return PTR_ERR(d); > > - if (d_is_positive(d)) { > > - /* update watch filter fields */ > > - watch->dev = d->d_sb->s_dev; > > - watch->ino = d_backing_inode(d)->i_ino; > > - } > > + /* update watch filter fields */ > > + watch->dev = d->d_sb->s_dev; > > + watch->ino = d_backing_inode(d)->i_ino; > > + > > inode_unlock(d_backing_inode(parent->dentry)); > > dput(d); > > return 0; > > @@ -419,10 +418,11 @@ int audit_add_watch(struct audit_krule *krule, struct list_head **list) > > /* caller expects mutex locked */ > > mutex_lock(&audit_filter_mutex); > > > > - if (ret) { > > + if (ret && ret != -ENOENT) { > > audit_put_watch(watch); > > return ret; > > } > > + ret = 0; > > So this is broken. > > If kern_path_locked() fails due to a negative dentry and returns ENOENT > it will have already called path_put() and @parent_path is invalid. > > But right after this audit does: > > > > > /* either find an old parent or attach a new one */ > > parent = audit_find_parent(d_backing_inode(parent_path.dentry)); > > and then later on calls path_put() again. So this is a UAF. We need to > fix this. > > This used to work before because kern_path_locked() return a path with a > negative dentry. *returned the parent path even if the looked up dentry was negative