Skip to content

Commit

Permalink
keys: don't generate user and user session keyrings unless they're ac…
Browse files Browse the repository at this point in the history
…cessed

Don't generate the per-UID user and user session keyrings unless they're
explicitly accessed.  This solves a problem during a login process whereby
set*uid() is called before the SELinux PAM module, resulting in the per-UID
keyrings having the wrong security labels.

This also cures the problem of multiple per-UID keyrings sometimes appearing
due to PAM modules (including pam_keyinit) setuiding and causing user_structs
to come into and go out of existence whilst the session keyring pins the user
keyring.  This is achieved by first searching for extant per-UID keyrings
before inventing new ones.

The serial bound argument is also dropped from find_keyring_by_name() as it's
not currently made use of (setting it to 0 disables the feature).

Signed-off-by: David Howells <dhowells@redhat.com>
Cc: <kwc@citi.umich.edu>
Cc: <arunsr@cse.iitk.ac.in>
Cc: <dwalsh@redhat.com>
Cc: Stephen Smalley <sds@tycho.nsa.gov>
Cc: James Morris <jmorris@namei.org>
Cc: Chris Wright <chrisw@sous-sol.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
dhowells authored and torvalds committed Apr 29, 2008
1 parent 6b79ccb commit 69664cf
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 145 deletions.
8 changes: 0 additions & 8 deletions include/linux/key.h
Original file line number Diff line number Diff line change
Expand Up @@ -268,9 +268,6 @@ extern struct key *key_lookup(key_serial_t id);
/*
* the userspace interface
*/
extern struct key root_user_keyring, root_session_keyring;
extern int alloc_uid_keyring(struct user_struct *user,
struct task_struct *ctx);
extern void switch_uid_keyring(struct user_struct *new_user);
extern int copy_keys(unsigned long clone_flags, struct task_struct *tsk);
extern int copy_thread_group_keys(struct task_struct *tsk);
Expand Down Expand Up @@ -299,7 +296,6 @@ extern void key_init(void);
#define make_key_ref(k, p) ({ NULL; })
#define key_ref_to_ptr(k) ({ NULL; })
#define is_key_possessed(k) 0
#define alloc_uid_keyring(u,c) 0
#define switch_uid_keyring(u) do { } while(0)
#define __install_session_keyring(t, k) ({ NULL; })
#define copy_keys(f,t) 0
Expand All @@ -312,10 +308,6 @@ extern void key_init(void);
#define key_fsgid_changed(t) do { } while(0)
#define key_init() do { } while(0)

/* Initial keyrings */
extern struct key root_user_keyring;
extern struct key root_session_keyring;

#endif /* CONFIG_KEYS */
#endif /* __KERNEL__ */
#endif /* _LINUX_KEY_H */
15 changes: 4 additions & 11 deletions kernel/user.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,6 @@ struct user_struct root_user = {
.files = ATOMIC_INIT(0),
.sigpending = ATOMIC_INIT(0),
.locked_shm = 0,
#ifdef CONFIG_KEYS
.uid_keyring = &root_user_keyring,
.session_keyring = &root_session_keyring,
#endif
#ifdef CONFIG_USER_SCHED
.tg = &init_task_group,
#endif
Expand Down Expand Up @@ -420,12 +416,12 @@ struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid)
new->mq_bytes = 0;
#endif
new->locked_shm = 0;

if (alloc_uid_keyring(new, current) < 0)
goto out_free_user;
#ifdef CONFIG_KEYS
new->uid_keyring = new->session_keyring = NULL;
#endif

if (sched_create_user(new) < 0)
goto out_put_keys;
goto out_free_user;

if (uids_user_create(new))
goto out_destoy_sched;
Expand Down Expand Up @@ -459,9 +455,6 @@ struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid)

out_destoy_sched:
sched_destroy_user(new);
out_put_keys:
key_put(new->uid_keyring);
key_put(new->session_keyring);
out_free_user:
kmem_cache_free(uid_cachep, new);
out_unlock:
Expand Down
4 changes: 1 addition & 3 deletions security/keys/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,6 @@ extern struct mutex key_construction_mutex;
extern wait_queue_head_t request_key_conswq;


extern void keyring_publish_name(struct key *keyring);

extern int __key_link(struct key *keyring, struct key *key);

extern key_ref_t __keyring_search_one(key_ref_t keyring_ref,
Expand All @@ -102,7 +100,7 @@ extern key_ref_t search_process_keyrings(struct key_type *type,
key_match_func_t match,
struct task_struct *tsk);

extern struct key *find_keyring_by_name(const char *name, key_serial_t bound);
extern struct key *find_keyring_by_name(const char *name, bool skip_perm_check);

extern int install_thread_keyring(struct task_struct *tsk);
extern int install_process_keyring(struct task_struct *tsk);
Expand Down
45 changes: 1 addition & 44 deletions security/keys/key.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* Basic authentication token and access key management
*
* Copyright (C) 2004-2007 Red Hat, Inc. All Rights Reserved.
* Copyright (C) 2004-2008 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
Expand Down Expand Up @@ -137,36 +137,6 @@ void key_user_put(struct key_user *user)

} /* end key_user_put() */

/*****************************************************************************/
/*
* insert a key with a fixed serial number
*/
static void __init __key_insert_serial(struct key *key)
{
struct rb_node *parent, **p;
struct key *xkey;

parent = NULL;
p = &key_serial_tree.rb_node;

while (*p) {
parent = *p;
xkey = rb_entry(parent, struct key, serial_node);

if (key->serial < xkey->serial)
p = &(*p)->rb_left;
else if (key->serial > xkey->serial)
p = &(*p)->rb_right;
else
BUG();
}

/* we've found a suitable hole - arrange for this key to occupy it */
rb_link_node(&key->serial_node, parent, p);
rb_insert_color(&key->serial_node, &key_serial_tree);

} /* end __key_insert_serial() */

/*****************************************************************************/
/*
* assign a key the next unique serial number
Expand Down Expand Up @@ -1020,17 +990,4 @@ void __init key_init(void)
rb_insert_color(&root_key_user.node,
&key_user_tree);

/* record root's user standard keyrings */
key_check(&root_user_keyring);
key_check(&root_session_keyring);

__key_insert_serial(&root_user_keyring);
__key_insert_serial(&root_session_keyring);

keyring_publish_name(&root_user_keyring);
keyring_publish_name(&root_session_keyring);

/* link the two root keyrings together */
key_link(&root_session_keyring, &root_user_keyring);

} /* end key_init() */
19 changes: 7 additions & 12 deletions security/keys/keyring.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* keyring.c: keyring handling
/* Keyring handling
*
* Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
* Copyright (C) 2004-2005, 2008 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
Expand Down Expand Up @@ -79,7 +79,7 @@ static DECLARE_RWSEM(keyring_serialise_link_sem);
* publish the name of a keyring so that it can be found by name (if it has
* one)
*/
void keyring_publish_name(struct key *keyring)
static void keyring_publish_name(struct key *keyring)
{
int bucket;

Expand Down Expand Up @@ -516,10 +516,9 @@ key_ref_t __keyring_search_one(key_ref_t keyring_ref,
/*
* find a keyring with the specified name
* - all named keyrings are searched
* - only find keyrings with search permission for the process
* - only find keyrings with a serial number greater than the one specified
* - normally only finds keyrings with search permission for the current process
*/
struct key *find_keyring_by_name(const char *name, key_serial_t bound)
struct key *find_keyring_by_name(const char *name, bool skip_perm_check)
{
struct key *keyring;
int bucket;
Expand All @@ -545,15 +544,11 @@ struct key *find_keyring_by_name(const char *name, key_serial_t bound)
if (strcmp(keyring->description, name) != 0)
continue;

if (key_permission(make_key_ref(keyring, 0),
if (!skip_perm_check &&
key_permission(make_key_ref(keyring, 0),
KEY_SEARCH) < 0)
continue;

/* found a potential candidate, but we still need to
* check the serial number */
if (keyring->serial <= bound)
continue;

/* we've got a match */
atomic_inc(&keyring->usage);
read_unlock(&keyring_name_lock);
Expand Down
Loading

0 comments on commit 69664cf

Please sign in to comment.