vfs-6.18-rc8.fixes

-----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQRAhzRXHqcMeLMyaSiRxhvAZXjcogUCaSmOegAKCRCRxhvAZXjc
 olHrAPwICALbFRDg/oj0kOFXEpUP2OrlCeKaZEMoxrKj1gZCUAEAzCATecAvZHZs
 ks1d77a0z9qMvQXxISws8ByNPueTMAA=
 =GH+q
 -----END PGP SIGNATURE-----

Merge tag 'vfs-6.18-rc8.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs

Pull vfs fixes from Christian Brauner:

 - afs: Fix delayed allocation of a cell's anonymous key

   The allocation of a cell's anonymous key is done in a background
   thread along with other cell setup such as doing a DNS upcall. The
   normal key lookup tries to use the key description on the anonymous
   authentication key as the reference for request_key() - but it may
   not yet be set, causing an oops

 - ovl: fail ovl_lock_rename_workdir() if either target is unhashed

   As well as checking that the parent hasn't changed after getting the
   lock, the code needs to check that the dentry hasn't been unhashed.
   Otherwise overlayfs might try to rename something that has been
   removed

 - namespace: fix a reference leak in grab_requested_mnt_ns

   lookup_mnt_ns() already takes a reference on mnt_ns, and so
   grab_requested_mnt_ns() doesn't need to take an extra reference

* tag 'vfs-6.18-rc8.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs:
  afs: Fix delayed allocation of a cell's anonymous key
  ovl: fail ovl_lock_rename_workdir() if either target is unhashed
  fs/namespace: fix reference leak in grab_requested_mnt_ns
This commit is contained in:
Linus Torvalds 2025-11-28 10:01:24 -08:00
commit f3b17337b9
5 changed files with 55 additions and 48 deletions

View File

@ -140,7 +140,9 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net,
return ERR_PTR(-ENOMEM);
}
cell->name = kmalloc(1 + namelen + 1, GFP_KERNEL);
/* Allocate the cell name and the key name in one go. */
cell->name = kmalloc(1 + namelen + 1 +
4 + namelen + 1, GFP_KERNEL);
if (!cell->name) {
kfree(cell);
return ERR_PTR(-ENOMEM);
@ -151,7 +153,11 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net,
cell->name_len = namelen;
for (i = 0; i < namelen; i++)
cell->name[i] = tolower(name[i]);
cell->name[i] = 0;
cell->name[i++] = 0;
cell->key_desc = cell->name + i;
memcpy(cell->key_desc, "afs@", 4);
memcpy(cell->key_desc + 4, cell->name, cell->name_len + 1);
cell->net = net;
refcount_set(&cell->ref, 1);
@ -710,33 +716,6 @@ void afs_set_cell_timer(struct afs_cell *cell, unsigned int delay_secs)
timer_reduce(&cell->management_timer, jiffies + delay_secs * HZ);
}
/*
* Allocate a key to use as a placeholder for anonymous user security.
*/
static int afs_alloc_anon_key(struct afs_cell *cell)
{
struct key *key;
char keyname[4 + AFS_MAXCELLNAME + 1], *cp, *dp;
/* Create a key to represent an anonymous user. */
memcpy(keyname, "afs@", 4);
dp = keyname + 4;
cp = cell->name;
do {
*dp++ = tolower(*cp);
} while (*cp++);
key = rxrpc_get_null_key(keyname);
if (IS_ERR(key))
return PTR_ERR(key);
cell->anonymous_key = key;
_debug("anon key %p{%x}",
cell->anonymous_key, key_serial(cell->anonymous_key));
return 0;
}
/*
* Activate a cell.
*/
@ -746,12 +725,6 @@ static int afs_activate_cell(struct afs_net *net, struct afs_cell *cell)
struct afs_cell *pcell;
int ret;
if (!cell->anonymous_key) {
ret = afs_alloc_anon_key(cell);
if (ret < 0)
return ret;
}
ret = afs_proc_cell_setup(cell);
if (ret < 0)
return ret;

View File

@ -413,6 +413,7 @@ struct afs_cell {
u8 name_len; /* Length of name */
char *name; /* Cell name, case-flattened and NUL-padded */
char *key_desc; /* Authentication key description */
};
/*

View File

@ -16,6 +16,30 @@
static DEFINE_HASHTABLE(afs_permits_cache, 10);
static DEFINE_SPINLOCK(afs_permits_lock);
static DEFINE_MUTEX(afs_key_lock);
/*
* Allocate a key to use as a placeholder for anonymous user security.
*/
static int afs_alloc_anon_key(struct afs_cell *cell)
{
struct key *key;
mutex_lock(&afs_key_lock);
if (!cell->anonymous_key) {
key = rxrpc_get_null_key(cell->key_desc);
if (!IS_ERR(key))
cell->anonymous_key = key;
}
mutex_unlock(&afs_key_lock);
if (IS_ERR(key))
return PTR_ERR(key);
_debug("anon key %p{%x}",
cell->anonymous_key, key_serial(cell->anonymous_key));
return 0;
}
/*
* get a key
@ -23,11 +47,12 @@ static DEFINE_SPINLOCK(afs_permits_lock);
struct key *afs_request_key(struct afs_cell *cell)
{
struct key *key;
int ret;
_enter("{%x}", key_serial(cell->anonymous_key));
_enter("{%s}", cell->key_desc);
_debug("key %s", cell->anonymous_key->description);
key = request_key_net(&key_type_rxrpc, cell->anonymous_key->description,
_debug("key %s", cell->key_desc);
key = request_key_net(&key_type_rxrpc, cell->key_desc,
cell->net->net, NULL);
if (IS_ERR(key)) {
if (PTR_ERR(key) != -ENOKEY) {
@ -35,6 +60,12 @@ struct key *afs_request_key(struct afs_cell *cell)
return key;
}
if (!cell->anonymous_key) {
ret = afs_alloc_anon_key(cell);
if (ret < 0)
return ERR_PTR(ret);
}
/* act as anonymous user */
_leave(" = {%x} [anon]", key_serial(cell->anonymous_key));
return key_get(cell->anonymous_key);
@ -52,11 +83,10 @@ struct key *afs_request_key_rcu(struct afs_cell *cell)
{
struct key *key;
_enter("{%x}", key_serial(cell->anonymous_key));
_enter("{%s}", cell->key_desc);
_debug("key %s", cell->anonymous_key->description);
key = request_key_net_rcu(&key_type_rxrpc,
cell->anonymous_key->description,
_debug("key %s", cell->key_desc);
key = request_key_net_rcu(&key_type_rxrpc, cell->key_desc,
cell->net->net);
if (IS_ERR(key)) {
if (PTR_ERR(key) != -ENOKEY) {
@ -65,6 +95,8 @@ struct key *afs_request_key_rcu(struct afs_cell *cell)
}
/* act as anonymous user */
if (!cell->anonymous_key)
return NULL; /* Need to allocate */
_leave(" = {%x} [anon]", key_serial(cell->anonymous_key));
return key_get(cell->anonymous_key);
} else {
@ -408,7 +440,7 @@ int afs_permission(struct mnt_idmap *idmap, struct inode *inode,
if (mask & MAY_NOT_BLOCK) {
key = afs_request_key_rcu(vnode->volume->cell);
if (IS_ERR(key))
if (IS_ERR_OR_NULL(key))
return -ECHILD;
ret = -ECHILD;

View File

@ -5746,6 +5746,8 @@ static struct mnt_namespace *grab_requested_mnt_ns(const struct mnt_id_req *kreq
if (kreq->mnt_ns_id) {
mnt_ns = lookup_mnt_ns(kreq->mnt_ns_id);
if (!mnt_ns)
return ERR_PTR(-ENOENT);
} else if (kreq->mnt_ns_fd) {
struct ns_common *ns;
@ -5761,13 +5763,12 @@ static struct mnt_namespace *grab_requested_mnt_ns(const struct mnt_id_req *kreq
return ERR_PTR(-EINVAL);
mnt_ns = to_mnt_ns(ns);
refcount_inc(&mnt_ns->passive);
} else {
mnt_ns = current->nsproxy->mnt_ns;
}
if (!mnt_ns)
return ERR_PTR(-ENOENT);
refcount_inc(&mnt_ns->passive);
}
return mnt_ns;
}

View File

@ -1234,9 +1234,9 @@ int ovl_lock_rename_workdir(struct dentry *workdir, struct dentry *work,
goto err;
if (trap)
goto err_unlock;
if (work && work->d_parent != workdir)
if (work && (work->d_parent != workdir || d_unhashed(work)))
goto err_unlock;
if (upper && upper->d_parent != upperdir)
if (upper && (upper->d_parent != upperdir || d_unhashed(upper)))
goto err_unlock;
return 0;