userns: Convert security/keys to the new userns infrastructure
- Replace key_user ->user_ns equality checks with kuid_has_mapping checks. - Use from_kuid to generate key descriptions - Use kuid_t and kgid_t and the associated helpers instead of uid_t and gid_t - Avoid potential problems with file descriptor passing by displaying keys in the user namespace of the opener of key status proc files. Cc: linux-security-module@vger.kernel.org Cc: keyrings@linux-nfs.org Cc: David Howells <dhowells@redhat.com> Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
This commit is contained in:
parent
5fce5e0bbd
commit
9a56c2db49
|
@ -24,6 +24,7 @@
|
||||||
#include <linux/atomic.h>
|
#include <linux/atomic.h>
|
||||||
|
|
||||||
#ifdef __KERNEL__
|
#ifdef __KERNEL__
|
||||||
|
#include <linux/uidgid.h>
|
||||||
|
|
||||||
/* key handle serial number */
|
/* key handle serial number */
|
||||||
typedef int32_t key_serial_t;
|
typedef int32_t key_serial_t;
|
||||||
|
@ -137,8 +138,8 @@ struct key {
|
||||||
time_t revoked_at; /* time at which key was revoked */
|
time_t revoked_at; /* time at which key was revoked */
|
||||||
};
|
};
|
||||||
time_t last_used_at; /* last time used for LRU keyring discard */
|
time_t last_used_at; /* last time used for LRU keyring discard */
|
||||||
uid_t uid;
|
kuid_t uid;
|
||||||
gid_t gid;
|
kgid_t gid;
|
||||||
key_perm_t perm; /* access permissions */
|
key_perm_t perm; /* access permissions */
|
||||||
unsigned short quotalen; /* length added to quota */
|
unsigned short quotalen; /* length added to quota */
|
||||||
unsigned short datalen; /* payload data length
|
unsigned short datalen; /* payload data length
|
||||||
|
@ -193,7 +194,7 @@ struct key {
|
||||||
|
|
||||||
extern struct key *key_alloc(struct key_type *type,
|
extern struct key *key_alloc(struct key_type *type,
|
||||||
const char *desc,
|
const char *desc,
|
||||||
uid_t uid, gid_t gid,
|
kuid_t uid, kgid_t gid,
|
||||||
const struct cred *cred,
|
const struct cred *cred,
|
||||||
key_perm_t perm,
|
key_perm_t perm,
|
||||||
unsigned long flags);
|
unsigned long flags);
|
||||||
|
@ -262,7 +263,7 @@ extern int key_link(struct key *keyring,
|
||||||
extern int key_unlink(struct key *keyring,
|
extern int key_unlink(struct key *keyring,
|
||||||
struct key *key);
|
struct key *key);
|
||||||
|
|
||||||
extern struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
|
extern struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid,
|
||||||
const struct cred *cred,
|
const struct cred *cred,
|
||||||
unsigned long flags,
|
unsigned long flags,
|
||||||
struct key *dest);
|
struct key *dest);
|
||||||
|
|
|
@ -927,7 +927,6 @@ config UIDGID_CONVERTED
|
||||||
# Features
|
# Features
|
||||||
depends on IMA = n
|
depends on IMA = n
|
||||||
depends on EVM = n
|
depends on EVM = n
|
||||||
depends on KEYS = n
|
|
||||||
depends on AUDIT = n
|
depends on AUDIT = n
|
||||||
depends on AUDITSYSCALL = n
|
depends on AUDITSYSCALL = n
|
||||||
depends on TASKSTATS = n
|
depends on TASKSTATS = n
|
||||||
|
|
|
@ -52,8 +52,7 @@ struct key_user {
|
||||||
atomic_t usage; /* for accessing qnkeys & qnbytes */
|
atomic_t usage; /* for accessing qnkeys & qnbytes */
|
||||||
atomic_t nkeys; /* number of keys */
|
atomic_t nkeys; /* number of keys */
|
||||||
atomic_t nikeys; /* number of instantiated keys */
|
atomic_t nikeys; /* number of instantiated keys */
|
||||||
uid_t uid;
|
kuid_t uid;
|
||||||
struct user_namespace *user_ns;
|
|
||||||
int qnkeys; /* number of keys allocated to this user */
|
int qnkeys; /* number of keys allocated to this user */
|
||||||
int qnbytes; /* number of bytes allocated to this user */
|
int qnbytes; /* number of bytes allocated to this user */
|
||||||
};
|
};
|
||||||
|
@ -62,8 +61,7 @@ extern struct rb_root key_user_tree;
|
||||||
extern spinlock_t key_user_lock;
|
extern spinlock_t key_user_lock;
|
||||||
extern struct key_user root_key_user;
|
extern struct key_user root_key_user;
|
||||||
|
|
||||||
extern struct key_user *key_user_lookup(uid_t uid,
|
extern struct key_user *key_user_lookup(kuid_t uid);
|
||||||
struct user_namespace *user_ns);
|
|
||||||
extern void key_user_put(struct key_user *user);
|
extern void key_user_put(struct key_user *user);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
#include <linux/random.h>
|
#include <linux/random.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/user_namespace.h>
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
struct kmem_cache *key_jar;
|
struct kmem_cache *key_jar;
|
||||||
|
@ -52,7 +51,7 @@ void __key_check(const struct key *key)
|
||||||
* Get the key quota record for a user, allocating a new record if one doesn't
|
* Get the key quota record for a user, allocating a new record if one doesn't
|
||||||
* already exist.
|
* already exist.
|
||||||
*/
|
*/
|
||||||
struct key_user *key_user_lookup(uid_t uid, struct user_namespace *user_ns)
|
struct key_user *key_user_lookup(kuid_t uid)
|
||||||
{
|
{
|
||||||
struct key_user *candidate = NULL, *user;
|
struct key_user *candidate = NULL, *user;
|
||||||
struct rb_node *parent = NULL;
|
struct rb_node *parent = NULL;
|
||||||
|
@ -67,13 +66,9 @@ try_again:
|
||||||
parent = *p;
|
parent = *p;
|
||||||
user = rb_entry(parent, struct key_user, node);
|
user = rb_entry(parent, struct key_user, node);
|
||||||
|
|
||||||
if (uid < user->uid)
|
if (uid_lt(uid, user->uid))
|
||||||
p = &(*p)->rb_left;
|
p = &(*p)->rb_left;
|
||||||
else if (uid > user->uid)
|
else if (uid_gt(uid, user->uid))
|
||||||
p = &(*p)->rb_right;
|
|
||||||
else if (user_ns < user->user_ns)
|
|
||||||
p = &(*p)->rb_left;
|
|
||||||
else if (user_ns > user->user_ns)
|
|
||||||
p = &(*p)->rb_right;
|
p = &(*p)->rb_right;
|
||||||
else
|
else
|
||||||
goto found;
|
goto found;
|
||||||
|
@ -102,7 +97,6 @@ try_again:
|
||||||
atomic_set(&candidate->nkeys, 0);
|
atomic_set(&candidate->nkeys, 0);
|
||||||
atomic_set(&candidate->nikeys, 0);
|
atomic_set(&candidate->nikeys, 0);
|
||||||
candidate->uid = uid;
|
candidate->uid = uid;
|
||||||
candidate->user_ns = get_user_ns(user_ns);
|
|
||||||
candidate->qnkeys = 0;
|
candidate->qnkeys = 0;
|
||||||
candidate->qnbytes = 0;
|
candidate->qnbytes = 0;
|
||||||
spin_lock_init(&candidate->lock);
|
spin_lock_init(&candidate->lock);
|
||||||
|
@ -131,7 +125,6 @@ void key_user_put(struct key_user *user)
|
||||||
if (atomic_dec_and_lock(&user->usage, &key_user_lock)) {
|
if (atomic_dec_and_lock(&user->usage, &key_user_lock)) {
|
||||||
rb_erase(&user->node, &key_user_tree);
|
rb_erase(&user->node, &key_user_tree);
|
||||||
spin_unlock(&key_user_lock);
|
spin_unlock(&key_user_lock);
|
||||||
put_user_ns(user->user_ns);
|
|
||||||
|
|
||||||
kfree(user);
|
kfree(user);
|
||||||
}
|
}
|
||||||
|
@ -229,7 +222,7 @@ serial_exists:
|
||||||
* key_alloc() calls don't race with module unloading.
|
* key_alloc() calls don't race with module unloading.
|
||||||
*/
|
*/
|
||||||
struct key *key_alloc(struct key_type *type, const char *desc,
|
struct key *key_alloc(struct key_type *type, const char *desc,
|
||||||
uid_t uid, gid_t gid, const struct cred *cred,
|
kuid_t uid, kgid_t gid, const struct cred *cred,
|
||||||
key_perm_t perm, unsigned long flags)
|
key_perm_t perm, unsigned long flags)
|
||||||
{
|
{
|
||||||
struct key_user *user = NULL;
|
struct key_user *user = NULL;
|
||||||
|
@ -253,16 +246,16 @@ struct key *key_alloc(struct key_type *type, const char *desc,
|
||||||
quotalen = desclen + type->def_datalen;
|
quotalen = desclen + type->def_datalen;
|
||||||
|
|
||||||
/* get hold of the key tracking for this user */
|
/* get hold of the key tracking for this user */
|
||||||
user = key_user_lookup(uid, cred->user_ns);
|
user = key_user_lookup(uid);
|
||||||
if (!user)
|
if (!user)
|
||||||
goto no_memory_1;
|
goto no_memory_1;
|
||||||
|
|
||||||
/* check that the user's quota permits allocation of another key and
|
/* check that the user's quota permits allocation of another key and
|
||||||
* its description */
|
* its description */
|
||||||
if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
|
if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
|
||||||
unsigned maxkeys = (uid == 0) ?
|
unsigned maxkeys = uid_eq(uid, GLOBAL_ROOT_UID) ?
|
||||||
key_quota_root_maxkeys : key_quota_maxkeys;
|
key_quota_root_maxkeys : key_quota_maxkeys;
|
||||||
unsigned maxbytes = (uid == 0) ?
|
unsigned maxbytes = uid_eq(uid, GLOBAL_ROOT_UID) ?
|
||||||
key_quota_root_maxbytes : key_quota_maxbytes;
|
key_quota_root_maxbytes : key_quota_maxbytes;
|
||||||
|
|
||||||
spin_lock(&user->lock);
|
spin_lock(&user->lock);
|
||||||
|
@ -380,7 +373,7 @@ int key_payload_reserve(struct key *key, size_t datalen)
|
||||||
|
|
||||||
/* contemplate the quota adjustment */
|
/* contemplate the quota adjustment */
|
||||||
if (delta != 0 && test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
|
if (delta != 0 && test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
|
||||||
unsigned maxbytes = (key->user->uid == 0) ?
|
unsigned maxbytes = uid_eq(key->user->uid, GLOBAL_ROOT_UID) ?
|
||||||
key_quota_root_maxbytes : key_quota_maxbytes;
|
key_quota_root_maxbytes : key_quota_maxbytes;
|
||||||
|
|
||||||
spin_lock(&key->user->lock);
|
spin_lock(&key->user->lock);
|
||||||
|
|
|
@ -569,8 +569,8 @@ okay:
|
||||||
ret = snprintf(tmpbuf, PAGE_SIZE - 1,
|
ret = snprintf(tmpbuf, PAGE_SIZE - 1,
|
||||||
"%s;%d;%d;%08x;%s",
|
"%s;%d;%d;%08x;%s",
|
||||||
key->type->name,
|
key->type->name,
|
||||||
key->uid,
|
from_kuid_munged(current_user_ns(), key->uid),
|
||||||
key->gid,
|
from_kgid_munged(current_user_ns(), key->gid),
|
||||||
key->perm,
|
key->perm,
|
||||||
key->description ?: "");
|
key->description ?: "");
|
||||||
|
|
||||||
|
@ -766,15 +766,25 @@ error:
|
||||||
*
|
*
|
||||||
* If successful, 0 will be returned.
|
* If successful, 0 will be returned.
|
||||||
*/
|
*/
|
||||||
long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
|
long keyctl_chown_key(key_serial_t id, uid_t user, gid_t group)
|
||||||
{
|
{
|
||||||
struct key_user *newowner, *zapowner = NULL;
|
struct key_user *newowner, *zapowner = NULL;
|
||||||
struct key *key;
|
struct key *key;
|
||||||
key_ref_t key_ref;
|
key_ref_t key_ref;
|
||||||
long ret;
|
long ret;
|
||||||
|
kuid_t uid;
|
||||||
|
kgid_t gid;
|
||||||
|
|
||||||
|
uid = make_kuid(current_user_ns(), user);
|
||||||
|
gid = make_kgid(current_user_ns(), group);
|
||||||
|
ret = -EINVAL;
|
||||||
|
if ((user != (uid_t) -1) && !uid_valid(uid))
|
||||||
|
goto error;
|
||||||
|
if ((group != (gid_t) -1) && !gid_valid(gid))
|
||||||
|
goto error;
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
if (uid == (uid_t) -1 && gid == (gid_t) -1)
|
if (user == (uid_t) -1 && group == (gid_t) -1)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL,
|
key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL,
|
||||||
|
@ -792,27 +802,27 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
|
||||||
|
|
||||||
if (!capable(CAP_SYS_ADMIN)) {
|
if (!capable(CAP_SYS_ADMIN)) {
|
||||||
/* only the sysadmin can chown a key to some other UID */
|
/* only the sysadmin can chown a key to some other UID */
|
||||||
if (uid != (uid_t) -1 && key->uid != uid)
|
if (user != (uid_t) -1 && !uid_eq(key->uid, uid))
|
||||||
goto error_put;
|
goto error_put;
|
||||||
|
|
||||||
/* only the sysadmin can set the key's GID to a group other
|
/* only the sysadmin can set the key's GID to a group other
|
||||||
* than one of those that the current process subscribes to */
|
* than one of those that the current process subscribes to */
|
||||||
if (gid != (gid_t) -1 && gid != key->gid && !in_group_p(gid))
|
if (group != (gid_t) -1 && !gid_eq(gid, key->gid) && !in_group_p(gid))
|
||||||
goto error_put;
|
goto error_put;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* change the UID */
|
/* change the UID */
|
||||||
if (uid != (uid_t) -1 && uid != key->uid) {
|
if (user != (uid_t) -1 && !uid_eq(uid, key->uid)) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
newowner = key_user_lookup(uid, current_user_ns());
|
newowner = key_user_lookup(uid);
|
||||||
if (!newowner)
|
if (!newowner)
|
||||||
goto error_put;
|
goto error_put;
|
||||||
|
|
||||||
/* transfer the quota burden to the new user */
|
/* transfer the quota burden to the new user */
|
||||||
if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
|
if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
|
||||||
unsigned maxkeys = (uid == 0) ?
|
unsigned maxkeys = uid_eq(uid, GLOBAL_ROOT_UID) ?
|
||||||
key_quota_root_maxkeys : key_quota_maxkeys;
|
key_quota_root_maxkeys : key_quota_maxkeys;
|
||||||
unsigned maxbytes = (uid == 0) ?
|
unsigned maxbytes = uid_eq(uid, GLOBAL_ROOT_UID) ?
|
||||||
key_quota_root_maxbytes : key_quota_maxbytes;
|
key_quota_root_maxbytes : key_quota_maxbytes;
|
||||||
|
|
||||||
spin_lock(&newowner->lock);
|
spin_lock(&newowner->lock);
|
||||||
|
@ -846,7 +856,7 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* change the GID */
|
/* change the GID */
|
||||||
if (gid != (gid_t) -1)
|
if (group != (gid_t) -1)
|
||||||
key->gid = gid;
|
key->gid = gid;
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
@ -897,7 +907,7 @@ long keyctl_setperm_key(key_serial_t id, key_perm_t perm)
|
||||||
down_write(&key->sem);
|
down_write(&key->sem);
|
||||||
|
|
||||||
/* if we're not the sysadmin, we can only change a key that we own */
|
/* if we're not the sysadmin, we can only change a key that we own */
|
||||||
if (capable(CAP_SYS_ADMIN) || key->uid == current_fsuid()) {
|
if (capable(CAP_SYS_ADMIN) || uid_eq(key->uid, current_fsuid())) {
|
||||||
key->perm = perm;
|
key->perm = perm;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
|
@ -1507,18 +1517,18 @@ long keyctl_session_to_parent(void)
|
||||||
|
|
||||||
/* the parent must have the same effective ownership and mustn't be
|
/* the parent must have the same effective ownership and mustn't be
|
||||||
* SUID/SGID */
|
* SUID/SGID */
|
||||||
if (pcred->uid != mycred->euid ||
|
if (!uid_eq(pcred->uid, mycred->euid) ||
|
||||||
pcred->euid != mycred->euid ||
|
!uid_eq(pcred->euid, mycred->euid) ||
|
||||||
pcred->suid != mycred->euid ||
|
!uid_eq(pcred->suid, mycred->euid) ||
|
||||||
pcred->gid != mycred->egid ||
|
!gid_eq(pcred->gid, mycred->egid) ||
|
||||||
pcred->egid != mycred->egid ||
|
!gid_eq(pcred->egid, mycred->egid) ||
|
||||||
pcred->sgid != mycred->egid)
|
!gid_eq(pcred->sgid, mycred->egid))
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
|
||||||
/* the keyrings must have the same UID */
|
/* the keyrings must have the same UID */
|
||||||
if ((pcred->tgcred->session_keyring &&
|
if ((pcred->tgcred->session_keyring &&
|
||||||
pcred->tgcred->session_keyring->uid != mycred->euid) ||
|
!uid_eq(pcred->tgcred->session_keyring->uid, mycred->euid)) ||
|
||||||
mycred->tgcred->session_keyring->uid != mycred->euid)
|
!uid_eq(mycred->tgcred->session_keyring->uid, mycred->euid))
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
|
||||||
/* cancel an already pending keyring replacement */
|
/* cancel an already pending keyring replacement */
|
||||||
|
|
|
@ -256,7 +256,7 @@ error:
|
||||||
/*
|
/*
|
||||||
* Allocate a keyring and link into the destination keyring.
|
* Allocate a keyring and link into the destination keyring.
|
||||||
*/
|
*/
|
||||||
struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
|
struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid,
|
||||||
const struct cred *cred, unsigned long flags,
|
const struct cred *cred, unsigned long flags,
|
||||||
struct key *dest)
|
struct key *dest)
|
||||||
{
|
{
|
||||||
|
@ -612,7 +612,7 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check)
|
||||||
&keyring_name_hash[bucket],
|
&keyring_name_hash[bucket],
|
||||||
type_data.link
|
type_data.link
|
||||||
) {
|
) {
|
||||||
if (keyring->user->user_ns != current_user_ns())
|
if (!kuid_has_mapping(current_user_ns(), keyring->user->uid))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
|
if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
|
||||||
|
|
|
@ -36,33 +36,27 @@ int key_task_permission(const key_ref_t key_ref, const struct cred *cred,
|
||||||
|
|
||||||
key = key_ref_to_ptr(key_ref);
|
key = key_ref_to_ptr(key_ref);
|
||||||
|
|
||||||
if (key->user->user_ns != cred->user_ns)
|
|
||||||
goto use_other_perms;
|
|
||||||
|
|
||||||
/* use the second 8-bits of permissions for keys the caller owns */
|
/* use the second 8-bits of permissions for keys the caller owns */
|
||||||
if (key->uid == cred->fsuid) {
|
if (uid_eq(key->uid, cred->fsuid)) {
|
||||||
kperm = key->perm >> 16;
|
kperm = key->perm >> 16;
|
||||||
goto use_these_perms;
|
goto use_these_perms;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* use the third 8-bits of permissions for keys the caller has a group
|
/* use the third 8-bits of permissions for keys the caller has a group
|
||||||
* membership in common with */
|
* membership in common with */
|
||||||
if (key->gid != -1 && key->perm & KEY_GRP_ALL) {
|
if (gid_valid(key->gid) && key->perm & KEY_GRP_ALL) {
|
||||||
if (key->gid == cred->fsgid) {
|
if (gid_eq(key->gid, cred->fsgid)) {
|
||||||
kperm = key->perm >> 8;
|
kperm = key->perm >> 8;
|
||||||
goto use_these_perms;
|
goto use_these_perms;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = groups_search(cred->group_info,
|
ret = groups_search(cred->group_info, key->gid);
|
||||||
make_kgid(current_user_ns(), key->gid));
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
kperm = key->perm >> 8;
|
kperm = key->perm >> 8;
|
||||||
goto use_these_perms;
|
goto use_these_perms;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use_other_perms:
|
|
||||||
|
|
||||||
/* otherwise use the least-significant 8-bits */
|
/* otherwise use the least-significant 8-bits */
|
||||||
kperm = key->perm;
|
kperm = key->perm;
|
||||||
|
|
||||||
|
|
|
@ -88,14 +88,14 @@ __initcall(key_proc_init);
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_KEYS_DEBUG_PROC_KEYS
|
#ifdef CONFIG_KEYS_DEBUG_PROC_KEYS
|
||||||
|
|
||||||
static struct rb_node *key_serial_next(struct rb_node *n)
|
static struct rb_node *key_serial_next(struct seq_file *p, struct rb_node *n)
|
||||||
{
|
{
|
||||||
struct user_namespace *user_ns = current_user_ns();
|
struct user_namespace *user_ns = seq_user_ns(p);
|
||||||
|
|
||||||
n = rb_next(n);
|
n = rb_next(n);
|
||||||
while (n) {
|
while (n) {
|
||||||
struct key *key = rb_entry(n, struct key, serial_node);
|
struct key *key = rb_entry(n, struct key, serial_node);
|
||||||
if (key->user->user_ns == user_ns)
|
if (kuid_has_mapping(user_ns, key->user->uid))
|
||||||
break;
|
break;
|
||||||
n = rb_next(n);
|
n = rb_next(n);
|
||||||
}
|
}
|
||||||
|
@ -107,9 +107,9 @@ static int proc_keys_open(struct inode *inode, struct file *file)
|
||||||
return seq_open(file, &proc_keys_ops);
|
return seq_open(file, &proc_keys_ops);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct key *find_ge_key(key_serial_t id)
|
static struct key *find_ge_key(struct seq_file *p, key_serial_t id)
|
||||||
{
|
{
|
||||||
struct user_namespace *user_ns = current_user_ns();
|
struct user_namespace *user_ns = seq_user_ns(p);
|
||||||
struct rb_node *n = key_serial_tree.rb_node;
|
struct rb_node *n = key_serial_tree.rb_node;
|
||||||
struct key *minkey = NULL;
|
struct key *minkey = NULL;
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ static struct key *find_ge_key(key_serial_t id)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (minkey->user->user_ns == user_ns)
|
if (kuid_has_mapping(user_ns, minkey->user->uid))
|
||||||
return minkey;
|
return minkey;
|
||||||
n = rb_next(&minkey->serial_node);
|
n = rb_next(&minkey->serial_node);
|
||||||
if (!n)
|
if (!n)
|
||||||
|
@ -151,7 +151,7 @@ static void *proc_keys_start(struct seq_file *p, loff_t *_pos)
|
||||||
|
|
||||||
if (*_pos > INT_MAX)
|
if (*_pos > INT_MAX)
|
||||||
return NULL;
|
return NULL;
|
||||||
key = find_ge_key(pos);
|
key = find_ge_key(p, pos);
|
||||||
if (!key)
|
if (!key)
|
||||||
return NULL;
|
return NULL;
|
||||||
*_pos = key->serial;
|
*_pos = key->serial;
|
||||||
|
@ -168,7 +168,7 @@ static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos)
|
||||||
{
|
{
|
||||||
struct rb_node *n;
|
struct rb_node *n;
|
||||||
|
|
||||||
n = key_serial_next(v);
|
n = key_serial_next(p, v);
|
||||||
if (n)
|
if (n)
|
||||||
*_pos = key_node_serial(n);
|
*_pos = key_node_serial(n);
|
||||||
return n;
|
return n;
|
||||||
|
@ -254,8 +254,8 @@ static int proc_keys_show(struct seq_file *m, void *v)
|
||||||
atomic_read(&key->usage),
|
atomic_read(&key->usage),
|
||||||
xbuf,
|
xbuf,
|
||||||
key->perm,
|
key->perm,
|
||||||
key->uid,
|
from_kuid_munged(seq_user_ns(m), key->uid),
|
||||||
key->gid,
|
from_kgid_munged(seq_user_ns(m), key->gid),
|
||||||
key->type->name);
|
key->type->name);
|
||||||
|
|
||||||
#undef showflag
|
#undef showflag
|
||||||
|
@ -270,26 +270,26 @@ static int proc_keys_show(struct seq_file *m, void *v)
|
||||||
|
|
||||||
#endif /* CONFIG_KEYS_DEBUG_PROC_KEYS */
|
#endif /* CONFIG_KEYS_DEBUG_PROC_KEYS */
|
||||||
|
|
||||||
static struct rb_node *__key_user_next(struct rb_node *n)
|
static struct rb_node *__key_user_next(struct user_namespace *user_ns, struct rb_node *n)
|
||||||
{
|
{
|
||||||
while (n) {
|
while (n) {
|
||||||
struct key_user *user = rb_entry(n, struct key_user, node);
|
struct key_user *user = rb_entry(n, struct key_user, node);
|
||||||
if (user->user_ns == current_user_ns())
|
if (kuid_has_mapping(user_ns, user->uid))
|
||||||
break;
|
break;
|
||||||
n = rb_next(n);
|
n = rb_next(n);
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct rb_node *key_user_next(struct rb_node *n)
|
static struct rb_node *key_user_next(struct user_namespace *user_ns, struct rb_node *n)
|
||||||
{
|
{
|
||||||
return __key_user_next(rb_next(n));
|
return __key_user_next(user_ns, rb_next(n));
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct rb_node *key_user_first(struct rb_root *r)
|
static struct rb_node *key_user_first(struct user_namespace *user_ns, struct rb_root *r)
|
||||||
{
|
{
|
||||||
struct rb_node *n = rb_first(r);
|
struct rb_node *n = rb_first(r);
|
||||||
return __key_user_next(n);
|
return __key_user_next(user_ns, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -309,10 +309,10 @@ static void *proc_key_users_start(struct seq_file *p, loff_t *_pos)
|
||||||
|
|
||||||
spin_lock(&key_user_lock);
|
spin_lock(&key_user_lock);
|
||||||
|
|
||||||
_p = key_user_first(&key_user_tree);
|
_p = key_user_first(seq_user_ns(p), &key_user_tree);
|
||||||
while (pos > 0 && _p) {
|
while (pos > 0 && _p) {
|
||||||
pos--;
|
pos--;
|
||||||
_p = key_user_next(_p);
|
_p = key_user_next(seq_user_ns(p), _p);
|
||||||
}
|
}
|
||||||
|
|
||||||
return _p;
|
return _p;
|
||||||
|
@ -321,7 +321,7 @@ static void *proc_key_users_start(struct seq_file *p, loff_t *_pos)
|
||||||
static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos)
|
static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos)
|
||||||
{
|
{
|
||||||
(*_pos)++;
|
(*_pos)++;
|
||||||
return key_user_next((struct rb_node *)v);
|
return key_user_next(seq_user_ns(p), (struct rb_node *)v);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void proc_key_users_stop(struct seq_file *p, void *v)
|
static void proc_key_users_stop(struct seq_file *p, void *v)
|
||||||
|
@ -334,13 +334,13 @@ static int proc_key_users_show(struct seq_file *m, void *v)
|
||||||
{
|
{
|
||||||
struct rb_node *_p = v;
|
struct rb_node *_p = v;
|
||||||
struct key_user *user = rb_entry(_p, struct key_user, node);
|
struct key_user *user = rb_entry(_p, struct key_user, node);
|
||||||
unsigned maxkeys = (user->uid == 0) ?
|
unsigned maxkeys = uid_eq(user->uid, GLOBAL_ROOT_UID) ?
|
||||||
key_quota_root_maxkeys : key_quota_maxkeys;
|
key_quota_root_maxkeys : key_quota_maxkeys;
|
||||||
unsigned maxbytes = (user->uid == 0) ?
|
unsigned maxbytes = uid_eq(user->uid, GLOBAL_ROOT_UID) ?
|
||||||
key_quota_root_maxbytes : key_quota_maxbytes;
|
key_quota_root_maxbytes : key_quota_maxbytes;
|
||||||
|
|
||||||
seq_printf(m, "%5u: %5d %d/%d %d/%d %d/%d\n",
|
seq_printf(m, "%5u: %5d %d/%d %d/%d %d/%d\n",
|
||||||
user->uid,
|
from_kuid_munged(seq_user_ns(m), user->uid),
|
||||||
atomic_read(&user->usage),
|
atomic_read(&user->usage),
|
||||||
atomic_read(&user->nkeys),
|
atomic_read(&user->nkeys),
|
||||||
atomic_read(&user->nikeys),
|
atomic_read(&user->nikeys),
|
||||||
|
|
|
@ -34,8 +34,7 @@ struct key_user root_key_user = {
|
||||||
.lock = __SPIN_LOCK_UNLOCKED(root_key_user.lock),
|
.lock = __SPIN_LOCK_UNLOCKED(root_key_user.lock),
|
||||||
.nkeys = ATOMIC_INIT(2),
|
.nkeys = ATOMIC_INIT(2),
|
||||||
.nikeys = ATOMIC_INIT(2),
|
.nikeys = ATOMIC_INIT(2),
|
||||||
.uid = 0,
|
.uid = GLOBAL_ROOT_UID,
|
||||||
.user_ns = &init_user_ns,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -48,11 +47,13 @@ int install_user_keyrings(void)
|
||||||
struct key *uid_keyring, *session_keyring;
|
struct key *uid_keyring, *session_keyring;
|
||||||
char buf[20];
|
char buf[20];
|
||||||
int ret;
|
int ret;
|
||||||
|
uid_t uid;
|
||||||
|
|
||||||
cred = current_cred();
|
cred = current_cred();
|
||||||
user = cred->user;
|
user = cred->user;
|
||||||
|
uid = from_kuid(cred->user_ns, user->uid);
|
||||||
|
|
||||||
kenter("%p{%u}", user, user->uid);
|
kenter("%p{%u}", user, uid);
|
||||||
|
|
||||||
if (user->uid_keyring) {
|
if (user->uid_keyring) {
|
||||||
kleave(" = 0 [exist]");
|
kleave(" = 0 [exist]");
|
||||||
|
@ -67,11 +68,11 @@ int install_user_keyrings(void)
|
||||||
* - there may be one in existence already as it may have been
|
* - there may be one in existence already as it may have been
|
||||||
* pinned by a session, but the user_struct pointing to it
|
* pinned by a session, but the user_struct pointing to it
|
||||||
* may have been destroyed by setuid */
|
* may have been destroyed by setuid */
|
||||||
sprintf(buf, "_uid.%u", user->uid);
|
sprintf(buf, "_uid.%u", uid);
|
||||||
|
|
||||||
uid_keyring = find_keyring_by_name(buf, true);
|
uid_keyring = find_keyring_by_name(buf, true);
|
||||||
if (IS_ERR(uid_keyring)) {
|
if (IS_ERR(uid_keyring)) {
|
||||||
uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1,
|
uid_keyring = keyring_alloc(buf, user->uid, INVALID_GID,
|
||||||
cred, KEY_ALLOC_IN_QUOTA,
|
cred, KEY_ALLOC_IN_QUOTA,
|
||||||
NULL);
|
NULL);
|
||||||
if (IS_ERR(uid_keyring)) {
|
if (IS_ERR(uid_keyring)) {
|
||||||
|
@ -82,12 +83,12 @@ int install_user_keyrings(void)
|
||||||
|
|
||||||
/* get a default session keyring (which might also exist
|
/* get a default session keyring (which might also exist
|
||||||
* already) */
|
* already) */
|
||||||
sprintf(buf, "_uid_ses.%u", user->uid);
|
sprintf(buf, "_uid_ses.%u", uid);
|
||||||
|
|
||||||
session_keyring = find_keyring_by_name(buf, true);
|
session_keyring = find_keyring_by_name(buf, true);
|
||||||
if (IS_ERR(session_keyring)) {
|
if (IS_ERR(session_keyring)) {
|
||||||
session_keyring =
|
session_keyring =
|
||||||
keyring_alloc(buf, user->uid, (gid_t) -1,
|
keyring_alloc(buf, user->uid, INVALID_GID,
|
||||||
cred, KEY_ALLOC_IN_QUOTA, NULL);
|
cred, KEY_ALLOC_IN_QUOTA, NULL);
|
||||||
if (IS_ERR(session_keyring)) {
|
if (IS_ERR(session_keyring)) {
|
||||||
ret = PTR_ERR(session_keyring);
|
ret = PTR_ERR(session_keyring);
|
||||||
|
|
|
@ -139,8 +139,8 @@ static int call_sbin_request_key(struct key_construction *cons,
|
||||||
goto error_link;
|
goto error_link;
|
||||||
|
|
||||||
/* record the UID and GID */
|
/* record the UID and GID */
|
||||||
sprintf(uid_str, "%d", cred->fsuid);
|
sprintf(uid_str, "%d", from_kuid(&init_user_ns, cred->fsuid));
|
||||||
sprintf(gid_str, "%d", cred->fsgid);
|
sprintf(gid_str, "%d", from_kgid(&init_user_ns, cred->fsgid));
|
||||||
|
|
||||||
/* we say which key is under construction */
|
/* we say which key is under construction */
|
||||||
sprintf(key_str, "%d", key->serial);
|
sprintf(key_str, "%d", key->serial);
|
||||||
|
@ -442,7 +442,7 @@ static struct key *construct_key_and_link(struct key_type *type,
|
||||||
|
|
||||||
kenter("");
|
kenter("");
|
||||||
|
|
||||||
user = key_user_lookup(current_fsuid(), current_user_ns());
|
user = key_user_lookup(current_fsuid());
|
||||||
if (!user)
|
if (!user)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue