diff options
Diffstat (limited to 'security/keys/proc.c')
-rw-r--r-- | security/keys/proc.c | 25 |
1 files changed, 16 insertions, 9 deletions
diff --git a/security/keys/proc.c b/security/keys/proc.c index 4e3266a2529e..b394ad1e874b 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c @@ -110,11 +110,13 @@ static struct key *find_ge_key(struct seq_file *p, key_serial_t id) } static void *proc_keys_start(struct seq_file *p, loff_t *_pos) + __acquires(rcu) __acquires(key_serial_lock) { key_serial_t pos = *_pos; struct key *key; + rcu_read_lock(); spin_lock(&key_serial_lock); if (*_pos > INT_MAX) @@ -144,12 +146,15 @@ static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos) static void proc_keys_stop(struct seq_file *p, void *v) __releases(key_serial_lock) + __releases(rcu) { spin_unlock(&key_serial_lock); + rcu_read_unlock(); } static int proc_keys_show(struct seq_file *m, void *v) { + const struct key_acl *acl; struct rb_node *_p = v; struct key *key = rb_entry(_p, struct key, serial_node); unsigned long flags; @@ -157,6 +162,7 @@ static int proc_keys_show(struct seq_file *m, void *v) time64_t now, expiry; char xbuf[16]; short state; + bool check_pos; u64 timo; int rc; @@ -166,16 +172,19 @@ static int proc_keys_show(struct seq_file *m, void *v) .match_data.cmp = lookup_user_key_possessed, .match_data.raw_data = key, .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, - .flags = KEYRING_SEARCH_NO_STATE_CHECK, + .flags = (KEYRING_SEARCH_NO_STATE_CHECK | + KEYRING_SEARCH_RECURSE), }; - key_ref = make_key_ref(key, 0); + acl = rcu_dereference(key->acl); + check_pos = acl->possessor_viewable; /* determine if the key is possessed by this process (a test we can * skip if the key does not indicate the possessor can view it */ - if (key->perm & KEY_POS_VIEW) { - skey_ref = search_my_process_keyrings(&ctx); + key_ref = make_key_ref(key, 0); + if (check_pos) { + skey_ref = search_cred_keyrings_rcu(&ctx); if (!IS_ERR(skey_ref)) { key_ref_put(skey_ref); key_ref = make_key_ref(key, 1); @@ -185,12 +194,10 @@ static int proc_keys_show(struct seq_file *m, void *v) /* check whether the current task is allowed to view the key */ rc = key_task_permission(key_ref, ctx.cred, KEY_NEED_VIEW); if (rc < 0) - return 0; + goto out; now = ktime_get_real_seconds(); - rcu_read_lock(); - /* come up with a suitable timeout value */ expiry = READ_ONCE(key->expiry); if (expiry == 0) { @@ -229,7 +236,7 @@ static int proc_keys_show(struct seq_file *m, void *v) showflag(flags, 'i', KEY_FLAG_INVALIDATED), refcount_read(&key->usage), xbuf, - key->perm, + key_acl_to_perm(acl), from_kuid_munged(seq_user_ns(m), key->uid), from_kgid_munged(seq_user_ns(m), key->gid), key->type->name); @@ -240,7 +247,7 @@ static int proc_keys_show(struct seq_file *m, void *v) key->type->describe(key, m); seq_putc(m, '\n'); - rcu_read_unlock(); +out: return 0; } |