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
17f60a7da1
("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: David Howells <dhowells@redhat.com>
Acked-by: Eric Paris <eparis@redhat.com>
Tested-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
eb96c92515
commit
879669961b
4 changed files with 15 additions and 14 deletions
|
@ -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;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
struct key;
|
struct cred;
|
||||||
struct file;
|
struct file;
|
||||||
|
|
||||||
enum umh_wait {
|
enum umh_wait {
|
||||||
|
@ -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,
|
||||||
|
|
||||||
/* 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);
|
||||||
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)
|
||||||
*/
|
*/
|
||||||
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)
|
||||||
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);
|
||||||
* 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);
|
||||||
* 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);
|
||||||
|
|
Loading…
Add table
Reference in a new issue