| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * umh - the kernel usermode helper |
|---|
| 3 | 4 | */ |
|---|
| .. | .. |
|---|
| 26 | 27 | #include <linux/ptrace.h> |
|---|
| 27 | 28 | #include <linux/async.h> |
|---|
| 28 | 29 | #include <linux/uaccess.h> |
|---|
| 29 | | -#include <linux/shmem_fs.h> |
|---|
| 30 | | -#include <linux/pipe_fs_i.h> |
|---|
| 31 | 30 | |
|---|
| 32 | 31 | #include <trace/events/module.h> |
|---|
| 33 | 32 | |
|---|
| .. | .. |
|---|
| 108 | 107 | |
|---|
| 109 | 108 | commit_creds(new); |
|---|
| 110 | 109 | |
|---|
| 111 | | - sub_info->pid = task_pid_nr(current); |
|---|
| 112 | | - if (sub_info->file) |
|---|
| 113 | | - retval = do_execve_file(sub_info->file, |
|---|
| 114 | | - sub_info->argv, sub_info->envp); |
|---|
| 115 | | - else |
|---|
| 116 | | - retval = do_execve(getname_kernel(sub_info->path), |
|---|
| 117 | | - (const char __user *const __user *)sub_info->argv, |
|---|
| 118 | | - (const char __user *const __user *)sub_info->envp); |
|---|
| 110 | + retval = kernel_execve(sub_info->path, |
|---|
| 111 | + (const char *const *)sub_info->argv, |
|---|
| 112 | + (const char *const *)sub_info->envp); |
|---|
| 119 | 113 | out: |
|---|
| 120 | 114 | sub_info->retval = retval; |
|---|
| 121 | 115 | /* |
|---|
| .. | .. |
|---|
| 134 | 128 | { |
|---|
| 135 | 129 | pid_t pid; |
|---|
| 136 | 130 | |
|---|
| 137 | | - /* If SIGCLD is ignored kernel_wait4 won't populate the status. */ |
|---|
| 131 | + /* If SIGCLD is ignored do_wait won't populate the status. */ |
|---|
| 138 | 132 | kernel_sigaction(SIGCHLD, SIG_DFL); |
|---|
| 139 | 133 | pid = kernel_thread(call_usermodehelper_exec_async, sub_info, SIGCHLD); |
|---|
| 140 | | - if (pid < 0) { |
|---|
| 134 | + if (pid < 0) |
|---|
| 141 | 135 | sub_info->retval = pid; |
|---|
| 142 | | - } else { |
|---|
| 143 | | - int ret = -ECHILD; |
|---|
| 144 | | - /* |
|---|
| 145 | | - * Normally it is bogus to call wait4() from in-kernel because |
|---|
| 146 | | - * wait4() wants to write the exit code to a userspace address. |
|---|
| 147 | | - * But call_usermodehelper_exec_sync() always runs as kernel |
|---|
| 148 | | - * thread (workqueue) and put_user() to a kernel address works |
|---|
| 149 | | - * OK for kernel threads, due to their having an mm_segment_t |
|---|
| 150 | | - * which spans the entire address space. |
|---|
| 151 | | - * |
|---|
| 152 | | - * Thus the __user pointer cast is valid here. |
|---|
| 153 | | - */ |
|---|
| 154 | | - kernel_wait4(pid, (int __user *)&ret, 0, NULL); |
|---|
| 155 | | - |
|---|
| 156 | | - /* |
|---|
| 157 | | - * If ret is 0, either call_usermodehelper_exec_async failed and |
|---|
| 158 | | - * the real error code is already in sub_info->retval or |
|---|
| 159 | | - * sub_info->retval is 0 anyway, so don't mess with it then. |
|---|
| 160 | | - */ |
|---|
| 161 | | - if (ret) |
|---|
| 162 | | - sub_info->retval = ret; |
|---|
| 163 | | - } |
|---|
| 136 | + else |
|---|
| 137 | + kernel_wait(pid, &sub_info->retval); |
|---|
| 164 | 138 | |
|---|
| 165 | 139 | /* Restore default kernel sig handler */ |
|---|
| 166 | 140 | kernel_sigaction(SIGCHLD, SIG_IGN); |
|---|
| 167 | | - |
|---|
| 168 | 141 | umh_complete(sub_info); |
|---|
| 169 | 142 | } |
|---|
| 170 | 143 | |
|---|
| .. | .. |
|---|
| 409 | 382 | } |
|---|
| 410 | 383 | EXPORT_SYMBOL(call_usermodehelper_setup); |
|---|
| 411 | 384 | |
|---|
| 412 | | -struct subprocess_info *call_usermodehelper_setup_file(struct file *file, |
|---|
| 413 | | - int (*init)(struct subprocess_info *info, struct cred *new), |
|---|
| 414 | | - void (*cleanup)(struct subprocess_info *info), void *data) |
|---|
| 415 | | -{ |
|---|
| 416 | | - struct subprocess_info *sub_info; |
|---|
| 417 | | - |
|---|
| 418 | | - sub_info = kzalloc(sizeof(struct subprocess_info), GFP_KERNEL); |
|---|
| 419 | | - if (!sub_info) |
|---|
| 420 | | - return NULL; |
|---|
| 421 | | - |
|---|
| 422 | | - INIT_WORK(&sub_info->work, call_usermodehelper_exec_work); |
|---|
| 423 | | - sub_info->path = "none"; |
|---|
| 424 | | - sub_info->file = file; |
|---|
| 425 | | - sub_info->init = init; |
|---|
| 426 | | - sub_info->cleanup = cleanup; |
|---|
| 427 | | - sub_info->data = data; |
|---|
| 428 | | - return sub_info; |
|---|
| 429 | | -} |
|---|
| 430 | | - |
|---|
| 431 | | -static int umh_pipe_setup(struct subprocess_info *info, struct cred *new) |
|---|
| 432 | | -{ |
|---|
| 433 | | - struct umh_info *umh_info = info->data; |
|---|
| 434 | | - struct file *from_umh[2]; |
|---|
| 435 | | - struct file *to_umh[2]; |
|---|
| 436 | | - int err; |
|---|
| 437 | | - |
|---|
| 438 | | - /* create pipe to send data to umh */ |
|---|
| 439 | | - err = create_pipe_files(to_umh, 0); |
|---|
| 440 | | - if (err) |
|---|
| 441 | | - return err; |
|---|
| 442 | | - err = replace_fd(0, to_umh[0], 0); |
|---|
| 443 | | - fput(to_umh[0]); |
|---|
| 444 | | - if (err < 0) { |
|---|
| 445 | | - fput(to_umh[1]); |
|---|
| 446 | | - return err; |
|---|
| 447 | | - } |
|---|
| 448 | | - |
|---|
| 449 | | - /* create pipe to receive data from umh */ |
|---|
| 450 | | - err = create_pipe_files(from_umh, 0); |
|---|
| 451 | | - if (err) { |
|---|
| 452 | | - fput(to_umh[1]); |
|---|
| 453 | | - replace_fd(0, NULL, 0); |
|---|
| 454 | | - return err; |
|---|
| 455 | | - } |
|---|
| 456 | | - err = replace_fd(1, from_umh[1], 0); |
|---|
| 457 | | - fput(from_umh[1]); |
|---|
| 458 | | - if (err < 0) { |
|---|
| 459 | | - fput(to_umh[1]); |
|---|
| 460 | | - replace_fd(0, NULL, 0); |
|---|
| 461 | | - fput(from_umh[0]); |
|---|
| 462 | | - return err; |
|---|
| 463 | | - } |
|---|
| 464 | | - |
|---|
| 465 | | - umh_info->pipe_to_umh = to_umh[1]; |
|---|
| 466 | | - umh_info->pipe_from_umh = from_umh[0]; |
|---|
| 467 | | - return 0; |
|---|
| 468 | | -} |
|---|
| 469 | | - |
|---|
| 470 | | -static void umh_save_pid(struct subprocess_info *info) |
|---|
| 471 | | -{ |
|---|
| 472 | | - struct umh_info *umh_info = info->data; |
|---|
| 473 | | - |
|---|
| 474 | | - umh_info->pid = info->pid; |
|---|
| 475 | | -} |
|---|
| 476 | | - |
|---|
| 477 | | -/** |
|---|
| 478 | | - * fork_usermode_blob - fork a blob of bytes as a usermode process |
|---|
| 479 | | - * @data: a blob of bytes that can be do_execv-ed as a file |
|---|
| 480 | | - * @len: length of the blob |
|---|
| 481 | | - * @info: information about usermode process (shouldn't be NULL) |
|---|
| 482 | | - * |
|---|
| 483 | | - * Returns either negative error or zero which indicates success |
|---|
| 484 | | - * in executing a blob of bytes as a usermode process. In such |
|---|
| 485 | | - * case 'struct umh_info *info' is populated with two pipes |
|---|
| 486 | | - * and a pid of the process. The caller is responsible for health |
|---|
| 487 | | - * check of the user process, killing it via pid, and closing the |
|---|
| 488 | | - * pipes when user process is no longer needed. |
|---|
| 489 | | - */ |
|---|
| 490 | | -int fork_usermode_blob(void *data, size_t len, struct umh_info *info) |
|---|
| 491 | | -{ |
|---|
| 492 | | - struct subprocess_info *sub_info; |
|---|
| 493 | | - struct file *file; |
|---|
| 494 | | - ssize_t written; |
|---|
| 495 | | - loff_t pos = 0; |
|---|
| 496 | | - int err; |
|---|
| 497 | | - |
|---|
| 498 | | - file = shmem_kernel_file_setup("", len, 0); |
|---|
| 499 | | - if (IS_ERR(file)) |
|---|
| 500 | | - return PTR_ERR(file); |
|---|
| 501 | | - |
|---|
| 502 | | - written = kernel_write(file, data, len, &pos); |
|---|
| 503 | | - if (written != len) { |
|---|
| 504 | | - err = written; |
|---|
| 505 | | - if (err >= 0) |
|---|
| 506 | | - err = -ENOMEM; |
|---|
| 507 | | - goto out; |
|---|
| 508 | | - } |
|---|
| 509 | | - |
|---|
| 510 | | - err = -ENOMEM; |
|---|
| 511 | | - sub_info = call_usermodehelper_setup_file(file, umh_pipe_setup, |
|---|
| 512 | | - umh_save_pid, info); |
|---|
| 513 | | - if (!sub_info) |
|---|
| 514 | | - goto out; |
|---|
| 515 | | - |
|---|
| 516 | | - err = call_usermodehelper_exec(sub_info, UMH_WAIT_EXEC); |
|---|
| 517 | | -out: |
|---|
| 518 | | - fput(file); |
|---|
| 519 | | - return err; |
|---|
| 520 | | -} |
|---|
| 521 | | -EXPORT_SYMBOL_GPL(fork_usermode_blob); |
|---|
| 522 | | - |
|---|
| 523 | 385 | /** |
|---|
| 524 | 386 | * call_usermodehelper_exec - start a usermode application |
|---|
| 525 | 387 | * @sub_info: information about the subprocessa |
|---|
| .. | .. |
|---|
| 622 | 484 | EXPORT_SYMBOL(call_usermodehelper); |
|---|
| 623 | 485 | |
|---|
| 624 | 486 | static int proc_cap_handler(struct ctl_table *table, int write, |
|---|
| 625 | | - void __user *buffer, size_t *lenp, loff_t *ppos) |
|---|
| 487 | + void *buffer, size_t *lenp, loff_t *ppos) |
|---|
| 626 | 488 | { |
|---|
| 627 | 489 | struct ctl_table t; |
|---|
| 628 | 490 | unsigned long cap_array[_KERNEL_CAPABILITY_U32S]; |
|---|