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 | 16 | obj-$(CONFIG_DEBUG_KMEMLEAK) += debug_kmemleak.o |
| 17 | 17 | obj-$(CONFIG_KALLSYMS) += kallsyms.o |
| 18 | 18 | obj-$(CONFIG_PROC_FS) += procfs.o |
| 19 | +obj-$(CONFIG_SYSFS) += sysfs.o | |
| @@ -34,6 +34,9 @@ · 33 unmodified lines | ||
| 34 | 34 | extern struct mutex module_mutex; |
| 35 | 35 | extern struct list_head modules; |
| 36 | 36 | |
| 37 | +extern struct module_attribute *modinfo_attrs[]; | |
| 38 | +extern size_t modinfo_attrs_count; | |
| 39 | + | |
| 37 | 40 | /* Provided by the linker */ |
| 38 | 41 | extern const struct kernel_symbol __start___ksymtab[]; |
| 39 | 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 | 207 | static inline void layout_symtab(struct module *mod, struct load_info *info) { } |
| 205 | 208 | static inline void add_kallsyms(struct module *mod, const struct load_info *info) { } |
| 206 | 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 | 14 | #include <linux/init.h> |
| 15 | 15 | #include <linux/kallsyms.h> |
| 16 | 16 | #include <linux/buildid.h> |
| 17 | −#include <linux/file.h> | |
| 18 | 17 | #include <linux/fs.h> |
| 19 | −#include <linux/sysfs.h> | |
| 20 | 18 | #include <linux/kernel.h> |
| 21 | 19 | #include <linux/kernel_read_file.h> |
| 22 | 20 | #include <linux/slab.h> |
| @@ -989,7 +987,7 @@ static ssize_t show_taint(struct module_attribute *mattr, · 966 unmodified lines | ||
| 989 | 987 | static struct module_attribute modinfo_taint = |
| 990 | 988 | __ATTR(taint, 0444, show_taint, NULL); |
| 991 | 989 | |
| 992 | −static struct module_attribute *modinfo_attrs[] = { | |
| 990 | +struct module_attribute *modinfo_attrs[] = { | |
| 993 | 991 | &module_uevent, |
| 994 | 992 | &modinfo_version, |
| 995 | 993 | &modinfo_srcversion, |
| @@ -1003,6 +1001,8 @@ static struct module_attribute *modinfo_attrs[] = { · 7 unmodified lines | ||
| 1003 | 1001 | NULL, |
| 1004 | 1002 | }; |
| 1005 | 1003 | |
| 1004 | +size_t modinfo_attrs_count = ARRAY_SIZE(modinfo_attrs); | |
| 1005 | + | |
| 1006 | 1006 | static const char vermagic[] = VERMAGIC_STRING; |
| 1007 | 1007 | |
| 1008 | 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 | 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 | 1257 | * LKM RO/NX protection: protect module's text/ro-data |
| 1721 | 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 | +} | |