diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-04 20:34:29 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-04 20:34:29 -0400 |
commit | 3398d252a4da80c47fe9b802184fa0a792387732 (patch) | |
tree | 3def3b476b597487193718508f5644a6075a736f | |
parent | 27703bb4a66df49ff16b44b864d307d2eb71774c (diff) | |
parent | 942e443127e928a5631c3d5102aca8c8b3c2dd98 (diff) |
Merge tag 'modules-next-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux
Pull module updates from Rusty Russell:
"Minor fixes mainly, including a potential use-after-free on remove
found by CONFIG_DEBUG_KOBJECT_RELEASE which may be theoretical"
* tag 'modules-next-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux:
module: Fix mod->mkobj.kobj potentially freed too early
kernel/params.c: use scnprintf() instead of sprintf()
kernel/module.c: use scnprintf() instead of sprintf()
module/lsm: Have apparmor module parameters work with no args
module: Add NOARG flag for ops with param_set_bool_enable_only() set function
module: Add flag to allow mod params to have no arguments
modules: add support for soft module dependencies
scripts/mod/modpost.c: permit '.cranges' secton for sh64 architecture.
module: fix sprintf format specifier in param_get_byte()
-rw-r--r-- | include/linux/module.h | 6 | ||||
-rw-r--r-- | include/linux/moduleparam.h | 13 | ||||
-rw-r--r-- | kernel/module.c | 17 | ||||
-rw-r--r-- | kernel/params.c | 22 | ||||
-rw-r--r-- | scripts/mod/modpost.c | 1 | ||||
-rw-r--r-- | security/apparmor/lsm.c | 2 |
6 files changed, 50 insertions, 11 deletions
diff --git a/include/linux/module.h b/include/linux/module.h index 46f1ea01e6f6..05f2447f8c15 100644 --- a/include/linux/module.h +++ b/include/linux/module.h | |||
@@ -42,6 +42,7 @@ struct module_kobject { | |||
42 | struct module *mod; | 42 | struct module *mod; |
43 | struct kobject *drivers_dir; | 43 | struct kobject *drivers_dir; |
44 | struct module_param_attrs *mp; | 44 | struct module_param_attrs *mp; |
45 | struct completion *kobj_completion; | ||
45 | }; | 46 | }; |
46 | 47 | ||
47 | struct module_attribute { | 48 | struct module_attribute { |
@@ -97,6 +98,11 @@ extern const struct gtype##_id __mod_##gtype##_table \ | |||
97 | /* For userspace: you can also call me... */ | 98 | /* For userspace: you can also call me... */ |
98 | #define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias) | 99 | #define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias) |
99 | 100 | ||
101 | /* Soft module dependencies. See man modprobe.d for details. | ||
102 | * Example: MODULE_SOFTDEP("pre: module-foo module-bar post: module-baz") | ||
103 | */ | ||
104 | #define MODULE_SOFTDEP(_softdep) MODULE_INFO(softdep, _softdep) | ||
105 | |||
100 | /* | 106 | /* |
101 | * The following license idents are currently accepted as indicating free | 107 | * The following license idents are currently accepted as indicating free |
102 | * software modules | 108 | * software modules |
diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h index 27d9da3f86ff..c3eb102a9cc8 100644 --- a/include/linux/moduleparam.h +++ b/include/linux/moduleparam.h | |||
@@ -36,7 +36,18 @@ static const char __UNIQUE_ID(name)[] \ | |||
36 | 36 | ||
37 | struct kernel_param; | 37 | struct kernel_param; |
38 | 38 | ||
39 | /* | ||
40 | * Flags available for kernel_param_ops | ||
41 | * | ||
42 | * NOARG - the parameter allows for no argument (foo instead of foo=1) | ||
43 | */ | ||
44 | enum { | ||
45 | KERNEL_PARAM_FL_NOARG = (1 << 0) | ||
46 | }; | ||
47 | |||
39 | struct kernel_param_ops { | 48 | struct kernel_param_ops { |
49 | /* How the ops should behave */ | ||
50 | unsigned int flags; | ||
40 | /* Returns 0, or -errno. arg is in kp->arg. */ | 51 | /* Returns 0, or -errno. arg is in kp->arg. */ |
41 | int (*set)(const char *val, const struct kernel_param *kp); | 52 | int (*set)(const char *val, const struct kernel_param *kp); |
42 | /* Returns length written or -errno. Buffer is 4k (ie. be short!) */ | 53 | /* Returns length written or -errno. Buffer is 4k (ie. be short!) */ |
@@ -187,7 +198,7 @@ struct kparam_array | |||
187 | /* Obsolete - use module_param_cb() */ | 198 | /* Obsolete - use module_param_cb() */ |
188 | #define module_param_call(name, set, get, arg, perm) \ | 199 | #define module_param_call(name, set, get, arg, perm) \ |
189 | static struct kernel_param_ops __param_ops_##name = \ | 200 | static struct kernel_param_ops __param_ops_##name = \ |
190 | { (void *)set, (void *)get }; \ | 201 | { 0, (void *)set, (void *)get }; \ |
191 | __module_param_call(MODULE_PARAM_PREFIX, \ | 202 | __module_param_call(MODULE_PARAM_PREFIX, \ |
192 | name, &__param_ops_##name, arg, \ | 203 | name, &__param_ops_##name, arg, \ |
193 | (perm) + sizeof(__check_old_set_param(set))*0, -1) | 204 | (perm) + sizeof(__check_old_set_param(set))*0, -1) |
diff --git a/kernel/module.c b/kernel/module.c index 206915830d29..9f5ddae72f44 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -136,6 +136,7 @@ static int param_set_bool_enable_only(const char *val, | |||
136 | } | 136 | } |
137 | 137 | ||
138 | static const struct kernel_param_ops param_ops_bool_enable_only = { | 138 | static const struct kernel_param_ops param_ops_bool_enable_only = { |
139 | .flags = KERNEL_PARAM_FL_NOARG, | ||
139 | .set = param_set_bool_enable_only, | 140 | .set = param_set_bool_enable_only, |
140 | .get = param_get_bool, | 141 | .get = param_get_bool, |
141 | }; | 142 | }; |
@@ -603,7 +604,7 @@ static void setup_modinfo_##field(struct module *mod, const char *s) \ | |||
603 | static ssize_t show_modinfo_##field(struct module_attribute *mattr, \ | 604 | static ssize_t show_modinfo_##field(struct module_attribute *mattr, \ |
604 | struct module_kobject *mk, char *buffer) \ | 605 | struct module_kobject *mk, char *buffer) \ |
605 | { \ | 606 | { \ |
606 | return sprintf(buffer, "%s\n", mk->mod->field); \ | 607 | return scnprintf(buffer, PAGE_SIZE, "%s\n", mk->mod->field); \ |
607 | } \ | 608 | } \ |
608 | static int modinfo_##field##_exists(struct module *mod) \ | 609 | static int modinfo_##field##_exists(struct module *mod) \ |
609 | { \ | 610 | { \ |
@@ -1611,6 +1612,14 @@ static void module_remove_modinfo_attrs(struct module *mod) | |||
1611 | kfree(mod->modinfo_attrs); | 1612 | kfree(mod->modinfo_attrs); |
1612 | } | 1613 | } |
1613 | 1614 | ||
1615 | static void mod_kobject_put(struct module *mod) | ||
1616 | { | ||
1617 | DECLARE_COMPLETION_ONSTACK(c); | ||
1618 | mod->mkobj.kobj_completion = &c; | ||
1619 | kobject_put(&mod->mkobj.kobj); | ||
1620 | wait_for_completion(&c); | ||
1621 | } | ||
1622 | |||
1614 | static int mod_sysfs_init(struct module *mod) | 1623 | static int mod_sysfs_init(struct module *mod) |
1615 | { | 1624 | { |
1616 | int err; | 1625 | int err; |
@@ -1638,7 +1647,7 @@ static int mod_sysfs_init(struct module *mod) | |||
1638 | err = kobject_init_and_add(&mod->mkobj.kobj, &module_ktype, NULL, | 1647 | err = kobject_init_and_add(&mod->mkobj.kobj, &module_ktype, NULL, |
1639 | "%s", mod->name); | 1648 | "%s", mod->name); |
1640 | if (err) | 1649 | if (err) |
1641 | kobject_put(&mod->mkobj.kobj); | 1650 | mod_kobject_put(mod); |
1642 | 1651 | ||
1643 | /* delay uevent until full sysfs population */ | 1652 | /* delay uevent until full sysfs population */ |
1644 | out: | 1653 | out: |
@@ -1682,7 +1691,7 @@ out_unreg_param: | |||
1682 | out_unreg_holders: | 1691 | out_unreg_holders: |
1683 | kobject_put(mod->holders_dir); | 1692 | kobject_put(mod->holders_dir); |
1684 | out_unreg: | 1693 | out_unreg: |
1685 | kobject_put(&mod->mkobj.kobj); | 1694 | mod_kobject_put(mod); |
1686 | out: | 1695 | out: |
1687 | return err; | 1696 | return err; |
1688 | } | 1697 | } |
@@ -1691,7 +1700,7 @@ static void mod_sysfs_fini(struct module *mod) | |||
1691 | { | 1700 | { |
1692 | remove_notes_attrs(mod); | 1701 | remove_notes_attrs(mod); |
1693 | remove_sect_attrs(mod); | 1702 | remove_sect_attrs(mod); |
1694 | kobject_put(&mod->mkobj.kobj); | 1703 | mod_kobject_put(mod); |
1695 | } | 1704 | } |
1696 | 1705 | ||
1697 | #else /* !CONFIG_SYSFS */ | 1706 | #else /* !CONFIG_SYSFS */ |
diff --git a/kernel/params.c b/kernel/params.c index 440e65d1a544..501bde4f3bee 100644 --- a/kernel/params.c +++ b/kernel/params.c | |||
@@ -103,8 +103,8 @@ static int parse_one(char *param, | |||
103 | || params[i].level > max_level) | 103 | || params[i].level > max_level) |
104 | return 0; | 104 | return 0; |
105 | /* No one handled NULL, so do it here. */ | 105 | /* No one handled NULL, so do it here. */ |
106 | if (!val && params[i].ops->set != param_set_bool | 106 | if (!val && |
107 | && params[i].ops->set != param_set_bint) | 107 | !(params[i].ops->flags & KERNEL_PARAM_FL_NOARG)) |
108 | return -EINVAL; | 108 | return -EINVAL; |
109 | pr_debug("handling %s with %p\n", param, | 109 | pr_debug("handling %s with %p\n", param, |
110 | params[i].ops->set); | 110 | params[i].ops->set); |
@@ -241,7 +241,8 @@ int parse_args(const char *doing, | |||
241 | } \ | 241 | } \ |
242 | int param_get_##name(char *buffer, const struct kernel_param *kp) \ | 242 | int param_get_##name(char *buffer, const struct kernel_param *kp) \ |
243 | { \ | 243 | { \ |
244 | return sprintf(buffer, format, *((type *)kp->arg)); \ | 244 | return scnprintf(buffer, PAGE_SIZE, format, \ |
245 | *((type *)kp->arg)); \ | ||
245 | } \ | 246 | } \ |
246 | struct kernel_param_ops param_ops_##name = { \ | 247 | struct kernel_param_ops param_ops_##name = { \ |
247 | .set = param_set_##name, \ | 248 | .set = param_set_##name, \ |
@@ -252,7 +253,7 @@ int parse_args(const char *doing, | |||
252 | EXPORT_SYMBOL(param_ops_##name) | 253 | EXPORT_SYMBOL(param_ops_##name) |
253 | 254 | ||
254 | 255 | ||
255 | STANDARD_PARAM_DEF(byte, unsigned char, "%c", unsigned long, strict_strtoul); | 256 | STANDARD_PARAM_DEF(byte, unsigned char, "%hhu", unsigned long, strict_strtoul); |
256 | STANDARD_PARAM_DEF(short, short, "%hi", long, strict_strtol); | 257 | STANDARD_PARAM_DEF(short, short, "%hi", long, strict_strtol); |
257 | STANDARD_PARAM_DEF(ushort, unsigned short, "%hu", unsigned long, strict_strtoul); | 258 | STANDARD_PARAM_DEF(ushort, unsigned short, "%hu", unsigned long, strict_strtoul); |
258 | STANDARD_PARAM_DEF(int, int, "%i", long, strict_strtol); | 259 | STANDARD_PARAM_DEF(int, int, "%i", long, strict_strtol); |
@@ -285,7 +286,7 @@ EXPORT_SYMBOL(param_set_charp); | |||
285 | 286 | ||
286 | int param_get_charp(char *buffer, const struct kernel_param *kp) | 287 | int param_get_charp(char *buffer, const struct kernel_param *kp) |
287 | { | 288 | { |
288 | return sprintf(buffer, "%s", *((char **)kp->arg)); | 289 | return scnprintf(buffer, PAGE_SIZE, "%s", *((char **)kp->arg)); |
289 | } | 290 | } |
290 | EXPORT_SYMBOL(param_get_charp); | 291 | EXPORT_SYMBOL(param_get_charp); |
291 | 292 | ||
@@ -320,6 +321,7 @@ int param_get_bool(char *buffer, const struct kernel_param *kp) | |||
320 | EXPORT_SYMBOL(param_get_bool); | 321 | EXPORT_SYMBOL(param_get_bool); |
321 | 322 | ||
322 | struct kernel_param_ops param_ops_bool = { | 323 | struct kernel_param_ops param_ops_bool = { |
324 | .flags = KERNEL_PARAM_FL_NOARG, | ||
323 | .set = param_set_bool, | 325 | .set = param_set_bool, |
324 | .get = param_get_bool, | 326 | .get = param_get_bool, |
325 | }; | 327 | }; |
@@ -370,6 +372,7 @@ int param_set_bint(const char *val, const struct kernel_param *kp) | |||
370 | EXPORT_SYMBOL(param_set_bint); | 372 | EXPORT_SYMBOL(param_set_bint); |
371 | 373 | ||
372 | struct kernel_param_ops param_ops_bint = { | 374 | struct kernel_param_ops param_ops_bint = { |
375 | .flags = KERNEL_PARAM_FL_NOARG, | ||
373 | .set = param_set_bint, | 376 | .set = param_set_bint, |
374 | .get = param_get_int, | 377 | .get = param_get_int, |
375 | }; | 378 | }; |
@@ -827,7 +830,7 @@ ssize_t __modver_version_show(struct module_attribute *mattr, | |||
827 | struct module_version_attribute *vattr = | 830 | struct module_version_attribute *vattr = |
828 | container_of(mattr, struct module_version_attribute, mattr); | 831 | container_of(mattr, struct module_version_attribute, mattr); |
829 | 832 | ||
830 | return sprintf(buf, "%s\n", vattr->version); | 833 | return scnprintf(buf, PAGE_SIZE, "%s\n", vattr->version); |
831 | } | 834 | } |
832 | 835 | ||
833 | extern const struct module_version_attribute *__start___modver[]; | 836 | extern const struct module_version_attribute *__start___modver[]; |
@@ -912,7 +915,14 @@ static const struct kset_uevent_ops module_uevent_ops = { | |||
912 | struct kset *module_kset; | 915 | struct kset *module_kset; |
913 | int module_sysfs_initialized; | 916 | int module_sysfs_initialized; |
914 | 917 | ||
918 | static void module_kobj_release(struct kobject *kobj) | ||
919 | { | ||
920 | struct module_kobject *mk = to_module_kobject(kobj); | ||
921 | complete(mk->kobj_completion); | ||
922 | } | ||
923 | |||
915 | struct kobj_type module_ktype = { | 924 | struct kobj_type module_ktype = { |
925 | .release = module_kobj_release, | ||
916 | .sysfs_ops = &module_sysfs_ops, | 926 | .sysfs_ops = &module_sysfs_ops, |
917 | }; | 927 | }; |
918 | 928 | ||
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 62164348ecf7..8247979e8f64 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c | |||
@@ -821,6 +821,7 @@ static const char *section_white_list[] = | |||
821 | { | 821 | { |
822 | ".comment*", | 822 | ".comment*", |
823 | ".debug*", | 823 | ".debug*", |
824 | ".cranges", /* sh64 */ | ||
824 | ".zdebug*", /* Compressed debug sections. */ | 825 | ".zdebug*", /* Compressed debug sections. */ |
825 | ".GCC-command-line", /* mn10300 */ | 826 | ".GCC-command-line", /* mn10300 */ |
826 | ".GCC.command.line", /* record-gcc-switches, non mn10300 */ | 827 | ".GCC.command.line", /* record-gcc-switches, non mn10300 */ |
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 2e2a0dd4a73f..e3a704c75ef6 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c | |||
@@ -666,6 +666,7 @@ static int param_set_aabool(const char *val, const struct kernel_param *kp); | |||
666 | static int param_get_aabool(char *buffer, const struct kernel_param *kp); | 666 | static int param_get_aabool(char *buffer, const struct kernel_param *kp); |
667 | #define param_check_aabool param_check_bool | 667 | #define param_check_aabool param_check_bool |
668 | static struct kernel_param_ops param_ops_aabool = { | 668 | static struct kernel_param_ops param_ops_aabool = { |
669 | .flags = KERNEL_PARAM_FL_NOARG, | ||
669 | .set = param_set_aabool, | 670 | .set = param_set_aabool, |
670 | .get = param_get_aabool | 671 | .get = param_get_aabool |
671 | }; | 672 | }; |
@@ -682,6 +683,7 @@ static int param_set_aalockpolicy(const char *val, const struct kernel_param *kp | |||
682 | static int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp); | 683 | static int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp); |
683 | #define param_check_aalockpolicy param_check_bool | 684 | #define param_check_aalockpolicy param_check_bool |
684 | static struct kernel_param_ops param_ops_aalockpolicy = { | 685 | static struct kernel_param_ops param_ops_aalockpolicy = { |
686 | .flags = KERNEL_PARAM_FL_NOARG, | ||
685 | .set = param_set_aalockpolicy, | 687 | .set = param_set_aalockpolicy, |
686 | .get = param_get_aalockpolicy | 688 | .get = param_get_aalockpolicy |
687 | }; | 689 | }; |