aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSubash Abhinov Kasiviswanathan <subashab@codeaurora.org>2016-08-25 18:16:51 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-08-26 20:39:35 -0400
commite7d316a02f683864a12389f8808570e37fb90aa3 (patch)
treed099ace7966955d8d2741e4c5bdc3202378c432f
parent8582fb59f7ee012f2b8118c2bb95168c1622a4c5 (diff)
sysctl: handle error writing UINT_MAX to u32 fields
We have scripts which write to certain fields on 3.18 kernels but this seems to be failing on 4.4 kernels. An entry which we write to here is xfrm_aevent_rseqth which is u32. echo 4294967295 > /proc/sys/net/core/xfrm_aevent_rseqth Commit 230633d109e3 ("kernel/sysctl.c: detect overflows when converting to int") prevented writing to sysctl entries when integer overflow occurs. However, this does not apply to unsigned integers. Heinrich suggested that we introduce a new option to handle 64 bit limits and set min as 0 and max as UINT_MAX. This might not work as it leads to issues similar to __do_proc_doulongvec_minmax. Alternatively, we would need to change the datatype of the entry to 64 bit. static int __do_proc_doulongvec_minmax(void *data, struct ctl_table { i = (unsigned long *) data; //This cast is causing to read beyond the size of data (u32) vleft = table->maxlen / sizeof(unsigned long); //vleft is 0 because maxlen is sizeof(u32) which is lesser than sizeof(unsigned long) on x86_64. Introduce a new proc handler proc_douintvec. Individual proc entries will need to be updated to use the new handler. [akpm@linux-foundation.org: coding-style fixes] Fixes: 230633d109e3 ("kernel/sysctl.c:detect overflows when converting to int") Link: http://lkml.kernel.org/r/1471479806-5252-1-git-send-email-subashab@codeaurora.org Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org> Cc: Heinrich Schuchardt <xypron.glpk@gmx.de> Cc: Kees Cook <keescook@chromium.org> Cc: "David S. Miller" <davem@davemloft.net> Cc: Ingo Molnar <mingo@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/sysctl.h2
-rw-r--r--kernel/sysctl.c45
2 files changed, 45 insertions, 2 deletions
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 697e160c78d0..a4f7203a9017 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -42,6 +42,8 @@ extern int proc_dostring(struct ctl_table *, int,
42 void __user *, size_t *, loff_t *); 42 void __user *, size_t *, loff_t *);
43extern int proc_dointvec(struct ctl_table *, int, 43extern int proc_dointvec(struct ctl_table *, int,
44 void __user *, size_t *, loff_t *); 44 void __user *, size_t *, loff_t *);
45extern int proc_douintvec(struct ctl_table *, int,
46 void __user *, size_t *, loff_t *);
45extern int proc_dointvec_minmax(struct ctl_table *, int, 47extern int proc_dointvec_minmax(struct ctl_table *, int,
46 void __user *, size_t *, loff_t *); 48 void __user *, size_t *, loff_t *);
47extern int proc_dointvec_jiffies(struct ctl_table *, int, 49extern int proc_dointvec_jiffies(struct ctl_table *, int,
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index b43d0b27c1fe..a13bbdaab47d 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -2140,6 +2140,21 @@ static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp,
2140 return 0; 2140 return 0;
2141} 2141}
2142 2142
2143static int do_proc_douintvec_conv(bool *negp, unsigned long *lvalp,
2144 int *valp,
2145 int write, void *data)
2146{
2147 if (write) {
2148 if (*negp)
2149 return -EINVAL;
2150 *valp = *lvalp;
2151 } else {
2152 unsigned int val = *valp;
2153 *lvalp = (unsigned long)val;
2154 }
2155 return 0;
2156}
2157
2143static const char proc_wspace_sep[] = { ' ', '\t', '\n' }; 2158static const char proc_wspace_sep[] = { ' ', '\t', '\n' };
2144 2159
2145static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table, 2160static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
@@ -2259,8 +2274,27 @@ static int do_proc_dointvec(struct ctl_table *table, int write,
2259int proc_dointvec(struct ctl_table *table, int write, 2274int proc_dointvec(struct ctl_table *table, int write,
2260 void __user *buffer, size_t *lenp, loff_t *ppos) 2275 void __user *buffer, size_t *lenp, loff_t *ppos)
2261{ 2276{
2262 return do_proc_dointvec(table,write,buffer,lenp,ppos, 2277 return do_proc_dointvec(table, write, buffer, lenp, ppos, NULL, NULL);
2263 NULL,NULL); 2278}
2279
2280/**
2281 * proc_douintvec - read a vector of unsigned integers
2282 * @table: the sysctl table
2283 * @write: %TRUE if this is a write to the sysctl file
2284 * @buffer: the user buffer
2285 * @lenp: the size of the user buffer
2286 * @ppos: file position
2287 *
2288 * Reads/writes up to table->maxlen/sizeof(unsigned int) unsigned integer
2289 * values from/to the user buffer, treated as an ASCII string.
2290 *
2291 * Returns 0 on success.
2292 */
2293int proc_douintvec(struct ctl_table *table, int write,
2294 void __user *buffer, size_t *lenp, loff_t *ppos)
2295{
2296 return do_proc_dointvec(table, write, buffer, lenp, ppos,
2297 do_proc_douintvec_conv, NULL);
2264} 2298}
2265 2299
2266/* 2300/*
@@ -2858,6 +2892,12 @@ int proc_dointvec(struct ctl_table *table, int write,
2858 return -ENOSYS; 2892 return -ENOSYS;
2859} 2893}
2860 2894
2895int proc_douintvec(struct ctl_table *table, int write,
2896 void __user *buffer, size_t *lenp, loff_t *ppos)
2897{
2898 return -ENOSYS;
2899}
2900
2861int proc_dointvec_minmax(struct ctl_table *table, int write, 2901int proc_dointvec_minmax(struct ctl_table *table, int write,
2862 void __user *buffer, size_t *lenp, loff_t *ppos) 2902 void __user *buffer, size_t *lenp, loff_t *ppos)
2863{ 2903{
@@ -2903,6 +2943,7 @@ int proc_doulongvec_ms_jiffies_minmax(struct ctl_table *table, int write,
2903 * exception granted :-) 2943 * exception granted :-)
2904 */ 2944 */
2905EXPORT_SYMBOL(proc_dointvec); 2945EXPORT_SYMBOL(proc_dointvec);
2946EXPORT_SYMBOL(proc_douintvec);
2906EXPORT_SYMBOL(proc_dointvec_jiffies); 2947EXPORT_SYMBOL(proc_dointvec_jiffies);
2907EXPORT_SYMBOL(proc_dointvec_minmax); 2948EXPORT_SYMBOL(proc_dointvec_minmax);
2908EXPORT_SYMBOL(proc_dointvec_userhz_jiffies); 2949EXPORT_SYMBOL(proc_dointvec_userhz_jiffies);