aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/sysctl.c
diff options
context:
space:
mode:
authorZev Weiss <zev@bewilderbeest.net>2019-03-12 02:28:06 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-03-12 13:04:00 -0400
commit2bc4fc60fb3e1a4cae429b889720755ebe9085bb (patch)
treefc497f2eb9ef6b496742e1d698830c7e3c8e567b /kernel/sysctl.c
parent8cf7630b29701d364f8df4a50e4f1f5e752b2778 (diff)
kernel/sysctl.c: define minmax conv functions in terms of non-minmax versions
do_proc_do[u]intvec_minmax_conv() had included open-coded versions of do_proc_do[u]intvec_conv(); the duplication led to buggy inconsistencies (missing range checks). To reduce the likelihood of such problems in the future, we can instead refactor both to be defined in terms of their non-bounded counterparts (plus the added check). Link: http://lkml.kernel.org/r/20190207165138.5oud57vq4ozwb4kh@hatter.bewilderbeest.net Signed-off-by: Zev Weiss <zev@bewilderbeest.net> Cc: Brendan Higgins <brendanhiggins@google.com> Cc: Iurii Zaikin <yzaikin@google.com> Cc: Kees Cook <keescook@chromium.org> Cc: Luis Chamberlain <mcgrof@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/sysctl.c')
-rw-r--r--kernel/sysctl.c59
1 files changed, 26 insertions, 33 deletions
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 0854197e0e67..e5da394d1ca3 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -2643,32 +2643,25 @@ static int do_proc_dointvec_minmax_conv(bool *negp, unsigned long *lvalp,
2643 int *valp, 2643 int *valp,
2644 int write, void *data) 2644 int write, void *data)
2645{ 2645{
2646 int tmp, ret;
2646 struct do_proc_dointvec_minmax_conv_param *param = data; 2647 struct do_proc_dointvec_minmax_conv_param *param = data;
2648 /*
2649 * If writing, first do so via a temporary local int so we can
2650 * bounds-check it before touching *valp.
2651 */
2652 int *ip = write ? &tmp : valp;
2653
2654 ret = do_proc_dointvec_conv(negp, lvalp, ip, write, data);
2655 if (ret)
2656 return ret;
2657
2647 if (write) { 2658 if (write) {
2648 int val; 2659 if ((param->min && *param->min > tmp) ||
2649 if (*negp) { 2660 (param->max && *param->max < tmp))
2650 if (*lvalp > (unsigned long) INT_MAX + 1)
2651 return -EINVAL;
2652 val = -*lvalp;
2653 } else {
2654 if (*lvalp > (unsigned long) INT_MAX)
2655 return -EINVAL;
2656 val = *lvalp;
2657 }
2658 if ((param->min && *param->min > val) ||
2659 (param->max && *param->max < val))
2660 return -EINVAL; 2661 return -EINVAL;
2661 *valp = val; 2662 *valp = tmp;
2662 } else {
2663 int val = *valp;
2664 if (val < 0) {
2665 *negp = true;
2666 *lvalp = -(unsigned long)val;
2667 } else {
2668 *negp = false;
2669 *lvalp = (unsigned long)val;
2670 }
2671 } 2663 }
2664
2672 return 0; 2665 return 0;
2673} 2666}
2674 2667
@@ -2717,22 +2710,22 @@ static int do_proc_douintvec_minmax_conv(unsigned long *lvalp,
2717 unsigned int *valp, 2710 unsigned int *valp,
2718 int write, void *data) 2711 int write, void *data)
2719{ 2712{
2713 int ret;
2714 unsigned int tmp;
2720 struct do_proc_douintvec_minmax_conv_param *param = data; 2715 struct do_proc_douintvec_minmax_conv_param *param = data;
2716 /* write via temporary local uint for bounds-checking */
2717 unsigned int *up = write ? &tmp : valp;
2721 2718
2722 if (write) { 2719 ret = do_proc_douintvec_conv(lvalp, up, write, data);
2723 unsigned int val = *lvalp; 2720 if (ret)
2721 return ret;
2724 2722
2725 if (*lvalp > UINT_MAX) 2723 if (write) {
2726 return -EINVAL; 2724 if ((param->min && *param->min > tmp) ||
2727 2725 (param->max && *param->max < tmp))
2728 if ((param->min && *param->min > val) ||
2729 (param->max && *param->max < val))
2730 return -ERANGE; 2726 return -ERANGE;
2731 2727
2732 *valp = val; 2728 *valp = tmp;
2733 } else {
2734 unsigned int val = *valp;
2735 *lvalp = (unsigned long) val;
2736 } 2729 }
2737 2730
2738 return 0; 2731 return 0;