Commit 87966996 authored by David Howells's avatar David Howells Committed by Linus Torvalds

KEYS/DNS: Fix ____call_usermodehelper() to not lose the session keyring

____call_usermodehelper() now erases any credentials set by the
subprocess_inf::init() function.  The problem is that commit
17f60a7d ("capabilites: allow the application of capability limits
to usermode helpers") creates and commits new credentials with
prepare_kernel_cred() after the call to the init() function.  This wipes
all keyrings after umh_keys_init() is called.

The best way to deal with this is to put the init() call just prior to
the commit_creds() call, and pass the cred pointer to init().  That
means that umh_keys_init() and suchlike can modify the credentials
_before_ they are published and potentially in use by the rest of the
system.

This prevents request_key() from working as it is prevented from passing
the session keyring it set up with the authorisation token to
/sbin/request-key, and so the latter can't assume the authority to
instantiate the key.  This causes the in-kernel DNS resolver to fail
with ENOKEY unconditionally.
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Acked-by: default avatarEric Paris <eparis@redhat.com>
Tested-by: default avatarJeff Layton <jlayton@redhat.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent eb96c925
...@@ -1996,7 +1996,7 @@ static void wait_for_dump_helpers(struct file *file) ...@@ -1996,7 +1996,7 @@ static void wait_for_dump_helpers(struct file *file)
* is a special value that we use to trap recursive * is a special value that we use to trap recursive
* core dumps * core dumps
*/ */
static int umh_pipe_setup(struct subprocess_info *info) static int umh_pipe_setup(struct subprocess_info *info, struct cred *new)
{ {
struct file *rp, *wp; struct file *rp, *wp;
struct fdtable *fdt; struct fdtable *fdt;
......
...@@ -45,7 +45,7 @@ static inline int request_module_nowait(const char *name, ...) { return -ENOSYS; ...@@ -45,7 +45,7 @@ static inline int request_module_nowait(const char *name, ...) { return -ENOSYS;
#endif #endif
struct key; struct cred;
struct file; struct file;
enum umh_wait { enum umh_wait {
...@@ -62,7 +62,7 @@ struct subprocess_info { ...@@ -62,7 +62,7 @@ struct subprocess_info {
char **envp; char **envp;
enum umh_wait wait; enum umh_wait wait;
int retval; int retval;
int (*init)(struct subprocess_info *info); int (*init)(struct subprocess_info *info, struct cred *new);
void (*cleanup)(struct subprocess_info *info); void (*cleanup)(struct subprocess_info *info);
void *data; void *data;
}; };
...@@ -73,7 +73,7 @@ struct subprocess_info *call_usermodehelper_setup(char *path, char **argv, ...@@ -73,7 +73,7 @@ struct subprocess_info *call_usermodehelper_setup(char *path, char **argv,
/* Set various pieces of state into the subprocess_info structure */ /* Set various pieces of state into the subprocess_info structure */
void call_usermodehelper_setfns(struct subprocess_info *info, void call_usermodehelper_setfns(struct subprocess_info *info,
int (*init)(struct subprocess_info *info), int (*init)(struct subprocess_info *info, struct cred *new),
void (*cleanup)(struct subprocess_info *info), void (*cleanup)(struct subprocess_info *info),
void *data); void *data);
...@@ -87,7 +87,7 @@ void call_usermodehelper_freeinfo(struct subprocess_info *info); ...@@ -87,7 +87,7 @@ void call_usermodehelper_freeinfo(struct subprocess_info *info);
static inline int static inline int
call_usermodehelper_fns(char *path, char **argv, char **envp, call_usermodehelper_fns(char *path, char **argv, char **envp,
enum umh_wait wait, enum umh_wait wait,
int (*init)(struct subprocess_info *info), int (*init)(struct subprocess_info *info, struct cred *new),
void (*cleanup)(struct subprocess_info *), void *data) void (*cleanup)(struct subprocess_info *), void *data)
{ {
struct subprocess_info *info; struct subprocess_info *info;
......
...@@ -156,12 +156,6 @@ static int ____call_usermodehelper(void *data) ...@@ -156,12 +156,6 @@ static int ____call_usermodehelper(void *data)
*/ */
set_user_nice(current, 0); set_user_nice(current, 0);
if (sub_info->init) {
retval = sub_info->init(sub_info);
if (retval)
goto fail;
}
retval = -ENOMEM; retval = -ENOMEM;
new = prepare_kernel_cred(current); new = prepare_kernel_cred(current);
if (!new) if (!new)
...@@ -173,6 +167,14 @@ static int ____call_usermodehelper(void *data) ...@@ -173,6 +167,14 @@ static int ____call_usermodehelper(void *data)
new->cap_inheritable); new->cap_inheritable);
spin_unlock(&umh_sysctl_lock); spin_unlock(&umh_sysctl_lock);
if (sub_info->init) {
retval = sub_info->init(sub_info, new);
if (retval) {
abort_creds(new);
goto fail;
}
}
commit_creds(new); commit_creds(new);
retval = kernel_execve(sub_info->path, retval = kernel_execve(sub_info->path,
...@@ -388,7 +390,7 @@ EXPORT_SYMBOL(call_usermodehelper_setup); ...@@ -388,7 +390,7 @@ EXPORT_SYMBOL(call_usermodehelper_setup);
* context in which call_usermodehelper_exec is called. * context in which call_usermodehelper_exec is called.
*/ */
void call_usermodehelper_setfns(struct subprocess_info *info, void call_usermodehelper_setfns(struct subprocess_info *info,
int (*init)(struct subprocess_info *info), int (*init)(struct subprocess_info *info, struct cred *new),
void (*cleanup)(struct subprocess_info *info), void (*cleanup)(struct subprocess_info *info),
void *data) void *data)
{ {
......
...@@ -71,9 +71,8 @@ EXPORT_SYMBOL(complete_request_key); ...@@ -71,9 +71,8 @@ EXPORT_SYMBOL(complete_request_key);
* This is called in context of freshly forked kthread before kernel_execve(), * This is called in context of freshly forked kthread before kernel_execve(),
* so we can simply install the desired session_keyring at this point. * so we can simply install the desired session_keyring at this point.
*/ */
static int umh_keys_init(struct subprocess_info *info) static int umh_keys_init(struct subprocess_info *info, struct cred *cred)
{ {
struct cred *cred = (struct cred*)current_cred();
struct key *keyring = info->data; struct key *keyring = info->data;
return install_session_keyring_to_cred(cred, keyring); return install_session_keyring_to_cred(cred, keyring);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment