diff options
Diffstat (limited to 'kernel/kmod.c')
| -rw-r--r-- | kernel/kmod.c | 30 |
1 files changed, 23 insertions, 7 deletions
diff --git a/kernel/kmod.c b/kernel/kmod.c index 3d3c3ea3a023..b46dbb908669 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c | |||
| @@ -118,10 +118,10 @@ EXPORT_SYMBOL(request_module); | |||
| 118 | struct subprocess_info { | 118 | struct subprocess_info { |
| 119 | struct work_struct work; | 119 | struct work_struct work; |
| 120 | struct completion *complete; | 120 | struct completion *complete; |
| 121 | struct cred *cred; | ||
| 121 | char *path; | 122 | char *path; |
| 122 | char **argv; | 123 | char **argv; |
| 123 | char **envp; | 124 | char **envp; |
| 124 | struct key *ring; | ||
| 125 | enum umh_wait wait; | 125 | enum umh_wait wait; |
| 126 | int retval; | 126 | int retval; |
| 127 | struct file *stdin; | 127 | struct file *stdin; |
| @@ -134,19 +134,20 @@ struct subprocess_info { | |||
| 134 | static int ____call_usermodehelper(void *data) | 134 | static int ____call_usermodehelper(void *data) |
| 135 | { | 135 | { |
| 136 | struct subprocess_info *sub_info = data; | 136 | struct subprocess_info *sub_info = data; |
| 137 | struct key *new_session, *old_session; | ||
| 138 | int retval; | 137 | int retval; |
| 139 | 138 | ||
| 140 | /* Unblock all signals and set the session keyring. */ | 139 | BUG_ON(atomic_read(&sub_info->cred->usage) != 1); |
| 141 | new_session = key_get(sub_info->ring); | 140 | |
| 141 | /* Unblock all signals */ | ||
| 142 | spin_lock_irq(¤t->sighand->siglock); | 142 | spin_lock_irq(¤t->sighand->siglock); |
| 143 | old_session = __install_session_keyring(current, new_session); | ||
| 144 | flush_signal_handlers(current, 1); | 143 | flush_signal_handlers(current, 1); |
| 145 | sigemptyset(¤t->blocked); | 144 | sigemptyset(¤t->blocked); |
| 146 | recalc_sigpending(); | 145 | recalc_sigpending(); |
| 147 | spin_unlock_irq(¤t->sighand->siglock); | 146 | spin_unlock_irq(¤t->sighand->siglock); |
| 148 | 147 | ||
| 149 | key_put(old_session); | 148 | /* Install the credentials */ |
| 149 | commit_creds(sub_info->cred); | ||
| 150 | sub_info->cred = NULL; | ||
| 150 | 151 | ||
| 151 | /* Install input pipe when needed */ | 152 | /* Install input pipe when needed */ |
| 152 | if (sub_info->stdin) { | 153 | if (sub_info->stdin) { |
| @@ -185,6 +186,8 @@ void call_usermodehelper_freeinfo(struct subprocess_info *info) | |||
| 185 | { | 186 | { |
| 186 | if (info->cleanup) | 187 | if (info->cleanup) |
| 187 | (*info->cleanup)(info->argv, info->envp); | 188 | (*info->cleanup)(info->argv, info->envp); |
| 189 | if (info->cred) | ||
| 190 | put_cred(info->cred); | ||
| 188 | kfree(info); | 191 | kfree(info); |
| 189 | } | 192 | } |
| 190 | EXPORT_SYMBOL(call_usermodehelper_freeinfo); | 193 | EXPORT_SYMBOL(call_usermodehelper_freeinfo); |
| @@ -240,6 +243,8 @@ static void __call_usermodehelper(struct work_struct *work) | |||
| 240 | pid_t pid; | 243 | pid_t pid; |
| 241 | enum umh_wait wait = sub_info->wait; | 244 | enum umh_wait wait = sub_info->wait; |
| 242 | 245 | ||
| 246 | BUG_ON(atomic_read(&sub_info->cred->usage) != 1); | ||
| 247 | |||
| 243 | /* CLONE_VFORK: wait until the usermode helper has execve'd | 248 | /* CLONE_VFORK: wait until the usermode helper has execve'd |
| 244 | * successfully We need the data structures to stay around | 249 | * successfully We need the data structures to stay around |
| 245 | * until that is done. */ | 250 | * until that is done. */ |
| @@ -362,6 +367,9 @@ struct subprocess_info *call_usermodehelper_setup(char *path, char **argv, | |||
| 362 | sub_info->path = path; | 367 | sub_info->path = path; |
| 363 | sub_info->argv = argv; | 368 | sub_info->argv = argv; |
| 364 | sub_info->envp = envp; | 369 | sub_info->envp = envp; |
| 370 | sub_info->cred = prepare_usermodehelper_creds(); | ||
| 371 | if (!sub_info->cred) | ||
| 372 | return NULL; | ||
| 365 | 373 | ||
| 366 | out: | 374 | out: |
| 367 | return sub_info; | 375 | return sub_info; |
| @@ -376,7 +384,13 @@ EXPORT_SYMBOL(call_usermodehelper_setup); | |||
| 376 | void call_usermodehelper_setkeys(struct subprocess_info *info, | 384 | void call_usermodehelper_setkeys(struct subprocess_info *info, |
| 377 | struct key *session_keyring) | 385 | struct key *session_keyring) |
| 378 | { | 386 | { |
| 379 | info->ring = session_keyring; | 387 | #ifdef CONFIG_KEYS |
| 388 | struct thread_group_cred *tgcred = info->cred->tgcred; | ||
| 389 | key_put(tgcred->session_keyring); | ||
| 390 | tgcred->session_keyring = key_get(session_keyring); | ||
| 391 | #else | ||
| 392 | BUG(); | ||
| 393 | #endif | ||
| 380 | } | 394 | } |
| 381 | EXPORT_SYMBOL(call_usermodehelper_setkeys); | 395 | EXPORT_SYMBOL(call_usermodehelper_setkeys); |
| 382 | 396 | ||
| @@ -444,6 +458,8 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info, | |||
| 444 | DECLARE_COMPLETION_ONSTACK(done); | 458 | DECLARE_COMPLETION_ONSTACK(done); |
| 445 | int retval = 0; | 459 | int retval = 0; |
| 446 | 460 | ||
| 461 | BUG_ON(atomic_read(&sub_info->cred->usage) != 1); | ||
| 462 | |||
| 447 | helper_lock(); | 463 | helper_lock(); |
| 448 | if (sub_info->path[0] == '\0') | 464 | if (sub_info->path[0] == '\0') |
| 449 | goto out; | 465 | goto out; |
