diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2006-02-16 16:50:23 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-03-20 16:42:58 -0500 |
commit | 03e88ae1b13dfdc8bbaa59b8198e1ca53aad12ac (patch) | |
tree | 322127d9875129d2e9b1c3cb744b4940bd7d8a47 | |
parent | b87ba0a33a634c9a8e3609702122a04034a0688d (diff) |
[PATCH] fix module sysfs files reference counting
The module files, refcnt, version, and srcversion did not properly
increment the owner's module reference count, allowing the modules to
be removed while the files were open, causing oopses.
This patch fixes this, and also fixes the problem that the version and
srcversion files were not showing up, unless CONFIG_MODULE_UNLOAD was
enabled, which is not correct.
Cc: Nathan Lynch <ntl@pobox.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | include/linux/module.h | 1 | ||||
-rw-r--r-- | kernel/module.c | 77 | ||||
-rw-r--r-- | kernel/params.c | 10 |
3 files changed, 32 insertions, 56 deletions
diff --git a/include/linux/module.h b/include/linux/module.h index a25d5f61548c..70bd843c71cb 100644 --- a/include/linux/module.h +++ b/include/linux/module.h | |||
@@ -245,6 +245,7 @@ struct module | |||
245 | /* Sysfs stuff. */ | 245 | /* Sysfs stuff. */ |
246 | struct module_kobject mkobj; | 246 | struct module_kobject mkobj; |
247 | struct module_param_attrs *param_attrs; | 247 | struct module_param_attrs *param_attrs; |
248 | struct module_attribute *modinfo_attrs; | ||
248 | const char *version; | 249 | const char *version; |
249 | const char *srcversion; | 250 | const char *srcversion; |
250 | 251 | ||
diff --git a/kernel/module.c b/kernel/module.c index 5ca99fbe9f44..77764f22f021 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -429,7 +429,6 @@ static inline void percpu_modcopy(void *pcpudst, const void *src, | |||
429 | } | 429 | } |
430 | #endif /* CONFIG_SMP */ | 430 | #endif /* CONFIG_SMP */ |
431 | 431 | ||
432 | #ifdef CONFIG_MODULE_UNLOAD | ||
433 | #define MODINFO_ATTR(field) \ | 432 | #define MODINFO_ATTR(field) \ |
434 | static void setup_modinfo_##field(struct module *mod, const char *s) \ | 433 | static void setup_modinfo_##field(struct module *mod, const char *s) \ |
435 | { \ | 434 | { \ |
@@ -461,12 +460,7 @@ static struct module_attribute modinfo_##field = { \ | |||
461 | MODINFO_ATTR(version); | 460 | MODINFO_ATTR(version); |
462 | MODINFO_ATTR(srcversion); | 461 | MODINFO_ATTR(srcversion); |
463 | 462 | ||
464 | static struct module_attribute *modinfo_attrs[] = { | 463 | #ifdef CONFIG_MODULE_UNLOAD |
465 | &modinfo_version, | ||
466 | &modinfo_srcversion, | ||
467 | NULL, | ||
468 | }; | ||
469 | |||
470 | /* Init the unload section of the module. */ | 464 | /* Init the unload section of the module. */ |
471 | static void module_unload_init(struct module *mod) | 465 | static void module_unload_init(struct module *mod) |
472 | { | 466 | { |
@@ -781,6 +775,15 @@ static inline void module_unload_init(struct module *mod) | |||
781 | } | 775 | } |
782 | #endif /* CONFIG_MODULE_UNLOAD */ | 776 | #endif /* CONFIG_MODULE_UNLOAD */ |
783 | 777 | ||
778 | static struct module_attribute *modinfo_attrs[] = { | ||
779 | &modinfo_version, | ||
780 | &modinfo_srcversion, | ||
781 | #ifdef CONFIG_MODULE_UNLOAD | ||
782 | &refcnt, | ||
783 | #endif | ||
784 | NULL, | ||
785 | }; | ||
786 | |||
784 | #ifdef CONFIG_OBSOLETE_MODPARM | 787 | #ifdef CONFIG_OBSOLETE_MODPARM |
785 | /* Bounds checking done below */ | 788 | /* Bounds checking done below */ |
786 | static int obsparm_copy_string(const char *val, struct kernel_param *kp) | 789 | static int obsparm_copy_string(const char *val, struct kernel_param *kp) |
@@ -1106,37 +1109,28 @@ static inline void remove_sect_attrs(struct module *mod) | |||
1106 | } | 1109 | } |
1107 | #endif /* CONFIG_KALLSYMS */ | 1110 | #endif /* CONFIG_KALLSYMS */ |
1108 | 1111 | ||
1109 | |||
1110 | #ifdef CONFIG_MODULE_UNLOAD | ||
1111 | static inline int module_add_refcnt_attr(struct module *mod) | ||
1112 | { | ||
1113 | return sysfs_create_file(&mod->mkobj.kobj, &refcnt.attr); | ||
1114 | } | ||
1115 | static void module_remove_refcnt_attr(struct module *mod) | ||
1116 | { | ||
1117 | return sysfs_remove_file(&mod->mkobj.kobj, &refcnt.attr); | ||
1118 | } | ||
1119 | #else | ||
1120 | static inline int module_add_refcnt_attr(struct module *mod) | ||
1121 | { | ||
1122 | return 0; | ||
1123 | } | ||
1124 | static void module_remove_refcnt_attr(struct module *mod) | ||
1125 | { | ||
1126 | } | ||
1127 | #endif | ||
1128 | |||
1129 | #ifdef CONFIG_MODULE_UNLOAD | ||
1130 | static int module_add_modinfo_attrs(struct module *mod) | 1112 | static int module_add_modinfo_attrs(struct module *mod) |
1131 | { | 1113 | { |
1132 | struct module_attribute *attr; | 1114 | struct module_attribute *attr; |
1115 | struct module_attribute *temp_attr; | ||
1133 | int error = 0; | 1116 | int error = 0; |
1134 | int i; | 1117 | int i; |
1135 | 1118 | ||
1119 | mod->modinfo_attrs = kzalloc((sizeof(struct module_attribute) * | ||
1120 | (ARRAY_SIZE(modinfo_attrs) + 1)), | ||
1121 | GFP_KERNEL); | ||
1122 | if (!mod->modinfo_attrs) | ||
1123 | return -ENOMEM; | ||
1124 | |||
1125 | temp_attr = mod->modinfo_attrs; | ||
1136 | for (i = 0; (attr = modinfo_attrs[i]) && !error; i++) { | 1126 | for (i = 0; (attr = modinfo_attrs[i]) && !error; i++) { |
1137 | if (!attr->test || | 1127 | if (!attr->test || |
1138 | (attr->test && attr->test(mod))) | 1128 | (attr->test && attr->test(mod))) { |
1139 | error = sysfs_create_file(&mod->mkobj.kobj,&attr->attr); | 1129 | memcpy(temp_attr, attr, sizeof(*temp_attr)); |
1130 | temp_attr->attr.owner = mod; | ||
1131 | error = sysfs_create_file(&mod->mkobj.kobj,&temp_attr->attr); | ||
1132 | ++temp_attr; | ||
1133 | } | ||
1140 | } | 1134 | } |
1141 | return error; | 1135 | return error; |
1142 | } | 1136 | } |
@@ -1146,12 +1140,16 @@ static void module_remove_modinfo_attrs(struct module *mod) | |||
1146 | struct module_attribute *attr; | 1140 | struct module_attribute *attr; |
1147 | int i; | 1141 | int i; |
1148 | 1142 | ||
1149 | for (i = 0; (attr = modinfo_attrs[i]); i++) { | 1143 | for (i = 0; (attr = &mod->modinfo_attrs[i]); i++) { |
1144 | /* pick a field to test for end of list */ | ||
1145 | if (!attr->attr.name) | ||
1146 | break; | ||
1150 | sysfs_remove_file(&mod->mkobj.kobj,&attr->attr); | 1147 | sysfs_remove_file(&mod->mkobj.kobj,&attr->attr); |
1151 | attr->free(mod); | 1148 | if (attr->free) |
1149 | attr->free(mod); | ||
1152 | } | 1150 | } |
1151 | kfree(mod->modinfo_attrs); | ||
1153 | } | 1152 | } |
1154 | #endif | ||
1155 | 1153 | ||
1156 | static int mod_sysfs_setup(struct module *mod, | 1154 | static int mod_sysfs_setup(struct module *mod, |
1157 | struct kernel_param *kparam, | 1155 | struct kernel_param *kparam, |
@@ -1169,19 +1167,13 @@ static int mod_sysfs_setup(struct module *mod, | |||
1169 | if (err) | 1167 | if (err) |
1170 | goto out; | 1168 | goto out; |
1171 | 1169 | ||
1172 | err = module_add_refcnt_attr(mod); | ||
1173 | if (err) | ||
1174 | goto out_unreg; | ||
1175 | |||
1176 | err = module_param_sysfs_setup(mod, kparam, num_params); | 1170 | err = module_param_sysfs_setup(mod, kparam, num_params); |
1177 | if (err) | 1171 | if (err) |
1178 | goto out_unreg; | 1172 | goto out_unreg; |
1179 | 1173 | ||
1180 | #ifdef CONFIG_MODULE_UNLOAD | ||
1181 | err = module_add_modinfo_attrs(mod); | 1174 | err = module_add_modinfo_attrs(mod); |
1182 | if (err) | 1175 | if (err) |
1183 | goto out_unreg; | 1176 | goto out_unreg; |
1184 | #endif | ||
1185 | 1177 | ||
1186 | return 0; | 1178 | return 0; |
1187 | 1179 | ||
@@ -1193,10 +1185,7 @@ out: | |||
1193 | 1185 | ||
1194 | static void mod_kobject_remove(struct module *mod) | 1186 | static void mod_kobject_remove(struct module *mod) |
1195 | { | 1187 | { |
1196 | #ifdef CONFIG_MODULE_UNLOAD | ||
1197 | module_remove_modinfo_attrs(mod); | 1188 | module_remove_modinfo_attrs(mod); |
1198 | #endif | ||
1199 | module_remove_refcnt_attr(mod); | ||
1200 | module_param_sysfs_remove(mod); | 1189 | module_param_sysfs_remove(mod); |
1201 | 1190 | ||
1202 | kobject_unregister(&mod->mkobj.kobj); | 1191 | kobject_unregister(&mod->mkobj.kobj); |
@@ -1474,7 +1463,6 @@ static char *get_modinfo(Elf_Shdr *sechdrs, | |||
1474 | return NULL; | 1463 | return NULL; |
1475 | } | 1464 | } |
1476 | 1465 | ||
1477 | #ifdef CONFIG_MODULE_UNLOAD | ||
1478 | static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs, | 1466 | static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs, |
1479 | unsigned int infoindex) | 1467 | unsigned int infoindex) |
1480 | { | 1468 | { |
@@ -1489,7 +1477,6 @@ static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs, | |||
1489 | attr->attr.name)); | 1477 | attr->attr.name)); |
1490 | } | 1478 | } |
1491 | } | 1479 | } |
1492 | #endif | ||
1493 | 1480 | ||
1494 | #ifdef CONFIG_KALLSYMS | 1481 | #ifdef CONFIG_KALLSYMS |
1495 | int is_exported(const char *name, const struct module *mod) | 1482 | int is_exported(const char *name, const struct module *mod) |
@@ -1803,10 +1790,8 @@ static struct module *load_module(void __user *umod, | |||
1803 | if (strcmp(mod->name, "driverloader") == 0) | 1790 | if (strcmp(mod->name, "driverloader") == 0) |
1804 | add_taint(TAINT_PROPRIETARY_MODULE); | 1791 | add_taint(TAINT_PROPRIETARY_MODULE); |
1805 | 1792 | ||
1806 | #ifdef CONFIG_MODULE_UNLOAD | ||
1807 | /* Set up MODINFO_ATTR fields */ | 1793 | /* Set up MODINFO_ATTR fields */ |
1808 | setup_modinfo(mod, sechdrs, infoindex); | 1794 | setup_modinfo(mod, sechdrs, infoindex); |
1809 | #endif | ||
1810 | 1795 | ||
1811 | /* Fix up syms, so that st_value is a pointer to location. */ | 1796 | /* Fix up syms, so that st_value is a pointer to location. */ |
1812 | err = simplify_symbols(sechdrs, symindex, strtab, versindex, pcpuindex, | 1797 | err = simplify_symbols(sechdrs, symindex, strtab, versindex, pcpuindex, |
diff --git a/kernel/params.c b/kernel/params.c index c76ad25e6a21..a29150582310 100644 --- a/kernel/params.c +++ b/kernel/params.c | |||
@@ -638,13 +638,8 @@ static ssize_t module_attr_show(struct kobject *kobj, | |||
638 | if (!attribute->show) | 638 | if (!attribute->show) |
639 | return -EIO; | 639 | return -EIO; |
640 | 640 | ||
641 | if (!try_module_get(mk->mod)) | ||
642 | return -ENODEV; | ||
643 | |||
644 | ret = attribute->show(attribute, mk->mod, buf); | 641 | ret = attribute->show(attribute, mk->mod, buf); |
645 | 642 | ||
646 | module_put(mk->mod); | ||
647 | |||
648 | return ret; | 643 | return ret; |
649 | } | 644 | } |
650 | 645 | ||
@@ -662,13 +657,8 @@ static ssize_t module_attr_store(struct kobject *kobj, | |||
662 | if (!attribute->store) | 657 | if (!attribute->store) |
663 | return -EIO; | 658 | return -EIO; |
664 | 659 | ||
665 | if (!try_module_get(mk->mod)) | ||
666 | return -ENODEV; | ||
667 | |||
668 | ret = attribute->store(attribute, mk->mod, buf, len); | 660 | ret = attribute->store(attribute, mk->mod, buf, len); |
669 | 661 | ||
670 | module_put(mk->mod); | ||
671 | |||
672 | return ret; | 662 | return ret; |
673 | } | 663 | } |
674 | 664 | ||