diff options
Diffstat (limited to 'kernel/kmod.c')
-rw-r--r-- | kernel/kmod.c | 98 |
1 files changed, 50 insertions, 48 deletions
diff --git a/kernel/kmod.c b/kernel/kmod.c index 56dd34976d7b..1296e72e4161 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c | |||
@@ -77,6 +77,7 @@ static void free_modprobe_argv(struct subprocess_info *info) | |||
77 | 77 | ||
78 | static int call_modprobe(char *module_name, int wait) | 78 | static int call_modprobe(char *module_name, int wait) |
79 | { | 79 | { |
80 | struct subprocess_info *info; | ||
80 | static char *envp[] = { | 81 | static char *envp[] = { |
81 | "HOME=/", | 82 | "HOME=/", |
82 | "TERM=linux", | 83 | "TERM=linux", |
@@ -98,8 +99,15 @@ static int call_modprobe(char *module_name, int wait) | |||
98 | argv[3] = module_name; /* check free_modprobe_argv() */ | 99 | argv[3] = module_name; /* check free_modprobe_argv() */ |
99 | argv[4] = NULL; | 100 | argv[4] = NULL; |
100 | 101 | ||
101 | return call_usermodehelper_fns(modprobe_path, argv, envp, | 102 | info = call_usermodehelper_setup(modprobe_path, argv, envp, GFP_KERNEL, |
102 | wait | UMH_KILLABLE, NULL, free_modprobe_argv, NULL); | 103 | NULL, free_modprobe_argv, NULL); |
104 | if (!info) | ||
105 | goto free_module_name; | ||
106 | |||
107 | return call_usermodehelper_exec(info, wait | UMH_KILLABLE); | ||
108 | |||
109 | free_module_name: | ||
110 | kfree(module_name); | ||
103 | free_argv: | 111 | free_argv: |
104 | kfree(argv); | 112 | kfree(argv); |
105 | out: | 113 | out: |
@@ -502,14 +510,28 @@ static void helper_unlock(void) | |||
502 | * @argv: arg vector for process | 510 | * @argv: arg vector for process |
503 | * @envp: environment for process | 511 | * @envp: environment for process |
504 | * @gfp_mask: gfp mask for memory allocation | 512 | * @gfp_mask: gfp mask for memory allocation |
513 | * @cleanup: a cleanup function | ||
514 | * @init: an init function | ||
515 | * @data: arbitrary context sensitive data | ||
505 | * | 516 | * |
506 | * Returns either %NULL on allocation failure, or a subprocess_info | 517 | * Returns either %NULL on allocation failure, or a subprocess_info |
507 | * structure. This should be passed to call_usermodehelper_exec to | 518 | * structure. This should be passed to call_usermodehelper_exec to |
508 | * exec the process and free the structure. | 519 | * exec the process and free the structure. |
520 | * | ||
521 | * The init function is used to customize the helper process prior to | ||
522 | * exec. A non-zero return code causes the process to error out, exit, | ||
523 | * and return the failure to the calling process | ||
524 | * | ||
525 | * The cleanup function is just before ethe subprocess_info is about to | ||
526 | * be freed. This can be used for freeing the argv and envp. The | ||
527 | * Function must be runnable in either a process context or the | ||
528 | * context in which call_usermodehelper_exec is called. | ||
509 | */ | 529 | */ |
510 | static | ||
511 | struct subprocess_info *call_usermodehelper_setup(char *path, char **argv, | 530 | struct subprocess_info *call_usermodehelper_setup(char *path, char **argv, |
512 | char **envp, gfp_t gfp_mask) | 531 | char **envp, gfp_t gfp_mask, |
532 | int (*init)(struct subprocess_info *info, struct cred *new), | ||
533 | void (*cleanup)(struct subprocess_info *info), | ||
534 | void *data) | ||
513 | { | 535 | { |
514 | struct subprocess_info *sub_info; | 536 | struct subprocess_info *sub_info; |
515 | sub_info = kzalloc(sizeof(struct subprocess_info), gfp_mask); | 537 | sub_info = kzalloc(sizeof(struct subprocess_info), gfp_mask); |
@@ -520,50 +542,27 @@ struct subprocess_info *call_usermodehelper_setup(char *path, char **argv, | |||
520 | sub_info->path = path; | 542 | sub_info->path = path; |
521 | sub_info->argv = argv; | 543 | sub_info->argv = argv; |
522 | sub_info->envp = envp; | 544 | sub_info->envp = envp; |
545 | |||
546 | sub_info->cleanup = cleanup; | ||
547 | sub_info->init = init; | ||
548 | sub_info->data = data; | ||
523 | out: | 549 | out: |
524 | return sub_info; | 550 | return sub_info; |
525 | } | 551 | } |
526 | 552 | EXPORT_SYMBOL(call_usermodehelper_setup); | |
527 | /** | ||
528 | * call_usermodehelper_setfns - set a cleanup/init function | ||
529 | * @info: a subprocess_info returned by call_usermodehelper_setup | ||
530 | * @cleanup: a cleanup function | ||
531 | * @init: an init function | ||
532 | * @data: arbitrary context sensitive data | ||
533 | * | ||
534 | * The init function is used to customize the helper process prior to | ||
535 | * exec. A non-zero return code causes the process to error out, exit, | ||
536 | * and return the failure to the calling process | ||
537 | * | ||
538 | * The cleanup function is just before ethe subprocess_info is about to | ||
539 | * be freed. This can be used for freeing the argv and envp. The | ||
540 | * Function must be runnable in either a process context or the | ||
541 | * context in which call_usermodehelper_exec is called. | ||
542 | */ | ||
543 | static | ||
544 | void call_usermodehelper_setfns(struct subprocess_info *info, | ||
545 | int (*init)(struct subprocess_info *info, struct cred *new), | ||
546 | void (*cleanup)(struct subprocess_info *info), | ||
547 | void *data) | ||
548 | { | ||
549 | info->cleanup = cleanup; | ||
550 | info->init = init; | ||
551 | info->data = data; | ||
552 | } | ||
553 | 553 | ||
554 | /** | 554 | /** |
555 | * call_usermodehelper_exec - start a usermode application | 555 | * call_usermodehelper_exec - start a usermode application |
556 | * @sub_info: information about the subprocessa | 556 | * @sub_info: information about the subprocessa |
557 | * @wait: wait for the application to finish and return status. | 557 | * @wait: wait for the application to finish and return status. |
558 | * when -1 don't wait at all, but you get no useful error back when | 558 | * when UMH_NO_WAIT don't wait at all, but you get no useful error back |
559 | * the program couldn't be exec'ed. This makes it safe to call | 559 | * when the program couldn't be exec'ed. This makes it safe to call |
560 | * from interrupt context. | 560 | * from interrupt context. |
561 | * | 561 | * |
562 | * Runs a user-space application. The application is started | 562 | * Runs a user-space application. The application is started |
563 | * asynchronously if wait is not set, and runs as a child of keventd. | 563 | * asynchronously if wait is not set, and runs as a child of keventd. |
564 | * (ie. it runs with full root capabilities). | 564 | * (ie. it runs with full root capabilities). |
565 | */ | 565 | */ |
566 | static | ||
567 | int call_usermodehelper_exec(struct subprocess_info *sub_info, int wait) | 566 | int call_usermodehelper_exec(struct subprocess_info *sub_info, int wait) |
568 | { | 567 | { |
569 | DECLARE_COMPLETION_ONSTACK(done); | 568 | DECLARE_COMPLETION_ONSTACK(done); |
@@ -615,31 +614,34 @@ unlock: | |||
615 | helper_unlock(); | 614 | helper_unlock(); |
616 | return retval; | 615 | return retval; |
617 | } | 616 | } |
617 | EXPORT_SYMBOL(call_usermodehelper_exec); | ||
618 | 618 | ||
619 | /* | 619 | /** |
620 | * call_usermodehelper_fns() will not run the caller-provided cleanup function | 620 | * call_usermodehelper() - prepare and start a usermode application |
621 | * if a memory allocation failure is experienced. So the caller might need to | 621 | * @path: path to usermode executable |
622 | * check the call_usermodehelper_fns() return value: if it is -ENOMEM, perform | 622 | * @argv: arg vector for process |
623 | * the necessaary cleanup within the caller. | 623 | * @envp: environment for process |
624 | * @wait: wait for the application to finish and return status. | ||
625 | * when UMH_NO_WAIT don't wait at all, but you get no useful error back | ||
626 | * when the program couldn't be exec'ed. This makes it safe to call | ||
627 | * from interrupt context. | ||
628 | * | ||
629 | * This function is the equivalent to use call_usermodehelper_setup() and | ||
630 | * call_usermodehelper_exec(). | ||
624 | */ | 631 | */ |
625 | int call_usermodehelper_fns( | 632 | int call_usermodehelper(char *path, char **argv, char **envp, int wait) |
626 | char *path, char **argv, char **envp, int wait, | ||
627 | int (*init)(struct subprocess_info *info, struct cred *new), | ||
628 | void (*cleanup)(struct subprocess_info *), void *data) | ||
629 | { | 633 | { |
630 | struct subprocess_info *info; | 634 | struct subprocess_info *info; |
631 | gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL; | 635 | gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL; |
632 | 636 | ||
633 | info = call_usermodehelper_setup(path, argv, envp, gfp_mask); | 637 | info = call_usermodehelper_setup(path, argv, envp, gfp_mask, |
634 | 638 | NULL, NULL, NULL); | |
635 | if (info == NULL) | 639 | if (info == NULL) |
636 | return -ENOMEM; | 640 | return -ENOMEM; |
637 | 641 | ||
638 | call_usermodehelper_setfns(info, init, cleanup, data); | ||
639 | |||
640 | return call_usermodehelper_exec(info, wait); | 642 | return call_usermodehelper_exec(info, wait); |
641 | } | 643 | } |
642 | EXPORT_SYMBOL(call_usermodehelper_fns); | 644 | EXPORT_SYMBOL(call_usermodehelper); |
643 | 645 | ||
644 | static int proc_cap_handler(struct ctl_table *table, int write, | 646 | static int proc_cap_handler(struct ctl_table *table, int write, |
645 | void __user *buffer, size_t *lenp, loff_t *ppos) | 647 | void __user *buffer, size_t *lenp, loff_t *ppos) |