From cc9f7ee01e6724f2320df15a919138413ea1a374 Mon Sep 17 00:00:00 2001 From: Joel Granados Date: Wed, 9 Aug 2023 12:49:53 +0200 Subject: sysctl: Prefer ctl_table_header in proc_sysctl This is a preparation commit that replaces ctl_table with ctl_table_header as the pointer that is passed around in proc_sysctl.c. This will become necessary in subsequent commits when the size of the ctl_table array can no longer be calculated by searching for an empty sentinel (last empty ctl_table element) but will be carried along inside the ctl_table_header struct. Signed-off-by: Joel Granados Signed-off-by: Luis Chamberlain --- fs/proc/proc_sysctl.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'fs/proc') diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 5ea42653126e..94d71446da39 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -1125,11 +1125,11 @@ static int sysctl_check_table_array(const char *path, struct ctl_table *table) return err; } -static int sysctl_check_table(const char *path, struct ctl_table *table) +static int sysctl_check_table(const char *path, struct ctl_table_header *header) { struct ctl_table *entry; int err = 0; - list_for_each_table_entry(entry, table) { + list_for_each_table_entry(entry, header->ctl_table) { if ((entry->proc_handler == proc_dostring) || (entry->proc_handler == proc_dobool) || (entry->proc_handler == proc_dointvec) || @@ -1159,8 +1159,7 @@ static int sysctl_check_table(const char *path, struct ctl_table *table) return err; } -static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table *table, - struct ctl_table_root *link_root) +static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table_header *head) { struct ctl_table *link_table, *entry, *link; struct ctl_table_header *links; @@ -1170,7 +1169,7 @@ static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table name_bytes = 0; nr_entries = 0; - list_for_each_table_entry(entry, table) { + list_for_each_table_entry(entry, head->ctl_table) { nr_entries++; name_bytes += strlen(entry->procname) + 1; } @@ -1189,12 +1188,12 @@ static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table link_name = (char *)&link_table[nr_entries + 1]; link = link_table; - list_for_each_table_entry(entry, table) { + list_for_each_table_entry(entry, head->ctl_table) { int len = strlen(entry->procname) + 1; memcpy(link_name, entry->procname, len); link->procname = link_name; link->mode = S_IFLNK|S_IRWXUGO; - link->data = link_root; + link->data = head->root; link_name += len; link++; } @@ -1205,15 +1204,16 @@ static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table } static bool get_links(struct ctl_dir *dir, - struct ctl_table *table, struct ctl_table_root *link_root) + struct ctl_table_header *header, + struct ctl_table_root *link_root) { - struct ctl_table_header *head; + struct ctl_table_header *tmp_head; struct ctl_table *entry, *link; /* Are there links available for every entry in table? */ - list_for_each_table_entry(entry, table) { + list_for_each_table_entry(entry, header->ctl_table) { const char *procname = entry->procname; - link = find_entry(&head, dir, procname, strlen(procname)); + link = find_entry(&tmp_head, dir, procname, strlen(procname)); if (!link) return false; if (S_ISDIR(link->mode) && S_ISDIR(entry->mode)) @@ -1224,10 +1224,10 @@ static bool get_links(struct ctl_dir *dir, } /* The checks passed. Increase the registration count on the links */ - list_for_each_table_entry(entry, table) { + list_for_each_table_entry(entry, header->ctl_table) { const char *procname = entry->procname; - link = find_entry(&head, dir, procname, strlen(procname)); - head->nreg++; + link = find_entry(&tmp_head, dir, procname, strlen(procname)); + tmp_head->nreg++; } return true; } @@ -1246,13 +1246,13 @@ static int insert_links(struct ctl_table_header *head) if (IS_ERR(core_parent)) return 0; - if (get_links(core_parent, head->ctl_table, head->root)) + if (get_links(core_parent, head, head->root)) return 0; core_parent->header.nreg++; spin_unlock(&sysctl_lock); - links = new_links(core_parent, head->ctl_table, head->root); + links = new_links(core_parent, head); spin_lock(&sysctl_lock); err = -ENOMEM; @@ -1260,7 +1260,7 @@ static int insert_links(struct ctl_table_header *head) goto out; err = 0; - if (get_links(core_parent, head->ctl_table, head->root)) { + if (get_links(core_parent, head, head->root)) { kfree(links); goto out; } @@ -1371,7 +1371,7 @@ struct ctl_table_header *__register_sysctl_table( node = (struct ctl_node *)(header + 1); init_header(header, root, set, node, table); - if (sysctl_check_table(path, table)) + if (sysctl_check_table(path, header)) goto fail; spin_lock(&sysctl_lock); -- cgit v1.2.3 From 18d4b42e9de61546c22c6f47dfc85ca1dbe9459a Mon Sep 17 00:00:00 2001 From: Joel Granados Date: Wed, 9 Aug 2023 12:49:54 +0200 Subject: sysctl: Use ctl_table_header in list_for_each_table_entry We replace the ctl_table with the ctl_table_header pointer in list_for_each_table_entry which is the macro responsible for traversing the ctl_table arrays. This is a preparation commit that will make it easier to add the ctl_table array size (that will be added to ctl_table_header in subsequent commits) to the already existing loop logic based on empty ctl_table elements (so called sentinels). Signed-off-by: Joel Granados Signed-off-by: Luis Chamberlain --- fs/proc/proc_sysctl.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'fs/proc') diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 94d71446da39..884460b0385b 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -19,8 +19,8 @@ #include #include "internal.h" -#define list_for_each_table_entry(entry, table) \ - for ((entry) = (table); (entry)->procname; (entry)++) +#define list_for_each_table_entry(entry, header) \ + for ((entry) = (header->ctl_table); (entry)->procname; (entry)++) static const struct dentry_operations proc_sys_dentry_operations; static const struct file_operations proc_sys_file_operations; @@ -204,7 +204,7 @@ static void init_header(struct ctl_table_header *head, if (node) { struct ctl_table *entry; - list_for_each_table_entry(entry, table) { + list_for_each_table_entry(entry, head) { node->header = head; node++; } @@ -215,7 +215,7 @@ static void erase_header(struct ctl_table_header *head) { struct ctl_table *entry; - list_for_each_table_entry(entry, head->ctl_table) + list_for_each_table_entry(entry, head) erase_entry(head, entry); } @@ -242,7 +242,7 @@ static int insert_header(struct ctl_dir *dir, struct ctl_table_header *header) err = insert_links(header); if (err) goto fail_links; - list_for_each_table_entry(entry, header->ctl_table) { + list_for_each_table_entry(entry, header) { err = insert_entry(header, entry); if (err) goto fail; @@ -1129,7 +1129,7 @@ static int sysctl_check_table(const char *path, struct ctl_table_header *header) { struct ctl_table *entry; int err = 0; - list_for_each_table_entry(entry, header->ctl_table) { + list_for_each_table_entry(entry, header) { if ((entry->proc_handler == proc_dostring) || (entry->proc_handler == proc_dobool) || (entry->proc_handler == proc_dointvec) || @@ -1169,7 +1169,7 @@ static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table_ name_bytes = 0; nr_entries = 0; - list_for_each_table_entry(entry, head->ctl_table) { + list_for_each_table_entry(entry, head) { nr_entries++; name_bytes += strlen(entry->procname) + 1; } @@ -1188,7 +1188,7 @@ static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table_ link_name = (char *)&link_table[nr_entries + 1]; link = link_table; - list_for_each_table_entry(entry, head->ctl_table) { + list_for_each_table_entry(entry, head) { int len = strlen(entry->procname) + 1; memcpy(link_name, entry->procname, len); link->procname = link_name; @@ -1211,7 +1211,7 @@ static bool get_links(struct ctl_dir *dir, struct ctl_table *entry, *link; /* Are there links available for every entry in table? */ - list_for_each_table_entry(entry, header->ctl_table) { + list_for_each_table_entry(entry, header) { const char *procname = entry->procname; link = find_entry(&tmp_head, dir, procname, strlen(procname)); if (!link) @@ -1224,7 +1224,7 @@ static bool get_links(struct ctl_dir *dir, } /* The checks passed. Increase the registration count on the links */ - list_for_each_table_entry(entry, header->ctl_table) { + list_for_each_table_entry(entry, header) { const char *procname = entry->procname; link = find_entry(&tmp_head, dir, procname, strlen(procname)); tmp_head->nreg++; @@ -1356,12 +1356,14 @@ struct ctl_table_header *__register_sysctl_table( { struct ctl_table_root *root = set->dir.header.root; struct ctl_table_header *header; + struct ctl_table_header h_tmp; struct ctl_dir *dir; struct ctl_table *entry; struct ctl_node *node; int nr_entries = 0; - list_for_each_table_entry(entry, table) + h_tmp.ctl_table = table; + list_for_each_table_entry(entry, (&h_tmp)) nr_entries++; header = kzalloc(sizeof(struct ctl_table_header) + @@ -1471,7 +1473,7 @@ static void put_links(struct ctl_table_header *header) if (IS_ERR(core_parent)) return; - list_for_each_table_entry(entry, header->ctl_table) { + list_for_each_table_entry(entry, header) { struct ctl_table_header *link_head; struct ctl_table *link; const char *name = entry->procname; -- cgit v1.2.3 From b1f01e2baefc5dbe240bbf529a813b452c064204 Mon Sep 17 00:00:00 2001 From: Joel Granados Date: Wed, 9 Aug 2023 12:49:56 +0200 Subject: sysctl: Add size argument to init_header In this commit, we add a table_size argument to the init_header function in order to initialize the ctl_table_size variable in ctl_table_header. Even though the size is not yet used, it is now initialized within the sysctl subsys. We need this commit for when we start adding the table_size arguments to the sysctl functions (e.g. register_sysctl, __register_sysctl_table and __register_sysctl_init). Note that in __register_sysctl_table we temporarily use a calculated size until we add the size argument to that function in subsequent commits. Signed-off-by: Joel Granados Signed-off-by: Luis Chamberlain --- fs/proc/proc_sysctl.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'fs/proc') diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 884460b0385b..fa1438f1a355 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -188,9 +188,10 @@ static void erase_entry(struct ctl_table_header *head, struct ctl_table *entry) static void init_header(struct ctl_table_header *head, struct ctl_table_root *root, struct ctl_table_set *set, - struct ctl_node *node, struct ctl_table *table) + struct ctl_node *node, struct ctl_table *table, size_t table_size) { head->ctl_table = table; + head->ctl_table_size = table_size; head->ctl_table_arg = table; head->used = 0; head->count = 1; @@ -973,7 +974,7 @@ static struct ctl_dir *new_dir(struct ctl_table_set *set, memcpy(new_name, name, namelen); table[0].procname = new_name; table[0].mode = S_IFDIR|S_IRUGO|S_IXUGO; - init_header(&new->header, set->dir.header.root, set, node, table); + init_header(&new->header, set->dir.header.root, set, node, table, 1); return new; } @@ -1197,7 +1198,8 @@ static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table_ link_name += len; link++; } - init_header(links, dir->header.root, dir->header.set, node, link_table); + init_header(links, dir->header.root, dir->header.set, node, link_table, + head->ctl_table_size); links->nreg = nr_entries; return links; @@ -1372,7 +1374,7 @@ struct ctl_table_header *__register_sysctl_table( return NULL; node = (struct ctl_node *)(header + 1); - init_header(header, root, set, node, table); + init_header(header, root, set, node, table, nr_entries); if (sysctl_check_table(path, header)) goto fail; @@ -1537,7 +1539,7 @@ void setup_sysctl_set(struct ctl_table_set *set, { memset(set, 0, sizeof(*set)); set->is_seen = is_seen; - init_header(&set->dir.header, root, set, NULL, root_table); + init_header(&set->dir.header, root, set, NULL, root_table, 1); } void retire_sysctl_set(struct ctl_table_set *set) -- cgit v1.2.3 From bff97cf11b261972cae90299432238cc9a9a6a51 Mon Sep 17 00:00:00 2001 From: Joel Granados Date: Wed, 9 Aug 2023 12:49:57 +0200 Subject: sysctl: Add a size arg to __register_sysctl_table We make these changes in order to prepare __register_sysctl_table and its callers for when we remove the sentinel element (empty element at the end of ctl_table arrays). We don't actually remove any sentinels in this commit, but we *do* make sure to use ARRAY_SIZE so the table_size is available when the removal occurs. We add a table_size argument to __register_sysctl_table and adjust callers, all of which pass ctl_table pointers and need an explicit call to ARRAY_SIZE. We implement a size calculation in register_net_sysctl in order to forward the size of the array pointer received from the network register calls. The new table_size argument does not yet have any effect in the init_header call which is still dependent on the sentinel's presence. table_size *does* however drive the `kzalloc` allocation in __register_sysctl_table with no adverse effects as the allocated memory is either one element greater than the calculated ctl_table array (for the calls in ipc_sysctl.c, mq_sysctl.c and ucount.c) or the exact size of the calculated ctl_table array (for the call from sysctl_net.c and register_sysctl). This approach will allows us to "just" remove the sentinel without further changes to __register_sysctl_table as table_size will represent the exact size for all the callers at that point. Signed-off-by: Joel Granados Signed-off-by: Luis Chamberlain --- fs/proc/proc_sysctl.c | 23 ++++++++++++----------- include/linux/sysctl.h | 2 +- ipc/ipc_sysctl.c | 4 +++- ipc/mq_sysctl.c | 4 +++- kernel/ucount.c | 3 ++- net/sysctl_net.c | 8 +++++++- 6 files changed, 28 insertions(+), 16 deletions(-) (limited to 'fs/proc') diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index fa1438f1a355..b8dd78e344ff 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -1312,6 +1312,7 @@ static struct ctl_dir *sysctl_mkdir_p(struct ctl_dir *dir, const char *path) * should not be free'd after registration. So it should not be * used on stack. It can either be a global or dynamically allocated * by the caller and free'd later after sysctl unregistration. + * @table_size : The number of elements in table * * Register a sysctl table hierarchy. @table should be a filled in ctl_table * array. A completely 0 filled entry terminates the table. @@ -1354,27 +1355,20 @@ static struct ctl_dir *sysctl_mkdir_p(struct ctl_dir *dir, const char *path) */ struct ctl_table_header *__register_sysctl_table( struct ctl_table_set *set, - const char *path, struct ctl_table *table) + const char *path, struct ctl_table *table, size_t table_size) { struct ctl_table_root *root = set->dir.header.root; struct ctl_table_header *header; - struct ctl_table_header h_tmp; struct ctl_dir *dir; - struct ctl_table *entry; struct ctl_node *node; - int nr_entries = 0; - - h_tmp.ctl_table = table; - list_for_each_table_entry(entry, (&h_tmp)) - nr_entries++; header = kzalloc(sizeof(struct ctl_table_header) + - sizeof(struct ctl_node)*nr_entries, GFP_KERNEL_ACCOUNT); + sizeof(struct ctl_node)*table_size, GFP_KERNEL_ACCOUNT); if (!header) return NULL; node = (struct ctl_node *)(header + 1); - init_header(header, root, set, node, table, nr_entries); + init_header(header, root, set, node, table, table_size); if (sysctl_check_table(path, header)) goto fail; @@ -1423,8 +1417,15 @@ fail: */ struct ctl_table_header *register_sysctl(const char *path, struct ctl_table *table) { + int count = 0; + struct ctl_table *entry; + struct ctl_table_header t_hdr; + + t_hdr.ctl_table = table; + list_for_each_table_entry(entry, (&t_hdr)) + count++; return __register_sysctl_table(&sysctl_table_root.default_set, - path, table); + path, table, count); } EXPORT_SYMBOL(register_sysctl); diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 33252ad58ebe..0495c858989f 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -226,7 +226,7 @@ extern void retire_sysctl_set(struct ctl_table_set *set); struct ctl_table_header *__register_sysctl_table( struct ctl_table_set *set, - const char *path, struct ctl_table *table); + const char *path, struct ctl_table *table, size_t table_size); struct ctl_table_header *register_sysctl(const char *path, struct ctl_table *table); void unregister_sysctl_table(struct ctl_table_header * table); diff --git a/ipc/ipc_sysctl.c b/ipc/ipc_sysctl.c index ef313ecfb53a..8c62e443f78b 100644 --- a/ipc/ipc_sysctl.c +++ b/ipc/ipc_sysctl.c @@ -259,7 +259,9 @@ bool setup_ipc_sysctls(struct ipc_namespace *ns) tbl[i].data = NULL; } - ns->ipc_sysctls = __register_sysctl_table(&ns->ipc_set, "kernel", tbl); + ns->ipc_sysctls = __register_sysctl_table(&ns->ipc_set, + "kernel", tbl, + ARRAY_SIZE(ipc_sysctls)); } if (!ns->ipc_sysctls) { kfree(tbl); diff --git a/ipc/mq_sysctl.c b/ipc/mq_sysctl.c index fbf6a8b93a26..ebb5ed81c151 100644 --- a/ipc/mq_sysctl.c +++ b/ipc/mq_sysctl.c @@ -109,7 +109,9 @@ bool setup_mq_sysctls(struct ipc_namespace *ns) tbl[i].data = NULL; } - ns->mq_sysctls = __register_sysctl_table(&ns->mq_set, "fs/mqueue", tbl); + ns->mq_sysctls = __register_sysctl_table(&ns->mq_set, + "fs/mqueue", tbl, + ARRAY_SIZE(mq_sysctls)); } if (!ns->mq_sysctls) { kfree(tbl); diff --git a/kernel/ucount.c b/kernel/ucount.c index ee8e57fd6f90..2b80264bb79f 100644 --- a/kernel/ucount.c +++ b/kernel/ucount.c @@ -104,7 +104,8 @@ bool setup_userns_sysctls(struct user_namespace *ns) for (i = 0; i < UCOUNT_COUNTS; i++) { tbl[i].data = &ns->ucount_max[i]; } - ns->sysctls = __register_sysctl_table(&ns->set, "user", tbl); + ns->sysctls = __register_sysctl_table(&ns->set, "user", tbl, + ARRAY_SIZE(user_table)); } if (!ns->sysctls) { kfree(tbl); diff --git a/net/sysctl_net.c b/net/sysctl_net.c index 4b45ed631eb8..8ee4b74bc009 100644 --- a/net/sysctl_net.c +++ b/net/sysctl_net.c @@ -163,10 +163,16 @@ static void ensure_safe_net_sysctl(struct net *net, const char *path, struct ctl_table_header *register_net_sysctl(struct net *net, const char *path, struct ctl_table *table) { + int count = 0; + struct ctl_table *entry; + if (!net_eq(net, &init_net)) ensure_safe_net_sysctl(net, path, table); - return __register_sysctl_table(&net->sysctls, path, table); + for (entry = table; entry->procname; entry++) + count++; + + return __register_sysctl_table(&net->sysctls, path, table, count); } EXPORT_SYMBOL_GPL(register_net_sysctl); -- cgit v1.2.3 From 9edbfe92a0a1355bae1e47c8f542ac0d39f19f8c Mon Sep 17 00:00:00 2001 From: Joel Granados Date: Wed, 9 Aug 2023 12:49:58 +0200 Subject: sysctl: Add size to register_sysctl This commit adds table_size to register_sysctl in preparation for the removal of the sentinel elements in the ctl_table arrays (last empty markers). And though we do *not* remove any sentinels in this commit, we set things up by either passing the table_size explicitly or using ARRAY_SIZE on the ctl_table arrays. We replace the register_syctl function with a macro that will add the ARRAY_SIZE to the new register_sysctl_sz function. In this way the callers that are already using an array of ctl_table structs do not change. For the callers that pass a ctl_table array pointer, we pass the table_size to register_sysctl_sz instead of the macro. Signed-off-by: Joel Granados Suggested-by: Greg Kroah-Hartman Signed-off-by: Luis Chamberlain --- arch/arm64/kernel/armv8_deprecated.c | 2 +- arch/s390/appldata/appldata_base.c | 2 +- fs/proc/proc_sysctl.c | 30 ++++++++++++++++-------------- include/linux/sysctl.h | 10 ++++++++-- kernel/ucount.c | 2 +- net/sysctl_net.c | 2 +- 6 files changed, 28 insertions(+), 20 deletions(-) (limited to 'fs/proc') diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c index 1febd412b4d2..e459cfd33711 100644 --- a/arch/arm64/kernel/armv8_deprecated.c +++ b/arch/arm64/kernel/armv8_deprecated.c @@ -569,7 +569,7 @@ static void __init register_insn_emulation(struct insn_emulation *insn) sysctl->extra2 = &insn->max; sysctl->proc_handler = emulation_proc_handler; - register_sysctl("abi", sysctl); + register_sysctl_sz("abi", sysctl, 1); } } diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c index bbefe5e86bdf..3b0994625652 100644 --- a/arch/s390/appldata/appldata_base.c +++ b/arch/s390/appldata/appldata_base.c @@ -365,7 +365,7 @@ int appldata_register_ops(struct appldata_ops *ops) ops->ctl_table[0].proc_handler = appldata_generic_handler; ops->ctl_table[0].data = ops; - ops->sysctl_header = register_sysctl(appldata_proc_name, ops->ctl_table); + ops->sysctl_header = register_sysctl_sz(appldata_proc_name, ops->ctl_table, 1); if (!ops->sysctl_header) goto out; return 0; diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index b8dd78e344ff..80d3e2f61947 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -43,7 +43,7 @@ static struct ctl_table sysctl_mount_point[] = { */ struct ctl_table_header *register_sysctl_mount_point(const char *path) { - return register_sysctl(path, sysctl_mount_point); + return register_sysctl_sz(path, sysctl_mount_point, 0); } EXPORT_SYMBOL(register_sysctl_mount_point); @@ -1399,7 +1399,7 @@ fail: } /** - * register_sysctl - register a sysctl table + * register_sysctl_sz - register a sysctl table * @path: The path to the directory the sysctl table is in. If the path * doesn't exist we will create it for you. * @table: the table structure. The calller must ensure the life of the @table @@ -1409,25 +1409,20 @@ fail: * to call unregister_sysctl_table() and can instead use something like * register_sysctl_init() which does not care for the result of the syctl * registration. + * @table_size: The number of elements in table. * * Register a sysctl table. @table should be a filled in ctl_table * array. A completely 0 filled entry terminates the table. * * See __register_sysctl_table for more details. */ -struct ctl_table_header *register_sysctl(const char *path, struct ctl_table *table) +struct ctl_table_header *register_sysctl_sz(const char *path, struct ctl_table *table, + size_t table_size) { - int count = 0; - struct ctl_table *entry; - struct ctl_table_header t_hdr; - - t_hdr.ctl_table = table; - list_for_each_table_entry(entry, (&t_hdr)) - count++; return __register_sysctl_table(&sysctl_table_root.default_set, - path, table, count); + path, table, table_size); } -EXPORT_SYMBOL(register_sysctl); +EXPORT_SYMBOL(register_sysctl_sz); /** * __register_sysctl_init() - register sysctl table to path @@ -1452,10 +1447,17 @@ EXPORT_SYMBOL(register_sysctl); void __init __register_sysctl_init(const char *path, struct ctl_table *table, const char *table_name) { - struct ctl_table_header *hdr = register_sysctl(path, table); + int count = 0; + struct ctl_table *entry; + struct ctl_table_header t_hdr, *hdr; + + t_hdr.ctl_table = table; + list_for_each_table_entry(entry, (&t_hdr)) + count++; + hdr = register_sysctl_sz(path, table, count); if (unlikely(!hdr)) { - pr_err("failed when register_sysctl %s to %s\n", table_name, path); + pr_err("failed when register_sysctl_sz %s to %s\n", table_name, path); return; } kmemleak_not_leak(hdr); diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 0495c858989f..b1168ae281c9 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -215,6 +215,9 @@ struct ctl_path { const char *procname; }; +#define register_sysctl(path, table) \ + register_sysctl_sz(path, table, ARRAY_SIZE(table)) + #ifdef CONFIG_SYSCTL void proc_sys_poll_notify(struct ctl_table_poll *poll); @@ -227,7 +230,8 @@ extern void retire_sysctl_set(struct ctl_table_set *set); struct ctl_table_header *__register_sysctl_table( struct ctl_table_set *set, const char *path, struct ctl_table *table, size_t table_size); -struct ctl_table_header *register_sysctl(const char *path, struct ctl_table *table); +struct ctl_table_header *register_sysctl_sz(const char *path, struct ctl_table *table, + size_t table_size); void unregister_sysctl_table(struct ctl_table_header * table); extern int sysctl_init_bases(void); @@ -262,7 +266,9 @@ static inline struct ctl_table_header *register_sysctl_mount_point(const char *p return NULL; } -static inline struct ctl_table_header *register_sysctl(const char *path, struct ctl_table *table) +static inline struct ctl_table_header *register_sysctl_sz(const char *path, + struct ctl_table *table, + size_t table_size) { return NULL; } diff --git a/kernel/ucount.c b/kernel/ucount.c index 2b80264bb79f..4aa6166cb856 100644 --- a/kernel/ucount.c +++ b/kernel/ucount.c @@ -365,7 +365,7 @@ static __init int user_namespace_sysctl_init(void) * default set so that registrations in the child sets work * properly. */ - user_header = register_sysctl("user", empty); + user_header = register_sysctl_sz("user", empty, 0); kmemleak_ignore(user_header); BUG_ON(!user_header); BUG_ON(!setup_userns_sysctls(&init_user_ns)); diff --git a/net/sysctl_net.c b/net/sysctl_net.c index 8ee4b74bc009..d9cbbb51b143 100644 --- a/net/sysctl_net.c +++ b/net/sysctl_net.c @@ -101,7 +101,7 @@ __init int net_sysctl_init(void) * registering "/proc/sys/net" as an empty directory not in a * network namespace. */ - net_header = register_sysctl("net", empty); + net_header = register_sysctl_sz("net", empty, 0); if (!net_header) goto out; ret = register_pernet_subsys(&sysctl_pernet_ops); -- cgit v1.2.3 From 3bc269cfd3e119be84b69d95aec3a9e147016bb2 Mon Sep 17 00:00:00 2001 From: Joel Granados Date: Wed, 9 Aug 2023 12:49:59 +0200 Subject: sysctl: Add size arg to __register_sysctl_init This commit adds table_size to __register_sysctl_init in preparation for the removal of the sentinel elements in the ctl_table arrays (last empty markers). And though we do *not* remove any sentinels in this commit, we set things up by calculating the ctl_table array size with ARRAY_SIZE. We add a table_size argument to __register_sysctl_init and modify the register_sysctl_init macro to calculate the array size with ARRAY_SIZE. The original callers do not need to be updated as they will go through the new macro. Signed-off-by: Joel Granados Suggested-by: Greg Kroah-Hartman Signed-off-by: Luis Chamberlain --- fs/proc/proc_sysctl.c | 12 +++--------- include/linux/sysctl.h | 5 +++-- 2 files changed, 6 insertions(+), 11 deletions(-) (limited to 'fs/proc') diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 80d3e2f61947..817bc51c58d8 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -1433,6 +1433,7 @@ EXPORT_SYMBOL(register_sysctl_sz); * lifetime use of the sysctl. * @table_name: The name of sysctl table, only used for log printing when * registration fails + * @table_size: The number of elements in table * * The sysctl interface is used by userspace to query or modify at runtime * a predefined value set on a variable. These variables however have default @@ -1445,16 +1446,9 @@ EXPORT_SYMBOL(register_sysctl_sz); * Context: if your base directory does not exist it will be created for you. */ void __init __register_sysctl_init(const char *path, struct ctl_table *table, - const char *table_name) + const char *table_name, size_t table_size) { - int count = 0; - struct ctl_table *entry; - struct ctl_table_header t_hdr, *hdr; - - t_hdr.ctl_table = table; - list_for_each_table_entry(entry, (&t_hdr)) - count++; - hdr = register_sysctl_sz(path, table, count); + struct ctl_table_header *hdr = register_sysctl_sz(path, table, table_size); if (unlikely(!hdr)) { pr_err("failed when register_sysctl_sz %s to %s\n", table_name, path); diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index b1168ae281c9..09d7429d67c0 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -236,8 +236,9 @@ void unregister_sysctl_table(struct ctl_table_header * table); extern int sysctl_init_bases(void); extern void __register_sysctl_init(const char *path, struct ctl_table *table, - const char *table_name); -#define register_sysctl_init(path, table) __register_sysctl_init(path, table, #table) + const char *table_name, size_t table_size); +#define register_sysctl_init(path, table) \ + __register_sysctl_init(path, table, #table, ARRAY_SIZE(table)) extern struct ctl_table_header *register_sysctl_mount_point(const char *path); void do_sysctl_args(void); -- cgit v1.2.3 From 53f3811dfd5e39507ee3aaea1be09aabce8f9c98 Mon Sep 17 00:00:00 2001 From: Joel Granados Date: Wed, 9 Aug 2023 12:50:06 +0200 Subject: sysctl: Use ctl_table_size as stopping criteria for list macro This is a preparation commit to make it easy to remove the sentinel elements (empty end markers) from the ctl_table arrays. It both allows the systematic removal of the sentinels and adds the ctl_table_size variable to the stopping criteria of the list_for_each_table_entry macro that traverses all ctl_table arrays. Once all the sentinels are removed by subsequent commits, ctl_table_size will become the only stopping criteria in the macro. We don't actually remove any elements in this commit, but it sets things up to for the removal process to take place. By adding header->ctl_table_size as an additional stopping criteria for the list_for_each_table_entry macro, it will execute until it finds an "empty" ->procname or until the size runs out. Therefore if a ctl_table array with a sentinel is passed its size will be too big (by one element) but it will stop on the sentinel. On the other hand, if the ctl_table array without a sentinel is passed its size will be just write and there will be no need for a sentinel. Signed-off-by: Joel Granados Suggested-by: Jani Nikula Signed-off-by: Luis Chamberlain --- fs/proc/proc_sysctl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'fs/proc') diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 817bc51c58d8..504e847c2a3a 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -19,8 +19,9 @@ #include #include "internal.h" -#define list_for_each_table_entry(entry, header) \ - for ((entry) = (header->ctl_table); (entry)->procname; (entry)++) +#define list_for_each_table_entry(entry, header) \ + entry = header->ctl_table; \ + for (size_t i = 0 ; i < header->ctl_table_size && entry->procname; ++i, entry++) static const struct dentry_operations proc_sys_dentry_operations; static const struct file_operations proc_sys_file_operations; -- cgit v1.2.3