sysctl changes for 6.11-rc1
Summary * 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. Testing * This got push to linux-next in v6.10-rc2, so it has had more than a month of testing -----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEErkcJVyXmMSXOyyeQupfNUreWQU8FAmaWdz4ACgkQupfNUreW QU/WKQwAkSuUz42yCQye77BK+Z8ANcTF1f3aI/wfv2nahq1GaSrNBpqUiXvEe9Tt KD2lM1PWiQfizVLIDPh96yxa5q69GQrPPOA/V1jwIXmk/HRpjjoONCFNNXVRCTls VCqDz/RatuXvzO35Yn87MnWnxv6PiX7X/zq/3WikVsUI381kvTgC6OwZxdFM52w4 ESwOa3LeOovtRnqV5dpHr6DCQKyd0N52nPxgXvaerjlsJsv7PlezN7z9YyLOOfmW xUD7X6LQcJq7HcEukaB6I9o2GQOi4yYXL2YOzed7qu9Thu+lasEoN3Bd7P+ilXkc JY6EXJ5o+d69PewKRuJ1QvD7wrHIkhNMNbMtvehNay124wAHDy3KtonFzyvlX4wE qCHBYc6rySJNhSqwVp9MoksOZfDM99pVIOs9YVIjc90Zzu5J7tORgYWRVOHTcAtj fd8nMdkK3+ZANapygFCyew6GueIzaqlQwveVgLGw4vc5L3ClknmURit3y487Pzdg B+BEVlsp =bs2G -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
f8a8b94d06
@ -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;
|
||||
@ -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;
|
||||
}
|
||||
@ -951,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;
|
||||
@ -1093,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) ||
|
||||
@ -1104,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) {
|
||||
@ -1119,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) ||
|
||||
@ -1154,18 +1168,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 +
|
||||
name_bytes,
|
||||
GFP_KERNEL);
|
||||
|
||||
@ -1173,8 +1185,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);
|
||||
link = link_table;
|
||||
|
||||
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_
|
||||
}
|
||||
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;
|
||||
}
|
||||
@ -1300,28 +1312,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.
|
||||
* 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
|
||||
* 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
|
||||
@ -1329,8 +1336,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 -
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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),
|
||||
{}
|
||||
};
|
||||
|
||||
@ -388,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");
|
||||
|
@ -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,
|
||||
@ -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;
|
||||
|
||||
@ -1023,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;
|
||||
@ -1096,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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -239,7 +239,6 @@ static struct ctl_table memory_allocation_profiling_sysctls[] = {
|
||||
#endif
|
||||
.proc_handler = proc_do_static_key,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
static void __init sysctl_init(void)
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user