summaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
Diffstat (limited to 'security')
-rw-r--r--security/keys/internal.h1
-rw-r--r--security/keys/keyctl.c2
-rw-r--r--security/keys/process_keys.c3
-rw-r--r--security/keys/request_key.c32
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>"
OpenPOWER on IntegriCloud