From 98ca62ba9e2be5863c7d069f84f7166b45a5b2f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Tue, 2 Apr 2024 23:10:34 +0200 Subject: [PATCH 01/13] sysctl: always initialize i_uid/i_gid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Always initialize i_uid/i_gid inside the sysfs core so set_ownership() can safely skip setting them. Commit 5ec27ec735ba ("fs/proc/proc_sysctl.c: fix the default values of i_uid/i_gid on /proc/sys inodes.") added defaults for i_uid/i_gid when set_ownership() was not implemented. It also missed adjusting net_ctl_set_ownership() to use the same default values in case the computation of a better value failed. Fixes: 5ec27ec735ba ("fs/proc/proc_sysctl.c: fix the default values of i_uid/i_gid on /proc/sys inodes.") Cc: stable@vger.kernel.org Signed-off-by: Thomas Weißschuh Signed-off-by: Joel Granados --- fs/proc/proc_sysctl.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index b1c2c0b82116..dd7b462387a0 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -476,12 +476,10 @@ static struct inode *proc_sys_make_inode(struct super_block *sb, make_empty_dir_inode(inode); } + inode->i_uid = GLOBAL_ROOT_UID; + inode->i_gid = GLOBAL_ROOT_GID; if (root->set_ownership) root->set_ownership(head, &inode->i_uid, &inode->i_gid); - else { - inode->i_uid = GLOBAL_ROOT_UID; - inode->i_gid = GLOBAL_ROOT_GID; - } return inode; } From b5ffbd1396885f76bf87e67d590a3ef063e6d831 Mon Sep 17 00:00:00 2001 From: Wen Yang Date: Fri, 19 Apr 2024 11:36:39 +0800 Subject: [PATCH 02/13] sysctl: move the extra1/2 boundary check of u8 to sysctl_check_table_array Move boundary checking for proc_dou8ved_minmax into module loading, thereby reporting errors in advance. And add a kunit test case ensuring the boundary check is done correctly. The boundary check in proc_dou8vec_minmax done to the extra elements in the ctl_table struct is currently performed at runtime. This allows buggy kernel modules to be loaded normally without any errors only to fail when used. This is a buggy example module: #include #include #include static struct ctl_table_header *_table_header = NULL; static unsigned char _data = 0; struct ctl_table table[] = { { .procname = "foo", .data = &_data, .maxlen = sizeof(u8), .mode = 0644, .proc_handler = proc_dou8vec_minmax, .extra1 = SYSCTL_ZERO, .extra2 = SYSCTL_ONE_THOUSAND, }, }; static int init_demo(void) { _table_header = register_sysctl("kernel", table); if (!_table_header) return -ENOMEM; return 0; } module_init(init_demo); MODULE_LICENSE("GPL"); And this is the result: # insmod test.ko # cat /proc/sys/kernel/foo cat: /proc/sys/kernel/foo: Invalid argument Suggested-by: Joel Granados Signed-off-by: Wen Yang Cc: Luis Chamberlain Cc: Kees Cook Cc: Joel Granados Cc: Eric W. Biederman Cc: Christian Brauner Cc: linux-kernel@vger.kernel.org Reviewed-by: Joel Granados Signed-off-by: Joel Granados --- fs/proc/proc_sysctl.c | 14 +++++++++++++ kernel/sysctl-test.c | 49 +++++++++++++++++++++++++++++++++++++++++++ kernel/sysctl.c | 10 ++------- 3 files changed, 65 insertions(+), 8 deletions(-) diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index dd7b462387a0..c467e36741d0 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -1091,6 +1091,7 @@ static int sysctl_err(const char *path, struct ctl_table *table, char *fmt, ...) static int sysctl_check_table_array(const char *path, struct ctl_table *table) { + unsigned int extra; int err = 0; if ((table->proc_handler == proc_douintvec) || @@ -1102,6 +1103,19 @@ static int sysctl_check_table_array(const char *path, struct ctl_table *table) if (table->proc_handler == proc_dou8vec_minmax) { if (table->maxlen != sizeof(u8)) err |= sysctl_err(path, table, "array not allowed"); + + if (table->extra1) { + extra = *(unsigned int *) table->extra1; + if (extra > 255U) + err |= sysctl_err(path, table, + "range value too large for proc_dou8vec_minmax"); + } + if (table->extra2) { + extra = *(unsigned int *) table->extra2; + if (extra > 255U) + err |= sysctl_err(path, table, + "range value too large for proc_dou8vec_minmax"); + } } if (table->proc_handler == proc_dobool) { diff --git a/kernel/sysctl-test.c b/kernel/sysctl-test.c index 6ef887c19c48..4e7dcc9187e2 100644 --- a/kernel/sysctl-test.c +++ b/kernel/sysctl-test.c @@ -367,6 +367,54 @@ static void sysctl_test_api_dointvec_write_single_greater_int_max( KUNIT_EXPECT_EQ(test, 0, *((int *)table.data)); } +/* + * Test that registering an invalid extra value is not allowed. + */ +static void sysctl_test_register_sysctl_sz_invalid_extra_value( + struct kunit *test) +{ + unsigned char data = 0; + struct ctl_table table_foo[] = { + { + .procname = "foo", + .data = &data, + .maxlen = sizeof(u8), + .mode = 0644, + .proc_handler = proc_dou8vec_minmax, + .extra1 = SYSCTL_FOUR, + .extra2 = SYSCTL_ONE_THOUSAND, + }, + }; + + struct ctl_table table_bar[] = { + { + .procname = "bar", + .data = &data, + .maxlen = sizeof(u8), + .mode = 0644, + .proc_handler = proc_dou8vec_minmax, + .extra1 = SYSCTL_NEG_ONE, + .extra2 = SYSCTL_ONE_HUNDRED, + }, + }; + + struct ctl_table table_qux[] = { + { + .procname = "qux", + .data = &data, + .maxlen = sizeof(u8), + .mode = 0644, + .proc_handler = proc_dou8vec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_TWO_HUNDRED, + }, + }; + + KUNIT_EXPECT_NULL(test, register_sysctl("foo", table_foo)); + KUNIT_EXPECT_NULL(test, register_sysctl("foo", table_bar)); + KUNIT_EXPECT_NOT_NULL(test, register_sysctl("foo", table_qux)); +} + static struct kunit_case sysctl_test_cases[] = { KUNIT_CASE(sysctl_test_api_dointvec_null_tbl_data), KUNIT_CASE(sysctl_test_api_dointvec_table_maxlen_unset), @@ -378,6 +426,7 @@ static struct kunit_case sysctl_test_cases[] = { KUNIT_CASE(sysctl_test_dointvec_write_happy_single_negative), KUNIT_CASE(sysctl_test_api_dointvec_write_single_less_int_min), KUNIT_CASE(sysctl_test_api_dointvec_write_single_greater_int_max), + KUNIT_CASE(sysctl_test_register_sysctl_sz_invalid_extra_value), {} }; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index e0b917328cf9..c0a1164eaf59 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -977,16 +977,10 @@ int proc_dou8vec_minmax(struct ctl_table *table, int write, if (table->maxlen != sizeof(u8)) return -EINVAL; - if (table->extra1) { + if (table->extra1) min = *(unsigned int *) table->extra1; - if (min > 255U) - return -EINVAL; - } - if (table->extra2) { + if (table->extra2) max = *(unsigned int *) table->extra2; - if (max > 255U) - return -EINVAL; - } tmp = *table; From 4154342bf153a6c2a2820e3d517188d7c76f7055 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sat, 18 May 2024 15:53:40 +0200 Subject: [PATCH 03/13] utsname: constify ctl_table arguments of utility function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sysctl core is preparing to only expose instances of struct ctl_table as "const". This will also affect the ctl_table argument of sysctl handlers. As the function prototype of all sysctl handlers throughout the tree needs to stay consistent that change will be done in one commit. To reduce the size of that final commit, switch utility functions which are not bound by "typedef proc_handler" to "const struct ctl_table". No functional change. Signed-off-by: Thomas Weißschuh Reviewed-by: Joel Granados Signed-off-by: Joel Granados --- kernel/utsname_sysctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/utsname_sysctl.c b/kernel/utsname_sysctl.c index 76a772072557..04e4513f2985 100644 --- a/kernel/utsname_sysctl.c +++ b/kernel/utsname_sysctl.c @@ -15,7 +15,7 @@ #ifdef CONFIG_PROC_SYSCTL -static void *get_uts(struct ctl_table *table) +static void *get_uts(const struct ctl_table *table) { char *which = table->data; struct uts_namespace *uts_ns; From 32fe91524e1651b9a0e11ddfbc63de9aa485cf48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Mon, 13 May 2024 11:25:18 +0200 Subject: [PATCH 04/13] sysctl: constify ctl_table arguments of utility function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In a future commit the proc_handlers themselves will change to "const struct ctl_table". As a preparation for that adapt the internal helper. Signed-off-by: Thomas Weißschuh Reviewed-by: Kees Cook Signed-off-by: Joel Granados --- include/linux/sysctl.h | 2 +- kernel/sysctl.c | 21 +++++++++++---------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 09db2f2e6488..54fbec062772 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -237,7 +237,7 @@ extern struct ctl_table_header *register_sysctl_mount_point(const char *path); void do_sysctl_args(void); bool sysctl_is_alias(char *param); -int do_proc_douintvec(struct ctl_table *table, int write, +int do_proc_douintvec(const struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos, int (*conv)(unsigned long *lvalp, unsigned int *valp, diff --git a/kernel/sysctl.c b/kernel/sysctl.c index c0a1164eaf59..e4421594fc25 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -205,7 +205,7 @@ static int _proc_do_string(char *data, int maxlen, int write, return 0; } -static void warn_sysctl_write(struct ctl_table *table) +static void warn_sysctl_write(const struct ctl_table *table) { pr_warn_once("%s wrote to %s when file position was not 0!\n" "This will not be supported in the future. To silence this\n" @@ -223,7 +223,7 @@ static void warn_sysctl_write(struct ctl_table *table) * handlers can ignore the return value. */ static bool proc_first_pos_non_zero_ignore(loff_t *ppos, - struct ctl_table *table) + const struct ctl_table *table) { if (!*ppos) return false; @@ -468,7 +468,7 @@ static int do_proc_douintvec_conv(unsigned long *lvalp, static const char proc_wspace_sep[] = { ' ', '\t', '\n' }; -static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table, +static int __do_proc_dointvec(void *tbl_data, const struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos, int (*conv)(bool *negp, unsigned long *lvalp, int *valp, @@ -541,7 +541,7 @@ out: return err; } -static int do_proc_dointvec(struct ctl_table *table, int write, +static int do_proc_dointvec(const struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos, int (*conv)(bool *negp, unsigned long *lvalp, int *valp, int write, void *data), @@ -552,7 +552,7 @@ static int do_proc_dointvec(struct ctl_table *table, int write, } static int do_proc_douintvec_w(unsigned int *tbl_data, - struct ctl_table *table, + const struct ctl_table *table, void *buffer, size_t *lenp, loff_t *ppos, int (*conv)(unsigned long *lvalp, @@ -639,7 +639,7 @@ out: return err; } -static int __do_proc_douintvec(void *tbl_data, struct ctl_table *table, +static int __do_proc_douintvec(void *tbl_data, const struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos, int (*conv)(unsigned long *lvalp, @@ -675,7 +675,7 @@ static int __do_proc_douintvec(void *tbl_data, struct ctl_table *table, return do_proc_douintvec_r(i, buffer, lenp, ppos, conv, data); } -int do_proc_douintvec(struct ctl_table *table, int write, +int do_proc_douintvec(const struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos, int (*conv)(unsigned long *lvalp, unsigned int *valp, @@ -1017,8 +1017,9 @@ static int sysrq_sysctl_handler(struct ctl_table *table, int write, } #endif -static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, - int write, void *buffer, size_t *lenp, loff_t *ppos, +static int __do_proc_doulongvec_minmax(void *data, + const struct ctl_table *table, int write, + void *buffer, size_t *lenp, loff_t *ppos, unsigned long convmul, unsigned long convdiv) { unsigned long *i, *min, *max; @@ -1090,7 +1091,7 @@ out: return err; } -static int do_proc_doulongvec_minmax(struct ctl_table *table, int write, +static int do_proc_doulongvec_minmax(const struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos, unsigned long convmul, unsigned long convdiv) { From c819e252c2874479b27f6a356b44f8aa73cf5a81 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Wed, 29 May 2024 14:25:41 -0700 Subject: [PATCH 05/13] sysctl: Add module description to sysctl-testing Added a module description to sysctl Kunit self test module to fix the 'make W=1' warning (" WARNING: modpost: missing MODULE_DESCRIPTION() in kernel/sysctl-test.o") Signed-off-by: Jeff Johnson Signed-off-by: Joel Granados --- kernel/sysctl-test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/sysctl-test.c b/kernel/sysctl-test.c index 4e7dcc9187e2..3ac98bb7fb82 100644 --- a/kernel/sysctl-test.c +++ b/kernel/sysctl-test.c @@ -437,4 +437,5 @@ static struct kunit_suite sysctl_test_suite = { kunit_test_suites(&sysctl_test_suite); +MODULE_DESCRIPTION("KUnit test of proc sysctl"); MODULE_LICENSE("GPL v2"); From 2f7c6248920523ca7468711891aa13f80ede8da4 Mon Sep 17 00:00:00 2001 From: Joel Granados Date: Tue, 4 Jun 2024 08:29:19 +0200 Subject: [PATCH 06/13] locking: Remove superfluous sentinel element from kern_lockdep_table This commit is part of a greater effort to remove all empty elements at the end of the ctl_table arrays (sentinels) which will reduce the overall build time size of the kernel and run time memory bloat by ~64 bytes per sentinel (further information Link : https://lore.kernel.org/all/ZO5Yx5JFogGi%2FcBo@bombadil.infradead.org/) Signed-off-by: Joel Granados --- kernel/locking/lockdep.c | 1 - 1 file changed, 1 deletion(-) diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index 151bd3de5936..726b22ce7d0b 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -97,7 +97,6 @@ static struct ctl_table kern_lockdep_table[] = { .proc_handler = proc_dointvec, }, #endif /* CONFIG_LOCK_STAT */ - { } }; static __init int kernel_lockdep_sysctls_init(void) From e2a6c472de7a5e5a1455a9fff1cfc55a1dd888af Mon Sep 17 00:00:00 2001 From: Joel Granados Date: Tue, 4 Jun 2024 08:29:20 +0200 Subject: [PATCH 07/13] mm profiling: Remove superfluous sentinel element from ctl_table This commit is part of a greater effort to remove all empty elements at the end of the ctl_table arrays (sentinels) which will reduce the overall build time size of the kernel and run time memory bloat by ~64 bytes per sentinel (further information Link : https://lore.kernel.org/all/ZO5Yx5JFogGi%2FcBo@bombadil.infradead.org/) Removed sentinel from memory_allocation_profiling_sysctls Signed-off-by: Joel Granados --- lib/alloc_tag.c | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/alloc_tag.c b/lib/alloc_tag.c index 11ed973ac359..7293cd54d1b1 100644 --- a/lib/alloc_tag.c +++ b/lib/alloc_tag.c @@ -238,7 +238,6 @@ static struct ctl_table memory_allocation_profiling_sysctls[] = { #endif .proc_handler = proc_do_static_key, }, - { } }; static int __init alloc_tag_init(void) From d7a76ec87195ced6910b0ca10ca133bb316c90f5 Mon Sep 17 00:00:00 2001 From: Joel Granados Date: Tue, 4 Jun 2024 08:29:21 +0200 Subject: [PATCH 08/13] sysctl: Remove check for sentinel element in ctl_table arrays Use ARRAY_SIZE exclusively by removing the check to ->procname in the stopping criteria of the loops traversing ctl_table arrays. This commit finalizes the removal of the sentinel elements at the end of ctl_table arrays which reduces the build time size and run time memory bloat by ~64 bytes per sentinel (further information Link : https://lore.kernel.org/all/ZO5Yx5JFogGi%2FcBo@bombadil.infradead.org/) Remove the entry->procname evaluation from the for loop stopping criteria in sysctl and sysctl_net. Signed-off-by: Joel Granados --- fs/proc/proc_sysctl.c | 2 +- net/sysctl_net.c | 11 ++--------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index c467e36741d0..832de1c64b5a 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -21,7 +21,7 @@ #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++) + for (size_t i = 0 ; i < header->ctl_table_size; ++i, entry++) static const struct dentry_operations proc_sys_dentry_operations; static const struct file_operations proc_sys_file_operations; diff --git a/net/sysctl_net.c b/net/sysctl_net.c index f5017012a049..19e8048241ba 100644 --- a/net/sysctl_net.c +++ b/net/sysctl_net.c @@ -127,7 +127,7 @@ static void ensure_safe_net_sysctl(struct net *net, const char *path, pr_debug("Registering net sysctl (net %p): %s\n", net, path); ent = table; - for (size_t i = 0; i < table_size && ent->procname; ent++, i++) { + for (size_t i = 0; i < table_size; ent++, i++) { unsigned long addr; const char *where; @@ -165,17 +165,10 @@ struct ctl_table_header *register_net_sysctl_sz(struct net *net, struct ctl_table *table, size_t table_size) { - int count; - struct ctl_table *entry; - if (!net_eq(net, &init_net)) ensure_safe_net_sysctl(net, path, table, table_size); - entry = table; - for (count = 0 ; count < table_size && entry->procname; entry++, count++) - ; - - return __register_sysctl_table(&net->sysctls, path, table, count); + return __register_sysctl_table(&net->sysctls, path, table, table_size); } EXPORT_SYMBOL_GPL(register_net_sysctl_sz); From 55bb7eb62db4995cec7e309c2b9a1070cfd60eb6 Mon Sep 17 00:00:00 2001 From: Joel Granados Date: Tue, 4 Jun 2024 08:29:22 +0200 Subject: [PATCH 09/13] sysctl: Replace nr_entries with ctl_table_size in new_links The number of ctl_table entries (nr_entries) calculation was previously based on the ctl_table_size and the sentinel element. Since the sentinels have been removed, we remove the calculation and just use the ctl_table_size from the ctl_table_header. Signed-off-by: Joel Granados --- fs/proc/proc_sysctl.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 832de1c64b5a..dc95a7bde1b3 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -1166,18 +1166,16 @@ static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table_ struct ctl_table_header *links; struct ctl_node *node; char *link_name; - int nr_entries, name_bytes; + int name_bytes; name_bytes = 0; - nr_entries = 0; list_for_each_table_entry(entry, head) { - nr_entries++; name_bytes += strlen(entry->procname) + 1; } links = kzalloc(sizeof(struct ctl_table_header) + - sizeof(struct ctl_node)*nr_entries + - sizeof(struct ctl_table)*(nr_entries + 1) + + sizeof(struct ctl_node)*head->ctl_table_size + + sizeof(struct ctl_table)*(head->ctl_table_size + 1) + name_bytes, GFP_KERNEL); @@ -1185,8 +1183,8 @@ static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table_ return NULL; node = (struct ctl_node *)(links + 1); - link_table = (struct ctl_table *)(node + nr_entries); - link_name = (char *)&link_table[nr_entries + 1]; + link_table = (struct ctl_table *)(node + head->ctl_table_size); + link_name = (char *)&link_table[head->ctl_table_size + 1]; link = link_table; list_for_each_table_entry(entry, head) { @@ -1200,7 +1198,7 @@ static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table_ } init_header(links, dir->header.root, dir->header.set, node, link_table, head->ctl_table_size); - links->nreg = nr_entries; + links->nreg = head->ctl_table_size; return links; } From aef9d25e7f5631543a0276d0532151f2c61174d6 Mon Sep 17 00:00:00 2001 From: Joel Granados Date: Tue, 4 Jun 2024 08:29:23 +0200 Subject: [PATCH 10/13] sysctl: Remove superfluous empty allocations from sysctl internals Now that the sentinels have been removed from ctl_table arrays, there is no need to artificially append empty ctl_table elements at ctl_table registration. Remove superfluous empty allocation from new_dir and new_links. Signed-off-by: Joel Granados --- fs/proc/proc_sysctl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index dc95a7bde1b3..ee1c48f854a2 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -949,14 +949,14 @@ static struct ctl_dir *new_dir(struct ctl_table_set *set, char *new_name; new = kzalloc(sizeof(*new) + sizeof(struct ctl_node) + - sizeof(struct ctl_table)*2 + namelen + 1, + sizeof(struct ctl_table) + namelen + 1, GFP_KERNEL); if (!new) return NULL; node = (struct ctl_node *)(new + 1); table = (struct ctl_table *)(node + 1); - new_name = (char *)(table + 2); + new_name = (char *)(table + 1); memcpy(new_name, name, namelen); table[0].procname = new_name; table[0].mode = S_IFDIR|S_IRUGO|S_IXUGO; @@ -1175,7 +1175,7 @@ static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table_ links = kzalloc(sizeof(struct ctl_table_header) + sizeof(struct ctl_node)*head->ctl_table_size + - sizeof(struct ctl_table)*(head->ctl_table_size + 1) + + sizeof(struct ctl_table)*head->ctl_table_size + name_bytes, GFP_KERNEL); @@ -1184,7 +1184,7 @@ static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table_ node = (struct ctl_node *)(links + 1); link_table = (struct ctl_table *)(node + head->ctl_table_size); - link_name = (char *)&link_table[head->ctl_table_size + 1]; + link_name = (char *)(link_table + head->ctl_table_size); link = link_table; list_for_each_table_entry(entry, head) { From a02fe70de4c2a7fbd971b49c5fa69f867fac16ff Mon Sep 17 00:00:00 2001 From: Joel Granados Date: Tue, 4 Jun 2024 08:29:24 +0200 Subject: [PATCH 11/13] sysctl: Remove "child" sysctl code comments Erase the code comments mentioning "child" that were forgotten when the child element was removed in commit 2f2665c13af48 ("sysctl: replace child with an enumeration"). Signed-off-by: Joel Granados --- fs/proc/proc_sysctl.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index ee1c48f854a2..985c1774a552 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -1310,28 +1310,23 @@ static struct ctl_dir *sysctl_mkdir_p(struct ctl_dir *dir, const char *path) * __register_sysctl_table - register a leaf sysctl table * @set: Sysctl tree to register on * @path: The path to the directory the sysctl table is in. - * @table: the top-level table structure without any child. This table - * 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: the top-level table structure. This table 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. * * The members of the &struct ctl_table structure are used as follows: - * * procname - the name of the sysctl file under /proc/sys. Set to %NULL to not * enter a sysctl file - * - * data - a pointer to data for use by proc_handler - * - * maxlen - the maximum size in bytes of the data - * - * mode - the file permissions for the /proc/sys file - * - * child - must be %NULL. - * + * data - a pointer to data for use by proc_handler + * maxlen - the maximum size in bytes of the data + * mode - the file permissions for the /proc/sys file + * type - Defines the target type (described in struct definition) * proc_handler - the text handler routine (described below) * * extra1, extra2 - extra pointers usable by the proc handler routines @@ -1339,8 +1334,7 @@ static struct ctl_dir *sysctl_mkdir_p(struct ctl_dir *dir, const char *path) * [0] https://lkml.kernel.org/87zgpte9o4.fsf@email.froward.int.ebiederm.org * * Leaf nodes in the sysctl tree will be represented by a single file - * under /proc; non-leaf nodes (where child is not NULL) are not allowed, - * sysctl_check_table() verifies this. + * under /proc; non-leaf nodes are not allowed. * * There must be a proc_handler routine for any terminal nodes. * Several default handlers are available to cover common cases - From 3717540377c500e28f4304b17a46dd5b025a61ac Mon Sep 17 00:00:00 2001 From: Joel Granados Date: Tue, 4 Jun 2024 08:29:25 +0200 Subject: [PATCH 12/13] sysctl: Remove ctl_table sentinel code comments Remove the mention of a "zero terminated entry" from the __register_sysctl_table function doc. Signed-off-by: Joel Granados --- fs/proc/proc_sysctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 985c1774a552..87396f9d599d 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -1318,7 +1318,7 @@ static struct ctl_dir *sysctl_mkdir_p(struct ctl_dir *dir, const char *path) * @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. + * array. * * The members of the &struct ctl_table structure are used as follows: * procname - the name of the sysctl file under /proc/sys. Set to %NULL to not From acc154691fc75e1a178fc36624bdeee1420585a4 Mon Sep 17 00:00:00 2001 From: Joel Granados Date: Tue, 4 Jun 2024 08:29:26 +0200 Subject: [PATCH 13/13] sysctl: Warn on an empty procname element Add a pr_err warning in case a ctl_table is registered with a sentinel element containing a NULL procname. Signed-off-by: Joel Granados --- fs/proc/proc_sysctl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 87396f9d599d..9553e77c9d31 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -1131,6 +1131,8 @@ 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) { + if (!entry->procname) + err |= sysctl_err(path, entry, "procname is null"); if ((entry->proc_handler == proc_dostring) || (entry->proc_handler == proc_dobool) || (entry->proc_handler == proc_dointvec) ||