Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 69664cf1 authored by David Howells's avatar David Howells Committed by Linus Torvalds
Browse files

keys: don't generate user and user session keyrings unless they're accessed



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: default avatarDavid 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: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 6b79ccb5
Loading
Loading
Loading
Loading
+0 −8
Original line number Diff line number Diff line
@@ -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);
@@ -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
@@ -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 */
+4 −11
Original line number Diff line number Diff line
@@ -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
@@ -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;
@@ -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:
+1 −3
Original line number Diff line number Diff line
@@ -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,
@@ -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);
+1 −44
Original line number Diff line number Diff line
/* 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
@@ -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
@@ -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() */
+7 −12
Original line number Diff line number Diff line
/* 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
@@ -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;

@@ -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;
@@ -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);
Loading