No functional change. This patch migrates module sysfs support out of core code into kernel/module/sysfs.c. In addition simple code refactoring to make this possible.
Showing the changes to kernel/module (4 of 4 files). Show all
Unified · Split
| @@ -16,3 +16,4 @@ obj-$(CONFIG_STRICT_MODULE_RWX) += strict_rwx.o · 15 unmodified lines | |||
| 16 | obj-$(CONFIG_DEBUG_KMEMLEAK) += debug_kmemleak.o | 16 | obj-$(CONFIG_DEBUG_KMEMLEAK) += debug_kmemleak.o |
| 17 | obj-$(CONFIG_KALLSYMS) += kallsyms.o | 17 | obj-$(CONFIG_KALLSYMS) += kallsyms.o |
| 18 | obj-$(CONFIG_PROC_FS) += procfs.o | 18 | obj-$(CONFIG_PROC_FS) += procfs.o |
| 19 | obj-$(CONFIG_SYSFS) += sysfs.o | ||
| @@ -34,6 +34,9 @@ · 33 unmodified lines | |||
| 34 | extern struct mutex module_mutex; | 34 | extern struct mutex module_mutex; |
| 35 | extern struct list_head modules; | 35 | extern struct list_head modules; |
| 36 | 36 | ||
| 37 | extern struct module_attribute *modinfo_attrs[]; | ||
| 38 | extern size_t modinfo_attrs_count; | ||
| 39 | |||
| 37 | /* Provided by the linker */ | 40 | /* Provided by the linker */ |
| 38 | extern const struct kernel_symbol __start___ksymtab[]; | 41 | extern const struct kernel_symbol __start___ksymtab[]; |
| 39 | extern const struct kernel_symbol __stop___ksymtab[]; | 42 | extern const struct kernel_symbol __stop___ksymtab[]; |
| @@ -204,3 +207,21 @@ static inline void init_build_id(struct module *mod, const struct load_info *inf · 164 unmodified lines | |||
| 204 | static inline void layout_symtab(struct module *mod, struct load_info *info) { } | 207 | static inline void layout_symtab(struct module *mod, struct load_info *info) { } |
| 205 | static inline void add_kallsyms(struct module *mod, const struct load_info *info) { } | 208 | static inline void add_kallsyms(struct module *mod, const struct load_info *info) { } |
| 206 | #endif /* CONFIG_KALLSYMS */ | 209 | #endif /* CONFIG_KALLSYMS */ |
| 210 | |||
| 211 | #ifdef CONFIG_SYSFS | ||
| 212 | int mod_sysfs_setup(struct module *mod, const struct load_info *info, | ||
| 213 | struct kernel_param *kparam, unsigned int num_params); | ||
| 214 | void mod_sysfs_teardown(struct module *mod); | ||
| 215 | void init_param_lock(struct module *mod); | ||
| 216 | #else /* !CONFIG_SYSFS */ | ||
| 217 | static inline int mod_sysfs_setup(struct module *mod, | ||
| 218 | const struct load_info *info, | ||
| 219 | struct kernel_param *kparam, | ||
| 220 | unsigned int num_params) | ||
| 221 | { | ||
| 222 | return 0; | ||
| 223 | } | ||
| 224 | |||
| 225 | static inline void mod_sysfs_teardown(struct module *mod) { } | ||
| 226 | static inline void init_param_lock(struct module *mod) { } | ||
| 227 | #endif /* CONFIG_SYSFS */ | ||
| @@ -14,9 +14,7 @@ · 13 unmodified lines | |||
| 14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
| 15 | #include <linux/kallsyms.h> | 15 | #include <linux/kallsyms.h> |
| 16 | #include <linux/buildid.h> | 16 | #include <linux/buildid.h> |
| 17 | #include <linux/file.h> | ||
| 18 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
| 19 | #include <linux/sysfs.h> | ||
| 20 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
| 21 | #include <linux/kernel_read_file.h> | 19 | #include <linux/kernel_read_file.h> |
| 22 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
| @@ -989,7 +987,7 @@ static ssize_t show_taint(struct module_attribute *mattr, · 966 unmodified lines | |||
| 989 | static struct module_attribute modinfo_taint = | 987 | static struct module_attribute modinfo_taint = |
| 990 | __ATTR(taint, 0444, show_taint, NULL); | 988 | __ATTR(taint, 0444, show_taint, NULL); |
| 991 | 989 | ||
| 992 | static struct module_attribute *modinfo_attrs[] = { | 990 | struct module_attribute *modinfo_attrs[] = { |
| 993 | &module_uevent, | 991 | &module_uevent, |
| 994 | &modinfo_version, | 992 | &modinfo_version, |
| 995 | &modinfo_srcversion, | 993 | &modinfo_srcversion, |
| @@ -1003,6 +1001,8 @@ static struct module_attribute *modinfo_attrs[] = { · 7 unmodified lines | |||
| 1003 | NULL, | 1001 | NULL, |
| 1004 | }; | 1002 | }; |
| 1005 | 1003 | ||
| 1004 | size_t modinfo_attrs_count = ARRAY_SIZE(modinfo_attrs); | ||
| 1005 | |||
| 1006 | static const char vermagic[] = VERMAGIC_STRING; | 1006 | static const char vermagic[] = VERMAGIC_STRING; |
| 1007 | 1007 | ||
| 1008 | static int try_to_force_load(struct module *mod, const char *reason) | 1008 | static int try_to_force_load(struct module *mod, const char *reason) |
| @@ -1253,469 +1253,6 @@ resolve_symbol_wait(struct module *mod, · 244 unmodified lines | |||
| 1253 | return ksym; | 1253 | return ksym; |
| 1254 | } | 1254 | } |
| 1255 | 1255 | ||
| 1256 | /* | ||
| 1257 | * /sys/module/foo/sections stuff | ||
| 1258 | * J. Corbet <corbet@lwn.net> | ||
| 1259 | */ | ||
| 1260 | #ifdef CONFIG_SYSFS | ||
| 1261 | |||
| 1262 | #ifdef CONFIG_KALLSYMS | ||
| 1263 | struct module_sect_attr { | ||
| 1264 | struct bin_attribute battr; | ||
| 1265 | unsigned long address; | ||
| 1266 | }; | ||
| 1267 | |||
| 1268 | struct module_sect_attrs { | ||
| 1269 | struct attribute_group grp; | ||
| 1270 | unsigned int nsections; | ||
| 1271 | struct module_sect_attr attrs[]; | ||
| 1272 | }; | ||
| 1273 | |||
| 1274 | #define MODULE_SECT_READ_SIZE (3 /* "0x", "\n" */ + (BITS_PER_LONG / 4)) | ||
| 1275 | static ssize_t module_sect_read(struct file *file, struct kobject *kobj, | ||
| 1276 | struct bin_attribute *battr, | ||
| 1277 | char *buf, loff_t pos, size_t count) | ||
| 1278 | { | ||
| 1279 | struct module_sect_attr *sattr = | ||
| 1280 | container_of(battr, struct module_sect_attr, battr); | ||
| 1281 | char bounce[MODULE_SECT_READ_SIZE + 1]; | ||
| 1282 | size_t wrote; | ||
| 1283 | |||
| 1284 | if (pos != 0) | ||
| 1285 | return -EINVAL; | ||
| 1286 | |||
| 1287 | /* | ||
| 1288 | * Since we're a binary read handler, we must account for the | ||
| 1289 | * trailing NUL byte that sprintf will write: if "buf" is | ||
| 1290 | * too small to hold the NUL, or the NUL is exactly the last | ||
| 1291 | * byte, the read will look like it got truncated by one byte. | ||
| 1292 | * Since there is no way to ask sprintf nicely to not write | ||
| 1293 | * the NUL, we have to use a bounce buffer. | ||
| 1294 | */ | ||
| 1295 | wrote = scnprintf(bounce, sizeof(bounce), "0x%px\n", | ||
| 1296 | kallsyms_show_value(file->f_cred) | ||
| 1297 | ? (void *)sattr->address : NULL); | ||
| 1298 | count = min(count, wrote); | ||
| 1299 | memcpy(buf, bounce, count); | ||
| 1300 | |||
| 1301 | return count; | ||
| 1302 | } | ||
| 1303 | |||
| 1304 | static void free_sect_attrs(struct module_sect_attrs *sect_attrs) | ||
| 1305 | { | ||
| 1306 | unsigned int section; | ||
| 1307 | |||
| 1308 | for (section = 0; section < sect_attrs->nsections; section++) | ||
| 1309 | kfree(sect_attrs->attrs[section].battr.attr.name); | ||
| 1310 | kfree(sect_attrs); | ||
| 1311 | } | ||
| 1312 | |||
| 1313 | static void add_sect_attrs(struct module *mod, const struct load_info *info) | ||
| 1314 | { | ||
| 1315 | unsigned int nloaded = 0, i, size[2]; | ||
| 1316 | struct module_sect_attrs *sect_attrs; | ||
| 1317 | struct module_sect_attr *sattr; | ||
| 1318 | struct bin_attribute **gattr; | ||
| 1319 | |||
| 1320 | /* Count loaded sections and allocate structures */ | ||
| 1321 | for (i = 0; i < info->hdr->e_shnum; i++) | ||
| 1322 | if (!sect_empty(&info->sechdrs[i])) | ||
| 1323 | nloaded++; | ||
| 1324 | size[0] = ALIGN(struct_size(sect_attrs, attrs, nloaded), | ||
| 1325 | sizeof(sect_attrs->grp.bin_attrs[0])); | ||
| 1326 | size[1] = (nloaded + 1) * sizeof(sect_attrs->grp.bin_attrs[0]); | ||
| 1327 | sect_attrs = kzalloc(size[0] + size[1], GFP_KERNEL); | ||
| 1328 | if (sect_attrs == NULL) | ||
| 1329 | return; | ||
| 1330 | |||
| 1331 | /* Setup section attributes. */ | ||
| 1332 | sect_attrs->grp.name = "sections"; | ||
| 1333 | sect_attrs->grp.bin_attrs = (void *)sect_attrs + size[0]; | ||
| 1334 | |||
| 1335 | sect_attrs->nsections = 0; | ||
| 1336 | sattr = §_attrs->attrs[0]; | ||
| 1337 | gattr = §_attrs->grp.bin_attrs[0]; | ||
| 1338 | for (i = 0; i < info->hdr->e_shnum; i++) { | ||
| 1339 | Elf_Shdr *sec = &info->sechdrs[i]; | ||
| 1340 | if (sect_empty(sec)) | ||
| 1341 | continue; | ||
| 1342 | sysfs_bin_attr_init(&sattr->battr); | ||
| 1343 | sattr->address = sec->sh_addr; | ||
| 1344 | sattr->battr.attr.name = | ||
| 1345 | kstrdup(info->secstrings + sec->sh_name, GFP_KERNEL); | ||
| 1346 | if (sattr->battr.attr.name == NULL) | ||
| 1347 | goto out; | ||
| 1348 | sect_attrs->nsections++; | ||
| 1349 | sattr->battr.read = module_sect_read; | ||
| 1350 | sattr->battr.size = MODULE_SECT_READ_SIZE; | ||
| 1351 | sattr->battr.attr.mode = 0400; | ||
| 1352 | *(gattr++) = &(sattr++)->battr; | ||
| 1353 | } | ||
| 1354 | *gattr = NULL; | ||
| 1355 | |||
| 1356 | if (sysfs_create_group(&mod->mkobj.kobj, §_attrs->grp)) | ||
| 1357 | goto out; | ||
| 1358 | |||
| 1359 | mod->sect_attrs = sect_attrs; | ||
| 1360 | return; | ||
| 1361 | out: | ||
| 1362 | free_sect_attrs(sect_attrs); | ||
| 1363 | } | ||
| 1364 | |||
| 1365 | static void remove_sect_attrs(struct module *mod) | ||
| 1366 | { | ||
| 1367 | if (mod->sect_attrs) { | ||
| 1368 | sysfs_remove_group(&mod->mkobj.kobj, | ||
| 1369 | &mod->sect_attrs->grp); | ||
| 1370 | /* | ||
| 1371 | * We are positive that no one is using any sect attrs | ||
| 1372 | * at this point. Deallocate immediately. | ||
| 1373 | */ | ||
| 1374 | free_sect_attrs(mod->sect_attrs); | ||
| 1375 | mod->sect_attrs = NULL; | ||
| 1376 | } | ||
| 1377 | } | ||
| 1378 | |||
| 1379 | /* | ||
| 1380 | * /sys/module/foo/notes/.section.name gives contents of SHT_NOTE sections. | ||
| 1381 | */ | ||
| 1382 | |||
| 1383 | struct module_notes_attrs { | ||
| 1384 | struct kobject *dir; | ||
| 1385 | unsigned int notes; | ||
| 1386 | struct bin_attribute attrs[]; | ||
| 1387 | }; | ||
| 1388 | |||
| 1389 | static ssize_t module_notes_read(struct file *filp, struct kobject *kobj, | ||
| 1390 | struct bin_attribute *bin_attr, | ||
| 1391 | char *buf, loff_t pos, size_t count) | ||
| 1392 | { | ||
| 1393 | /* | ||
| 1394 | * The caller checked the pos and count against our size. | ||
| 1395 | */ | ||
| 1396 | memcpy(buf, bin_attr->private + pos, count); | ||
| 1397 | return count; | ||
| 1398 | } | ||
| 1399 | |||
| 1400 | static void free_notes_attrs(struct module_notes_attrs *notes_attrs, | ||
| 1401 | unsigned int i) | ||
| 1402 | { | ||
| 1403 | if (notes_attrs->dir) { | ||
| 1404 | while (i-- > 0) | ||
| 1405 | sysfs_remove_bin_file(notes_attrs->dir, | ||
| 1406 | ¬es_attrs->attrs[i]); | ||
| 1407 | kobject_put(notes_attrs->dir); | ||
| 1408 | } | ||
| 1409 | kfree(notes_attrs); | ||
| 1410 | } | ||
| 1411 | |||
| 1412 | static void add_notes_attrs(struct module *mod, const struct load_info *info) | ||
| 1413 | { | ||
| 1414 | unsigned int notes, loaded, i; | ||
| 1415 | struct module_notes_attrs *notes_attrs; | ||
| 1416 | struct bin_attribute *nattr; | ||
| 1417 | |||
| 1418 | /* failed to create section attributes, so can't create notes */ | ||
| 1419 | if (!mod->sect_attrs) | ||
| 1420 | return; | ||
| 1421 | |||
| 1422 | /* Count notes sections and allocate structures. */ | ||
| 1423 | notes = 0; | ||
| 1424 | for (i = 0; i < info->hdr->e_shnum; i++) | ||
| 1425 | if (!sect_empty(&info->sechdrs[i]) && | ||
| 1426 | (info->sechdrs[i].sh_type == SHT_NOTE)) | ||
| 1427 | ++notes; | ||
| 1428 | |||
| 1429 | if (notes == 0) | ||
| 1430 | return; | ||
| 1431 | |||
| 1432 | notes_attrs = kzalloc(struct_size(notes_attrs, attrs, notes), | ||
| 1433 | GFP_KERNEL); | ||
| 1434 | if (notes_attrs == NULL) | ||
| 1435 | return; | ||
| 1436 | |||
| 1437 | notes_attrs->notes = notes; | ||
| 1438 | nattr = ¬es_attrs->attrs[0]; | ||
| 1439 | for (loaded = i = 0; i < info->hdr->e_shnum; ++i) { | ||
| 1440 | if (sect_empty(&info->sechdrs[i])) | ||
| 1441 | continue; | ||
| 1442 | if (info->sechdrs[i].sh_type == SHT_NOTE) { | ||
| 1443 | sysfs_bin_attr_init(nattr); | ||
| 1444 | nattr->attr.name = mod->sect_attrs->attrs[loaded].battr.attr.name; | ||
| 1445 | nattr->attr.mode = S_IRUGO; | ||
| 1446 | nattr->size = info->sechdrs[i].sh_size; | ||
| 1447 | nattr->private = (void *) info->sechdrs[i].sh_addr; | ||
| 1448 | nattr->read = module_notes_read; | ||
| 1449 | ++nattr; | ||
| 1450 | } | ||
| 1451 | ++loaded; | ||
| 1452 | } | ||
| 1453 | |||
| 1454 | notes_attrs->dir = kobject_create_and_add("notes", &mod->mkobj.kobj); | ||
| 1455 | if (!notes_attrs->dir) | ||
| 1456 | goto out; | ||
| 1457 | |||
| 1458 | for (i = 0; i < notes; ++i) | ||
| 1459 | if (sysfs_create_bin_file(notes_attrs->dir, | ||
| 1460 | ¬es_attrs->attrs[i])) | ||
| 1461 | goto out; | ||
| 1462 | |||
| 1463 | mod->notes_attrs = notes_attrs; | ||
| 1464 | return; | ||
| 1465 | |||
| 1466 | out: | ||
| 1467 | free_notes_attrs(notes_attrs, i); | ||
| 1468 | } | ||
| 1469 | |||
| 1470 | static void remove_notes_attrs(struct module *mod) | ||
| 1471 | { | ||
| 1472 | if (mod->notes_attrs) | ||
| 1473 | free_notes_attrs(mod->notes_attrs, mod->notes_attrs->notes); | ||
| 1474 | } | ||
| 1475 | |||
| 1476 | #else | ||
| 1477 | |||
| 1478 | static inline void add_sect_attrs(struct module *mod, | ||
| 1479 | const struct load_info *info) | ||
| 1480 | { | ||
| 1481 | } | ||
| 1482 | |||
| 1483 | static inline void remove_sect_attrs(struct module *mod) | ||
| 1484 | { | ||
| 1485 | } | ||
| 1486 | |||
| 1487 | static inline void add_notes_attrs(struct module *mod, | ||
| 1488 | const struct load_info *info) | ||
| 1489 | { | ||
| 1490 | } | ||
| 1491 | |||
| 1492 | static inline void remove_notes_attrs(struct module *mod) | ||
| 1493 | { | ||
| 1494 | } | ||
| 1495 | #endif /* CONFIG_KALLSYMS */ | ||
| 1496 | |||
| 1497 | static void del_usage_links(struct module *mod) | ||
| 1498 | { | ||
| 1499 | #ifdef CONFIG_MODULE_UNLOAD | ||
| 1500 | struct module_use *use; | ||
| 1501 | |||
| 1502 | mutex_lock(&module_mutex); | ||
| 1503 | list_for_each_entry(use, &mod->target_list, target_list) | ||
| 1504 | sysfs_remove_link(use->target->holders_dir, mod->name); | ||
| 1505 | mutex_unlock(&module_mutex); | ||
| 1506 | #endif | ||
| 1507 | } | ||
| 1508 | |||
| 1509 | static int add_usage_links(struct module *mod) | ||
| 1510 | { | ||
| 1511 | int ret = 0; | ||
| 1512 | #ifdef CONFIG_MODULE_UNLOAD | ||
| 1513 | struct module_use *use; | ||
| 1514 | |||
| 1515 | mutex_lock(&module_mutex); | ||
| 1516 | list_for_each_entry(use, &mod->target_list, target_list) { | ||
| 1517 | ret = sysfs_create_link(use->target->holders_dir, | ||
| 1518 | &mod->mkobj.kobj, mod->name); | ||
| 1519 | if (ret) | ||
| 1520 | break; | ||
| 1521 | } | ||
| 1522 | mutex_unlock(&module_mutex); | ||
| 1523 | if (ret) | ||
| 1524 | del_usage_links(mod); | ||
| 1525 | #endif | ||
| 1526 | return ret; | ||
| 1527 | } | ||
| 1528 | |||
| 1529 | static void module_remove_modinfo_attrs(struct module *mod, int end); | ||
| 1530 | |||
| 1531 | static int module_add_modinfo_attrs(struct module *mod) | ||
| 1532 | { | ||
| 1533 | struct module_attribute *attr; | ||
| 1534 | struct module_attribute *temp_attr; | ||
| 1535 | int error = 0; | ||
| 1536 | int i; | ||
| 1537 | |||
| 1538 | mod->modinfo_attrs = kzalloc((sizeof(struct module_attribute) * | ||
| 1539 | (ARRAY_SIZE(modinfo_attrs) + 1)), | ||
| 1540 | GFP_KERNEL); | ||
| 1541 | if (!mod->modinfo_attrs) | ||
| 1542 | return -ENOMEM; | ||
| 1543 | |||
| 1544 | temp_attr = mod->modinfo_attrs; | ||
| 1545 | for (i = 0; (attr = modinfo_attrs[i]); i++) { | ||
| 1546 | if (!attr->test || attr->test(mod)) { | ||
| 1547 | memcpy(temp_attr, attr, sizeof(*temp_attr)); | ||
| 1548 | sysfs_attr_init(&temp_attr->attr); | ||
| 1549 | error = sysfs_create_file(&mod->mkobj.kobj, | ||
| 1550 | &temp_attr->attr); | ||
| 1551 | if (error) | ||
| 1552 | goto error_out; | ||
| 1553 | ++temp_attr; | ||
| 1554 | } | ||
| 1555 | } | ||
| 1556 | |||
| 1557 | return 0; | ||
| 1558 | |||
| 1559 | error_out: | ||
| 1560 | if (i > 0) | ||
| 1561 | module_remove_modinfo_attrs(mod, --i); | ||
| 1562 | else | ||
| 1563 | kfree(mod->modinfo_attrs); | ||
| 1564 | return error; | ||
| 1565 | } | ||
| 1566 | |||
| 1567 | static void module_remove_modinfo_attrs(struct module *mod, int end) | ||
| 1568 | { | ||
| 1569 | struct module_attribute *attr; | ||
| 1570 | int i; | ||
| 1571 | |||
| 1572 | for (i = 0; (attr = &mod->modinfo_attrs[i]); i++) { | ||
| 1573 | if (end >= 0 && i > end) | ||
| 1574 | break; | ||
| 1575 | /* pick a field to test for end of list */ | ||
| 1576 | if (!attr->attr.name) | ||
| 1577 | break; | ||
| 1578 | sysfs_remove_file(&mod->mkobj.kobj, &attr->attr); | ||
| 1579 | if (attr->free) | ||
| 1580 | attr->free(mod); | ||
| 1581 | } | ||
| 1582 | kfree(mod->modinfo_attrs); | ||
| 1583 | } | ||
| 1584 | |||
| 1585 | static void mod_kobject_put(struct module *mod) | ||
| 1586 | { | ||
| 1587 | DECLARE_COMPLETION_ONSTACK(c); | ||
| 1588 | mod->mkobj.kobj_completion = &c; | ||
| 1589 | kobject_put(&mod->mkobj.kobj); | ||
| 1590 | wait_for_completion(&c); | ||
| 1591 | } | ||
| 1592 | |||
| 1593 | static int mod_sysfs_init(struct module *mod) | ||
| 1594 | { | ||
| 1595 | int err; | ||
| 1596 | struct kobject *kobj; | ||
| 1597 | |||
| 1598 | if (!module_sysfs_initialized) { | ||
| 1599 | pr_err("%s: module sysfs not initialized\n", mod->name); | ||
| 1600 | err = -EINVAL; | ||
| 1601 | goto out; | ||
| 1602 | } | ||
| 1603 | |||
| 1604 | kobj = kset_find_obj(module_kset, mod->name); | ||
| 1605 | if (kobj) { | ||
| 1606 | pr_err("%s: module is already loaded\n", mod->name); | ||
| 1607 | kobject_put(kobj); | ||
| 1608 | err = -EINVAL; | ||
| 1609 | goto out; | ||
| 1610 | } | ||
| 1611 | |||
| 1612 | mod->mkobj.mod = mod; | ||
| 1613 | |||
| 1614 | memset(&mod->mkobj.kobj, 0, sizeof(mod->mkobj.kobj)); | ||
| 1615 | mod->mkobj.kobj.kset = module_kset; | ||
| 1616 | err = kobject_init_and_add(&mod->mkobj.kobj, &module_ktype, NULL, | ||
| 1617 | "%s", mod->name); | ||
| 1618 | if (err) | ||
| 1619 | mod_kobject_put(mod); | ||
| 1620 | |||
| 1621 | out: | ||
| 1622 | return err; | ||
| 1623 | } | ||
| 1624 | |||
| 1625 | static int mod_sysfs_setup(struct module *mod, | ||
| 1626 | const struct load_info *info, | ||
| 1627 | struct kernel_param *kparam, | ||
| 1628 | unsigned int num_params) | ||
| 1629 | { | ||
| 1630 | int err; | ||
| 1631 | |||
| 1632 | err = mod_sysfs_init(mod); | ||
| 1633 | if (err) | ||
| 1634 | goto out; | ||
| 1635 | |||
| 1636 | mod->holders_dir = kobject_create_and_add("holders", &mod->mkobj.kobj); | ||
| 1637 | if (!mod->holders_dir) { | ||
| 1638 | err = -ENOMEM; | ||
| 1639 | goto out_unreg; | ||
| 1640 | } | ||
| 1641 | |||
| 1642 | err = module_param_sysfs_setup(mod, kparam, num_params); | ||
| 1643 | if (err) | ||
| 1644 | goto out_unreg_holders; | ||
| 1645 | |||
| 1646 | err = module_add_modinfo_attrs(mod); | ||
| 1647 | if (err) | ||
| 1648 | goto out_unreg_param; | ||
| 1649 | |||
| 1650 | err = add_usage_links(mod); | ||
| 1651 | if (err) | ||
| 1652 | goto out_unreg_modinfo_attrs; | ||
| 1653 | |||
| 1654 | add_sect_attrs(mod, info); | ||
| 1655 | add_notes_attrs(mod, info); | ||
| 1656 | |||
| 1657 | return 0; | ||
| 1658 | |||
| 1659 | out_unreg_modinfo_attrs: | ||
| 1660 | module_remove_modinfo_attrs(mod, -1); | ||
| 1661 | out_unreg_param: | ||
| 1662 | module_param_sysfs_remove(mod); | ||
| 1663 | out_unreg_holders: | ||
| 1664 | kobject_put(mod->holders_dir); | ||
| 1665 | out_unreg: | ||
| 1666 | mod_kobject_put(mod); | ||
| 1667 | out: | ||
| 1668 | return err; | ||
| 1669 | } | ||
| 1670 | |||
| 1671 | static void mod_sysfs_fini(struct module *mod) | ||
| 1672 | { | ||
| 1673 | remove_notes_attrs(mod); | ||
| 1674 | remove_sect_attrs(mod); | ||
| 1675 | mod_kobject_put(mod); | ||
| 1676 | } | ||
| 1677 | |||
| 1678 | static void init_param_lock(struct module *mod) | ||
| 1679 | { | ||
| 1680 | mutex_init(&mod->param_lock); | ||
| 1681 | } | ||
| 1682 | #else /* !CONFIG_SYSFS */ | ||
| 1683 | |||
| 1684 | static int mod_sysfs_setup(struct module *mod, | ||
| 1685 | const struct load_info *info, | ||
| 1686 | struct kernel_param *kparam, | ||
| 1687 | unsigned int num_params) | ||
| 1688 | { | ||
| 1689 | return 0; | ||
| 1690 | } | ||
| 1691 | |||
| 1692 | static void mod_sysfs_fini(struct module *mod) | ||
| 1693 | { | ||
| 1694 | } | ||
| 1695 | |||
| 1696 | static void module_remove_modinfo_attrs(struct module *mod, int end) | ||
| 1697 | { | ||
| 1698 | } | ||
| 1699 | |||
| 1700 | static void del_usage_links(struct module *mod) | ||
| 1701 | { | ||
| 1702 | } | ||
| 1703 | |||
| 1704 | static void init_param_lock(struct module *mod) | ||
| 1705 | { | ||
| 1706 | } | ||
| 1707 | #endif /* CONFIG_SYSFS */ | ||
| 1708 | |||
| 1709 | static void mod_sysfs_teardown(struct module *mod) | ||
| 1710 | { | ||
| 1711 | del_usage_links(mod); | ||
| 1712 | module_remove_modinfo_attrs(mod, -1); | ||
| 1713 | module_param_sysfs_remove(mod); | ||
| 1714 | kobject_put(mod->mkobj.drivers_dir); | ||
| 1715 | kobject_put(mod->holders_dir); | ||
| 1716 | mod_sysfs_fini(mod); | ||
| 1717 | } | ||
| 1718 | |||
| 1719 | /* | 1256 | /* |
| 1720 | * LKM RO/NX protection: protect module's text/ro-data | 1257 | * LKM RO/NX protection: protect module's text/ro-data |
| 1721 | * from modification and any data from execution. | 1258 | * from modification and any data from execution. |
| @@ -0,0 +1,436 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 2 | /* | ||
| 3 | * Module sysfs support | ||
| 4 | * | ||
| 5 | * Copyright (C) 2008 Rusty Russell | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/module.h> | ||
| 9 | #include <linux/kernel.h> | ||
| 10 | #include <linux/fs.h> | ||
| 11 | #include <linux/sysfs.h> | ||
| 12 | #include <linux/slab.h> | ||
| 13 | #include <linux/kallsyms.h> | ||
| 14 | #include <linux/mutex.h> | ||
| 15 | #include "internal.h" | ||
| 16 | |||
| 17 | /* | ||
| 18 | * /sys/module/foo/sections stuff | ||
| 19 | * J. Corbet <corbet@lwn.net> | ||
| 20 | */ | ||
| 21 | #ifdef CONFIG_KALLSYMS | ||
| 22 | struct module_sect_attr { | ||
| 23 | struct bin_attribute battr; | ||
| 24 | unsigned long address; | ||
| 25 | }; | ||
| 26 | |||
| 27 | struct module_sect_attrs { | ||
| 28 | struct attribute_group grp; | ||
| 29 | unsigned int nsections; | ||
| 30 | struct module_sect_attr attrs[]; | ||
| 31 | }; | ||
| 32 | |||
| 33 | #define MODULE_SECT_READ_SIZE (3 /* "0x", "\n" */ + (BITS_PER_LONG / 4)) | ||
| 34 | static ssize_t module_sect_read(struct file *file, struct kobject *kobj, | ||
| 35 | struct bin_attribute *battr, | ||
| 36 | char *buf, loff_t pos, size_t count) | ||
| 37 | { | ||
| 38 | struct module_sect_attr *sattr = | ||
| 39 | container_of(battr, struct module_sect_attr, battr); | ||
| 40 | char bounce[MODULE_SECT_READ_SIZE + 1]; | ||
| 41 | size_t wrote; | ||
| 42 | |||
| 43 | if (pos != 0) | ||
| 44 | return -EINVAL; | ||
| 45 | |||
| 46 | /* | ||
| 47 | * Since we're a binary read handler, we must account for the | ||
| 48 | * trailing NUL byte that sprintf will write: if "buf" is | ||
| 49 | * too small to hold the NUL, or the NUL is exactly the last | ||
| 50 | * byte, the read will look like it got truncated by one byte. | ||
| 51 | * Since there is no way to ask sprintf nicely to not write | ||
| 52 | * the NUL, we have to use a bounce buffer. | ||
| 53 | */ | ||
| 54 | wrote = scnprintf(bounce, sizeof(bounce), "0x%px\n", | ||
| 55 | kallsyms_show_value(file->f_cred) | ||
| 56 | ? (void *)sattr->address : NULL); | ||
| 57 | count = min(count, wrote); | ||
| 58 | memcpy(buf, bounce, count); | ||
| 59 | |||
| 60 | return count; | ||
| 61 | } | ||
| 62 | |||
| 63 | static void free_sect_attrs(struct module_sect_attrs *sect_attrs) | ||
| 64 | { | ||
| 65 | unsigned int section; | ||
| 66 | |||
| 67 | for (section = 0; section < sect_attrs->nsections; section++) | ||
| 68 | kfree(sect_attrs->attrs[section].battr.attr.name); | ||
| 69 | kfree(sect_attrs); | ||
| 70 | } | ||
| 71 | |||
| 72 | static void add_sect_attrs(struct module *mod, const struct load_info *info) | ||
| 73 | { | ||
| 74 | unsigned int nloaded = 0, i, size[2]; | ||
| 75 | struct module_sect_attrs *sect_attrs; | ||
| 76 | struct module_sect_attr *sattr; | ||
| 77 | struct bin_attribute **gattr; | ||
| 78 | |||
| 79 | /* Count loaded sections and allocate structures */ | ||
| 80 | for (i = 0; i < info->hdr->e_shnum; i++) | ||
| 81 | if (!sect_empty(&info->sechdrs[i])) | ||
| 82 | nloaded++; | ||
| 83 | size[0] = ALIGN(struct_size(sect_attrs, attrs, nloaded), | ||
| 84 | sizeof(sect_attrs->grp.bin_attrs[0])); | ||
| 85 | size[1] = (nloaded + 1) * sizeof(sect_attrs->grp.bin_attrs[0]); | ||
| 86 | sect_attrs = kzalloc(size[0] + size[1], GFP_KERNEL); | ||
| 87 | if (!sect_attrs) | ||
| 88 | return; | ||
| 89 | |||
| 90 | /* Setup section attributes. */ | ||
| 91 | sect_attrs->grp.name = "sections"; | ||
| 92 | sect_attrs->grp.bin_attrs = (void *)sect_attrs + size[0]; | ||
| 93 | |||
| 94 | sect_attrs->nsections = 0; | ||
| 95 | sattr = §_attrs->attrs[0]; | ||
| 96 | gattr = §_attrs->grp.bin_attrs[0]; | ||
| 97 | for (i = 0; i < info->hdr->e_shnum; i++) { | ||
| 98 | Elf_Shdr *sec = &info->sechdrs[i]; | ||
| 99 | |||
| 100 | if (sect_empty(sec)) | ||
| 101 | continue; | ||
| 102 | sysfs_bin_attr_init(&sattr->battr); | ||
| 103 | sattr->address = sec->sh_addr; | ||
| 104 | sattr->battr.attr.name = | ||
| 105 | kstrdup(info->secstrings + sec->sh_name, GFP_KERNEL); | ||
| 106 | if (!sattr->battr.attr.name) | ||
| 107 | goto out; | ||
| 108 | sect_attrs->nsections++; | ||
| 109 | sattr->battr.read = module_sect_read; | ||
| 110 | sattr->battr.size = MODULE_SECT_READ_SIZE; | ||
| 111 | sattr->battr.attr.mode = 0400; | ||
| 112 | *(gattr++) = &(sattr++)->battr; | ||
| 113 | } | ||
| 114 | *gattr = NULL; | ||
| 115 | |||
| 116 | if (sysfs_create_group(&mod->mkobj.kobj, §_attrs->grp)) | ||
| 117 | goto out; | ||
| 118 | |||
| 119 | mod->sect_attrs = sect_attrs; | ||
| 120 | return; | ||
| 121 | out: | ||
| 122 | free_sect_attrs(sect_attrs); | ||
| 123 | } | ||
| 124 | |||
| 125 | static void remove_sect_attrs(struct module *mod) | ||
| 126 | { | ||
| 127 | if (mod->sect_attrs) { | ||
| 128 | sysfs_remove_group(&mod->mkobj.kobj, | ||
| 129 | &mod->sect_attrs->grp); | ||
| 130 | /* | ||
| 131 | * We are positive that no one is using any sect attrs | ||
| 132 | * at this point. Deallocate immediately. | ||
| 133 | */ | ||
| 134 | free_sect_attrs(mod->sect_attrs); | ||
| 135 | mod->sect_attrs = NULL; | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | /* | ||
| 140 | * /sys/module/foo/notes/.section.name gives contents of SHT_NOTE sections. | ||
| 141 | */ | ||
| 142 | |||
| 143 | struct module_notes_attrs { | ||
| 144 | struct kobject *dir; | ||
| 145 | unsigned int notes; | ||
| 146 | struct bin_attribute attrs[]; | ||
| 147 | }; | ||
| 148 | |||
| 149 | static ssize_t module_notes_read(struct file *filp, struct kobject *kobj, | ||
| 150 | struct bin_attribute *bin_attr, | ||
| 151 | char *buf, loff_t pos, size_t count) | ||
| 152 | { | ||
| 153 | /* | ||
| 154 | * The caller checked the pos and count against our size. | ||
| 155 | */ | ||
| 156 | memcpy(buf, bin_attr->private + pos, count); | ||
| 157 | return count; | ||
| 158 | } | ||
| 159 | |||
| 160 | static void free_notes_attrs(struct module_notes_attrs *notes_attrs, | ||
| 161 | unsigned int i) | ||
| 162 | { | ||
| 163 | if (notes_attrs->dir) { | ||
| 164 | while (i-- > 0) | ||
| 165 | sysfs_remove_bin_file(notes_attrs->dir, | ||
| 166 | ¬es_attrs->attrs[i]); | ||
| 167 | kobject_put(notes_attrs->dir); | ||
| 168 | } | ||
| 169 | kfree(notes_attrs); | ||
| 170 | } | ||
| 171 | |||
| 172 | static void add_notes_attrs(struct module *mod, const struct load_info *info) | ||
| 173 | { | ||
| 174 | unsigned int notes, loaded, i; | ||
| 175 | struct module_notes_attrs *notes_attrs; | ||
| 176 | struct bin_attribute *nattr; | ||
| 177 | |||
| 178 | /* failed to create section attributes, so can't create notes */ | ||
| 179 | if (!mod->sect_attrs) | ||
| 180 | return; | ||
| 181 | |||
| 182 | /* Count notes sections and allocate structures. */ | ||
| 183 | notes = 0; | ||
| 184 | for (i = 0; i < info->hdr->e_shnum; i++) | ||
| 185 | if (!sect_empty(&info->sechdrs[i]) && | ||
| 186 | info->sechdrs[i].sh_type == SHT_NOTE) | ||
| 187 | ++notes; | ||
| 188 | |||
| 189 | if (notes == 0) | ||
| 190 | return; | ||
| 191 | |||
| 192 | notes_attrs = kzalloc(struct_size(notes_attrs, attrs, notes), | ||
| 193 | GFP_KERNEL); | ||
| 194 | if (!notes_attrs) | ||
| 195 | return; | ||
| 196 | |||
| 197 | notes_attrs->notes = notes; | ||
| 198 | nattr = ¬es_attrs->attrs[0]; | ||
| 199 | for (loaded = i = 0; i < info->hdr->e_shnum; ++i) { | ||
| 200 | if (sect_empty(&info->sechdrs[i])) | ||
| 201 | continue; | ||
| 202 | if (info->sechdrs[i].sh_type == SHT_NOTE) { | ||
| 203 | sysfs_bin_attr_init(nattr); | ||
| 204 | nattr->attr.name = mod->sect_attrs->attrs[loaded].battr.attr.name; | ||
| 205 | nattr->attr.mode = 0444; | ||
| 206 | nattr->size = info->sechdrs[i].sh_size; | ||
| 207 | nattr->private = (void *)info->sechdrs[i].sh_addr; | ||
| 208 | nattr->read = module_notes_read; | ||
| 209 | ++nattr; | ||
| 210 | } | ||
| 211 | ++loaded; | ||
| 212 | } | ||
| 213 | |||
| 214 | notes_attrs->dir = kobject_create_and_add("notes", &mod->mkobj.kobj); | ||
| 215 | if (!notes_attrs->dir) | ||
| 216 | goto out; | ||
| 217 | |||
| 218 | for (i = 0; i < notes; ++i) | ||
| 219 | if (sysfs_create_bin_file(notes_attrs->dir, | ||
| 220 | ¬es_attrs->attrs[i])) | ||
| 221 | goto out; | ||
| 222 | |||
| 223 | mod->notes_attrs = notes_attrs; | ||
| 224 | return; | ||
| 225 | |||
| 226 | out: | ||
| 227 | free_notes_attrs(notes_attrs, i); | ||
| 228 | } | ||
| 229 | |||
| 230 | static void remove_notes_attrs(struct module *mod) | ||
| 231 | { | ||
| 232 | if (mod->notes_attrs) | ||
| 233 | free_notes_attrs(mod->notes_attrs, mod->notes_attrs->notes); | ||
| 234 | } | ||
| 235 | |||
| 236 | #else /* !CONFIG_KALLSYMS */ | ||
| 237 | static inline void add_sect_attrs(struct module *mod, const struct load_info *info) { } | ||
| 238 | static inline void remove_sect_attrs(struct module *mod) { } | ||
| 239 | static inline void add_notes_attrs(struct module *mod, const struct load_info *info) { } | ||
| 240 | static inline void remove_notes_attrs(struct module *mod) { } | ||
| 241 | #endif /* CONFIG_KALLSYMS */ | ||
| 242 | |||
| 243 | static void del_usage_links(struct module *mod) | ||
| 244 | { | ||
| 245 | #ifdef CONFIG_MODULE_UNLOAD | ||
| 246 | struct module_use *use; | ||
| 247 | |||
| 248 | mutex_lock(&module_mutex); | ||
| 249 | list_for_each_entry(use, &mod->target_list, target_list) | ||
| 250 | sysfs_remove_link(use->target->holders_dir, mod->name); | ||
| 251 | mutex_unlock(&module_mutex); | ||
| 252 | #endif | ||
| 253 | } | ||
| 254 | |||
| 255 | static int add_usage_links(struct module *mod) | ||
| 256 | { | ||
| 257 | int ret = 0; | ||
| 258 | #ifdef CONFIG_MODULE_UNLOAD | ||
| 259 | struct module_use *use; | ||
| 260 | |||
| 261 | mutex_lock(&module_mutex); | ||
| 262 | list_for_each_entry(use, &mod->target_list, target_list) { | ||
| 263 | ret = sysfs_create_link(use->target->holders_dir, | ||
| 264 | &mod->mkobj.kobj, mod->name); | ||
| 265 | if (ret) | ||
| 266 | break; | ||
| 267 | } | ||
| 268 | mutex_unlock(&module_mutex); | ||
| 269 | if (ret) | ||
| 270 | del_usage_links(mod); | ||
| 271 | #endif | ||
| 272 | return ret; | ||
| 273 | } | ||
| 274 | |||
| 275 | static void module_remove_modinfo_attrs(struct module *mod, int end) | ||
| 276 | { | ||
| 277 | struct module_attribute *attr; | ||
| 278 | int i; | ||
| 279 | |||
| 280 | for (i = 0; (attr = &mod->modinfo_attrs[i]); i++) { | ||
| 281 | if (end >= 0 && i > end) | ||
| 282 | break; | ||
| 283 | /* pick a field to test for end of list */ | ||
| 284 | if (!attr->attr.name) | ||
| 285 | break; | ||
| 286 | sysfs_remove_file(&mod->mkobj.kobj, &attr->attr); | ||
| 287 | if (attr->free) | ||
| 288 | attr->free(mod); | ||
| 289 | } | ||
| 290 | kfree(mod->modinfo_attrs); | ||
| 291 | } | ||
| 292 | |||
| 293 | static int module_add_modinfo_attrs(struct module *mod) | ||
| 294 | { | ||
| 295 | struct module_attribute *attr; | ||
| 296 | struct module_attribute *temp_attr; | ||
| 297 | int error = 0; | ||
| 298 | int i; | ||
| 299 | |||
| 300 | mod->modinfo_attrs = kzalloc((sizeof(struct module_attribute) * | ||
| 301 | (modinfo_attrs_count + 1)), | ||
| 302 | GFP_KERNEL); | ||
| 303 | if (!mod->modinfo_attrs) | ||
| 304 | return -ENOMEM; | ||
| 305 | |||
| 306 | temp_attr = mod->modinfo_attrs; | ||
| 307 | for (i = 0; (attr = modinfo_attrs[i]); i++) { | ||
| 308 | if (!attr->test || attr->test(mod)) { | ||
| 309 | memcpy(temp_attr, attr, sizeof(*temp_attr)); | ||
| 310 | sysfs_attr_init(&temp_attr->attr); | ||
| 311 | error = sysfs_create_file(&mod->mkobj.kobj, | ||
| 312 | &temp_attr->attr); | ||
| 313 | if (error) | ||
| 314 | goto error_out; | ||
| 315 | ++temp_attr; | ||
| 316 | } | ||
| 317 | } | ||
| 318 | |||
| 319 | return 0; | ||
| 320 | |||
| 321 | error_out: | ||
| 322 | if (i > 0) | ||
| 323 | module_remove_modinfo_attrs(mod, --i); | ||
| 324 | else | ||
| 325 | kfree(mod->modinfo_attrs); | ||
| 326 | return error; | ||
| 327 | } | ||
| 328 | |||
| 329 | static void mod_kobject_put(struct module *mod) | ||
| 330 | { | ||
| 331 | DECLARE_COMPLETION_ONSTACK(c); | ||
| 332 | |||
| 333 | mod->mkobj.kobj_completion = &c; | ||
| 334 | kobject_put(&mod->mkobj.kobj); | ||
| 335 | wait_for_completion(&c); | ||
| 336 | } | ||
| 337 | |||
| 338 | static int mod_sysfs_init(struct module *mod) | ||
| 339 | { | ||
| 340 | int err; | ||
| 341 | struct kobject *kobj; | ||
| 342 | |||
| 343 | if (!module_sysfs_initialized) { | ||
| 344 | pr_err("%s: module sysfs not initialized\n", mod->name); | ||
| 345 | err = -EINVAL; | ||
| 346 | goto out; | ||
| 347 | } | ||
| 348 | |||
| 349 | kobj = kset_find_obj(module_kset, mod->name); | ||
| 350 | if (kobj) { | ||
| 351 | pr_err("%s: module is already loaded\n", mod->name); | ||
| 352 | kobject_put(kobj); | ||
| 353 | err = -EINVAL; | ||
| 354 | goto out; | ||
| 355 | } | ||
| 356 | |||
| 357 | mod->mkobj.mod = mod; | ||
| 358 | |||
| 359 | memset(&mod->mkobj.kobj, 0, sizeof(mod->mkobj.kobj)); | ||
| 360 | mod->mkobj.kobj.kset = module_kset; | ||
| 361 | err = kobject_init_and_add(&mod->mkobj.kobj, &module_ktype, NULL, | ||
| 362 | "%s", mod->name); | ||
| 363 | if (err) | ||
| 364 | mod_kobject_put(mod); | ||
| 365 | |||
| 366 | out: | ||
| 367 | return err; | ||
| 368 | } | ||
| 369 | |||
| 370 | int mod_sysfs_setup(struct module *mod, | ||
| 371 | const struct load_info *info, | ||
| 372 | struct kernel_param *kparam, | ||
| 373 | unsigned int num_params) | ||
| 374 | { | ||
| 375 | int err; | ||
| 376 | |||
| 377 | err = mod_sysfs_init(mod); | ||
| 378 | if (err) | ||
| 379 | goto out; | ||
| 380 | |||
| 381 | mod->holders_dir = kobject_create_and_add("holders", &mod->mkobj.kobj); | ||
| 382 | if (!mod->holders_dir) { | ||
| 383 | err = -ENOMEM; | ||
| 384 | goto out_unreg; | ||
| 385 | } | ||
| 386 | |||
| 387 | err = module_param_sysfs_setup(mod, kparam, num_params); | ||
| 388 | if (err) | ||
| 389 | goto out_unreg_holders; | ||
| 390 | |||
| 391 | err = module_add_modinfo_attrs(mod); | ||
| 392 | if (err) | ||
| 393 | goto out_unreg_param; | ||
| 394 | |||
| 395 | err = add_usage_links(mod); | ||
| 396 | if (err) | ||
| 397 | goto out_unreg_modinfo_attrs; | ||
| 398 | |||
| 399 | add_sect_attrs(mod, info); | ||
| 400 | add_notes_attrs(mod, info); | ||
| 401 | |||
| 402 | return 0; | ||
| 403 | |||
| 404 | out_unreg_modinfo_attrs: | ||
| 405 | module_remove_modinfo_attrs(mod, -1); | ||
| 406 | out_unreg_param: | ||
| 407 | module_param_sysfs_remove(mod); | ||
| 408 | out_unreg_holders: | ||
| 409 | kobject_put(mod->holders_dir); | ||
| 410 | out_unreg: | ||
| 411 | mod_kobject_put(mod); | ||
| 412 | out: | ||
| 413 | return err; | ||
| 414 | } | ||
| 415 | |||
| 416 | static void mod_sysfs_fini(struct module *mod) | ||
| 417 | { | ||
| 418 | remove_notes_attrs(mod); | ||
| 419 | remove_sect_attrs(mod); | ||
| 420 | mod_kobject_put(mod); | ||
| 421 | } | ||
| 422 | |||
| 423 | void mod_sysfs_teardown(struct module *mod) | ||
| 424 | { | ||
| 425 | del_usage_links(mod); | ||
| 426 | module_remove_modinfo_attrs(mod, -1); | ||
| 427 | module_param_sysfs_remove(mod); | ||
| 428 | kobject_put(mod->mkobj.drivers_dir); | ||
| 429 | kobject_put(mod->holders_dir); | ||
| 430 | mod_sysfs_fini(mod); | ||
| 431 | } | ||
| 432 | |||
| 433 | void init_param_lock(struct module *mod) | ||
| 434 | { | ||
| 435 | mutex_init(&mod->param_lock); | ||
| 436 | } | ||