From 9a56c2db49e7349c7963f0ce66c1ef578d44ebd3 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 8 Feb 2012 07:53:04 -0800 Subject: 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 Signed-off-by: Eric W. Biederman --- security/keys/internal.h | 6 ++---- security/keys/key.c | 23 +++++++------------- security/keys/keyctl.c | 50 ++++++++++++++++++++++++++------------------ security/keys/keyring.c | 4 ++-- security/keys/permission.c | 14 ++++--------- security/keys/proc.c | 44 +++++++++++++++++++------------------- security/keys/process_keys.c | 15 ++++++------- security/keys/request_key.c | 6 +++--- 8 files changed, 79 insertions(+), 83 deletions(-) (limited to 'security') 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 50d96d4e06f2..4289c5ba2710 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -18,7 +18,6 @@ #include #include #include -#include #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 3364fbf46807..1ecc0f79906e 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; } @@ -1507,18 +1517,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); -- cgit v1.2.3-58-ga151 From 2db81452931eb51cc739d6e495cf1bd4860c3c99 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 7 Feb 2012 16:33:13 -0800 Subject: userns: Convert apparmor to use kuid and kgid where appropriate Cc: John Johansen Acked-by: Serge Hallyn Signed-off-by: Eric W. Biederman --- init/Kconfig | 1 - security/apparmor/domain.c | 4 ++-- security/apparmor/file.c | 12 +++++++----- security/apparmor/include/audit.h | 2 +- security/apparmor/include/file.h | 4 ++-- 5 files changed, 12 insertions(+), 11 deletions(-) (limited to 'security') diff --git a/init/Kconfig b/init/Kconfig index f31599739f7f..637faf8626cc 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -964,7 +964,6 @@ config UIDGID_CONVERTED # Security modules depends on SECURITY_TOMOYO = n - depends on SECURITY_APPARMOR = n config UIDGID_STRICT_TYPE_CHECKS bool "Require conversions between uid/gids and their internal representation" 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 -- cgit v1.2.3-58-ga151 From 609fcd1b3a55f99667c61609895c83019b21baad Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 7 Feb 2012 16:34:10 -0800 Subject: userns: Convert tomoyo to use kuid and kgid where appropriate Acked-by: Tetsuo Handa Acked-by: Serge Hallyn Signed-off-by: Eric W. Biederman --- init/Kconfig | 3 --- security/tomoyo/audit.c | 23 ++++++++++++++++------- security/tomoyo/common.c | 4 +++- security/tomoyo/common.h | 4 ++-- security/tomoyo/condition.c | 20 ++++++++++---------- 5 files changed, 31 insertions(+), 23 deletions(-) (limited to 'security') diff --git a/init/Kconfig b/init/Kconfig index 637faf8626cc..381f765df923 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -962,9 +962,6 @@ config UIDGID_CONVERTED # The rare drivers that won't build depends on ANDROID_BINDER_IPC = n - # Security modules - depends on SECURITY_TOMOYO = n - config UIDGID_STRICT_TYPE_CHECKS bool "Require conversions between uid/gids and their internal representation" depends on UIDGID_CONVERTED 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: -- cgit v1.2.3-58-ga151 From 581abc09c2205e05256d7f75410345d5392d5098 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 20 Aug 2012 00:09:36 -0700 Subject: userns: Convert selinux to use kuid and kgid where appropriate Cc: Stephen Smalley Cc: James Morris Cc: Eric Paris Signed-off-by: "Eric W. Biederman" --- security/selinux/selinuxfs.c | 6 +++--- security/selinux/ss/services.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'security') 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]) -- cgit v1.2.3-58-ga151 From cf9c93526f4517581a9e8f1c0d9093a4c7748ec6 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 25 May 2012 18:22:35 -0600 Subject: userns: Convert EVM to deal with kuids and kgids in it's hmac computation Cc: Mimi Zohar Acked-by: Serge Hallyn Signed-off-by: Eric W. Biederman --- init/Kconfig | 1 - security/integrity/evm/evm_crypto.c | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'security') diff --git a/init/Kconfig b/init/Kconfig index 8450442da6cd..96ee3f32fe36 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -926,7 +926,6 @@ config UIDGID_CONVERTED # List of kernel pieces that need user namespace work # Features depends on IMA = n - depends on EVM = n # Networking depends on NET_9P = n 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); -- cgit v1.2.3-58-ga151 From 8b94eea4bfb8df693c5b35d08b74f13cfb92f3de Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 25 May 2012 18:24:12 -0600 Subject: userns: Add user namespace support to IMA Use kuid's in the IMA rules. When reporting the current uid in audit logs use from_kuid to get a usable value. Cc: Mimi Zohar Acked-by: Serge Hallyn Signed-off-by: Eric W. Biederman --- init/Kconfig | 4 ---- security/integrity/ima/ima_audit.c | 5 +++-- security/integrity/ima/ima_policy.c | 14 +++++++------- 3 files changed, 10 insertions(+), 13 deletions(-) (limited to 'security') diff --git a/init/Kconfig b/init/Kconfig index 96ee3f32fe36..570cd337e961 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -923,10 +923,6 @@ config UIDGID_CONVERTED bool default y - # List of kernel pieces that need user namespace work - # Features - depends on IMA = n - # Networking depends on NET_9P = n 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; -- cgit v1.2.3-58-ga151 From d2b31ca644fdc8704de3367a6a56a5c958c77f53 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 1 Jun 2012 16:14:19 -0600 Subject: userns: Teach security_path_chown to take kuids and kgids Don't make the security modules deal with raw user space uid and gids instead pass in a kuid_t and a kgid_t so that security modules only have to deal with internal kernel uids and gids. Cc: Al Viro Cc: James Morris Cc: John Johansen Cc: Kentaro Takeda Cc: Tetsuo Handa Acked-by: Serge Hallyn Signed-off-by: Eric W. Biederman --- fs/open.c | 2 +- include/linux/security.h | 6 +++--- security/apparmor/lsm.c | 2 +- security/capability.c | 2 +- security/security.c | 2 +- security/tomoyo/tomoyo.c | 12 +++++++----- 6 files changed, 14 insertions(+), 12 deletions(-) (limited to 'security') diff --git a/fs/open.c b/fs/open.c index f3d96e7e7b19..2b2573980d0f 100644 --- a/fs/open.c +++ b/fs/open.c @@ -534,7 +534,7 @@ static int chown_common(struct path *path, uid_t user, gid_t group) newattrs.ia_valid |= ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV; mutex_lock(&inode->i_mutex); - error = security_path_chown(path, user, group); + error = security_path_chown(path, uid, gid); if (!error) error = notify_change(path->dentry, &newattrs); mutex_unlock(&inode->i_mutex); diff --git a/include/linux/security.h b/include/linux/security.h index 4e5a73cdbbef..ebb92cb1fa28 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -1437,7 +1437,7 @@ struct security_operations { int (*path_rename) (struct path *old_dir, struct dentry *old_dentry, struct path *new_dir, struct dentry *new_dentry); int (*path_chmod) (struct path *path, umode_t mode); - int (*path_chown) (struct path *path, uid_t uid, gid_t gid); + int (*path_chown) (struct path *path, kuid_t uid, kgid_t gid); int (*path_chroot) (struct path *path); #endif @@ -2832,7 +2832,7 @@ int security_path_link(struct dentry *old_dentry, struct path *new_dir, int security_path_rename(struct path *old_dir, struct dentry *old_dentry, struct path *new_dir, struct dentry *new_dentry); int security_path_chmod(struct path *path, umode_t 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); int security_path_chroot(struct path *path); #else /* CONFIG_SECURITY_PATH */ static inline int security_path_unlink(struct path *dir, struct dentry *dentry) @@ -2888,7 +2888,7 @@ static inline int security_path_chmod(struct path *path, umode_t mode) return 0; } -static inline int security_path_chown(struct path *path, uid_t uid, gid_t gid) +static inline int security_path_chown(struct path *path, kuid_t uid, kgid_t gid) { return 0; } 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/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/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; } -- cgit v1.2.3-58-ga151