mirror of https://github.com/torvalds/linux.git
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:
commit
f3b17337b9
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue