diff options
Diffstat (limited to 'kernel/params.c')
-rw-r--r-- | kernel/params.c | 121 |
1 files changed, 63 insertions, 58 deletions
diff --git a/kernel/params.c b/kernel/params.c index 34f527023794..0af9b2c4e56c 100644 --- a/kernel/params.c +++ b/kernel/params.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/string.h> | 19 | #include <linux/string.h> |
20 | #include <linux/errno.h> | 20 | #include <linux/errno.h> |
21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
22 | #include <linux/moduleparam.h> | ||
22 | #include <linux/device.h> | 23 | #include <linux/device.h> |
23 | #include <linux/err.h> | 24 | #include <linux/err.h> |
24 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
@@ -83,6 +84,15 @@ bool parameq(const char *a, const char *b) | |||
83 | return parameqn(a, b, strlen(a)+1); | 84 | return parameqn(a, b, strlen(a)+1); |
84 | } | 85 | } |
85 | 86 | ||
87 | static void param_check_unsafe(const struct kernel_param *kp) | ||
88 | { | ||
89 | if (kp->flags & KERNEL_PARAM_FL_UNSAFE) { | ||
90 | pr_warn("Setting dangerous option %s - tainting kernel\n", | ||
91 | kp->name); | ||
92 | add_taint(TAINT_USER, LOCKDEP_STILL_OK); | ||
93 | } | ||
94 | } | ||
95 | |||
86 | static int parse_one(char *param, | 96 | static int parse_one(char *param, |
87 | char *val, | 97 | char *val, |
88 | const char *doing, | 98 | const char *doing, |
@@ -104,11 +114,12 @@ static int parse_one(char *param, | |||
104 | return 0; | 114 | return 0; |
105 | /* No one handled NULL, so do it here. */ | 115 | /* No one handled NULL, so do it here. */ |
106 | if (!val && | 116 | if (!val && |
107 | !(params[i].ops->flags & KERNEL_PARAM_FL_NOARG)) | 117 | !(params[i].ops->flags & KERNEL_PARAM_OPS_FL_NOARG)) |
108 | return -EINVAL; | 118 | return -EINVAL; |
109 | pr_debug("handling %s with %p\n", param, | 119 | pr_debug("handling %s with %p\n", param, |
110 | params[i].ops->set); | 120 | params[i].ops->set); |
111 | mutex_lock(¶m_lock); | 121 | mutex_lock(¶m_lock); |
122 | param_check_unsafe(¶ms[i]); | ||
112 | err = params[i].ops->set(val, ¶ms[i]); | 123 | err = params[i].ops->set(val, ¶ms[i]); |
113 | mutex_unlock(¶m_lock); | 124 | mutex_unlock(¶m_lock); |
114 | return err; | 125 | return err; |
@@ -318,7 +329,7 @@ int param_get_bool(char *buffer, const struct kernel_param *kp) | |||
318 | EXPORT_SYMBOL(param_get_bool); | 329 | EXPORT_SYMBOL(param_get_bool); |
319 | 330 | ||
320 | struct kernel_param_ops param_ops_bool = { | 331 | struct kernel_param_ops param_ops_bool = { |
321 | .flags = KERNEL_PARAM_FL_NOARG, | 332 | .flags = KERNEL_PARAM_OPS_FL_NOARG, |
322 | .set = param_set_bool, | 333 | .set = param_set_bool, |
323 | .get = param_get_bool, | 334 | .get = param_get_bool, |
324 | }; | 335 | }; |
@@ -369,7 +380,7 @@ int param_set_bint(const char *val, const struct kernel_param *kp) | |||
369 | EXPORT_SYMBOL(param_set_bint); | 380 | EXPORT_SYMBOL(param_set_bint); |
370 | 381 | ||
371 | struct kernel_param_ops param_ops_bint = { | 382 | struct kernel_param_ops param_ops_bint = { |
372 | .flags = KERNEL_PARAM_FL_NOARG, | 383 | .flags = KERNEL_PARAM_OPS_FL_NOARG, |
373 | .set = param_set_bint, | 384 | .set = param_set_bint, |
374 | .get = param_get_int, | 385 | .get = param_get_int, |
375 | }; | 386 | }; |
@@ -503,8 +514,6 @@ EXPORT_SYMBOL(param_ops_string); | |||
503 | #define to_module_attr(n) container_of(n, struct module_attribute, attr) | 514 | #define to_module_attr(n) container_of(n, struct module_attribute, attr) |
504 | #define to_module_kobject(n) container_of(n, struct module_kobject, kobj) | 515 | #define to_module_kobject(n) container_of(n, struct module_kobject, kobj) |
505 | 516 | ||
506 | extern struct kernel_param __start___param[], __stop___param[]; | ||
507 | |||
508 | struct param_attribute | 517 | struct param_attribute |
509 | { | 518 | { |
510 | struct module_attribute mattr; | 519 | struct module_attribute mattr; |
@@ -552,6 +561,7 @@ static ssize_t param_attr_store(struct module_attribute *mattr, | |||
552 | return -EPERM; | 561 | return -EPERM; |
553 | 562 | ||
554 | mutex_lock(¶m_lock); | 563 | mutex_lock(¶m_lock); |
564 | param_check_unsafe(attribute->param); | ||
555 | err = attribute->param->ops->set(buf, attribute->param); | 565 | err = attribute->param->ops->set(buf, attribute->param); |
556 | mutex_unlock(¶m_lock); | 566 | mutex_unlock(¶m_lock); |
557 | if (!err) | 567 | if (!err) |
@@ -593,74 +603,67 @@ static __modinit int add_sysfs_param(struct module_kobject *mk, | |||
593 | const struct kernel_param *kp, | 603 | const struct kernel_param *kp, |
594 | const char *name) | 604 | const char *name) |
595 | { | 605 | { |
596 | struct module_param_attrs *new; | 606 | struct module_param_attrs *new_mp; |
597 | struct attribute **attrs; | 607 | struct attribute **new_attrs; |
598 | int err, num; | 608 | unsigned int i; |
599 | 609 | ||
600 | /* We don't bother calling this with invisible parameters. */ | 610 | /* We don't bother calling this with invisible parameters. */ |
601 | BUG_ON(!kp->perm); | 611 | BUG_ON(!kp->perm); |
602 | 612 | ||
603 | if (!mk->mp) { | 613 | if (!mk->mp) { |
604 | num = 0; | 614 | /* First allocation. */ |
605 | attrs = NULL; | 615 | mk->mp = kzalloc(sizeof(*mk->mp), GFP_KERNEL); |
606 | } else { | 616 | if (!mk->mp) |
607 | num = mk->mp->num; | 617 | return -ENOMEM; |
608 | attrs = mk->mp->grp.attrs; | 618 | mk->mp->grp.name = "parameters"; |
619 | /* NULL-terminated attribute array. */ | ||
620 | mk->mp->grp.attrs = kzalloc(sizeof(mk->mp->grp.attrs[0]), | ||
621 | GFP_KERNEL); | ||
622 | /* Caller will cleanup via free_module_param_attrs */ | ||
623 | if (!mk->mp->grp.attrs) | ||
624 | return -ENOMEM; | ||
609 | } | 625 | } |
610 | 626 | ||
611 | /* Enlarge. */ | 627 | /* Enlarge allocations. */ |
612 | new = krealloc(mk->mp, | 628 | new_mp = krealloc(mk->mp, |
613 | sizeof(*mk->mp) + sizeof(mk->mp->attrs[0]) * (num+1), | 629 | sizeof(*mk->mp) + |
614 | GFP_KERNEL); | 630 | sizeof(mk->mp->attrs[0]) * (mk->mp->num + 1), |
615 | if (!new) { | 631 | GFP_KERNEL); |
616 | kfree(attrs); | 632 | if (!new_mp) |
617 | err = -ENOMEM; | 633 | return -ENOMEM; |
618 | goto fail; | 634 | mk->mp = new_mp; |
619 | } | ||
620 | /* Despite looking like the typical realloc() bug, this is safe. | ||
621 | * We *want* the old 'attrs' to be freed either way, and we'll store | ||
622 | * the new one in the success case. */ | ||
623 | attrs = krealloc(attrs, sizeof(new->grp.attrs[0])*(num+2), GFP_KERNEL); | ||
624 | if (!attrs) { | ||
625 | err = -ENOMEM; | ||
626 | goto fail_free_new; | ||
627 | } | ||
628 | 635 | ||
629 | /* Sysfs wants everything zeroed. */ | 636 | /* Extra pointer for NULL terminator */ |
630 | memset(new, 0, sizeof(*new)); | 637 | new_attrs = krealloc(mk->mp->grp.attrs, |
631 | memset(&new->attrs[num], 0, sizeof(new->attrs[num])); | 638 | sizeof(mk->mp->grp.attrs[0]) * (mk->mp->num + 2), |
632 | memset(&attrs[num], 0, sizeof(attrs[num])); | 639 | GFP_KERNEL); |
633 | new->grp.name = "parameters"; | 640 | if (!new_attrs) |
634 | new->grp.attrs = attrs; | 641 | return -ENOMEM; |
642 | mk->mp->grp.attrs = new_attrs; | ||
635 | 643 | ||
636 | /* Tack new one on the end. */ | 644 | /* Tack new one on the end. */ |
637 | sysfs_attr_init(&new->attrs[num].mattr.attr); | 645 | sysfs_attr_init(&mk->mp->attrs[mk->mp->num].mattr.attr); |
638 | new->attrs[num].param = kp; | 646 | mk->mp->attrs[mk->mp->num].param = kp; |
639 | new->attrs[num].mattr.show = param_attr_show; | 647 | mk->mp->attrs[mk->mp->num].mattr.show = param_attr_show; |
640 | new->attrs[num].mattr.store = param_attr_store; | 648 | /* Do not allow runtime DAC changes to make param writable. */ |
641 | new->attrs[num].mattr.attr.name = (char *)name; | 649 | if ((kp->perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0) |
642 | new->attrs[num].mattr.attr.mode = kp->perm; | 650 | mk->mp->attrs[mk->mp->num].mattr.store = param_attr_store; |
643 | new->num = num+1; | 651 | mk->mp->attrs[mk->mp->num].mattr.attr.name = (char *)name; |
652 | mk->mp->attrs[mk->mp->num].mattr.attr.mode = kp->perm; | ||
653 | mk->mp->num++; | ||
644 | 654 | ||
645 | /* Fix up all the pointers, since krealloc can move us */ | 655 | /* Fix up all the pointers, since krealloc can move us */ |
646 | for (num = 0; num < new->num; num++) | 656 | for (i = 0; i < mk->mp->num; i++) |
647 | new->grp.attrs[num] = &new->attrs[num].mattr.attr; | 657 | mk->mp->grp.attrs[i] = &mk->mp->attrs[i].mattr.attr; |
648 | new->grp.attrs[num] = NULL; | 658 | mk->mp->grp.attrs[mk->mp->num] = NULL; |
649 | |||
650 | mk->mp = new; | ||
651 | return 0; | 659 | return 0; |
652 | |||
653 | fail_free_new: | ||
654 | kfree(new); | ||
655 | fail: | ||
656 | mk->mp = NULL; | ||
657 | return err; | ||
658 | } | 660 | } |
659 | 661 | ||
660 | #ifdef CONFIG_MODULES | 662 | #ifdef CONFIG_MODULES |
661 | static void free_module_param_attrs(struct module_kobject *mk) | 663 | static void free_module_param_attrs(struct module_kobject *mk) |
662 | { | 664 | { |
663 | kfree(mk->mp->grp.attrs); | 665 | if (mk->mp) |
666 | kfree(mk->mp->grp.attrs); | ||
664 | kfree(mk->mp); | 667 | kfree(mk->mp); |
665 | mk->mp = NULL; | 668 | mk->mp = NULL; |
666 | } | 669 | } |
@@ -685,8 +688,10 @@ int module_param_sysfs_setup(struct module *mod, | |||
685 | if (kparam[i].perm == 0) | 688 | if (kparam[i].perm == 0) |
686 | continue; | 689 | continue; |
687 | err = add_sysfs_param(&mod->mkobj, &kparam[i], kparam[i].name); | 690 | err = add_sysfs_param(&mod->mkobj, &kparam[i], kparam[i].name); |
688 | if (err) | 691 | if (err) { |
692 | free_module_param_attrs(&mod->mkobj); | ||
689 | return err; | 693 | return err; |
694 | } | ||
690 | params = true; | 695 | params = true; |
691 | } | 696 | } |
692 | 697 | ||
@@ -763,7 +768,7 @@ static struct module_kobject * __init locate_module_kobject(const char *name) | |||
763 | } | 768 | } |
764 | 769 | ||
765 | static void __init kernel_add_sysfs_param(const char *name, | 770 | static void __init kernel_add_sysfs_param(const char *name, |
766 | struct kernel_param *kparam, | 771 | const struct kernel_param *kparam, |
767 | unsigned int name_skip) | 772 | unsigned int name_skip) |
768 | { | 773 | { |
769 | struct module_kobject *mk; | 774 | struct module_kobject *mk; |
@@ -798,7 +803,7 @@ static void __init kernel_add_sysfs_param(const char *name, | |||
798 | */ | 803 | */ |
799 | static void __init param_sysfs_builtin(void) | 804 | static void __init param_sysfs_builtin(void) |
800 | { | 805 | { |
801 | struct kernel_param *kp; | 806 | const struct kernel_param *kp; |
802 | unsigned int name_len; | 807 | unsigned int name_len; |
803 | char modname[MODULE_NAME_LEN]; | 808 | char modname[MODULE_NAME_LEN]; |
804 | 809 | ||