diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-02 20:11:09 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-02 20:11:09 +0200 |
commit | 437589a74b6a590d175f86cf9f7b2efcee7765e7 (patch) | |
tree | 37bf8635b1356d80ef002b00e84f3faf3d555a63 /security | |
parent | Merge branch 'for-3.7-hierarchy' of git://git.kernel.org/pub/scm/linux/kernel... (diff) | |
parent | userns: Convert the ufs filesystem to use kuid/kgid where appropriate (diff) | |
download | linux-437589a74b6a590d175f86cf9f7b2efcee7765e7.tar.xz linux-437589a74b6a590d175f86cf9f7b2efcee7765e7.zip |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace
Pull user namespace changes from Eric Biederman:
"This is a mostly modest set of changes to enable basic user namespace
support. This allows the code to code to compile with user namespaces
enabled and removes the assumption there is only the initial user
namespace. Everything is converted except for the most complex of the
filesystems: autofs4, 9p, afs, ceph, cifs, coda, fuse, gfs2, ncpfs,
nfs, ocfs2 and xfs as those patches need a bit more review.
The strategy is to push kuid_t and kgid_t values are far down into
subsystems and filesystems as reasonable. Leaving the make_kuid and
from_kuid operations to happen at the edge of userspace, as the values
come off the disk, and as the values come in from the network.
Letting compile type incompatible compile errors (present when user
namespaces are enabled) guide me to find the issues.
The most tricky areas have been the places where we had an implicit
union of uid and gid values and were storing them in an unsigned int.
Those places were converted into explicit unions. I made certain to
handle those places with simple trivial patches.
Out of that work I discovered we have generic interfaces for storing
quota by projid. I had never heard of the project identifiers before.
Adding full user namespace support for project identifiers accounts
for most of the code size growth in my git tree.
Ultimately there will be work to relax privlige checks from
"capable(FOO)" to "ns_capable(user_ns, FOO)" where it is safe allowing
root in a user names to do those things that today we only forbid to
non-root users because it will confuse suid root applications.
While I was pushing kuid_t and kgid_t changes deep into the audit code
I made a few other cleanups. I capitalized on the fact we process
netlink messages in the context of the message sender. I removed
usage of NETLINK_CRED, and started directly using current->tty.
Some of these patches have also made it into maintainer trees, with no
problems from identical code from different trees showing up in
linux-next.
After reading through all of this code I feel like I might be able to
win a game of kernel trivial pursuit."
Fix up some fairly trivial conflicts in netfilter uid/git logging code.
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace: (107 commits)
userns: Convert the ufs filesystem to use kuid/kgid where appropriate
userns: Convert the udf filesystem to use kuid/kgid where appropriate
userns: Convert ubifs to use kuid/kgid
userns: Convert squashfs to use kuid/kgid where appropriate
userns: Convert reiserfs to use kuid and kgid where appropriate
userns: Convert jfs to use kuid/kgid where appropriate
userns: Convert jffs2 to use kuid and kgid where appropriate
userns: Convert hpfs to use kuid and kgid where appropriate
userns: Convert btrfs to use kuid/kgid where appropriate
userns: Convert bfs to use kuid/kgid where appropriate
userns: Convert affs to use kuid/kgid wherwe appropriate
userns: On alpha modify linux_to_osf_stat to use convert from kuids and kgids
userns: On ia64 deal with current_uid and current_gid being kuid and kgid
userns: On ppc convert current_uid from a kuid before printing.
userns: Convert s390 getting uid and gid system calls to use kuid and kgid
userns: Convert s390 hypfs to use kuid and kgid where appropriate
userns: Convert binder ipc to use kuids
userns: Teach security_path_chown to take kuids and kgids
userns: Add user namespace support to IMA
userns: Convert EVM to deal with kuids and kgids in it's hmac computation
...
Diffstat (limited to 'security')
-rw-r--r-- | security/apparmor/domain.c | 4 | ||||
-rw-r--r-- | security/apparmor/file.c | 12 | ||||
-rw-r--r-- | security/apparmor/include/audit.h | 2 | ||||
-rw-r--r-- | security/apparmor/include/file.h | 4 | ||||
-rw-r--r-- | security/apparmor/lsm.c | 2 | ||||
-rw-r--r-- | security/capability.c | 2 | ||||
-rw-r--r-- | security/integrity/evm/evm_crypto.c | 4 | ||||
-rw-r--r-- | security/integrity/ima/ima_audit.c | 5 | ||||
-rw-r--r-- | security/integrity/ima/ima_policy.c | 14 | ||||
-rw-r--r-- | security/keys/internal.h | 6 | ||||
-rw-r--r-- | security/keys/key.c | 23 | ||||
-rw-r--r-- | security/keys/keyctl.c | 50 | ||||
-rw-r--r-- | security/keys/keyring.c | 4 | ||||
-rw-r--r-- | security/keys/permission.c | 14 | ||||
-rw-r--r-- | security/keys/proc.c | 44 | ||||
-rw-r--r-- | security/keys/process_keys.c | 15 | ||||
-rw-r--r-- | security/keys/request_key.c | 6 | ||||
-rw-r--r-- | security/security.c | 2 | ||||
-rw-r--r-- | security/selinux/selinuxfs.c | 6 | ||||
-rw-r--r-- | security/selinux/ss/services.c | 2 | ||||
-rw-r--r-- | security/tomoyo/audit.c | 23 | ||||
-rw-r--r-- | security/tomoyo/common.c | 4 | ||||
-rw-r--r-- | security/tomoyo/common.h | 4 | ||||
-rw-r--r-- | security/tomoyo/condition.c | 20 | ||||
-rw-r--r-- | security/tomoyo/tomoyo.c | 12 |
25 files changed, 148 insertions, 136 deletions
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index b81ea10a17a3..60f0c76a27d3 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -721,7 +721,7 @@ audit: if (!permtest) error = aa_audit_file(profile, &perms, GFP_KERNEL, OP_CHANGE_HAT, AA_MAY_CHANGEHAT, NULL, - target, 0, info, error); + target, GLOBAL_ROOT_UID, info, error); out: aa_put_profile(hat); @@ -848,7 +848,7 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec, audit: if (!permtest) error = aa_audit_file(profile, &perms, GFP_KERNEL, op, request, - name, hname, 0, info, error); + name, hname, GLOBAL_ROOT_UID, info, error); aa_put_namespace(ns); aa_put_profile(target); diff --git a/security/apparmor/file.c b/security/apparmor/file.c index cf19d4093ca4..cd21ec5b90af 100644 --- a/security/apparmor/file.c +++ b/security/apparmor/file.c @@ -65,7 +65,7 @@ static void audit_file_mask(struct audit_buffer *ab, u32 mask) static void file_audit_cb(struct audit_buffer *ab, void *va) { struct common_audit_data *sa = va; - uid_t fsuid = current_fsuid(); + kuid_t fsuid = current_fsuid(); if (sa->aad->fs.request & AA_AUDIT_FILE_MASK) { audit_log_format(ab, " requested_mask="); @@ -76,8 +76,10 @@ static void file_audit_cb(struct audit_buffer *ab, void *va) audit_file_mask(ab, sa->aad->fs.denied); } if (sa->aad->fs.request & AA_AUDIT_FILE_MASK) { - audit_log_format(ab, " fsuid=%d", fsuid); - audit_log_format(ab, " ouid=%d", sa->aad->fs.ouid); + audit_log_format(ab, " fsuid=%d", + from_kuid(&init_user_ns, fsuid)); + audit_log_format(ab, " ouid=%d", + from_kuid(&init_user_ns, sa->aad->fs.ouid)); } if (sa->aad->fs.target) { @@ -103,7 +105,7 @@ static void file_audit_cb(struct audit_buffer *ab, void *va) */ int aa_audit_file(struct aa_profile *profile, struct file_perms *perms, gfp_t gfp, int op, u32 request, const char *name, - const char *target, uid_t ouid, const char *info, int error) + const char *target, kuid_t ouid, const char *info, int error) { int type = AUDIT_APPARMOR_AUTO; struct common_audit_data sa; @@ -201,7 +203,7 @@ static struct file_perms compute_perms(struct aa_dfa *dfa, unsigned int state, */ perms.kill = 0; - if (current_fsuid() == cond->uid) { + if (uid_eq(current_fsuid(), cond->uid)) { perms.allow = map_old_perms(dfa_user_allow(dfa, state)); perms.audit = map_old_perms(dfa_user_audit(dfa, state)); perms.quiet = map_old_perms(dfa_user_quiet(dfa, state)); diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h index 4b7e18951aea..69d8cae634e7 100644 --- a/security/apparmor/include/audit.h +++ b/security/apparmor/include/audit.h @@ -125,7 +125,7 @@ struct apparmor_audit_data { const char *target; u32 request; u32 denied; - uid_t ouid; + kuid_t ouid; } fs; }; }; diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h index f98fd4701d80..967b2deda376 100644 --- a/security/apparmor/include/file.h +++ b/security/apparmor/include/file.h @@ -71,7 +71,7 @@ struct path; /* need to make conditional which ones are being set */ struct path_cond { - uid_t uid; + kuid_t uid; umode_t mode; }; @@ -146,7 +146,7 @@ static inline u16 dfa_map_xindex(u16 mask) int aa_audit_file(struct aa_profile *profile, struct file_perms *perms, gfp_t gfp, int op, u32 request, const char *name, - const char *target, uid_t ouid, const char *info, int error); + const char *target, kuid_t ouid, const char *info, int error); /** * struct aa_file_rules - components used for file rule permissions diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 8ea39aabe948..8c2a7f6b35e2 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -352,7 +352,7 @@ static int apparmor_path_chmod(struct path *path, umode_t mode) return common_perm_mnt_dentry(OP_CHMOD, path->mnt, path->dentry, AA_MAY_CHMOD); } -static int apparmor_path_chown(struct path *path, uid_t uid, gid_t gid) +static int apparmor_path_chown(struct path *path, kuid_t uid, kgid_t gid) { struct path_cond cond = { path->dentry->d_inode->i_uid, path->dentry->d_inode->i_mode diff --git a/security/capability.c b/security/capability.c index 61095df8b89a..a40aac677c72 100644 --- a/security/capability.c +++ b/security/capability.c @@ -284,7 +284,7 @@ static int cap_path_chmod(struct path *path, umode_t mode) return 0; } -static int cap_path_chown(struct path *path, uid_t uid, gid_t gid) +static int cap_path_chown(struct path *path, kuid_t uid, kgid_t gid) { return 0; } diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c index 49a464f5595b..dfb26918699c 100644 --- a/security/integrity/evm/evm_crypto.c +++ b/security/integrity/evm/evm_crypto.c @@ -106,8 +106,8 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode, memset(&hmac_misc, 0, sizeof hmac_misc); hmac_misc.ino = inode->i_ino; hmac_misc.generation = inode->i_generation; - hmac_misc.uid = inode->i_uid; - hmac_misc.gid = inode->i_gid; + hmac_misc.uid = from_kuid(&init_user_ns, inode->i_uid); + hmac_misc.gid = from_kgid(&init_user_ns, inode->i_gid); hmac_misc.mode = inode->i_mode; crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof hmac_misc); crypto_shash_final(desc, digest); diff --git a/security/integrity/ima/ima_audit.c b/security/integrity/ima/ima_audit.c index 7a57f6769e9c..c586faae8fd6 100644 --- a/security/integrity/ima/ima_audit.c +++ b/security/integrity/ima/ima_audit.c @@ -39,8 +39,9 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode, ab = audit_log_start(current->audit_context, GFP_KERNEL, audit_msgno); audit_log_format(ab, "pid=%d uid=%u auid=%u ses=%u", - current->pid, current_cred()->uid, - audit_get_loginuid(current), + current->pid, + from_kuid(&init_user_ns, current_cred()->uid), + from_kuid(&init_user_ns, audit_get_loginuid(current)), audit_get_sessionid(current)); audit_log_task_context(ab); audit_log_format(ab, " op="); diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 1a9583008aae..c84df05180cb 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -39,7 +39,7 @@ struct ima_measure_rule_entry { enum ima_hooks func; int mask; unsigned long fsmagic; - uid_t uid; + kuid_t uid; struct { void *rule; /* LSM file metadata specific */ int type; /* audit type */ @@ -71,7 +71,7 @@ static struct ima_measure_rule_entry default_rules[] = { .flags = IMA_FUNC | IMA_MASK}, {.action = MEASURE,.func = BPRM_CHECK,.mask = MAY_EXEC, .flags = IMA_FUNC | IMA_MASK}, - {.action = MEASURE,.func = FILE_CHECK,.mask = MAY_READ,.uid = 0, + {.action = MEASURE,.func = FILE_CHECK,.mask = MAY_READ,.uid = GLOBAL_ROOT_UID, .flags = IMA_FUNC | IMA_MASK | IMA_UID}, }; @@ -112,7 +112,7 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule, if ((rule->flags & IMA_FSMAGIC) && rule->fsmagic != inode->i_sb->s_magic) return false; - if ((rule->flags & IMA_UID) && rule->uid != cred->uid) + if ((rule->flags & IMA_UID) && !uid_eq(rule->uid, cred->uid)) return false; for (i = 0; i < MAX_LSM_RULES; i++) { int rc = 0; @@ -277,7 +277,7 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_RULE); - entry->uid = -1; + entry->uid = INVALID_UID; entry->action = UNKNOWN; while ((p = strsep(&rule, " \t")) != NULL) { substring_t args[MAX_OPT_ARGS]; @@ -361,15 +361,15 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) case Opt_uid: ima_log_string(ab, "uid", args[0].from); - if (entry->uid != -1) { + if (uid_valid(entry->uid)) { result = -EINVAL; break; } result = strict_strtoul(args[0].from, 10, &lnum); if (!result) { - entry->uid = (uid_t) lnum; - if (entry->uid != lnum) + entry->uid = make_kuid(current_user_ns(), (uid_t)lnum); + if (!uid_valid(entry->uid) || (((uid_t)lnum) != lnum)) result = -EINVAL; else entry->flags |= IMA_UID; diff --git a/security/keys/internal.h b/security/keys/internal.h index 22ff05269e3d..8bbefc3b55d4 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -52,8 +52,7 @@ struct key_user { atomic_t usage; /* for accessing qnkeys & qnbytes */ atomic_t nkeys; /* number of keys */ atomic_t nikeys; /* number of instantiated keys */ - uid_t uid; - struct user_namespace *user_ns; + kuid_t uid; int qnkeys; /* number of keys 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 struct key_user root_key_user; -extern struct key_user *key_user_lookup(uid_t uid, - struct user_namespace *user_ns); +extern struct key_user *key_user_lookup(kuid_t uid); extern void key_user_put(struct key_user *user); /* diff --git a/security/keys/key.c b/security/keys/key.c index 3cbe3529c418..a30e92734905 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -18,7 +18,6 @@ #include <linux/workqueue.h> #include <linux/random.h> #include <linux/err.h> -#include <linux/user_namespace.h> #include "internal.h" 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 * 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 rb_node *parent = NULL; @@ -67,13 +66,9 @@ try_again: parent = *p; user = rb_entry(parent, struct key_user, node); - if (uid < user->uid) + if (uid_lt(uid, user->uid)) p = &(*p)->rb_left; - else if (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) + else if (uid_gt(uid, user->uid)) p = &(*p)->rb_right; else goto found; @@ -102,7 +97,6 @@ try_again: atomic_set(&candidate->nkeys, 0); atomic_set(&candidate->nikeys, 0); candidate->uid = uid; - candidate->user_ns = get_user_ns(user_ns); candidate->qnkeys = 0; candidate->qnbytes = 0; 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)) { rb_erase(&user->node, &key_user_tree); spin_unlock(&key_user_lock); - put_user_ns(user->user_ns); kfree(user); } @@ -229,7 +222,7 @@ serial_exists: * key_alloc() calls don't race with module unloading. */ 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) { 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; /* get hold of the key tracking for this user */ - user = key_user_lookup(uid, cred->user_ns); + user = key_user_lookup(uid); if (!user) goto no_memory_1; /* check that the user's quota permits allocation of another key and * its description */ 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; - unsigned maxbytes = (uid == 0) ? + unsigned maxbytes = uid_eq(uid, GLOBAL_ROOT_UID) ? key_quota_root_maxbytes : key_quota_maxbytes; spin_lock(&user->lock); @@ -380,7 +373,7 @@ int key_payload_reserve(struct key *key, size_t datalen) /* contemplate the quota adjustment */ 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; spin_lock(&key->user->lock); diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 6cfc6478863e..305ecb76519c 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -569,8 +569,8 @@ okay: ret = snprintf(tmpbuf, PAGE_SIZE - 1, "%s;%d;%d;%08x;%s", key->type->name, - key->uid, - key->gid, + from_kuid_munged(current_user_ns(), key->uid), + from_kgid_munged(current_user_ns(), key->gid), key->perm, key->description ?: ""); @@ -766,15 +766,25 @@ error: * * 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 *key; key_ref_t key_ref; 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; - if (uid == (uid_t) -1 && gid == (gid_t) -1) + if (user == (uid_t) -1 && group == (gid_t) -1) goto error; 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)) { /* 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; /* only the sysadmin can set the key's GID to a group other * 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; } /* change the UID */ - if (uid != (uid_t) -1 && uid != key->uid) { + if (user != (uid_t) -1 && !uid_eq(uid, key->uid)) { ret = -ENOMEM; - newowner = key_user_lookup(uid, current_user_ns()); + newowner = key_user_lookup(uid); if (!newowner) goto error_put; /* transfer the quota burden to the new user */ 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; - unsigned maxbytes = (uid == 0) ? + unsigned maxbytes = uid_eq(uid, GLOBAL_ROOT_UID) ? key_quota_root_maxbytes : key_quota_maxbytes; 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 */ - if (gid != (gid_t) -1) + if (group != (gid_t) -1) key->gid = gid; ret = 0; @@ -897,7 +907,7 @@ long keyctl_setperm_key(key_serial_t id, key_perm_t perm) down_write(&key->sem); /* 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; ret = 0; } @@ -1506,18 +1516,18 @@ long keyctl_session_to_parent(void) /* the parent must have the same effective ownership and mustn't be * SUID/SGID */ - if (pcred->uid != mycred->euid || - pcred->euid != mycred->euid || - pcred->suid != mycred->euid || - pcred->gid != mycred->egid || - pcred->egid != mycred->egid || - pcred->sgid != mycred->egid) + if (!uid_eq(pcred->uid, mycred->euid) || + !uid_eq(pcred->euid, mycred->euid) || + !uid_eq(pcred->suid, mycred->euid) || + !gid_eq(pcred->gid, mycred->egid) || + !gid_eq(pcred->egid, mycred->egid) || + !gid_eq(pcred->sgid, mycred->egid)) goto unlock; /* the keyrings must have the same UID */ if ((pcred->tgcred->session_keyring && - pcred->tgcred->session_keyring->uid != mycred->euid) || - mycred->tgcred->session_keyring->uid != mycred->euid) + !uid_eq(pcred->tgcred->session_keyring->uid, mycred->euid)) || + !uid_eq(mycred->tgcred->session_keyring->uid, mycred->euid)) goto unlock; /* cancel an already pending keyring replacement */ diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 81e7852d281d..a5f5c4b6edc5 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c @@ -256,7 +256,7 @@ error: /* * 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, struct key *dest) { @@ -612,7 +612,7 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check) &keyring_name_hash[bucket], type_data.link ) { - if (keyring->user->user_ns != current_user_ns()) + if (!kuid_has_mapping(current_user_ns(), keyring->user->uid)) continue; if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) diff --git a/security/keys/permission.c b/security/keys/permission.c index 0b4d019e027d..efcc0c855a0d 100644 --- a/security/keys/permission.c +++ b/security/keys/permission.c @@ -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); - if (key->user->user_ns != cred->user_ns) - goto use_other_perms; - /* 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; goto use_these_perms; } /* use the third 8-bits of permissions for keys the caller has a group * membership in common with */ - if (key->gid != -1 && key->perm & KEY_GRP_ALL) { - if (key->gid == cred->fsgid) { + if (gid_valid(key->gid) && key->perm & KEY_GRP_ALL) { + if (gid_eq(key->gid, cred->fsgid)) { kperm = key->perm >> 8; goto use_these_perms; } - ret = groups_search(cred->group_info, - make_kgid(current_user_ns(), key->gid)); + ret = groups_search(cred->group_info, key->gid); if (ret) { kperm = key->perm >> 8; goto use_these_perms; } } -use_other_perms: - /* otherwise use the least-significant 8-bits */ kperm = key->perm; diff --git a/security/keys/proc.c b/security/keys/proc.c index 30d1ddfd9cef..217b6855e815 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c @@ -88,14 +88,14 @@ __initcall(key_proc_init); */ #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); while (n) { 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; 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); } -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 key *minkey = NULL; @@ -132,7 +132,7 @@ static struct key *find_ge_key(key_serial_t id) return NULL; for (;;) { - if (minkey->user->user_ns == user_ns) + if (kuid_has_mapping(user_ns, minkey->user->uid)) return minkey; n = rb_next(&minkey->serial_node); if (!n) @@ -151,7 +151,7 @@ static void *proc_keys_start(struct seq_file *p, loff_t *_pos) if (*_pos > INT_MAX) return NULL; - key = find_ge_key(pos); + key = find_ge_key(p, pos); if (!key) return NULL; *_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; - n = key_serial_next(v); + n = key_serial_next(p, v); if (n) *_pos = key_node_serial(n); return n; @@ -254,8 +254,8 @@ static int proc_keys_show(struct seq_file *m, void *v) atomic_read(&key->usage), xbuf, key->perm, - key->uid, - key->gid, + from_kuid_munged(seq_user_ns(m), key->uid), + from_kgid_munged(seq_user_ns(m), key->gid), key->type->name); #undef showflag @@ -270,26 +270,26 @@ static int proc_keys_show(struct seq_file *m, void *v) #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) { 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; n = rb_next(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); - 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); - _p = key_user_first(&key_user_tree); + _p = key_user_first(seq_user_ns(p), &key_user_tree); while (pos > 0 && _p) { pos--; - _p = key_user_next(_p); + _p = key_user_next(seq_user_ns(p), _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) { (*_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) @@ -334,13 +334,13 @@ static int proc_key_users_show(struct seq_file *m, void *v) { struct rb_node *_p = v; 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; - unsigned maxbytes = (user->uid == 0) ? + unsigned maxbytes = uid_eq(user->uid, GLOBAL_ROOT_UID) ? key_quota_root_maxbytes : key_quota_maxbytes; 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->nkeys), atomic_read(&user->nikeys), diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 54339cfd6734..a58f712605d8 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c @@ -34,8 +34,7 @@ struct key_user root_key_user = { .lock = __SPIN_LOCK_UNLOCKED(root_key_user.lock), .nkeys = ATOMIC_INIT(2), .nikeys = ATOMIC_INIT(2), - .uid = 0, - .user_ns = &init_user_ns, + .uid = GLOBAL_ROOT_UID, }; /* @@ -48,11 +47,13 @@ int install_user_keyrings(void) struct key *uid_keyring, *session_keyring; char buf[20]; int ret; + uid_t uid; cred = current_cred(); 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) { kleave(" = 0 [exist]"); @@ -67,11 +68,11 @@ int install_user_keyrings(void) * - there may be one in existence already as it may have been * pinned by a session, but the user_struct pointing to it * 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); 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, NULL); if (IS_ERR(uid_keyring)) { @@ -82,12 +83,12 @@ int install_user_keyrings(void) /* get a default session keyring (which might also exist * already) */ - sprintf(buf, "_uid_ses.%u", user->uid); + sprintf(buf, "_uid_ses.%u", uid); session_keyring = find_keyring_by_name(buf, true); if (IS_ERR(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); if (IS_ERR(session_keyring)) { ret = PTR_ERR(session_keyring); diff --git a/security/keys/request_key.c b/security/keys/request_key.c index 000e75017520..66e21184b559 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c @@ -139,8 +139,8 @@ static int call_sbin_request_key(struct key_construction *cons, goto error_link; /* record the UID and GID */ - sprintf(uid_str, "%d", cred->fsuid); - sprintf(gid_str, "%d", cred->fsgid); + sprintf(uid_str, "%d", from_kuid(&init_user_ns, cred->fsuid)); + sprintf(gid_str, "%d", from_kgid(&init_user_ns, cred->fsgid)); /* we say which key is under construction */ sprintf(key_str, "%d", key->serial); @@ -442,7 +442,7 @@ static struct key *construct_key_and_link(struct key_type *type, kenter(""); - user = key_user_lookup(current_fsuid(), current_user_ns()); + user = key_user_lookup(current_fsuid()); if (!user) return ERR_PTR(-ENOMEM); diff --git a/security/security.c b/security/security.c index 860aeb349cb3..f9a2f2ef2454 100644 --- a/security/security.c +++ b/security/security.c @@ -434,7 +434,7 @@ int security_path_chmod(struct path *path, umode_t mode) return security_ops->path_chmod(path, mode); } -int security_path_chown(struct path *path, uid_t uid, gid_t gid) +int security_path_chown(struct path *path, kuid_t uid, kgid_t gid) { if (unlikely(IS_PRIVATE(path->dentry->d_inode))) return 0; diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 298e695d6822..55af8c5b57e6 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -174,7 +174,7 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf, audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS, "enforcing=%d old_enforcing=%d auid=%u ses=%u", new_value, selinux_enforcing, - audit_get_loginuid(current), + from_kuid(&init_user_ns, audit_get_loginuid(current)), audit_get_sessionid(current)); selinux_enforcing = new_value; if (selinux_enforcing) @@ -305,7 +305,7 @@ static ssize_t sel_write_disable(struct file *file, const char __user *buf, goto out; audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS, "selinux=0 auid=%u ses=%u", - audit_get_loginuid(current), + from_kuid(&init_user_ns, audit_get_loginuid(current)), audit_get_sessionid(current)); } @@ -551,7 +551,7 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf, out1: audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_POLICY_LOAD, "policy loaded auid=%u ses=%u", - audit_get_loginuid(current), + from_kuid(&init_user_ns, audit_get_loginuid(current)), audit_get_sessionid(current)); out: mutex_unlock(&sel_mutex); diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 4321b8fc8863..b4feecc3fe01 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -2440,7 +2440,7 @@ int security_set_bools(int len, int *values) sym_name(&policydb, SYM_BOOLS, i), !!values[i], policydb.bool_val_to_struct[i]->state, - audit_get_loginuid(current), + from_kuid(&init_user_ns, audit_get_loginuid(current)), audit_get_sessionid(current)); } if (values[i]) diff --git a/security/tomoyo/audit.c b/security/tomoyo/audit.c index 7ef9fa3e37e0..c1b00375c9ad 100644 --- a/security/tomoyo/audit.c +++ b/security/tomoyo/audit.c @@ -168,9 +168,14 @@ static char *tomoyo_print_header(struct tomoyo_request_info *r) stamp.day, stamp.hour, stamp.min, stamp.sec, r->profile, tomoyo_mode[r->mode], tomoyo_yesno(r->granted), gpid, tomoyo_sys_getpid(), tomoyo_sys_getppid(), - current_uid(), current_gid(), current_euid(), - current_egid(), current_suid(), current_sgid(), - current_fsuid(), current_fsgid()); + from_kuid(&init_user_ns, current_uid()), + from_kgid(&init_user_ns, current_gid()), + from_kuid(&init_user_ns, current_euid()), + from_kgid(&init_user_ns, current_egid()), + from_kuid(&init_user_ns, current_suid()), + from_kgid(&init_user_ns, current_sgid()), + from_kuid(&init_user_ns, current_fsuid()), + from_kgid(&init_user_ns, current_fsgid())); if (!obj) goto no_obj_info; if (!obj->validate_done) { @@ -191,15 +196,19 @@ static char *tomoyo_print_header(struct tomoyo_request_info *r) tomoyo_buffer_len - 1 - pos, " path%u.parent={ uid=%u gid=%u " "ino=%lu perm=0%o }", (i >> 1) + 1, - stat->uid, stat->gid, (unsigned long) - stat->ino, stat->mode & S_IALLUGO); + from_kuid(&init_user_ns, stat->uid), + from_kgid(&init_user_ns, stat->gid), + (unsigned long)stat->ino, + stat->mode & S_IALLUGO); continue; } pos += snprintf(buffer + pos, tomoyo_buffer_len - 1 - pos, " path%u={ uid=%u gid=%u ino=%lu major=%u" " minor=%u perm=0%o type=%s", (i >> 1) + 1, - stat->uid, stat->gid, (unsigned long) - stat->ino, MAJOR(dev), MINOR(dev), + from_kuid(&init_user_ns, stat->uid), + from_kgid(&init_user_ns, stat->gid), + (unsigned long)stat->ino, + MAJOR(dev), MINOR(dev), mode & S_IALLUGO, tomoyo_filetype(mode)); if (S_ISCHR(mode) || S_ISBLK(mode)) { dev = stat->rdev; diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 2e0f12c62938..f89a0333b813 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -925,7 +925,9 @@ static bool tomoyo_manager(void) if (!tomoyo_policy_loaded) return true; - if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid)) + if (!tomoyo_manage_by_non_root && + (!uid_eq(task->cred->uid, GLOBAL_ROOT_UID) || + !uid_eq(task->cred->euid, GLOBAL_ROOT_UID))) return false; exe = tomoyo_get_exe(); if (!exe) diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 75e4dc1c02a0..af010b62d544 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -561,8 +561,8 @@ struct tomoyo_address_group { /* Subset of "struct stat". Used by conditional ACL and audit logs. */ struct tomoyo_mini_stat { - uid_t uid; - gid_t gid; + kuid_t uid; + kgid_t gid; ino_t ino; umode_t mode; dev_t dev; diff --git a/security/tomoyo/condition.c b/security/tomoyo/condition.c index 986330b8c73e..63681e8be628 100644 --- a/security/tomoyo/condition.c +++ b/security/tomoyo/condition.c @@ -813,28 +813,28 @@ bool tomoyo_condition(struct tomoyo_request_info *r, unsigned long value = 0; switch (index) { case TOMOYO_TASK_UID: - value = current_uid(); + value = from_kuid(&init_user_ns, current_uid()); break; case TOMOYO_TASK_EUID: - value = current_euid(); + value = from_kuid(&init_user_ns, current_euid()); break; case TOMOYO_TASK_SUID: - value = current_suid(); + value = from_kuid(&init_user_ns, current_suid()); break; case TOMOYO_TASK_FSUID: - value = current_fsuid(); + value = from_kuid(&init_user_ns, current_fsuid()); break; case TOMOYO_TASK_GID: - value = current_gid(); + value = from_kgid(&init_user_ns, current_gid()); break; case TOMOYO_TASK_EGID: - value = current_egid(); + value = from_kgid(&init_user_ns, current_egid()); break; case TOMOYO_TASK_SGID: - value = current_sgid(); + value = from_kgid(&init_user_ns, current_sgid()); break; case TOMOYO_TASK_FSGID: - value = current_fsgid(); + value = from_kgid(&init_user_ns, current_fsgid()); break; case TOMOYO_TASK_PID: value = tomoyo_sys_getpid(); @@ -970,13 +970,13 @@ bool tomoyo_condition(struct tomoyo_request_info *r, case TOMOYO_PATH2_UID: case TOMOYO_PATH1_PARENT_UID: case TOMOYO_PATH2_PARENT_UID: - value = stat->uid; + value = from_kuid(&init_user_ns, stat->uid); break; case TOMOYO_PATH1_GID: case TOMOYO_PATH2_GID: case TOMOYO_PATH1_PARENT_GID: case TOMOYO_PATH2_PARENT_GID: - value = stat->gid; + value = from_kgid(&init_user_ns, stat->gid); break; case TOMOYO_PATH1_INO: case TOMOYO_PATH2_INO: diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index c2d04a50f76a..d88eb3a046ed 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -373,13 +373,15 @@ static int tomoyo_path_chmod(struct path *path, umode_t mode) * * Returns 0 on success, negative value otherwise. */ -static int tomoyo_path_chown(struct path *path, uid_t uid, gid_t gid) +static int tomoyo_path_chown(struct path *path, kuid_t uid, kgid_t gid) { int error = 0; - if (uid != (uid_t) -1) - error = tomoyo_path_number_perm(TOMOYO_TYPE_CHOWN, path, uid); - if (!error && gid != (gid_t) -1) - error = tomoyo_path_number_perm(TOMOYO_TYPE_CHGRP, path, gid); + if (uid_valid(uid)) + error = tomoyo_path_number_perm(TOMOYO_TYPE_CHOWN, path, + from_kuid(&init_user_ns, uid)); + if (!error && gid_valid(gid)) + error = tomoyo_path_number_perm(TOMOYO_TYPE_CHGRP, path, + from_kgid(&init_user_ns, gid)); return error; } |