diff options
Diffstat (limited to 'security')
| -rw-r--r-- | security/keys/internal.h | 1 | ||||
| -rw-r--r-- | security/keys/keyctl.c | 2 | ||||
| -rw-r--r-- | security/keys/process_keys.c | 3 | ||||
| -rw-r--r-- | security/keys/request_key.c | 32 | 
4 files changed, 35 insertions, 3 deletions
| diff --git a/security/keys/internal.h b/security/keys/internal.h index 5d4402a1161a..38783dcf6c61 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -124,6 +124,7 @@ extern struct key *find_keyring_by_name(const char *name, bool skip_perm_check);  extern int install_user_keyrings(void);  extern int install_thread_keyring_to_cred(struct cred *);  extern int install_process_keyring_to_cred(struct cred *); +extern int install_session_keyring_to_cred(struct cred *, struct key *);  extern struct key *request_key_and_link(struct key_type *type,  					const char *description, diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 8f4dce1987c4..13074b454743 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -1269,7 +1269,7 @@ long keyctl_session_to_parent(void)  		goto not_permitted;  	/* the parent must be single threaded */ -	if (atomic_read(&parent->signal->count) != 1) +	if (!thread_group_empty(parent))  		goto not_permitted;  	/* the parent and the child must have different session keyrings or diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 20a38fed61b1..6b8e4ff4cc68 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c @@ -216,8 +216,7 @@ static int install_process_keyring(void)  /*   * install a session keyring directly to a credentials struct   */ -static int install_session_keyring_to_cred(struct cred *cred, -					   struct key *keyring) +int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)  {  	unsigned long flags;  	struct key *old; diff --git a/security/keys/request_key.c b/security/keys/request_key.c index f656e9c069e3..f5ec9ac5d57c 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c @@ -58,6 +58,38 @@ void complete_request_key(struct key_construction *cons, int error)  }  EXPORT_SYMBOL(complete_request_key); +static int umh_keys_init(struct subprocess_info *info) +{ +	struct cred *cred = (struct cred*)current_cred(); +	struct key *keyring = info->data; +	/* +	 * This is called in context of freshly forked kthread before +	 * kernel_execve(), we can just change our ->session_keyring. +	 */ +	return install_session_keyring_to_cred(cred, keyring); +} + +static void umh_keys_cleanup(struct subprocess_info *info) +{ +	struct key *keyring = info->data; +	key_put(keyring); +} + +static int call_usermodehelper_keys(char *path, char **argv, char **envp, +			 struct key *session_keyring, enum umh_wait wait) +{ +	gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL; +	struct subprocess_info *info = +		call_usermodehelper_setup(path, argv, envp, gfp_mask); + +	if (!info) +		return -ENOMEM; + +	call_usermodehelper_setfns(info, umh_keys_init, umh_keys_cleanup, +					key_get(session_keyring)); +	return call_usermodehelper_exec(info, wait); +} +  /*   * request userspace finish the construction of a key   * - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring>" | 
