Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit f8a8b94

Browse files
committed
Merge tag 'sysctl-6.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/sysctl/sysctl
Pull sysctl updates from Joel Granados: - Remove "->procname == NULL" check when iterating through sysctl table arrays Removing sentinels in ctl_table arrays reduces the build time size and runtime memory consumed by ~64 bytes per array. With all ctl_table sentinels gone, the additional check for ->procname == NULL that worked in tandem with the ARRAY_SIZE to calculate the size of the ctl_table arrays is no longer needed and has been removed. The sysctl register functions now returns an error if a sentinel is used. - Preparation patches for sysctl constification Constifying ctl_table structs prevents the modification of proc_handler function pointers as they would reside in .rodata. The ctl_table arguments in sysctl utility functions are const qualified in preparation for a future treewide proc_handler argument constification commit. - Misc fixes Increase robustness of set_ownership by providing sane default ownership values in case the callee doesn't set them. Bound check proc_dou8vec_minmax to avoid loading buggy modules and give sysctl testing module a name to avoid compiler complaints. * tag 'sysctl-6.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/sysctl/sysctl: sysctl: Warn on an empty procname element sysctl: Remove ctl_table sentinel code comments sysctl: Remove "child" sysctl code comments sysctl: Remove superfluous empty allocations from sysctl internals sysctl: Replace nr_entries with ctl_table_size in new_links sysctl: Remove check for sentinel element in ctl_table arrays mm profiling: Remove superfluous sentinel element from ctl_table locking: Remove superfluous sentinel element from kern_lockdep_table sysctl: Add module description to sysctl-testing sysctl: constify ctl_table arguments of utility function utsname: constify ctl_table arguments of utility function sysctl: move the extra1/2 boundary check of u8 to sysctl_check_table_array sysctl: always initialize i_uid/i_gid
2 parents ce5a51b + acc1546 commit f8a8b94

File tree

8 files changed

+105
-63
lines changed

8 files changed

+105
-63
lines changed

fs/proc/proc_sysctl.c

Lines changed: 38 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
#define list_for_each_table_entry(entry, header) \
2323
entry = header->ctl_table; \
24-
for (size_t i = 0 ; i < header->ctl_table_size && entry->procname; ++i, entry++)
24+
for (size_t i = 0 ; i < header->ctl_table_size; ++i, entry++)
2525

2626
static const struct dentry_operations proc_sys_dentry_operations;
2727
static const struct file_operations proc_sys_file_operations;
@@ -476,12 +476,10 @@ static struct inode *proc_sys_make_inode(struct super_block *sb,
476476
make_empty_dir_inode(inode);
477477
}
478478

479+
inode->i_uid = GLOBAL_ROOT_UID;
480+
inode->i_gid = GLOBAL_ROOT_GID;
479481
if (root->set_ownership)
480482
root->set_ownership(head, &inode->i_uid, &inode->i_gid);
481-
else {
482-
inode->i_uid = GLOBAL_ROOT_UID;
483-
inode->i_gid = GLOBAL_ROOT_GID;
484-
}
485483

486484
return inode;
487485
}
@@ -951,14 +949,14 @@ static struct ctl_dir *new_dir(struct ctl_table_set *set,
951949
char *new_name;
952950

953951
new = kzalloc(sizeof(*new) + sizeof(struct ctl_node) +
954-
sizeof(struct ctl_table)*2 + namelen + 1,
952+
sizeof(struct ctl_table) + namelen + 1,
955953
GFP_KERNEL);
956954
if (!new)
957955
return NULL;
958956

959957
node = (struct ctl_node *)(new + 1);
960958
table = (struct ctl_table *)(node + 1);
961-
new_name = (char *)(table + 2);
959+
new_name = (char *)(table + 1);
962960
memcpy(new_name, name, namelen);
963961
table[0].procname = new_name;
964962
table[0].mode = S_IFDIR|S_IRUGO|S_IXUGO;
@@ -1093,6 +1091,7 @@ static int sysctl_err(const char *path, struct ctl_table *table, char *fmt, ...)
10931091

10941092
static int sysctl_check_table_array(const char *path, struct ctl_table *table)
10951093
{
1094+
unsigned int extra;
10961095
int err = 0;
10971096

10981097
if ((table->proc_handler == proc_douintvec) ||
@@ -1104,6 +1103,19 @@ static int sysctl_check_table_array(const char *path, struct ctl_table *table)
11041103
if (table->proc_handler == proc_dou8vec_minmax) {
11051104
if (table->maxlen != sizeof(u8))
11061105
err |= sysctl_err(path, table, "array not allowed");
1106+
1107+
if (table->extra1) {
1108+
extra = *(unsigned int *) table->extra1;
1109+
if (extra > 255U)
1110+
err |= sysctl_err(path, table,
1111+
"range value too large for proc_dou8vec_minmax");
1112+
}
1113+
if (table->extra2) {
1114+
extra = *(unsigned int *) table->extra2;
1115+
if (extra > 255U)
1116+
err |= sysctl_err(path, table,
1117+
"range value too large for proc_dou8vec_minmax");
1118+
}
11071119
}
11081120

11091121
if (table->proc_handler == proc_dobool) {
@@ -1119,6 +1131,8 @@ static int sysctl_check_table(const char *path, struct ctl_table_header *header)
11191131
struct ctl_table *entry;
11201132
int err = 0;
11211133
list_for_each_table_entry(entry, header) {
1134+
if (!entry->procname)
1135+
err |= sysctl_err(path, entry, "procname is null");
11221136
if ((entry->proc_handler == proc_dostring) ||
11231137
(entry->proc_handler == proc_dobool) ||
11241138
(entry->proc_handler == proc_dointvec) ||
@@ -1154,27 +1168,25 @@ static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table_
11541168
struct ctl_table_header *links;
11551169
struct ctl_node *node;
11561170
char *link_name;
1157-
int nr_entries, name_bytes;
1171+
int name_bytes;
11581172

11591173
name_bytes = 0;
1160-
nr_entries = 0;
11611174
list_for_each_table_entry(entry, head) {
1162-
nr_entries++;
11631175
name_bytes += strlen(entry->procname) + 1;
11641176
}
11651177

11661178
links = kzalloc(sizeof(struct ctl_table_header) +
1167-
sizeof(struct ctl_node)*nr_entries +
1168-
sizeof(struct ctl_table)*(nr_entries + 1) +
1179+
sizeof(struct ctl_node)*head->ctl_table_size +
1180+
sizeof(struct ctl_table)*head->ctl_table_size +
11691181
name_bytes,
11701182
GFP_KERNEL);
11711183

11721184
if (!links)
11731185
return NULL;
11741186

11751187
node = (struct ctl_node *)(links + 1);
1176-
link_table = (struct ctl_table *)(node + nr_entries);
1177-
link_name = (char *)&link_table[nr_entries + 1];
1188+
link_table = (struct ctl_table *)(node + head->ctl_table_size);
1189+
link_name = (char *)(link_table + head->ctl_table_size);
11781190
link = link_table;
11791191

11801192
list_for_each_table_entry(entry, head) {
@@ -1188,7 +1200,7 @@ static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table_
11881200
}
11891201
init_header(links, dir->header.root, dir->header.set, node, link_table,
11901202
head->ctl_table_size);
1191-
links->nreg = nr_entries;
1203+
links->nreg = head->ctl_table_size;
11921204

11931205
return links;
11941206
}
@@ -1300,37 +1312,31 @@ static struct ctl_dir *sysctl_mkdir_p(struct ctl_dir *dir, const char *path)
13001312
* __register_sysctl_table - register a leaf sysctl table
13011313
* @set: Sysctl tree to register on
13021314
* @path: The path to the directory the sysctl table is in.
1303-
* @table: the top-level table structure without any child. This table
1304-
* should not be free'd after registration. So it should not be
1305-
* used on stack. It can either be a global or dynamically allocated
1306-
* by the caller and free'd later after sysctl unregistration.
1315+
*
1316+
* @table: the top-level table structure. This table should not be free'd
1317+
* after registration. So it should not be used on stack. It can either
1318+
* be a global or dynamically allocated by the caller and free'd later
1319+
* after sysctl unregistration.
13071320
* @table_size : The number of elements in table
13081321
*
13091322
* Register a sysctl table hierarchy. @table should be a filled in ctl_table
1310-
* array. A completely 0 filled entry terminates the table.
1323+
* array.
13111324
*
13121325
* The members of the &struct ctl_table structure are used as follows:
1313-
*
13141326
* procname - the name of the sysctl file under /proc/sys. Set to %NULL to not
13151327
* enter a sysctl file
1316-
*
1317-
* data - a pointer to data for use by proc_handler
1318-
*
1319-
* maxlen - the maximum size in bytes of the data
1320-
*
1321-
* mode - the file permissions for the /proc/sys file
1322-
*
1323-
* child - must be %NULL.
1324-
*
1328+
* data - a pointer to data for use by proc_handler
1329+
* maxlen - the maximum size in bytes of the data
1330+
* mode - the file permissions for the /proc/sys file
1331+
* type - Defines the target type (described in struct definition)
13251332
* proc_handler - the text handler routine (described below)
13261333
*
13271334
* extra1, extra2 - extra pointers usable by the proc handler routines
13281335
* XXX: we should eventually modify these to use long min / max [0]
13291336
* [0] https://lkml.kernel.org/87zgpte9o4.fsf@email.froward.int.ebiederm.org
13301337
*
13311338
* Leaf nodes in the sysctl tree will be represented by a single file
1332-
* under /proc; non-leaf nodes (where child is not NULL) are not allowed,
1333-
* sysctl_check_table() verifies this.
1339+
* under /proc; non-leaf nodes are not allowed.
13341340
*
13351341
* There must be a proc_handler routine for any terminal nodes.
13361342
* Several default handlers are available to cover common cases -

include/linux/sysctl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ extern struct ctl_table_header *register_sysctl_mount_point(const char *path);
237237

238238
void do_sysctl_args(void);
239239
bool sysctl_is_alias(char *param);
240-
int do_proc_douintvec(struct ctl_table *table, int write,
240+
int do_proc_douintvec(const struct ctl_table *table, int write,
241241
void *buffer, size_t *lenp, loff_t *ppos,
242242
int (*conv)(unsigned long *lvalp,
243243
unsigned int *valp,

kernel/locking/lockdep.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,6 @@ static struct ctl_table kern_lockdep_table[] = {
9797
.proc_handler = proc_dointvec,
9898
},
9999
#endif /* CONFIG_LOCK_STAT */
100-
{ }
101100
};
102101

103102
static __init int kernel_lockdep_sysctls_init(void)

kernel/sysctl-test.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,54 @@ static void sysctl_test_api_dointvec_write_single_greater_int_max(
367367
KUNIT_EXPECT_EQ(test, 0, *((int *)table.data));
368368
}
369369

370+
/*
371+
* Test that registering an invalid extra value is not allowed.
372+
*/
373+
static void sysctl_test_register_sysctl_sz_invalid_extra_value(
374+
struct kunit *test)
375+
{
376+
unsigned char data = 0;
377+
struct ctl_table table_foo[] = {
378+
{
379+
.procname = "foo",
380+
.data = &data,
381+
.maxlen = sizeof(u8),
382+
.mode = 0644,
383+
.proc_handler = proc_dou8vec_minmax,
384+
.extra1 = SYSCTL_FOUR,
385+
.extra2 = SYSCTL_ONE_THOUSAND,
386+
},
387+
};
388+
389+
struct ctl_table table_bar[] = {
390+
{
391+
.procname = "bar",
392+
.data = &data,
393+
.maxlen = sizeof(u8),
394+
.mode = 0644,
395+
.proc_handler = proc_dou8vec_minmax,
396+
.extra1 = SYSCTL_NEG_ONE,
397+
.extra2 = SYSCTL_ONE_HUNDRED,
398+
},
399+
};
400+
401+
struct ctl_table table_qux[] = {
402+
{
403+
.procname = "qux",
404+
.data = &data,
405+
.maxlen = sizeof(u8),
406+
.mode = 0644,
407+
.proc_handler = proc_dou8vec_minmax,
408+
.extra1 = SYSCTL_ZERO,
409+
.extra2 = SYSCTL_TWO_HUNDRED,
410+
},
411+
};
412+
413+
KUNIT_EXPECT_NULL(test, register_sysctl("foo", table_foo));
414+
KUNIT_EXPECT_NULL(test, register_sysctl("foo", table_bar));
415+
KUNIT_EXPECT_NOT_NULL(test, register_sysctl("foo", table_qux));
416+
}
417+
370418
static struct kunit_case sysctl_test_cases[] = {
371419
KUNIT_CASE(sysctl_test_api_dointvec_null_tbl_data),
372420
KUNIT_CASE(sysctl_test_api_dointvec_table_maxlen_unset),
@@ -378,6 +426,7 @@ static struct kunit_case sysctl_test_cases[] = {
378426
KUNIT_CASE(sysctl_test_dointvec_write_happy_single_negative),
379427
KUNIT_CASE(sysctl_test_api_dointvec_write_single_less_int_min),
380428
KUNIT_CASE(sysctl_test_api_dointvec_write_single_greater_int_max),
429+
KUNIT_CASE(sysctl_test_register_sysctl_sz_invalid_extra_value),
381430
{}
382431
};
383432

@@ -388,4 +437,5 @@ static struct kunit_suite sysctl_test_suite = {
388437

389438
kunit_test_suites(&sysctl_test_suite);
390439

440+
MODULE_DESCRIPTION("KUnit test of proc sysctl");
391441
MODULE_LICENSE("GPL v2");

kernel/sysctl.c

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ static int _proc_do_string(char *data, int maxlen, int write,
205205
return 0;
206206
}
207207

208-
static void warn_sysctl_write(struct ctl_table *table)
208+
static void warn_sysctl_write(const struct ctl_table *table)
209209
{
210210
pr_warn_once("%s wrote to %s when file position was not 0!\n"
211211
"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)
223223
* handlers can ignore the return value.
224224
*/
225225
static bool proc_first_pos_non_zero_ignore(loff_t *ppos,
226-
struct ctl_table *table)
226+
const struct ctl_table *table)
227227
{
228228
if (!*ppos)
229229
return false;
@@ -468,7 +468,7 @@ static int do_proc_douintvec_conv(unsigned long *lvalp,
468468

469469
static const char proc_wspace_sep[] = { ' ', '\t', '\n' };
470470

471-
static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
471+
static int __do_proc_dointvec(void *tbl_data, const struct ctl_table *table,
472472
int write, void *buffer,
473473
size_t *lenp, loff_t *ppos,
474474
int (*conv)(bool *negp, unsigned long *lvalp, int *valp,
@@ -541,7 +541,7 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
541541
return err;
542542
}
543543

544-
static int do_proc_dointvec(struct ctl_table *table, int write,
544+
static int do_proc_dointvec(const struct ctl_table *table, int write,
545545
void *buffer, size_t *lenp, loff_t *ppos,
546546
int (*conv)(bool *negp, unsigned long *lvalp, int *valp,
547547
int write, void *data),
@@ -552,7 +552,7 @@ static int do_proc_dointvec(struct ctl_table *table, int write,
552552
}
553553

554554
static int do_proc_douintvec_w(unsigned int *tbl_data,
555-
struct ctl_table *table,
555+
const struct ctl_table *table,
556556
void *buffer,
557557
size_t *lenp, loff_t *ppos,
558558
int (*conv)(unsigned long *lvalp,
@@ -639,7 +639,7 @@ static int do_proc_douintvec_r(unsigned int *tbl_data, void *buffer,
639639
return err;
640640
}
641641

642-
static int __do_proc_douintvec(void *tbl_data, struct ctl_table *table,
642+
static int __do_proc_douintvec(void *tbl_data, const struct ctl_table *table,
643643
int write, void *buffer,
644644
size_t *lenp, loff_t *ppos,
645645
int (*conv)(unsigned long *lvalp,
@@ -675,7 +675,7 @@ static int __do_proc_douintvec(void *tbl_data, struct ctl_table *table,
675675
return do_proc_douintvec_r(i, buffer, lenp, ppos, conv, data);
676676
}
677677

678-
int do_proc_douintvec(struct ctl_table *table, int write,
678+
int do_proc_douintvec(const struct ctl_table *table, int write,
679679
void *buffer, size_t *lenp, loff_t *ppos,
680680
int (*conv)(unsigned long *lvalp,
681681
unsigned int *valp,
@@ -977,16 +977,10 @@ int proc_dou8vec_minmax(struct ctl_table *table, int write,
977977
if (table->maxlen != sizeof(u8))
978978
return -EINVAL;
979979

980-
if (table->extra1) {
980+
if (table->extra1)
981981
min = *(unsigned int *) table->extra1;
982-
if (min > 255U)
983-
return -EINVAL;
984-
}
985-
if (table->extra2) {
982+
if (table->extra2)
986983
max = *(unsigned int *) table->extra2;
987-
if (max > 255U)
988-
return -EINVAL;
989-
}
990984

991985
tmp = *table;
992986

@@ -1023,8 +1017,9 @@ static int sysrq_sysctl_handler(struct ctl_table *table, int write,
10231017
}
10241018
#endif
10251019

1026-
static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table,
1027-
int write, void *buffer, size_t *lenp, loff_t *ppos,
1020+
static int __do_proc_doulongvec_minmax(void *data,
1021+
const struct ctl_table *table, int write,
1022+
void *buffer, size_t *lenp, loff_t *ppos,
10281023
unsigned long convmul, unsigned long convdiv)
10291024
{
10301025
unsigned long *i, *min, *max;
@@ -1096,7 +1091,7 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table,
10961091
return err;
10971092
}
10981093

1099-
static int do_proc_doulongvec_minmax(struct ctl_table *table, int write,
1094+
static int do_proc_doulongvec_minmax(const struct ctl_table *table, int write,
11001095
void *buffer, size_t *lenp, loff_t *ppos, unsigned long convmul,
11011096
unsigned long convdiv)
11021097
{

kernel/utsname_sysctl.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
#ifdef CONFIG_PROC_SYSCTL
1717

18-
static void *get_uts(struct ctl_table *table)
18+
static void *get_uts(const struct ctl_table *table)
1919
{
2020
char *which = table->data;
2121
struct uts_namespace *uts_ns;

lib/alloc_tag.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,6 @@ static struct ctl_table memory_allocation_profiling_sysctls[] = {
239239
#endif
240240
.proc_handler = proc_do_static_key,
241241
},
242-
{ }
243242
};
244243

245244
static void __init sysctl_init(void)

0 commit comments

Comments
 (0)