sysctl: add proper unsigned int support
Subsystems (4)
PATCH 1/1 sysctl: add proper unsigned int support
Commit e7d316a02f6838 ("sysctl: handle error writing UINT_MAX to u32 fields") added proc_douintvec() to start help adding support for unsigned int, this however was only half the work needed, all these issues are present with the current implementation:
o Printing the values shows a negative value, this happens since do_proc_dointvec() and this uses proc_put_long()
o We can easily wrap around the int values: UINT_MAX is
4294967295, if we echo in 4294967295 + 1 we end up with 0,
using 4294967295 + 2 we end up with 1.o We echo negative values in and they are accepted
Fix all these issues by adding our own do_proc_douintvec().
---
I split this off as its own atomic fix from a larger RFC series [0]. I've only provided the fix here, and split off further functionality into a separate patch for the future. Although this is a fix I don't think its super critical, and specially due to its size do not think it can be stable material.
I do have proc_douintvec_minmax() but since we have no users for it it can wait until I add something that makes use of it. If someone needs it now though please let me know.
Likewise adding proc_douintvec_minmax_sysadmin() is very trivial but I have no immediate users for it so it can wait even longer.
[0] https://lkml.kernel.org/r/[email protected]
kernel/sysctl.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 115 insertions(+), 6 deletions(-)
kernel/sysctl.c +115 -6
@@ -2125,12 +2125,12 @@ static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp,return 0 ; } -static int do_proc_douintvec_conv (bool *negp,unsigned long *lvalp, -int *valp, -int write,void *data) +static int do_proc_douintvec_conv (unsigned long *lvalp, +unsigned int *valp, +int write,void *data) {if (write) { -if (*negp) +if (*lvalp > (unsigned long )UINT_MAX )return -EINVAL ; *valp = *lvalp; }else {
@@ -2243,6 +2243,115 @@ static int do_proc_dointvec(struct ctl_table *table, int write, buffer, lenp, ppos, conv, data); } +static int __do_proc_douintvec (void *tbl_data,struct ctl_table *table, +int write,void __user *buffer, +size_t *lenp,loff_t *ppos, +int (*conv)(unsigned long *lvalp, +unsigned int *valp, +int write,void *data), +void *data) +{ +unsigned int *i, vleft; +bool first = true; +int err =0 ; +size_t left; +char *kbuf =NULL , *p; + +if (!tbl_data || !table->maxlen || !*lenp || (*ppos && !write)) { + *lenp =0 ; +return 0 ; + } + + i = (unsigned int *) tbl_data; + vleft = table->maxlen /sizeof (*i); + left = *lenp; + +if (!conv) + conv = do_proc_douintvec_conv; + +if (write) { +if (*ppos) { +switch (sysctl_writes_strict) { +case SYSCTL_WRITES_STRICT : + goto out; +case SYSCTL_WRITES_WARN : +warn_sysctl_write (table); +break ; +default : +break ; + } + } + +if (left >PAGE_SIZE -1 ) + left =PAGE_SIZE -1 ; + p = kbuf =memdup_user_nul (buffer, left); +if (IS_ERR (kbuf)) +return PTR_ERR (kbuf); + } + +for (; left && vleft--; i++, first=false) { +unsigned long lval; +bool neg; + +if (write) { + left -=proc_skip_spaces (&p); + +if (!left) +break ; + err =proc_get_long (&p, &left, &lval, &neg, + proc_wspace_sep, +sizeof (proc_wspace_sep),NULL ); +if (neg) { + err = -EINVAL ; +break ; + } +if (err) +break ; +if (conv (&lval, i,1 , data)) { + err = -EINVAL ; +break ; + } + }else { +if (conv (&lval, i,0 , data)) { + err = -EINVAL ; +break ; + } +if (!first) + err =proc_put_char (&buffer, &left,'\t' ); +if (err) +break ; + err =proc_put_long (&buffer, &left, lval, false); +if (err) +break ; + } + } + +if (!write && !first && left && !err) + err =proc_put_char (&buffer, &left,'\n' ); +if (write && !err && left) + left -=proc_skip_spaces (&p); +if (write) { +kfree (kbuf); +if (first) +return err ? : -EINVAL ; + } + *lenp -= left; +out: + *ppos += *lenp; +return err; +} + +static int do_proc_douintvec (struct ctl_table *table,int write, +void __user *buffer,size_t *lenp,loff_t *ppos, +int (*conv)(unsigned long *lvalp, +unsigned int *valp, +int write,void *data), +void *data) +{ +return __do_proc_douintvec (table->data, table, write, + buffer, lenp, ppos, conv, data); +} +/** * proc_dointvec - read a vector of integers * @table: the sysctl table
@@ -2278,8 +2387,8 @@ int proc_dointvec(struct ctl_table *table, int write,int proc_douintvec (struct ctl_table *table,int write,void __user *buffer,size_t *lenp,loff_t *ppos) { -return do_proc_dointvec (table, write, buffer, lenp, ppos, - do_proc_douintvec_conv,NULL ); +return do_proc_douintvec (table, write, buffer, lenp, ppos, + do_proc_douintvec_conv,NULL ); }/*
Signature · 1 line
2.11.0
Quoted 52 lines · Luis R. Rodriguez
Commit
e7d316a02f6838("sysctl: handle error writingUINT_MAXto u32 fields") addedproc_douintvec()to start help adding support for unsigned int, this however was only half the work needed, all these issues are present with the current implementation:o Printing the values shows a negative value, this happens since
do_proc_dointvec()and this usesproc_put_long()
o We can easily wrap around the int values:UINT_MAXis4294967295, if we echo in 4294967295 + 1 we end up with 0, using 4294967295 + 2 we end up with 1.o We echo negative values in and they are accepted
Fix all these issues by adding our own
do_proc_douintvec().Cc Subash Abhinov Kasiviswanathan <[email protected]>Cc Heinrich Schuchardt <[email protected]>Cc Kees Cook <[email protected]>Cc "David S. Miller" <[email protected]>Cc Ingo Molnar <[email protected]>Cc Andrew Morton <[email protected]>Cc Linus Torvalds <[email protected]>Cc Greg Kroah-Hartman <[email protected]>Fixes e7d316a02f68 ("sysctl: handle error writing UINT_MAX to u32 fields")Signed-off-by Luis R. Rodriguez <[email protected]>---
I split this off as its own atomic fix from a larger RFC series [0]. I've only provided the fix here, and split off further functionality into a separate patch for the future. Although this is a fix I don't think its super critical, and specially due to its size do not think it can be stable material.
I do have
proc_douintvec_minmax()but since we have no users for it it can wait until I add something that makes use of it. If someone needs it now though please let me know.Likewise adding
proc_douintvec_minmax_sysadmin()is very trivial but I have no immediate users for it so it can wait even longer.[0] https://lkml.kernel.org/r/[email protected]
kernel/sysctl.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 115 insertions(+), 6 deletions(-)kernel/sysctl.c +0
-0@@ -2125,12 +2125,12 @@ static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp,return 0 ; }
kernel/sysctl.c static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp, · line 2133
Quoted 10 lines
kernel/sysctl.c +4
-4-static int do_proc_douintvec_conv (bool *negp,unsigned long *lvalp, -int *valp, -int write,void *data) +static int do_proc_douintvec_conv (unsigned long *lvalp, +unsigned int *valp, +int write,void *data) {if (write) { -if (*negp) +if (*lvalp > (unsigned long )UINT_MAX )
Cast is unnecessary here.
kernel/sysctl.c static int do_proc_dointvec(struct ctl_table *table, int write, · line 2292
Quoted 3 lines
kernel/sysctl.c +2
-0+static int __do_proc_douintvec (void *tbl_data,struct ctl_table *table, + for (; left && vleft--; i++, first=false) {
I'd suggest to not implement "array of unsigned int" unless such sysctl already exists. Much of the complexity arises from this case.
Quoted 53 lines · Alexey Dobriyan
Quoted 52 lines · Luis R. Rodriguez
Commit
e7d316a02f6838("sysctl: handle error writingUINT_MAXto u32 fields") addedproc_douintvec()to start help adding support for unsigned int, this however was only half the work needed, all these issues are present with the current implementation:o Printing the values shows a negative value, this happens since
do_proc_dointvec()and this usesproc_put_long()
o We can easily wrap around the int values:UINT_MAXis4294967295, if we echo in 4294967295 + 1 we end up with 0, using 4294967295 + 2 we end up with 1.o We echo negative values in and they are accepted
Fix all these issues by adding our own
do_proc_douintvec().Cc Subash Abhinov Kasiviswanathan <[email protected]>Cc Heinrich Schuchardt <[email protected]>Cc Kees Cook <[email protected]>Cc "David S. Miller" <[email protected]>Cc Ingo Molnar <[email protected]>Cc Andrew Morton <[email protected]>Cc Linus Torvalds <[email protected]>Cc Greg Kroah-Hartman <[email protected]>Fixes e7d316a02f68 ("sysctl: handle error writing UINT_MAX to u32 fields")Signed-off-by Luis R. Rodriguez <[email protected]>---
I split this off as its own atomic fix from a larger RFC series [0]. I've only provided the fix here, and split off further functionality into a separate patch for the future. Although this is a fix I don't think its super critical, and specially due to its size do not think it can be stable material.
I do have
proc_douintvec_minmax()but since we have no users for it it can wait until I add something that makes use of it. If someone needs it now though please let me know.Likewise adding
proc_douintvec_minmax_sysadmin()is very trivial but I have no immediate users for it so it can wait even longer.[0] https://lkml.kernel.org/r/[email protected]
kernel/sysctl.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 115 insertions(+), 6 deletions(-)kernel/sysctl.c +0
-0@@ -2125,12 +2125,12 @@ static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp,return 0 ; }
Quoted 12 lines
kernel/sysctl.c static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp, · line 2133
Quoted 10 lines
kernel/sysctl.c +4
-4-static int do_proc_douintvec_conv (bool *negp,unsigned long *lvalp, -int *valp, -int write,void *data) +static int do_proc_douintvec_conv (unsigned long *lvalp, +unsigned int *valp, +int write,void *data) {if (write) { -if (*negp) +if (*lvalp > (unsigned long )UINT_MAX )Cast is unnecessary here.
Fixed, thanks!
Quoted 6 lines
kernel/sysctl.c static int do_proc_dointvec(struct ctl_table *table, int write, · line 2292
Quoted 3 lines
kernel/sysctl.c +2
-0+static int __do_proc_douintvec (void *tbl_data,struct ctl_table *table, + for (; left && vleft--; i++, first=false) {I'd suggest to not implement "array of unsigned int" unless such sysctl already exists. Much of the complexity arises from this case.
Uh, yeah that is such crap.
As much as I'd like to I'm afraid the problem with this is there may be array int setups which should / could be ported to unsigned int. I tried to do a grammatical search with Coccinelle but ran into issues, I'll follow up with Julia about that. A manual search however reveals one so far:
ipv4_local_port_range(). There may be others. So, do we deal with the old cases by leaving them as-is or provide a new separate interface? I take it the array stuff is long tested, so don't the harm in providing similar functionality for unsigned int. I'm perfectly happy in just ripping out unsigned int array support though. Who makes this call ?
Luis
Quoted 69 lines · Luis R. Rodriguez
Quoted 53 lines · Alexey Dobriyan
Quoted 52 lines · Luis R. Rodriguez
Commit
e7d316a02f6838("sysctl: handle error writingUINT_MAXto u32 fields") addedproc_douintvec()to start help adding support for unsigned int, this however was only half the work needed, all these issues are present with the current implementation:o Printing the values shows a negative value, this happens since
do_proc_dointvec()and this usesproc_put_long()
o We can easily wrap around the int values:UINT_MAXis4294967295, if we echo in 4294967295 + 1 we end up with 0, using 4294967295 + 2 we end up with 1.o We echo negative values in and they are accepted
Fix all these issues by adding our own
do_proc_douintvec().Cc Subash Abhinov Kasiviswanathan <[email protected]>Cc Heinrich Schuchardt <[email protected]>Cc Kees Cook <[email protected]>Cc "David S. Miller" <[email protected]>Cc Ingo Molnar <[email protected]>Cc Andrew Morton <[email protected]>Cc Linus Torvalds <[email protected]>Cc Greg Kroah-Hartman <[email protected]>Fixes e7d316a02f68 ("sysctl: handle error writing UINT_MAX to u32 fields")Signed-off-by Luis R. Rodriguez <[email protected]>---
I split this off as its own atomic fix from a larger RFC series [0]. I've only provided the fix here, and split off further functionality into a separate patch for the future. Although this is a fix I don't think its super critical, and specially due to its size do not think it can be stable material.
I do have
proc_douintvec_minmax()but since we have no users for it it can wait until I add something that makes use of it. If someone needs it now though please let me know.Likewise adding
proc_douintvec_minmax_sysadmin()is very trivial but I have no immediate users for it so it can wait even longer.[0] https://lkml.kernel.org/r/[email protected]
kernel/sysctl.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 115 insertions(+), 6 deletions(-)kernel/sysctl.c +0
-0@@ -2125,12 +2125,12 @@ static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp,return 0 ; }Quoted 12 lines
kernel/sysctl.c static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp, · line 2133
Quoted 10 lines
kernel/sysctl.c +4
-4-static int do_proc_douintvec_conv (bool *negp,unsigned long *lvalp, -int *valp, -int write,void *data) +static int do_proc_douintvec_conv (unsigned long *lvalp, +unsigned int *valp, +int write,void *data) {if (write) { -if (*negp) +if (*lvalp > (unsigned long )UINT_MAX )Cast is unnecessary here.
Fixed, thanks!
Quoted 8 lines
Quoted 6 lines
kernel/sysctl.c static int do_proc_dointvec(struct ctl_table *table, int write, · line 2292
Quoted 3 lines
kernel/sysctl.c +2
-0+static int __do_proc_douintvec (void *tbl_data,struct ctl_table *table, + for (; left && vleft--; i++, first=false) {I'd suggest to not implement "array of unsigned int" unless such sysctl already exists. Much of the complexity arises from this case.
Uh, yeah that is such crap.
The more I studied this the more I supported the idea of ripping the array crap out from unsigned int support.
Quoted 4 lines
As much as I'd like to I'm afraid the problem with this is there may be array int setups which should / could be ported to unsigned int. I tried to do a grammatical search with Coccinelle but ran into issues, I'll follow up with Julia about that.
I've now completed a preliminary evaluation using Coccinelle to perform a grammatical search to ask ourselves:
o How many sysctl proc_dointvec() (int) users exist which likely should be moved over to proc_douintvec() (unsigned int) ?
Answer: about 8
- Of these how many are array users ?
Answer: Probably only 1
o How many sysctl array users exist ?
Answer: about 12
This last question gives us an idea just how popular arrays: they are not. Array support should probably just be kept for strings.
So unless anyone finds evidence to the contrary I will be ripping out array support from unsigned int. I'll also go ahead and extend the test cases and add a test_sysctl driver for selftests.
Luis
Quoted 2 lines · Luis R. Rodriguez
So unless anyone finds evidence to the contrary I will be ripping out array support from unsigned int
Oh so I should probably explain: the reason for this is that even though I found one possible user for array for unsigned int, we support ranges with int, and that should suffice for that driver.
Luis
v2 cover sysctl: add and fix proper unsigned int support
In reply to Luis R. RodriguezOn this v2 I've taken Alexey's recommendation and looked at array users of the proc sysctl interface which complicate the interfece to see if we can instead just simplify the unsigned int implementation. I could not find any clear candidate. As such I've just ripped out array support.
Since some future unsigned int proc sysctl users might think there is array support I've taken measures to do sanity checks on initialization and warn the kernel if such users creep up. To validate this I ended up just writing a simple test driver, and extending our tests. In doing this I also found a really old issue with sysctl_check_table(), and yet another issue with the first incarnation of proc_douintvec().
I hammered on proc_douintvec() as much as I could, and extended tests for this to ensure we don't regress should some int users convert over.
I noticed one more issue but I did not fix as I figured it was worth
discussing: proc_doi*_minmax() handlers have historically allowed users to register even if their own data does not match the expressed min/max values. When this happens the value is exposed on /proc/sys but reading or writing does not work against it. I'm of the opinion that sysctl_check_table() should just validate this and bail preventing such entries from ever creeping up. The only reason I didn't do this is this *could* mean some tables don't get registered in some cases -- I haven't done the vetting. If we're fine with this I can add it later.
Luis R. Rodriguez (9):
sysctl: fix lax sysctl_check_table() sanity check
sysctl: add proper unsigned int support
sysctl: add unsigned int range support
test_sysctl: add dedicated proc sysctl test driver
test_sysctl: add generic script to expand on tests
test_sysctl: test against PAGE_SIZE for int
test_sysctl: add simple proc_dointvec() case
test_sysctl: add simple proc_douintvec() case
test_sysctl: test against int proc_dointvec() array support
fs/proc/proc_sysctl.c | 27 +- include/linux/sysctl.h | 3 + kernel/sysctl.c | 227 +++++++- lib/Kconfig.debug | 11 + lib/Makefile | 1 + lib/test_sysctl.c | 141 +++++ tools/testing/selftests/sysctl/Makefile | 3 +- tools/testing/selftests/sysctl/common_tests | 109 ---- tools/testing/selftests/sysctl/config | 1 + tools/testing/selftests/sysctl/run_numerictests | 10 - tools/testing/selftests/sysctl/run_stringtests | 77 --- tools/testing/selftests/sysctl/sysctl.sh | 738 ++++++++++++++++++++++++ 12 files changed, 1139 insertions(+), 209 deletions(-) create mode 100644 lib/test_sysctl.c delete mode 100644 tools/testing/selftests/sysctl/common_tests create mode 100644 tools/testing/selftests/sysctl/config delete mode 100755 tools/testing/selftests/sysctl/run_numerictests delete mode 100755 tools/testing/selftests/sysctl/run_stringtests create mode 100755 tools/testing/selftests/sysctl/sysctl.sh
Signature · 1 line
2.11.0
PATCH v2 1/9 sysctl: fix lax sysctl_check_table() sanity check
Commit 7c60c48f58a7 ("sysctl: Improve the sysctl sanity checks") improved sanity checks considerbly, however the enhancements on sysctl_check_table() meant adding a functional change so that only the last table entry's sanity error is propagated. It also changed the way errors were propagated so that each new check reset the err value, this means only last sanity check computed is used for an error. This has been in the kernel since v3.4 days.
Fix this by carrying on errors from previous checks and iterations as we traverse the table and ensuring we keep any error from previous checks. We keep iterating on the table even if an error is found so we can complain for all errors found in one shot. This works as -EINVAL is always returned on error anyway, and the check for error is any non-zero value.
--- fs/proc/proc_sysctl.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
fs/proc/proc_sysctl.c +5 -5
@@ -1036,7 +1036,7 @@ static int sysctl_check_table(const char *path, struct ctl_table *table)int err =0 ;for (; table->procname; table++) {if (table->child) - err =sysctl_err (path, table,"Not a file" ); + err |=sysctl_err (path, table,"Not a file" ); if ((table->proc_handler == proc_dostring) || (table->proc_handler == proc_dointvec) ||
@@ -1047,15 +1047,15 @@ static int sysctl_check_table(const char *path, struct ctl_table *table) (table->proc_handler == proc_doulongvec_minmax) || (table->proc_handler == proc_doulongvec_ms_jiffies_minmax)) {if (!table->data) - err =sysctl_err (path, table,"No data" ); + err |=sysctl_err (path, table,"No data" );if (!table->maxlen) - err =sysctl_err (path, table,"No maxlen" ); + err |=sysctl_err (path, table,"No maxlen" ); }if (!table->proc_handler) - err =sysctl_err (path, table,"No proc_handler" ); + err |=sysctl_err (path, table,"No proc_handler" );if ((table->mode & (S_IRUGO |S_IWUGO )) != table->mode) - err =sysctl_err (path, table,"bogus .mode 0%o" , + err |=sysctl_err (path, table,"bogus .mode 0%o" , table->mode); }return err;
Signature · 1 line
2.11.0
Re: [PATCH v2 1/9] sysctl: fix lax sysctl_check_table() sanity check
Quoted 8 lines · Luis R. Rodriguez
Commit
7c60c48f58a7("sysctl: Improve the sysctl sanity checks") improved sanity checks considerbly, however the enhancements onsysctl_check_table()meant adding a functional change so that only the last table entry's sanity error is propagated. It also changed the way errors were propagated so that each new check reset the err value, this means only last sanity check computed is used for an error. This has been in the kernel since v3.4 days.
Quoted 6 lines
Fix this by carrying on errors from previous checks and iterations as we traverse the table and ensuring we keep any error from previous checks. We keep iterating on the table even if an error is found so we can complain for all errors found in one shot. This works as
-EINVALis always returned on error anyway, and the check for error is any non-zero value.
I assume this didn't catch anything that was broken-but-hidden in the kernel?
Quoted 3 lines
Fixes 7c60c48f58a7 ("sysctl: Improve the sysctl sanity checks")Signed-off-by Luis R. Rodriguez <[email protected]>
-Kees
Signature · 2 lines
Kees Cook Pixel Security
PATCH v2 2/9 sysctl: add proper unsigned int support
In reply to Luis R. RodriguezCommit e7d316a02f6838 ("sysctl: handle error writing UINT_MAX to u32 fields") added proc_douintvec() to start help adding support for unsigned int, this however was only half the work needed, all these issues are present with the current implementation:
o Printing the values shows a negative value, this happens since do_proc_dointvec() and this uses proc_put_long()
o We can easily wrap around the int values: UINT_MAX is 4294967295, if we echo in 4294967295 + 1 we end up with 0, using 4294967295 + 2 we end up with 1.
o We echo negative values in and they are accepted
o sysctl_check_table() was never extended for proc_douintvec()
Fix all these issues by adding our own do_proc_douintvec() and adding proc_douintvec() to sysctl_check_table().
Historically sysctl proc helpers have supported arrays, due to the complexity this adds though we've taken a step back to evaluate array users to determine if its worth upkeeping for unsigned int. An evaluation using Coccinelle has been done to perform a grammatical search to ask ourselves:
o How many sysctl proc_dointvec() (int) users exist which likely should be moved over to proc_douintvec() (unsigned int) ?
Answer: about 8
- Of these how many are array users ?
Answer: Probably only 1
o How many sysctl array users exist ?
Answer: about 12
This last question gives us an idea just how popular arrays: they are not. Array support should probably just be kept for strings.
The identified uint ports are:
drivers/infiniband/core/ucma.c - max_backlog drivers/infiniband/core/iwcm.c - default_backlog net/core/sysctl_net_core.c - rps_sock_flow_sysctl() net/netfilter/nf_conntrack_timestamp.c - nf_conntrack_timestamp -- bool net/netfilter/nf_conntrack_acct.c nf_conntrack_acct -- bool net/netfilter/nf_conntrack_ecache.c - nf_conntrack_events -- bool net/netfilter/nf_conntrack_helper.c - nf_conntrack_helper -- bool net/phonet/sysctl.c proc_local_port_range()
The only possible array users is proc_local_port_range() but it does not seem worth it to add array support just for this given the range support works just as well. Unsigned int support should be desirable more for when you *need* more than INT_MAX or using int min/max support then does not suffice for your ranges.
If you forget and by mistake happen to register an unsigned int proc entry with an array, the driver will fail and you will get something as follows:
sysctl table check failed: debug/test_sysctl//uint_0002 array now allowed
CPU: 2 PID: 1342 Comm: modprobe Tainted: G W E <etc> Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS <etc> Call Trace: dump_stack+0x63/0x81 __register_sysctl_table+0x350/0x650 ? kmem_cache_alloc_trace+0x107/0x240 __register_sysctl_paths+0x1b3/0x1e0 ? 0xffffffffc005f000 register_sysctl_table+0x1f/0x30 test_sysctl_init+0x10/0x1000 [test_sysctl] do_one_initcall+0x52/0x1a0 ? kmem_cache_alloc_trace+0x107/0x240 do_init_module+0x5f/0x200 load_module+0x1867/0x1bd0 ? __symbol_put+0x60/0x60 SYSC_finit_module+0xdf/0x110 SyS_finit_module+0xe/0x10 entry_SYSCALL_64_fastpath+0x1e/0xad RIP: 0033:0x7f042b22d119
<etc>
--- fs/proc/proc_sysctl.c | 15 +++++ kernel/sysctl.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 170 insertions(+), 6 deletions(-)
fs/proc/proc_sysctl.c +15 -0
@@ -1031,6 +1031,18 @@ static int sysctl_err(const char *path, struct ctl_table *table, char *fmt, ...)return -EINVAL ; } +static int sysctl_check_table_array (const char *path,struct ctl_table *table) +{ +int err =0 ; + +if (table->proc_handler == proc_douintvec) { +if (table->maxlen !=sizeof (unsigned int )) + err |=sysctl_err (path, table,"array now allowed" ); + } + +return err; +} +static int sysctl_check_table (const char *path,struct ctl_table *table) {int err =0 ;
@@ -1040,6 +1052,7 @@ static int sysctl_check_table(const char *path, struct ctl_table *table) if ((table->proc_handler == proc_dostring) || (table->proc_handler == proc_dointvec) || + (table->proc_handler == proc_douintvec) || (table->proc_handler == proc_dointvec_minmax) || (table->proc_handler == proc_dointvec_jiffies) || (table->proc_handler == proc_dointvec_userhz_jiffies) ||
@@ -1050,6 +1063,8 @@ static int sysctl_check_table(const char *path, struct ctl_table *table) err |=sysctl_err (path, table,"No data" );if (!table->maxlen) err |=sysctl_err (path, table,"No maxlen" ); +else + err |=sysctl_check_table_array (path, table); }if (!table->proc_handler) err |=sysctl_err (path, table,"No proc_handler" );
kernel/sysctl.c +155 -6
181 lines not on this page · raw message
Signature · 1 line
2.11.0
Quoted 94 lines · Luis R. Rodriguez
Commit
e7d316a02f6838("sysctl: handle error writingUINT_MAXto u32 fields") addedproc_douintvec()to start help adding support for unsigned int, this however was only half the work needed, all these issues are present with the current implementation:o Printing the values shows a negative value, this happens since
do_proc_dointvec()and this usesproc_put_long()
o We can easily wrap around the int values:UINT_MAXis 4294967295, if we echo in 4294967295 + 1 we end up with 0, using 4294967295 + 2 we end up with 1.
o We echo negative values in and they are accepted
osysctl_check_table()was never extended forproc_douintvec()Fix all these issues by adding our own
do_proc_douintvec()and addingproc_douintvec()tosysctl_check_table().Historically sysctl proc helpers have supported arrays, due to the complexity this adds though we've taken a step back to evaluate array users to determine if its worth upkeeping for unsigned int. An evaluation using Coccinelle has been done to perform a grammatical search to ask ourselves:
o How many sysctl
proc_dointvec()(int) users exist which likely should be moved over toproc_douintvec()(unsigned int) ?
Answer: about 8
- Of these how many are array users ?
Answer: Probably only 1
o How many sysctl array users exist ?
Answer: about 12This last question gives us an idea just how popular arrays: they are not. Array support should probably just be kept for strings.
The identified uint ports are:
drivers/infiniband/core/ucma.c-max_backlogdrivers/infiniband/core/iwcm.c-default_backlognet/core/sysctl_net_core.c-rps_sock_flow_sysctl()net/netfilter/nf_conntrack_timestamp.c-nf_conntrack_timestamp-- boolnet/netfilter/nf_conntrack_acct.cnf_conntrack_acct-- boolnet/netfilter/nf_conntrack_ecache.c-nf_conntrack_events-- boolnet/netfilter/nf_conntrack_helper.c-nf_conntrack_helper-- boolnet/phonet/sysctl.cproc_local_port_range()The only possible array users is
proc_local_port_range()but it does not seem worth it to add array support just for this given the range support works just as well. Unsigned int support should be desirable more for when you *need* more thanINT_MAXor using int min/max support then does not suffice for your ranges.If you forget and by mistake happen to register an unsigned int proc entry with an array, the driver will fail and you will get something as follows:
sysctl table check failed: debug/test_sysctl//uint_0002 array now allowed
CPU: 2 PID: 1342 Comm: modprobe Tainted: G W E <etc> Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS <etc> Call Trace: dump_stack+0x63/0x81 __register_sysctl_table+0x350/0x650 ? kmem_cache_alloc_trace+0x107/0x240 __register_sysctl_paths+0x1b3/0x1e0 ? 0xffffffffc005f000 register_sysctl_table+0x1f/0x30 test_sysctl_init+0x10/0x1000 [test_sysctl] do_one_initcall+0x52/0x1a0 ? kmem_cache_alloc_trace+0x107/0x240 do_init_module+0x5f/0x200 load_module+0x1867/0x1bd0 ? __symbol_put+0x60/0x60 SYSC_finit_module+0xdf/0x110 SyS_finit_module+0xe/0x10 entry_SYSCALL_64_fastpath+0x1e/0xad RIP: 0033:0x7f042b22d119<etc>
Cc Subash Abhinov Kasiviswanathan <[email protected]>Cc Heinrich Schuchardt <[email protected]>Cc Kees Cook <[email protected]>Cc "David S. Miller" <[email protected]>Cc Ingo Molnar <[email protected]>Cc Andrew Morton <[email protected]>Cc Linus Torvalds <[email protected]>Fixes e7d316a02f68 ("sysctl: handle error writing UINT_MAX to u32 fields")Signed-off-by Luis R. Rodriguez <[email protected]>--- fs/proc/proc_sysctl.c | 15 +++++ kernel/sysctl.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 170 insertions(+), 6 deletions(-)fs/proc/proc_sysctl.c +0
-0
fs/proc/proc_sysctl.c static int sysctl_err(const char *path, struct ctl_table *table, char *fmt, ...) · line 1038
Quoted 8 lines
fs/proc/proc_sysctl.c +5
-0@@ -1031,6 +1031,18 @@ static int sysctl_err(const char *path, struct ctl_table *table, char *fmt, ...)return -EINVAL ; } +static int sysctl_check_table_array (const char *path,struct ctl_table *table) +{ +int err =0 ; + +if (table->proc_handler == proc_douintvec) {
Should this be inverted? i.e. explicitly allow proc_handlers instead of only rejecting douintvec?
Quoted 70 lines
fs/proc/proc_sysctl.c +10
-0+if (table->maxlen !=sizeof (unsigned int )) + err |=sysctl_err (path, table,"array now allowed" ); + } + +return err; +} +static int sysctl_check_table (const char *path,struct ctl_table *table) {int err =0 ;@@ -1040,6 +1052,7 @@ static int sysctl_check_table(const char *path, struct ctl_table *table) if ((table->proc_handler == proc_dostring) || (table->proc_handler == proc_dointvec) || + (table->proc_handler == proc_douintvec) || (table->proc_handler == proc_dointvec_minmax) || (table->proc_handler == proc_dointvec_jiffies) || (table->proc_handler == proc_dointvec_userhz_jiffies) ||@@ -1050,6 +1063,8 @@ static int sysctl_check_table(const char *path, struct ctl_table *table) err |=sysctl_err (path, table,"No data" );if (!table->maxlen) err |=sysctl_err (path, table,"No maxlen" ); +else + err |=sysctl_check_table_array (path, table); }if (!table->proc_handler) err |=sysctl_err (path, table,"No proc_handler" );kernel/sysctl.c +22
-4@@ -2125,12 +2125,12 @@ static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp,return 0 ; } -static int do_proc_douintvec_conv (bool *negp,unsigned long *lvalp, -int *valp, -int write,void *data) +static int do_proc_douintvec_conv (unsigned long *lvalp, +unsigned int *valp, +int write,void *data) {if (write) { -if (*negp) +if (*lvalp >UINT_MAX )return -EINVAL ; *valp = *lvalp; }else {@@ -2243,6 +2243,155 @@ static int do_proc_dointvec(struct ctl_table *table, int write, buffer, lenp, ppos, conv, data); } +static int do_proc_douintvec_w (unsigned int *tbl_data, +struct ctl_table *table, +void __user *buffer, +size_t *lenp,loff_t *ppos, +int (*conv)(unsigned long *lvalp, +unsigned int *valp, +int write,void *data), +void *data) +{ +unsigned long lval; +int err =0 ; +size_t left; +bool neg; +char *kbuf =NULL , *p; + + left = *lenp; + +if (*ppos) {
kernel/sysctl.c static int do_proc_dointvec(struct ctl_table *table, int write, · line 2273
Quoted 10 lines
kernel/sysctl.c +10
-0+switch (sysctl_writes_strict) { +case SYSCTL_WRITES_STRICT : + goto bail_early; +case SYSCTL_WRITES_WARN : +warn_sysctl_write (table); +break ; +default : +break ; + } + }
I wonder if this SYSCTL_WRITES_* test copy/pasting needs to be a function?
Quoted 99 lines
kernel/sysctl.c +99
-0+ +if (left >PAGE_SIZE -1 ) + left =PAGE_SIZE -1 ; + + p = kbuf =memdup_user_nul (buffer, left); +if (IS_ERR (kbuf)) +return -EINVAL ; + + left -=proc_skip_spaces (&p); +if (!left) { + err = -EINVAL ; + goto out_free; + } + + err =proc_get_long (&p, &left, &lval, &neg, + proc_wspace_sep, +sizeof (proc_wspace_sep),NULL ); +if (err || neg) { + err = -EINVAL ; + goto out_free; + } + +if (conv (&lval, tbl_data,1 , data)) { + err = -EINVAL ; + goto out_free; + } + +if (!err && left) + left -=proc_skip_spaces (&p); + +out_free: +kfree (kbuf); +if (err) +return -EINVAL ; + +return 0 ; + +/* This is in keeping with old __do_proc_dointvec() */ +bail_early: + *ppos += *lenp; +return err; +} + +static int do_proc_douintvec_r (unsigned int *tbl_data,void __user *buffer, +size_t *lenp,loff_t *ppos, +int (*conv)(unsigned long *lvalp, +unsigned int *valp, +int write,void *data), +void *data) +{ +unsigned long lval; +int err =0 ; +size_t left; + + left = *lenp; + +if (conv (&lval, tbl_data,0 , data)) { + err = -EINVAL ; + goto out; + } + + err =proc_put_long (&buffer, &left, lval, false); +if (err || !left) + goto out; + + err =proc_put_char (&buffer, &left,'\n' ); + +out: + *lenp -= left; + *ppos += *lenp; + +return err; +} + +static int __do_proc_douintvec (void *tbl_data,struct ctl_table *table, +int write,void __user *buffer, +size_t *lenp,loff_t *ppos, +int (*conv)(unsigned long *lvalp, +unsigned int *valp, +int write,void *data), +void *data) +{ +unsigned int *i, vleft; + +if (!tbl_data || !table->maxlen || !*lenp || (*ppos && !write)) { + *lenp =0 ; +return 0 ; + } + + i = (unsigned int *) tbl_data; + vleft = table->maxlen /sizeof (*i); + +/* +* Arrays are not supported, keep this simple. *Do not* add +* support for them. +*/ +if (vleft !=1 ) { + *lenp =0 ; +return -EINVAL ;
kernel/sysctl.c static int do_proc_dointvec(struct ctl_table *table, int write, · line 2382
Quoted 10 lines
kernel/sysctl.c +10
-0+ } + +if (!conv) + conv = do_proc_douintvec_conv; + +if (write) +return do_proc_douintvec_w (i, table, buffer, lenp, ppos, + conv, data); +return do_proc_douintvec_r (i, buffer, lenp, ppos, conv, data); +}
I like the split of read/write. That makes things easier to review.
Quoted 27 lines
kernel/sysctl.c +14
-3+ +static int do_proc_douintvec (struct ctl_table *table,int write, +void __user *buffer,size_t *lenp,loff_t *ppos, +int (*conv)(unsigned long *lvalp, +unsigned int *valp, +int write,void *data), +void *data) +{ +return __do_proc_douintvec (table->data, table, write, + buffer, lenp, ppos, conv, data); +} +/** * proc_dointvec - read a vector of integers * @table: the sysctl table @@ -2278,8 +2427,8 @@ int proc_dointvec(struct ctl_table *table, int write,int proc_douintvec (struct ctl_table *table,int write,void __user *buffer,size_t *lenp,loff_t *ppos) { -return do_proc_dointvec (table, write, buffer, lenp, ppos, - do_proc_douintvec_conv,NULL ); +return do_proc_douintvec (table, write, buffer, lenp, ppos, + do_proc_douintvec_conv,NULL ); }/* --
Quoted 2 lines
2.11.0
-Kees
Signature · 2 lines
Kees Cook Pixel Security
Quoted 14 lines · Kees Cook
Quoted 13 lines · Luis R. Rodriguez
--- fs/proc/proc_sysctl.c | 15 +++++ kernel/sysctl.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 170 insertions(+), 6 deletions(-)fs/proc/proc_sysctl.c +0
-0@@ -1031,6 +1031,18 @@ static int sysctl_err(const char *path, struct ctl_table *table, char *fmt, ...)return -EINVAL ; }
Quoted 8 lines
fs/proc/proc_sysctl.c static int sysctl_err(const char *path, struct ctl_table *table, char *fmt, ...) · line 1038
Quoted 5 lines
fs/proc/proc_sysctl.c +5
-0+static int sysctl_check_table_array (const char *path,struct ctl_table *table) +{ +int err =0 ; + +if (table->proc_handler == proc_douintvec) {Should this be inverted? i.e. explicitly allow
proc_handlersinstead of only rejecting douintvec?
The goal is to start avoiding the use of the silly arrays, and we start drawing the line with proc_douintvec. The expectation then is that this list will grow so the check should easily allow for growth of more exclusions for now, once we are done we would hopefully only end up with strings that use arrays. For now then we are limited to a specific check against the size of the parameter that the proc handler uses, so for instance:
Quoted 3 lines
fs/proc/proc_sysctl.c static int sysctl_err(const char *path, struct ctl_table *table, char *fmt, ...) · line 1041
Quoted 3 lines
fs/proc/proc_sysctl.c +3
-0+if (table->maxlen !=sizeof (unsigned int )) + err |=sysctl_err (path, table,"array now allowed" ); + }
This uses unsigned int, I expect the check to be different for proc_dointvec_jiffies once we vet no array uses exist for it. The way I think its best to expand on this list is to later add:
else if (table->proc_handler == proc_dointvec_jiffies) {
...
}If did the other way around and started this check with:
if (table->proc_handler != proc_douintvec)
return 0;
We'd still have to add a specific check for each handler for the actual expected size for one element. So I would prefer to keep it this way for now. Once we have vetted arrays are only needed for strings (and hopefully if we can change a few ints users, not sure if proc is "uapi"; think it is so we might be shit out of luck), then we'd only have a short white-list. Even so, the size check on the others is probably good to leave, as such a check does not exist so we would not have to nuke those old checks.
Quoted 30 lines
Quoted 30 lines
kernel/sysctl.c +22
-0@@ -2243,6 +2243,155 @@ static int do_proc_dointvec(struct ctl_table *table, int write, buffer, lenp, ppos, conv, data); } +static int do_proc_douintvec_w (unsigned int *tbl_data, +struct ctl_table *table, +void __user *buffer, +size_t *lenp,loff_t *ppos, +int (*conv)(unsigned long *lvalp, +unsigned int *valp, +int write,void *data), +void *data) +{ +unsigned long lval; +int err =0 ; +size_t left; +bool neg; +char *kbuf =NULL , *p; + + left = *lenp; + +if (*ppos) { +switch (sysctl_writes_strict) { +case SYSCTL_WRITES_STRICT : + goto bail_early; +case SYSCTL_WRITES_WARN :
Quoted 8 lines
kernel/sysctl.c static int do_proc_dointvec(struct ctl_table *table, int write, · line 2273
Quoted 6 lines
kernel/sysctl.c +6
-0+warn_sysctl_write (table); +break ; +default : +break ; + } + }I wonder if this SYSCTL_WRITES_* test copy/pasting needs to be a function?
Good call. Folded in a new patch that does this. This stuff was a bit cryptic so also folded in another patch which documented the strict stuff a bit in kdoc form. Later with time we can move to new sphinx doc format and take advantage of that.
<-- snip -->
Quoted 29 lines
Quoted 29 lines
kernel/sysctl.c +29
-0+static int __do_proc_douintvec (void *tbl_data,struct ctl_table *table, +int write,void __user *buffer, +size_t *lenp,loff_t *ppos, +int (*conv)(unsigned long *lvalp, +unsigned int *valp, +int write,void *data), +void *data) +{ +unsigned int *i, vleft; + +if (!tbl_data || !table->maxlen || !*lenp || (*ppos && !write)) { + *lenp =0 ; +return 0 ; + } + + i = (unsigned int *) tbl_data; + vleft = table->maxlen /sizeof (*i); + +/* +* Arrays are not supported, keep this simple. *Do not* add +* support for them. +*/ +if (vleft !=1 ) { + *lenp =0 ; +return -EINVAL ; + } + +if (!conv) + conv = do_proc_douintvec_conv;
Quoted 8 lines
kernel/sysctl.c static int do_proc_dointvec(struct ctl_table *table, int write, · line 2382
Quoted 6 lines
kernel/sysctl.c +6
-0+ +if (write) +return do_proc_douintvec_w (i, table, buffer, lenp, ppos, + conv, data); +return do_proc_douintvec_r (i, buffer, lenp, ppos, conv, data); +}I like the split of read/write. That makes things easier to review.
Great.
Luis
PATCH v2 3/9 sysctl: add unsigned int range support
In reply to Luis R. RodriguezTo keep parity with regular int interfaces provide the an unsigned int proc_douintvec_minmax() which allows you to specify a range of allowed valid numbers.
Adding proc_douintvec_minmax_sysadmin() is easy but we can wait for an actual user for that.
--- fs/proc/proc_sysctl.c | 4 ++- include/linux/sysctl.h | 3 +++ kernel/sysctl.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-)
fs/proc/proc_sysctl.c +3 -1
@@ -1035,7 +1035,8 @@ static int sysctl_check_table_array(const char *path, struct ctl_table *table) {int err =0 ; -if (table->proc_handler == proc_douintvec) { +if ((table->proc_handler == proc_douintvec) || + (table->proc_handler == proc_douintvec_minmax)) {if (table->maxlen !=sizeof (unsigned int )) err |=sysctl_err (path, table,"array now allowed" ); }
@@ -1053,6 +1054,7 @@ static int sysctl_check_table(const char *path, struct ctl_table *table) if ((table->proc_handler == proc_dostring) || (table->proc_handler == proc_dointvec) || (table->proc_handler == proc_douintvec) || + (table->proc_handler == proc_douintvec_minmax) || (table->proc_handler == proc_dointvec_minmax) || (table->proc_handler == proc_dointvec_jiffies) || (table->proc_handler == proc_dointvec_userhz_jiffies) ||
include/linux/sysctl.h +3 -0
@@ -47,6 +47,9 @@ extern int proc_douintvec(struct ctl_table *, int, void __user *, size_t *, loff_t *);extern int proc_dointvec_minmax (struct ctl_table *,int ,void __user *,size_t *,loff_t *); +extern int proc_douintvec_minmax (struct ctl_table *table,int write, +void __user *buffer,size_t *lenp, +loff_t *ppos);extern int proc_dointvec_jiffies (struct ctl_table *,int ,void __user *,size_t *,loff_t *); extern int proc_dointvec_userhz_jiffies(struct ctl_table *, int,
kernel/sysctl.c +66 -0
84 lines not on this page · raw message
Signature · 1 line
2.11.0
Re: [PATCH v2 3/9] sysctl: add unsigned int range support
Quoted 7 lines · Luis R. Rodriguez
To keep parity with regular int interfaces provide the an unsigned int
proc_douintvec_minmax()which allows you to specify a range of allowed valid numbers.Adding
proc_douintvec_minmax_sysadmin()is easy but we can wait for an actual user for that.
Quoted 8 lines
Cc Subash Abhinov Kasiviswanathan <[email protected]>Cc Heinrich Schuchardt <[email protected]>Cc Kees Cook <[email protected]>Cc "David S. Miller" <[email protected]>Cc Ingo Molnar <[email protected]>Cc Andrew Morton <[email protected]>Cc Linus Torvalds <[email protected]>Signed-off-by Luis R. Rodriguez <[email protected]>
This looks sensible. :)
-Kees
Signature · 2 lines
Kees Cook Pixel Security
PATCH v2 4/9 test_sysctl: add dedicated proc sysctl test driver
In reply to Luis R. RodriguezAlthough we have had tools/testing/selftests/sysctl/ with two test cases these use existing kernel sysctl interfaces. We want to expand test coverage, we can't just be looking for random safe production values to poke at, instead just dedicate a test driver for debugging purposes and port the existing scripts to use it. This will make it easier for further tests to be added.
--- lib/Kconfig.debug | 11 +++ lib/Makefile | 1 + lib/test_sysctl.c | 106 ++++++++++++++++++++++++ tools/testing/selftests/sysctl/config | 1 + tools/testing/selftests/sysctl/run_numerictests | 4 +- tools/testing/selftests/sysctl/run_stringtests | 4 +- 6 files changed, 123 insertions(+), 4 deletions(-) create mode 100644 lib/test_sysctl.c create mode 100644 tools/testing/selftests/sysctl/config
lib/Kconfig.debug +11 -0
@@ -1975,6 +1975,17 @@ config TEST_FIRMWARE If unsure, say N. +config TEST_SYSCTL + tristate "sysctl test driver" + default n + depends on PROC_SYSCTL + help + This builds the "test_sysctl" module. This driver enables to test the + proc sysctl interfaces available to drivers safely without affecting + production knobs which might alter system functionality. + + If unsure, say N. + config TEST_UDELAY tristate "udelay test driver" default n
lib/Makefile +1 -0
@@ -45,6 +45,7 @@ obj-$(CONFIG_TEST_HEXDUMP) += test_hexdump.o obj-y += kstrtox.o obj-$(CONFIG_TEST_BPF) += test_bpf.o obj-$(CONFIG_TEST_FIRMWARE) += test_firmware.o +obj-$(CONFIG_TEST_SYSCTL) += test_sysctl.o obj-$(CONFIG_TEST_HASH) += test_hash.o test_siphash.o obj-$(CONFIG_TEST_KASAN) += test_kasan.o obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o
lib/test_sysctl.c new file +106 -0
106 lines not on this page · raw message
tools/testing/selftests/sysctl/config new file +1 -0
@@ -0,0 +1 @@ +CONFIG_TEST_SYSCTL=y
tools/testing/selftests/sysctl/run_numerictests +2 -2
@@ -1,7 +1,7 @@ #!/bin/sh -SYSCTL="/proc/sys" -TARGET="${SYSCTL}/vm/swappiness" +SYSCTL="/proc/sys/debug/test_sysctl/" +TARGET="${SYSCTL}/int_0001" ORIG=$(cat "${TARGET}") TEST_STR=$(( $ORIG + 1 ))
tools/testing/selftests/sysctl/run_stringtests +2 -2
@@ -1,7 +1,7 @@ #!/bin/sh -SYSCTL="/proc/sys" -TARGET="${SYSCTL}/kernel/domainname" +SYSCTL="/proc/sys/debug/test_sysctl/" +TARGET="${SYSCTL}/string_0001" ORIG=$(cat "${TARGET}") TEST_STR="Testing sysctl"
Signature · 1 line
2.11.0
Re: [PATCH v2 4/9] test_sysctl: add dedicated proc sysctl test driver
Quoted 8 lines · Luis R. Rodriguez
Although we have had
tools/testing/selftests/sysctl/with two test cases these use existing kernel sysctl interfaces. We want to expand test coverage, we can't just be looking for random safe production values to poke at, instead just dedicate a test driver for debugging purposes and port the existing scripts to use it. This will make it easier for further tests to be added.Signed-off-by Luis R. Rodriguez <[email protected]>
Yes please!
Quoted 78 lines
--- lib/Kconfig.debug | 11 +++ lib/Makefile | 1 + lib/test_sysctl.c | 106 ++++++++++++++++++++++++ tools/testing/selftests/sysctl/config | 1 + tools/testing/selftests/sysctl/run_numerictests | 4 +- tools/testing/selftests/sysctl/run_stringtests | 4 +- 6 files changed, 123 insertions(+), 4 deletions(-) create mode 100644 lib/test_sysctl.c create mode 100644 tools/testing/selftests/sysctl/configlib/Kconfig.debug +11
-0@@ -1975,6 +1975,17 @@ config TEST_FIRMWARE If unsure, say N. +config TEST_SYSCTL + tristate "sysctl test driver" + default n + depends on PROC_SYSCTL + help + This builds the "test_sysctl" module. This driver enables to test the + proc sysctl interfaces available to drivers safely without affecting + production knobs which might alter system functionality. + + If unsure, say N. + config TEST_UDELAY tristate "udelay test driver" default nlib/Makefile +1
-0@@ -45,6 +45,7 @@ obj-$(CONFIG_TEST_HEXDUMP) += test_hexdump.o obj-y += kstrtox.o obj-$(CONFIG_TEST_BPF) += test_bpf.o obj-$(CONFIG_TEST_FIRMWARE) += test_firmware.o +obj-$(CONFIG_TEST_SYSCTL) += test_sysctl.o obj-$(CONFIG_TEST_HASH) += test_hash.o test_siphash.o obj-$(CONFIG_TEST_KASAN) += test_kasan.o obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.olib/test_sysctl.c new file +27
-0@@ -0,0 +1,106 @@ +/* +* proc sysctl test driver +* +* Copyright (C) 2017 Luis R. Rodriguez <[email protected]> +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of copyleft-next (version 0.3.1 or later) as published +* at http://copyleft-next.org/. +*/ + +/* +* This module provides an interface to the the proc sysctl interfaces. This +* driver requires CONFIG_PROC_SYSCTL. It will not normally be loaded by the +* system unless explicitly requested by name. You can also build this driver +* into your kernel. +*/ + +#define pr_fmt (fmt) KBUILD_MODNAME ": " fmt + +#include <linux/init.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/printk.h> +#include <linux/fs.h> +#include <linux/miscdevice.h> +#include <linux/slab.h> +#include <linux/uaccess.h>
lib/test_sysctl.c line 37
Quoted 10 lines
lib/test_sysctl.c new file +10
-0+#include <linux/async.h> +#include <linux/delay.h> +#include <linux/vmalloc.h> + +static int i_zero; +static int i_one_hundred =100 ; + +struct test_sysctl_data { +int int_0001; +char string_0001[65 ];
I wonder if it's worth adding a comment here that "65" is tied to the sysctl string self-test.
Quoted 75 lines
lib/test_sysctl.c new file +69
-0+}; + +static struct test_sysctl_data test_data = { + .int_0001 =60 , + .string_0001 ="(none)" , +}; + +/* These are all under /proc/sys/debug/test_sysctl/ */ +static struct ctl_table test_table[] = { + { + .procname ="int_0001" , + .data = &test_data.int_0001, + .maxlen =sizeof (int ), + .mode =0644 , + .proc_handler = proc_dointvec_minmax, + .extra1 = &i_zero, + .extra2 = &i_one_hundred, + }, + { + .procname ="string_0001" , + .data = &test_data.string_0001, + .maxlen =sizeof (test_data.string_0001), + .mode =0644 , + .proc_handler = proc_dostring, + }, + { } +}; + +static struct ctl_table test_sysctl_table[] = { + { + .procname ="test_sysctl" , + .maxlen =0 , + .mode =0555 , + .child = test_table, + }, + { } +}; + +static struct ctl_table test_sysctl_root_table[] = { + { + .procname ="debug" , + .maxlen =0 , + .mode =0555 , + .child = test_sysctl_table, + }, + { } +}; + +static struct ctl_table_header *test_sysctl_header; + +static int __init test_sysctl_init (void ) +{ + test_sysctl_header =register_sysctl_table (test_sysctl_root_table); +if (!test_sysctl_header) +return -ENOMEM ; +return 0 ; +} +late_initcall (test_sysctl_init); + +static void __exit test_sysctl_exit(void) +{ +if (test_sysctl_header) +unregister_sysctl_table (test_sysctl_header); +} + +module_exit (test_sysctl_exit); + +MODULE_AUTHOR ("Luis R. Rodriguez <[email protected]>" ); +MODULE_LICENSE ("GPL" );tools/testing/selftests/sysctl/config new file +0
-0
tools/testing/selftests/sysctl/config line 1
Quoted 1 line
tools/testing/selftests/sysctl/config new file +1
-0@@ -0,0 +1 @@ +CONFIG_TEST_SYSCTL=y
Technically, this works with =m too, but whatever reads "config" would need to know to load it first...
Quoted 29 lines
tools/testing/selftests/sysctl/run_numerictests +2
-2@@ -1,7 +1,7 @@ #!/bin/sh -SYSCTL="/proc/sys" -TARGET="${SYSCTL}/vm/swappiness" +SYSCTL="/proc/sys/debug/test_sysctl/" +TARGET="${SYSCTL}/int_0001" ORIG=$(cat "${TARGET}") TEST_STR=$(( $ORIG + 1 ))tools/testing/selftests/sysctl/run_stringtests +2
-3@@ -1,7 +1,7 @@ #!/bin/sh -SYSCTL="/proc/sys" -TARGET="${SYSCTL}/kernel/domainname" +SYSCTL="/proc/sys/debug/test_sysctl/" +TARGET="${SYSCTL}/string_0001" ORIG=$(cat "${TARGET}") TEST_STR="Testing sysctl" --
Quoted 2 lines
2.11.0
-Kees
Signature · 2 lines
Kees Cook Pixel Security
PATCH v2 5/9 test_sysctl: add generic script to expand on tests
In reply to Luis R. RodriguezThis adds a generic script to let us more easily add more tests cases. Since we really have only two types of tests cases just fold them into the one file. Each test unit is now identified into its separate function:
# ./sysctl.sh -l Test ID list:
TEST_ID x NUM_TEST
TEST_ID: Test ID NUM_TESTS: Number of recommended times to run the test
0001 x 1 - tests proc_dointvec_minmax()
0002 x 1 - tests proc_dostring()
For now we start off with what we had before, and run only each test once. We can now watch a test case until it fails:
./sysctl.sh -w 0002
We can also run a test case x number of times, say we want to run a test case 100 times:
./sysctl.sh -c 0001 100
To run a test case only once, for example:
./sysctl.sh -s 0002
The default settings are specified at the top of sysctl.sh.
--- tools/testing/selftests/sysctl/Makefile | 3 +- tools/testing/selftests/sysctl/common_tests | 109 ------ tools/testing/selftests/sysctl/run_numerictests | 10 - tools/testing/selftests/sysctl/run_stringtests | 77 ---- tools/testing/selftests/sysctl/sysctl.sh | 459 ++++++++++++++++++++++++ 5 files changed, 460 insertions(+), 198 deletions(-) delete mode 100644 tools/testing/selftests/sysctl/common_tests delete mode 100755 tools/testing/selftests/sysctl/run_numerictests delete mode 100755 tools/testing/selftests/sysctl/run_stringtests create mode 100755 tools/testing/selftests/sysctl/sysctl.sh
tools/testing/selftests/sysctl/Makefile +1 -2
@@ -4,8 +4,7 @@ # No binaries, but make sure arg-less "make" doesn't trigger "run_tests". all: -TEST_PROGS := run_numerictests run_stringtests -TEST_FILES := common_tests +TEST_PROGS := sysctl.sh include ../lib.mk
tools/testing/selftests/sysctl/common_tests deleted +0 -109
109 lines not on this page · raw message
tools/testing/selftests/sysctl/run_numerictests deleted +0 -10
@@ -1,10 +0,0 @@ -#!/bin/sh - -SYSCTL="/proc/sys/debug/test_sysctl/" -TARGET="${SYSCTL}/int_0001" -ORIG=$(cat "${TARGET}") -TEST_STR=$(( $ORIG + 1 )) - -. ./common_tests - -exit $rc
tools/testing/selftests/sysctl/run_stringtests deleted +0 -77
77 lines not on this page · raw message
tools/testing/selftests/sysctl/sysctl.sh new file +459 -0
459 lines not on this page · raw message
Signature · 1 line
2.11.0
Re: [PATCH v2 5/9] test_sysctl: add generic script to expand on tests
Quoted 25 lines · Luis R. Rodriguez
This adds a generic script to let us more easily add more tests cases. Since we really have only two types of tests cases just fold them into the one file. Each test unit is now identified into its separate function:
# ./sysctl.sh -l Test ID list:
TEST_IDxNUM_TESTTEST_ID: Test ID NUM_TESTS: Number of recommended times to run the test0001 x 1 - tests
proc_dointvec_minmax()
0002 x 1 - testsproc_dostring()For now we start off with what we had before, and run only each test once. We can now watch a test case until it fails:
./sysctl.sh -w 0002
We can also run a test case x number of times, say we want to run a test case 100 times:
./sysctl.sh -c 0001 100
Quoted 7 lines
To run a test case only once, for example:
./sysctl.sh -s 0002
The default settings are specified at the top of
sysctl.sh.Signed-off-by Luis R. Rodriguez <[email protected]>
I'm not a fan of this: it consolidates tests when it's not needed and creates a test running infrastructure at the wrong level of abstraction. I'd like to see individual tests that are one-off runnable. Whatever consumes the tools/testing/selftests/ tree is what should be doing the -w, -c, etc style options.
-Kees
Signature · 2 lines
Kees Cook Pixel Security
Re: [PATCH v2 5/9] test_sysctl: add generic script to expand on tests
Quoted 28 lines · Kees Cook
Quoted 27 lines · Luis R. Rodriguez
This adds a generic script to let us more easily add more tests cases. Since we really have only two types of tests cases just fold them into the one file. Each test unit is now identified into its separate function:
# ./sysctl.sh -l Test ID list:
TEST_IDxNUM_TESTTEST_ID: Test ID NUM_TESTS: Number of recommended times to run the test0001 x 1 - tests
proc_dointvec_minmax()
0002 x 1 - testsproc_dostring()For now we start off with what we had before, and run only each test once. We can now watch a test case until it fails:
./sysctl.sh -w 0002
We can also run a test case x number of times, say we want to run a test case 100 times:
./sysctl.sh -c 0001 100
To run a test case only once, for example:
Quoted 7 lines
Quoted 5 lines
./sysctl.sh -s 0002
The default settings are specified at the top of
sysctl.sh.Signed-off-by Luis R. Rodriguez <[email protected]>I'm not a fan of this: it consolidates tests when it's not needed
Tests can easily be split off even with the above syntax, right now its all just stuffed in one file but the syntax does not impede this to change.
Quoted 2 lines
and creates a test running infrastructure at the wrong level of abstraction.
In lieu of an existing abstraction layer which provides this having each script *for now* do what it wishes seems fair. To create an generic test abstraction layer we need to study each test case, and I'm afraid I can't do that at this time. But I do by now have about 3 test drivers pending upstream which share similar testing taste, so I can later try to groom a generic infrastructure for what I want but for now I can't find the issue with having each test script have what it needs.
Quoted 1 line
I'd like to see individual tests that are one-off runnable.
The above allows for this: './sysctl.sh -s 0002' will run the test case 0002 once.
Quoted 2 lines
Whatever consumes the
tools/testing/selftests/tree is what should be doing the -w, -c, etc style options.
In the end I agree, but I also believe in evolving this.
If you feel strongly this needs to be generalized at the right layer from the start I'm afraid I'll just have to drop these tests as I just don't have the time to address expanding the selftest infrastructure with a generic solution which covers all that I added, I expect this to be quite a bit of work.
Luis
PATCH v2 6/9 test_sysctl: test against PAGE_SIZE for int
In reply to Luis R. RodriguezAdd the following tests to ensure we do not regress:
o Test using a buffer full of space (PAGE_SIZE-1) followed by a single digit works
o Test using a buffer full of spaces (PAGE_SIZE or over) will fail
As tests increase instead of unloading the module and reloading it we can just do a shell reset_vals() with a reset to values we know are set at init on the driver.
--- tools/testing/selftests/sysctl/sysctl.sh | 65 ++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+)
tools/testing/selftests/sysctl/sysctl.sh +65 -0
@@ -46,6 +46,12 @@ function allow_user_defaults() if [ -z $SYSCTL ]; then SYSCTL="/proc/sys/debug/test_sysctl" fi + if [ -z $PAGE_SIZE ]; then + PAGE_SIZE=$(getconf PAGESIZE) + fi + if [ -z $MAX_DIGITS ]; then + MAX_DIGITS=$(($PAGE_SIZE/8)) + fi } test_reqs()
@@ -60,6 +66,10 @@ test_reqs() echo "$0: You need perl installed" exit 1 fi + if ! which getconf 2> /dev/null > /dev/null; then + echo "$0: You need getconf installed" + exit 1 + fi } function load_req_mod()
@@ -74,6 +84,23 @@ function load_req_mod() fi } +reset_vals() +{ + VAL="" + TRIGGER=$(basename ${TARGET}) + case "$TRIGGER" in + int_0001) + VAL="60" + ;; + string_0001) + VAL="(none)" + ;; + *) + ;; + esac + echo -n $VAL > $TARGET +} + set_orig() { if [ ! -z $TARGET ]; then
@@ -195,7 +222,42 @@ run_numerictests() else echo "ok" fi + test_rc +} + +# Your test must accept digits 3 and 4 to use this +run_limit_digit() +{ + echo -n "Checking ignoring spaces up to PAGE_SIZE works on write ..." + reset_vals + + LIMIT=$((MAX_DIGITS -1)) + TEST_STR="3" + (perl -e 'print " " x '$LIMIT';'; echo "${TEST_STR}") | \ + dd of="${TARGET}" 2>/dev/null + + if ! verify "${TARGET}"; then + echo "FAIL" >&2 + rc=1 + else + echo "ok" + fi + test_rc + + echo -n "Checking passing PAGE_SIZE of spaces fails on write ..." + reset_vals + LIMIT=$((MAX_DIGITS)) + TEST_STR="4" + (perl -e 'print " " x '$LIMIT';'; echo "${TEST_STR}") | \ + dd of="${TARGET}" 2>/dev/null + + if verify "${TARGET}"; then + echo "FAIL" >&2 + rc=1 + else + echo "ok" + fi test_rc }
@@ -271,15 +333,18 @@ run_stringtests() sysctl_test_0001() { TARGET="${SYSCTL}/int_0001" + reset_vals ORIG=$(cat "${TARGET}") TEST_STR=$(( $ORIG + 1 )) run_numerictests + run_limit_digit } sysctl_test_0002() { TARGET="${SYSCTL}/string_0001" + reset_vals ORIG=$(cat "${TARGET}") TEST_STR="Testing sysctl" # Only string sysctls support seeking/appending.
Signature · 1 line
2.11.0
PATCH v2 7/9 test_sysctl: add simple proc_dointvec() case
In reply to Luis R. RodriguezTest against a simple proc_dointvec() case. While at it, add a test against INT_MAX. Make sure INT_MAX works, and INT_MAX+1 will fail. Also test negative values work.
--- lib/test_sysctl.c | 11 ++++++ tools/testing/selftests/sysctl/sysctl.sh | 62 ++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+)
lib/test_sysctl.c +11 -0
@@ -34,11 +34,15 @@ static int i_one_hundred = 100;struct test_sysctl_data {int int_0001; +int int_0002; +char string_0001[65 ]; };static struct test_sysctl_data test_data = { .int_0001 =60 , + .int_0002 =1 , + .string_0001 ="(none)" , };
@@ -54,6 +58,13 @@ static struct ctl_table test_table[] = { .extra2 = &i_one_hundred, }, { + .procname = "int_0002", + .data = &test_data.int_0002, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { .procname = "string_0001", .data = &test_data.string_0001, .maxlen = sizeof(test_data.string_0001),
tools/testing/selftests/sysctl/sysctl.sh +62 -0
98 lines not on this page · raw message
Signature · 1 line
2.11.0
Re: [PATCH v2 7/9] test_sysctl: add simple proc_dointvec() case
Quoted 89 lines · Luis R. Rodriguez
Test against a simple
proc_dointvec()case. While at it, add a test againstINT_MAX. Make sureINT_MAXworks, and INT_MAX+1 will fail. Also test negative values work.Signed-off-by Luis R. Rodriguez <[email protected]>--- lib/test_sysctl.c | 11 ++++++ tools/testing/selftests/sysctl/sysctl.sh | 62 ++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+)lib/test_sysctl.c +11
-0@@ -34,11 +34,15 @@ static int i_one_hundred = 100;struct test_sysctl_data {int int_0001; +int int_0002; +char string_0001[65 ]; };static struct test_sysctl_data test_data = { .int_0001 =60 , + .int_0002 =1 , + .string_0001 ="(none)" , };@@ -54,6 +58,13 @@ static struct ctl_table test_table[] = { .extra2 = &i_one_hundred, }, { + .procname = "int_0002", + .data = &test_data.int_0002, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { .procname = "string_0001", .data = &test_data.string_0001, .maxlen = sizeof(test_data.string_0001),tools/testing/selftests/sysctl/sysctl.sh +16
-0@@ -24,6 +24,7 @@ TEST_FILE=$(mktemp) # we have tons of space. ALL_TESTS="0001:1:1" ALL_TESTS="$ALL_TESTS 0002:1:1" +ALL_TESTS="$ALL_TESTS 0003:1:1" test_modprobe() {@@ -52,6 +53,9 @@ function allow_user_defaults() if [ -z $MAX_DIGITS ]; then MAX_DIGITS=$(($PAGE_SIZE/8)) fi + if [ -z $INT_MAX ]; then + INT_MAX=$(getconf INT_MAX) + fi } test_reqs()@@ -92,6 +96,9 @@ reset_vals() int_0001) VAL="60" ;; + int_0002) + VAL="1" + ;; string_0001) VAL="(none)" ;;@@ -261,6 +268,48 @@ run_limit_digit() test_rc } +# You are using an int +run_limit_digit_int() +{ + echo -n "Testing INT_MAX works ..." + reset_vals + TEST_STR="$INT_MAX" + echo -n $TEST_STR > $TARGET + + if ! verify "${TARGET}"; then
tools/testing/selftests/sysctl/sysctl.sh run_limit_digit() · line 289
Quoted 10 lines
tools/testing/selftests/sysctl/sysctl.sh +10
-0+ echo "FAIL" >&2 + rc=1 + else + echo "ok" + fi + test_rc + + echo -n "Testing INT_MAX + 1 will fail as expected..." + reset_vals + TEST_STR=$(($INT_MAX+1))
Is the shell always going to do the right thing here? Maybe these test values should be explicitly hard-coded? I'm on the fence...
-Kees
Signature · 2 lines
Kees Cook Pixel Security
Re: [PATCH v2 7/9] test_sysctl: add simple proc_dointvec() case
Quoted 24 lines · Kees Cook
Quoted 23 lines · Luis R. Rodriguez
tools/testing/selftests/sysctl/sysctl.sh +14
-0@@ -24,6 +24,7 @@ TEST_FILE=$(mktemp)@@ -261,6 +268,48 @@ run_limit_digit() test_rc } +# You are using an int +run_limit_digit_int() +{ + echo -n "Testing INT_MAX works ..." + reset_vals + TEST_STR="$INT_MAX" + echo -n $TEST_STR > $TARGET + + if ! verify "${TARGET}"; then + echo "FAIL" >&2 + rc=1 + else + echo "ok" + fi
Quoted 8 lines
tools/testing/selftests/sysctl/sysctl.sh run_limit_digit() · line 289
Quoted 5 lines
tools/testing/selftests/sysctl/sysctl.sh +5
-0+ test_rc + + echo -n "Testing INT_MAX + 1 will fail as expected..." + reset_vals + TEST_STR=$(($INT_MAX+1))Is the shell always going to do the right thing here? Maybe these test values should be explicitly hard-coded? I'm on the fence...
Will use the good 'ol time tested:
let TEST_STR=$INT_MAX+1
I had used it for all other sums before, not sure why I went short-cut mode. Either way this is requiring /bin/bash at the top header, but yeah not sure when that short cut mode addition was added to bash. Better to be both safe and consistent.
Luis
PATCH v2 8/9 test_sysctl: add simple proc_douintvec() case
In reply to Luis R. RodriguezTest against a simple proc_douintvec() case. While at it, add a test against UINT_MAX. Make sure UINT_MAX works, and UINT_MAX+1 will fail and that negative values are not accepted.
--- lib/test_sysctl.c | 11 ++++++ tools/testing/selftests/sysctl/sysctl.sh | 63 ++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+)
lib/test_sysctl.c +11 -0
@@ -36,6 +36,8 @@ struct test_sysctl_data {int int_0001;int int_0002; +unsigned int uint_0001; +char string_0001[65 ]; };
@@ -43,6 +45,8 @@ static struct test_sysctl_data test_data = { .int_0001 = 60, .int_0002 = 1, + .uint_0001 = 314, + .string_0001 = "(none)", };
@@ -65,6 +69,13 @@ static struct ctl_table test_table[] = { .proc_handler = proc_dointvec, }, { + .procname = "uint_0001", + .data = &test_data.uint_0001, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_douintvec, + }, + { .procname = "string_0001", .data = &test_data.string_0001, .maxlen = sizeof(test_data.string_0001),
tools/testing/selftests/sysctl/sysctl.sh +63 -0
99 lines not on this page · raw message
Signature · 1 line
2.11.0
PATCH v2 9/9 test_sysctl: test against int proc_dointvec() array support
In reply to Luis R. RodriguezAdd a few initial respective tests for an array:
o Echoing values separated by spaces works
o Echoing only first elements will set first elements
o Confirm PAGE_SIZE limit still applies even if an array is used
--- lib/test_sysctl.c | 13 +++++ tools/testing/selftests/sysctl/sysctl.sh | 89 ++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+)
lib/test_sysctl.c +13 -0
@@ -35,6 +35,7 @@ static int i_one_hundred = 100;struct test_sysctl_data {int int_0001;int int_0002; +int int_0003[4 ];unsigned int uint_0001;
@@ -45,6 +46,11 @@ static struct test_sysctl_data test_data = { .int_0001 = 60, .int_0002 = 1, + .int_0003[0] = 0, + .int_0003[1] = 1, + .int_0003[2] = 2, + .int_0003[3] = 3, + .uint_0001 = 314, .string_0001 = "(none)",
@@ -69,6 +75,13 @@ static struct ctl_table test_table[] = { .proc_handler = proc_dointvec, }, { + .procname = "int_0003", + .data = &test_data.int_0003, + .maxlen = sizeof(test_data.int_0003), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { .procname = "uint_0001", .data = &test_data.uint_0001, .maxlen = sizeof(unsigned int),
tools/testing/selftests/sysctl/sysctl.sh +89 -0
125 lines not on this page · raw message
Signature · 1 line
2.11.0
Re: [PATCH v2 9/9] test_sysctl: test against int proc_dointvec() array support
Quoted 74 lines · Luis R. Rodriguez
Add a few initial respective tests for an array:
o Echoing values separated by spaces works
o Echoing only first elements will set first elements
o ConfirmPAGE_SIZElimit still applies even if an array is usedSigned-off-by Luis R. Rodriguez <[email protected]>--- lib/test_sysctl.c | 13 +++++ tools/testing/selftests/sysctl/sysctl.sh | 89 ++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+)lib/test_sysctl.c +13
-0@@ -35,6 +35,7 @@ static int i_one_hundred = 100;struct test_sysctl_data {int int_0001;int int_0002; +int int_0003[4 ];unsigned int uint_0001;@@ -45,6 +46,11 @@ static struct test_sysctl_data test_data = { .int_0001 = 60, .int_0002 = 1, + .int_0003[0] = 0, + .int_0003[1] = 1, + .int_0003[2] = 2, + .int_0003[3] = 3, + .uint_0001 = 314, .string_0001 = "(none)",@@ -69,6 +75,13 @@ static struct ctl_table test_table[] = { .proc_handler = proc_dointvec, }, { + .procname = "int_0003", + .data = &test_data.int_0003, + .maxlen = sizeof(test_data.int_0003), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { .procname = "uint_0001", .data = &test_data.uint_0001, .maxlen = sizeof(unsigned int),tools/testing/selftests/sysctl/sysctl.sh +5
-0@@ -26,6 +26,7 @@ ALL_TESTS="0001:1:1" ALL_TESTS="$ALL_TESTS 0002:1:1" ALL_TESTS="$ALL_TESTS 0003:1:1" ALL_TESTS="$ALL_TESTS 0004:1:1" +ALL_TESTS="$ALL_TESTS 0005:3:1" test_modprobe() {@@ -78,6 +79,10 @@ test_reqs() echo "$0: You need getconf installed" exit 1 fi + if ! which diff 2> /dev/null > /dev/null; then + echo "$0: You need diff installed" + exit 1 + fi } function load_req_mod()
tools/testing/selftests/sysctl/sysctl.sh verify() · line 147
Quoted 6 lines
tools/testing/selftests/sysctl/sysctl.sh +3
-0@@ -137,6 +142,12 @@ verify() return 0 } +verify_diff_w() +{ + echo "$TEST_STR" | diff -w -u - $1 2>&1 > /dev/null
Instead of shell redirection, just use -q ?
Quoted 106 lines
tools/testing/selftests/sysctl/sysctl.sh +81
-1+ return $? +} + test_rc() { if [[ $rc != 0 ]]; then@@ -317,6 +328,74 @@ run_limit_digit_int() test_rc } +# You used an int array +run_limit_digit_int_array() +{ + echo -n "Testing array works as expected ... " + TEST_STR="4 3 2 1" + echo -n $TEST_STR > $TARGET + + if ! verify_diff_w "${TARGET}"; then + echo "FAIL" >&2 + rc=1 + else + echo "ok" + fi + test_rc + + echo -n "Testing skipping trailing array elements works ... " + # Do not reset_vals, carry on the values from the last test. + # If we only echo in two digits the last two are left intact + TEST_STR="100 101" + echo -n $TEST_STR > $TARGET + # After we echo in, to help diff we need to set on TEST_STR what + # we expect the result to be. + TEST_STR="100 101 2 1" + + if ! verify_diff_w "${TARGET}"; then + echo "FAIL" >&2 + rc=1 + else + echo "ok" + fi + test_rc + + echo -n "Testing PAGE_SIZE limit on array works ... " + # Do not reset_vals, carry on the values from the last test. + # Even if you use an int array, you are still restricted to + # MAX_DIGITS, this is a known limitation. Test limit works. + LIMIT=$((MAX_DIGITS -1)) + TEST_STR="9" + (perl -e 'print " " x '$LIMIT';'; echo "${TEST_STR}") | \ + dd of="${TARGET}" 2>/dev/null + + TEST_STR="9 101 2 1" + if ! verify_diff_w "${TARGET}"; then + echo "FAIL" >&2 + rc=1 + else + echo "ok" + fi + test_rc + + echo -n "Testing exceeding PAGE_SIZE limit fails as expected ... " + # Do not reset_vals, carry on the values from the last test. + # Now go over limit. + LIMIT=$((MAX_DIGITS)) + TEST_STR="7" + (perl -e 'print " " x '$LIMIT';'; echo "${TEST_STR}") | \ + dd of="${TARGET}" 2>/dev/null + + TEST_STR="7 101 2 1" + if verify_diff_w "${TARGET}"; then + echo "FAIL" >&2 + rc=1 + else + echo "ok" + fi + test_rc +} + # You are using an unsigned int run_limit_digit_uint() {@@ -477,6 +556,15 @@ sysctl_test_0004() run_limit_digit_uint } +sysctl_test_0005() +{ + TARGET="${SYSCTL}/int_0003" + reset_vals + ORIG=$(cat "${TARGET}") + + run_limit_digit_int_array +} + list_tests() { echo "Test ID list:"@@ -489,6 +577,7 @@ list_tests() echo "0002 x $(get_test_count 0002) - tests proc_dostring()" echo "0003 x $(get_test_count 0003) - tests proc_dointvec()" echo "0004 x $(get_test_count 0004) - tests proc_douintvec()" + echo "0005 x $(get_test_count 0005) - tests proc_douintvec() array" } test_reqs --
Quoted 2 lines
2.11.0
I love seeing these tests added. I have one other change I'd like to add to sysctl, but I haven't had time to make sure it doesn't break stuff. I haven't been able to prove it to myself, but I think it's safe; I just need to update the tests to handle it:
It'd need an update for the uint handler...
-Kees
Signature · 2 lines
Kees Cook Pixel Security
Re: [PATCH v2 9/9] test_sysctl: test against int proc_dointvec() array support
Quoted 9 lines · Kees Cook
Quoted 8 lines · Luis R. Rodriguez
tools/testing/selftests/sysctl/sysctl.sh +0
-0@@ -137,6 +142,12 @@ verify() return 0 }
Quoted 5 lines
tools/testing/selftests/sysctl/sysctl.sh verify() · line 147
Quoted 3 lines
tools/testing/selftests/sysctl/sysctl.sh +3
-0+verify_diff_w() +{ + echo "$TEST_STR" | diff -w -u - $1 2>&1 > /dev/nullInstead of shell redirection, just use -q ?
Will try.
Quoted 2 lines
I love seeing these tests added. I have one other change I'd like to add to sysctl,
Upon a glance again at this stuff I can think of a few other checks but one battle at a time...
Quoted 7 lines
but I haven't had time to make sure it doesn't break stuff. I haven't been able to prove it to myself, but I think it's safe; I just need to update the tests to handle it:
It'd need an update for the uint handler...
That would also expands on the definition of the strict mode. I think this is fair if we take it for granted strict will always aim for correctness, but we also have to be fair and be clear on possible impact and ensure nothing will bust. I have a feeling though that we'd keep on going with these semantics on and on and on... which really is just irritating and it tells me something more wrong about this crap interface.
Just a rant here...
Luis
Re: [PATCH v2 0/9] sysctl: add and fix proper unsigned int support
In reply to Luis R. RodriguezQuoted 26 lines · Luis R. Rodriguez
On this v2 I've taken Alexey's recommendation and looked at array users of the proc sysctl interface which complicate the interfece to see if we can instead just simplify the unsigned int implementation. I could not find any clear candidate. As such I've just ripped out array support.
Since some future unsigned int proc sysctl users might think there is array support I've taken measures to do sanity checks on initialization and warn the kernel if such users creep up. To validate this I ended up just writing a simple test driver, and extending our tests. In doing this I also found a really old issue with
sysctl_check_table(), and yet another issue with the first incarnation ofproc_douintvec().I hammered on
proc_douintvec()as much as I could, and extended tests for this to ensure we don't regress should some int users convert over.I noticed one more issue but I did not fix as I figured it was worth
discussing: proc_doi*_minmax() handlers have historically allowed users to register even if their own data does not match the expressed min/max values. When this happens the value is exposed on/proc/sysbut reading or writing does not work against it. I'm of the opinion thatsysctl_check_table()should just validate this and bail preventing such entries from ever creeping up. The only reason I didn't do this is this *could* mean some tables don't get registered in some cases -- I haven't done the vetting. If we're fine with this I can add it later.
Quoted 10 lines
Luis R. Rodriguez (9):
sysctl: fix laxsysctl_check_table()sanity check
sysctl: add proper unsigned int support
sysctl: add unsigned int range support
test_sysctl: add dedicated proc sysctl test driver
test_sysctl: add generic script to expand on tests
test_sysctl: test againstPAGE_SIZEfor int
test_sysctl: add simpleproc_dointvec()case
test_sysctl: add simpleproc_douintvec()case
test_sysctl: test against intproc_dointvec()array support
Please go ahead and add a MAINTAINERS file entry for the two of us (and Eric if he wants) for sysctl. We poke at it enough that really we should declare it maintained (as you suggested privately). For now we should likely still land it all through akpm, though.
-Kees
Signature · 2 lines
Kees Cook Pixel Security
v3 cover sysctl: few fixes
In reply to Luis R. RodriguezI've been working on making kmod more deterministic, and as I did that I couldn't help but notice a few issues with sysctl. My end goal was just to fix unsigned int support, which back then was completely broken. Liping Zhang has sent up small atomic fixes, however it still missed yet one more fix and Alexey Dobriyan had also suggested to just drop array support given its complexity.
I have inspected array support using Coccinelle and indeed its not that popular, so if in fact we can avoid it for new interfaces, I agree its best.
I did develop a sysctl stress driver but will hold that off for another series.
Luis R. Rodriguez (5):
sysctl: fix lax sysctl_check_table() sanity check
sysctl: kdoc'ify sysctl_writes_strict
sysctl: fold sysctl_writes_strict checks into helper
sysctl: simplify unsigned int support
sysctl: add unsigned int range support
fs/proc/proc_sysctl.c | 26 ++++- include/linux/sysctl.h | 3 + kernel/sysctl.c | 304 +++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 293 insertions(+), 40 deletions(-)
Signature · 1 line
2.11.0
PATCH v3 1/5 sysctl: fix lax sysctl_check_table() sanity check
Commit 7c60c48f58a7 ("sysctl: Improve the sysctl sanity checks") improved sanity checks considerbly, however the enhancements on sysctl_check_table() meant adding a functional change so that only the last table entry's sanity error is propagated. It also changed the way errors were propagated so that each new check reset the err value, this means only last sanity check computed is used for an error. This has been in the kernel since v3.4 days.
Fix this by carrying on errors from previous checks and iterations as we traverse the table and ensuring we keep any error from previous checks. We keep iterating on the table even if an error is found so we can complain for all errors found in one shot. This works as -EINVAL is always returned on error anyway, and the check for error is any non-zero value.
--- fs/proc/proc_sysctl.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
fs/proc/proc_sysctl.c +5 -5
@@ -1066,7 +1066,7 @@ static int sysctl_check_table(const char *path, struct ctl_table *table)int err =0 ;for (; table->procname; table++) {if (table->child) - err =sysctl_err (path, table,"Not a file" ); + err |=sysctl_err (path, table,"Not a file" ); if ((table->proc_handler == proc_dostring) || (table->proc_handler == proc_dointvec) ||
@@ -1078,15 +1078,15 @@ static int sysctl_check_table(const char *path, struct ctl_table *table) (table->proc_handler == proc_doulongvec_minmax) || (table->proc_handler == proc_doulongvec_ms_jiffies_minmax)) {if (!table->data) - err =sysctl_err (path, table,"No data" ); + err |=sysctl_err (path, table,"No data" );if (!table->maxlen) - err =sysctl_err (path, table,"No maxlen" ); + err |=sysctl_err (path, table,"No maxlen" ); }if (!table->proc_handler) - err =sysctl_err (path, table,"No proc_handler" ); + err |=sysctl_err (path, table,"No proc_handler" );if ((table->mode & (S_IRUGO |S_IWUGO )) != table->mode) - err =sysctl_err (path, table,"bogus .mode 0%o" , + err |=sysctl_err (path, table,"bogus .mode 0%o" , table->mode); }return err;
Signature · 1 line
2.11.0
Andrew Morton
maintainerRe: [PATCH v3 1/5] sysctl: fix lax sysctl_check_table() sanity check
Quoted 38 lines · On Thu, 18 May 2017 20:35:50 -0700 "Luis R. Rodriguez" <[email protected]>…
Commit
7c60c48f58a7("sysctl: Improve the sysctl sanity checks") improved sanity checks considerbly, however the enhancements onsysctl_check_table()meant adding a functional change so that only the last table entry's sanity error is propagated. It also changed the way errors were propagated so that each new check reset the err value, this means only last sanity check computed is used for an error. This has been in the kernel since v3.4 days.Fix this by carrying on errors from previous checks and iterations as we traverse the table and ensuring we keep any error from previous checks. We keep iterating on the table even if an error is found so we can complain for all errors found in one shot. This works as
-EINVALis always returned on error anyway, and the check for error is any non-zero value....
fs/proc/proc_sysctl.c +3
-3@@ -1066,7 +1066,7 @@ static int sysctl_check_table(const char *path, struct ctl_table *table)int err =0 ;for (; table->procname; table++) {if (table->child) - err =sysctl_err (path, table,"Not a file" ); + err |=sysctl_err (path, table,"Not a file" ); if ((table->proc_handler == proc_dostring) || (table->proc_handler == proc_dointvec) ||@@ -1078,15 +1078,15 @@ static int sysctl_check_table(const char *path, struct ctl_table *table) (table->proc_handler == proc_doulongvec_minmax) || (table->proc_handler == proc_doulongvec_ms_jiffies_minmax)) {if (!table->data) - err =sysctl_err (path, table,"No data" ); + err |=sysctl_err (path, table,"No data" );if (!table->maxlen) - err =sysctl_err (path, table,"No maxlen" ); + err |=sysctl_err (path, table,"No maxlen" ); }
fs/proc/proc_sysctl.c static int sysctl_check_table(const char *path, struct ctl_table *table) · line 1092
Quoted 10 lines
fs/proc/proc_sysctl.c +2
-2if (!table->proc_handler) - err =sysctl_err (path, table,"No proc_handler" ); + err |=sysctl_err (path, table,"No proc_handler" );if ((table->mode & (S_IRUGO |S_IWUGO )) != table->mode) - err =sysctl_err (path, table,"bogus .mode 0%o" , + err |=sysctl_err (path, table,"bogus .mode 0%o" , table->mode); }return err;
glumpf. I'm not a fan of this err|=foo() trick - if foo() returns different errnos we can a mangled result. This patch assumes that syscal_err() will only ever return a single errno.
I guess we're safe enough in this case but still... ugh.
PATCH v3 2/5 sysctl: kdoc'ify sysctl_writes_strict
In reply to Luis R. RodriguezDocument the different sysctl_writes_strict modes in code.
--- kernel/sysctl.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-)
kernel/sysctl.c +25 -4
@@ -174,11 +174,32 @@ extern int no_unaligned_warning;#ifdef CONFIG_PROC_SYSCTL -#define SYSCTL_WRITES_LEGACY -1 -#define SYSCTL_WRITES_WARN 0 -#define SYSCTL_WRITES_STRICT 1 +/** +* enum sysctl_writes_mode - supported sysctl write modes +* +* @SYSCTL_WRITES_LEGACY: each write syscall must fully contain the sysctl value +* to be written, and multiple writes on the same sysctl file descriptor +* will rewrite the sysctl value, regardless of file position. No warning +* is issued when the initial position is not 0. +* @SYSCTL_WRITES_WARN: same as above but warn when the initial file position is +* not 0. +* @SYSCTL_WRITES_STRICT: writes to numeric sysctl entries must always be at +* file position 0 and the value must be fully contained in the buffer +* sent to the write syscall. If dealing with strings respect the file +* position, but restrict this to the max length of the buffer, anything +* passed the max lenght will be ignored. Multiple writes will append +* to the buffer. +* +* These write modes control how current file position affects the behavior of +* updating sysctl values through the proc interface on each write. +*/ +enum sysctl_writes_mode { +SYSCTL_WRITES_LEGACY =-1 , +SYSCTL_WRITES_WARN =0 , +SYSCTL_WRITES_STRICT =1 , +}; -static int sysctl_writes_strict =SYSCTL_WRITES_STRICT ; +static enum sysctl_writes_mode sysctl_writes_strict =SYSCTL_WRITES_STRICT ;static int proc_do_cad_pid (struct ctl_table *table,int write,void __user *buffer,size_t *lenp,loff_t *ppos);
Signature · 1 line
2.11.0
PATCH v3 3/5 sysctl: fold sysctl_writes_strict checks into helper
In reply to Luis R. RodriguezThe mode sysctl_writes_strict positional checks keep being copy and pasted as we add new proc handlers. Just add a helper to avoid code duplication.
--- kernel/sysctl.c | 56 ++++++++++++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 24 deletions(-)
kernel/sysctl.c +32 -24
@@ -1971,6 +1971,32 @@ static void warn_sysctl_write(struct ctl_table *table) }/** +* proc_first_pos_non_zero_ignore - check if firs position is allowed +* @ppos: file position +* @table: the sysctl table +* +* Returns true if the first position is non-zero and the sysctl_writes_strict +* mode indicates this is not allowed for numeric input types. String proc +* hadlers can ignore the return value. +*/ +static bool proc_first_pos_non_zero_ignore (loff_t *ppos, +struct ctl_table *table) +{ +if (!*ppos) +return false; + +switch (sysctl_writes_strict) { +case SYSCTL_WRITES_STRICT : +return true; +case SYSCTL_WRITES_WARN : +warn_sysctl_write (table); +return false; +default : +return false; + } +} + +/** * proc_dostring - read a string sysctl * @table: the sysctl table * @write: %TRUE if this is a write to the sysctl file
@@ -1990,8 +2016,8 @@ static void warn_sysctl_write(struct ctl_table *table)int proc_dostring (struct ctl_table *table,int write,void __user *buffer,size_t *lenp,loff_t *ppos) { -if (write && *ppos && sysctl_writes_strict ==SYSCTL_WRITES_WARN ) -warn_sysctl_write (table); +if (write) +proc_first_pos_non_zero_ignore (ppos, table);return _proc_do_string ((char *)(table->data), table->maxlen, write, (char __user *)buffer, lenp, ppos);
@@ -2193,17 +2219,8 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table, conv = do_proc_dointvec_conv;if (write) { -if (*ppos) { -switch (sysctl_writes_strict) { -case SYSCTL_WRITES_STRICT : - goto out; -case SYSCTL_WRITES_WARN : -warn_sysctl_write (table); -break ; -default : -break ; - } - } +if (proc_first_pos_non_zero_ignore (ppos, table)) + goto out;if (left >PAGE_SIZE -1 ) left =PAGE_SIZE -1 ;
@@ -2468,17 +2485,8 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int left = *lenp;if (write) { -if (*ppos) { -switch (sysctl_writes_strict) { -case SYSCTL_WRITES_STRICT : - goto out; -case SYSCTL_WRITES_WARN : -warn_sysctl_write (table); -break ; -default : -break ; - } - } +if (proc_first_pos_non_zero_ignore (ppos, table)) + goto out;if (left >PAGE_SIZE -1 ) left =PAGE_SIZE -1 ;
Signature · 1 line
2.11.0
PATCH v3 4/5 sysctl: simplify unsigned int support
In reply to Luis R. RodriguezCommit e7d316a02f6838 ("sysctl: handle error writing UINT_MAX to u32 fields") added proc_douintvec() to start help adding support for unsigned int, this however was only half the work needed. Two fixes have come in since then for the following issues:
o Printing the values shows a negative value, this happens since do_proc_dointvec() and this uses proc_put_long()
This was fixed by commit 5380e5644afbba9 ("sysctl: don't print negative flag for proc_douintvec").
o We can easily wrap around the int values: UINT_MAX is 4294967295, if we echo in 4294967295 + 1 we end up with 0, using 4294967295 + 2 we end up with 1.
o We echo negative values in and they are accepted
This was fixed by commit 425fffd886bae3d1 ("sysctl: report EINVAL if value is larger than UINT_MAX for proc_douintvec").
It still also failed to be added to sysctl_check_table()... instead of adding it with the current implementation just provide a proper and simplified unsigned int support without any array unsigned int support with no negative support at all.
Historically sysctl proc helpers have supported arrays, due to the complexity this adds though we've taken a step back to evaluate array users to determine if its worth upkeeping for unsigned int. An evaluation using Coccinelle has been done to perform a grammatical search to ask ourselves:
o How many sysctl proc_dointvec() (int) users exist which likely should be moved over to proc_douintvec() (unsigned int) ?
Answer: about 8
- Of these how many are array users ?
Answer: Probably only 1
o How many sysctl array users exist ?
Answer: about 12
This last question gives us an idea just how popular arrays: they are not. Array support should probably just be kept for strings.
The identified uint ports are:
drivers/infiniband/core/ucma.c - max_backlog drivers/infiniband/core/iwcm.c - default_backlog net/core/sysctl_net_core.c - rps_sock_flow_sysctl() net/netfilter/nf_conntrack_timestamp.c - nf_conntrack_timestamp -- bool net/netfilter/nf_conntrack_acct.c nf_conntrack_acct -- bool net/netfilter/nf_conntrack_ecache.c - nf_conntrack_events -- bool net/netfilter/nf_conntrack_helper.c - nf_conntrack_helper -- bool net/phonet/sysctl.c proc_local_port_range()
The only possible array users is proc_local_port_range() but it does not seem worth it to add array support just for this given the range support works just as well. Unsigned int support should be desirable more for when you *need* more than INT_MAX or using int min/max support then does not suffice for your ranges.
If you forget and by mistake happen to register an unsigned int proc entry with an array, the driver will fail and you will get something as follows:
sysctl table check failed: debug/test_sysctl//uint_0002 array now allowed
CPU: 2 PID: 1342 Comm: modprobe Tainted: G W E <etc> Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS <etc> Call Trace: dump_stack+0x63/0x81 __register_sysctl_table+0x350/0x650 ? kmem_cache_alloc_trace+0x107/0x240 __register_sysctl_paths+0x1b3/0x1e0 ? 0xffffffffc005f000 register_sysctl_table+0x1f/0x30 test_sysctl_init+0x10/0x1000 [test_sysctl] do_one_initcall+0x52/0x1a0 ? kmem_cache_alloc_trace+0x107/0x240 do_init_module+0x5f/0x200 load_module+0x1867/0x1bd0 ? __symbol_put+0x60/0x60 SYSC_finit_module+0xdf/0x110 SyS_finit_module+0xe/0x10 entry_SYSCALL_64_fastpath+0x1e/0xad RIP: 0033:0x7f042b22d119
<etc>
--- fs/proc/proc_sysctl.c | 14 +++++ kernel/sysctl.c | 153 +++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 160 insertions(+), 7 deletions(-)
fs/proc/proc_sysctl.c +14 -0
@@ -1061,6 +1061,18 @@ static int sysctl_err(const char *path, struct ctl_table *table, char *fmt, ...)return -EINVAL ; } +static int sysctl_check_table_array (const char *path,struct ctl_table *table) +{ +int err =0 ; + +if (table->proc_handler == proc_douintvec) { +if (table->maxlen !=sizeof (unsigned int )) + err |=sysctl_err (path, table,"array now allowed" ); + } + +return err; +} +static int sysctl_check_table (const char *path,struct ctl_table *table) {int err =0 ;
@@ -1081,6 +1093,8 @@ static int sysctl_check_table(const char *path, struct ctl_table *table) err |=sysctl_err (path, table,"No data" );if (!table->maxlen) err |=sysctl_err (path, table,"No maxlen" ); +else + err |=sysctl_check_table_array (path, table); }if (!table->proc_handler) err |=sysctl_err (path, table,"No proc_handler" );
kernel/sysctl.c +146 -7
179 lines not on this page · raw message
Signature · 1 line
2.11.0
PATCH v3 5/5 sysctl: add unsigned int range support
In reply to Luis R. RodriguezTo keep parity with regular int interfaces provide the an unsigned int proc_douintvec_minmax() which allows you to specify a range of allowed valid numbers.
Adding proc_douintvec_minmax_sysadmin() is easy but we can wait for an actual user for that.
--- fs/proc/proc_sysctl.c | 4 ++- include/linux/sysctl.h | 3 +++ kernel/sysctl.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-)
fs/proc/proc_sysctl.c +3 -1
@@ -1065,7 +1065,8 @@ static int sysctl_check_table_array(const char *path, struct ctl_table *table) {int err =0 ; -if (table->proc_handler == proc_douintvec) { +if ((table->proc_handler == proc_douintvec) || + (table->proc_handler == proc_douintvec_minmax)) {if (table->maxlen !=sizeof (unsigned int )) err |=sysctl_err (path, table,"array now allowed" ); }
@@ -1083,6 +1084,7 @@ static int sysctl_check_table(const char *path, struct ctl_table *table) if ((table->proc_handler == proc_dostring) || (table->proc_handler == proc_dointvec) || (table->proc_handler == proc_douintvec) || + (table->proc_handler == proc_douintvec_minmax) || (table->proc_handler == proc_dointvec_minmax) || (table->proc_handler == proc_dointvec_jiffies) || (table->proc_handler == proc_dointvec_userhz_jiffies) ||
include/linux/sysctl.h +3 -0
@@ -47,6 +47,9 @@ extern int proc_douintvec(struct ctl_table *, int, void __user *, size_t *, loff_t *);extern int proc_dointvec_minmax (struct ctl_table *,int ,void __user *,size_t *,loff_t *); +extern int proc_douintvec_minmax (struct ctl_table *table,int write, +void __user *buffer,size_t *lenp, +loff_t *ppos);extern int proc_dointvec_jiffies (struct ctl_table *,int ,void __user *,size_t *,loff_t *); extern int proc_dointvec_userhz_jiffies(struct ctl_table *, int,
kernel/sysctl.c +66 -0
84 lines not on this page · raw message
Signature · 1 line
2.11.0