Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

sysctl: Create converter functions with two new macros

Eight converter functions are created using two new macros
(SYSCTL_USER_TO_KERN_INT_CONV & SYSCTL_KERN_TO_USER_INT_CONV); they are
called from four pre-existing converter functions: do_proc_dointvec_conv
and do_proc_dointvec{,_userhz,_ms}_jiffies_conv. The function names
generated by the macros are differentiated by a string suffix passed as
the first macro argument.

The SYSCTL_USER_TO_KERN_INT_CONV macro first executes the u_ptr_op
operation, then checks for overflow, assigns sign (-, +) and finally
writes to the kernel var with WRITE_ONCE; it always returns an -EINVAL
when an overflow is detected. The SYSCTL_KERN_TO_USER_INT_CONV uses
READ_ONCE, casts to unsigned long, then executes the k_ptr_op before
assigning the value to the user space buffer.

The overflow check is always done against MAX_INT after applying
{k,u}_ptr_op. This approach avoids rounding or precision errors that
might occur when using the inverse operations.

Signed-off-by: Joel Granados <joel.granados@kernel.org>

+61 -70
+61 -70
kernel/sysctl.c
··· 368 368 } 369 369 } 370 370 371 + #define SYSCTL_USER_TO_KERN_INT_CONV(name, u_ptr_op) \ 372 + int sysctl_user_to_kern_int_conv##name(const bool *negp, \ 373 + const unsigned long *u_ptr,\ 374 + int *k_ptr) \ 375 + { \ 376 + unsigned long u = u_ptr_op(*u_ptr); \ 377 + if (*negp) { \ 378 + if (u > (unsigned long) INT_MAX + 1) \ 379 + return -EINVAL; \ 380 + WRITE_ONCE(*k_ptr, -u); \ 381 + } else { \ 382 + if (u > (unsigned long) INT_MAX) \ 383 + return -EINVAL; \ 384 + WRITE_ONCE(*k_ptr, u); \ 385 + } \ 386 + return 0; \ 387 + } 388 + 389 + #define SYSCTL_KERN_TO_USER_INT_CONV(name, k_ptr_op) \ 390 + int sysctl_kern_to_user_int_conv##name(bool *negp, \ 391 + unsigned long *u_ptr, \ 392 + const int *k_ptr) \ 393 + { \ 394 + int val = READ_ONCE(*k_ptr); \ 395 + if (val < 0) { \ 396 + *negp = true; \ 397 + *u_ptr = -k_ptr_op((unsigned long)val); \ 398 + } else { \ 399 + *negp = false; \ 400 + *u_ptr = k_ptr_op((unsigned long)val); \ 401 + } \ 402 + return 0; \ 403 + } 404 + 405 + #define SYSCTL_CONV_IDENTITY(val) val 406 + #define SYSCTL_CONV_MULT_HZ(val) ((val) * HZ) 407 + #define SYSCTL_CONV_DIV_HZ(val) ((val) / HZ) 408 + 409 + static SYSCTL_USER_TO_KERN_INT_CONV(, SYSCTL_CONV_IDENTITY) 410 + static SYSCTL_KERN_TO_USER_INT_CONV(, SYSCTL_CONV_IDENTITY) 411 + 412 + static SYSCTL_USER_TO_KERN_INT_CONV(_hz, SYSCTL_CONV_MULT_HZ) 413 + static SYSCTL_KERN_TO_USER_INT_CONV(_hz, SYSCTL_CONV_DIV_HZ) 414 + 415 + static SYSCTL_USER_TO_KERN_INT_CONV(_userhz, clock_t_to_jiffies) 416 + static SYSCTL_KERN_TO_USER_INT_CONV(_userhz, jiffies_to_clock_t) 417 + 418 + static SYSCTL_USER_TO_KERN_INT_CONV(_ms, msecs_to_jiffies) 419 + static SYSCTL_KERN_TO_USER_INT_CONV(_ms, jiffies_to_msecs) 420 + 371 421 static int do_proc_dointvec_conv(bool *negp, unsigned long *u_ptr, 372 422 int *k_ptr, int dir, 373 423 const struct ctl_table *table) 374 424 { 375 425 if (SYSCTL_USER_TO_KERN(dir)) { 376 - if (*negp) { 377 - if (*u_ptr > (unsigned long) INT_MAX + 1) 378 - return -EINVAL; 379 - WRITE_ONCE(*k_ptr, -*u_ptr); 380 - } else { 381 - if (*u_ptr > (unsigned long) INT_MAX) 382 - return -EINVAL; 383 - WRITE_ONCE(*k_ptr, *u_ptr); 384 - } 385 - } else { 386 - int val = READ_ONCE(*k_ptr); 387 - if (val < 0) { 388 - *negp = true; 389 - *u_ptr = -(unsigned long)val; 390 - } else { 391 - *negp = false; 392 - *u_ptr = (unsigned long)val; 393 - } 426 + return sysctl_user_to_kern_int_conv(negp, u_ptr, k_ptr); 394 427 } 395 - return 0; 428 + 429 + return sysctl_kern_to_user_int_conv(negp, u_ptr, k_ptr); 396 430 } 397 431 398 432 static int do_proc_douintvec_conv(unsigned long *u_ptr, ··· 986 952 lenp, ppos, HZ, 1000l); 987 953 } 988 954 989 - 990 955 static int do_proc_dointvec_jiffies_conv(bool *negp, unsigned long *u_ptr, 991 956 int *k_ptr, int dir, 992 957 const struct ctl_table *table) 993 958 { 994 959 if (SYSCTL_USER_TO_KERN(dir)) { 995 - if (*u_ptr > INT_MAX / HZ) 996 - return 1; 997 - if (*negp) 998 - WRITE_ONCE(*k_ptr, -*u_ptr * HZ); 999 - else 1000 - WRITE_ONCE(*k_ptr, *u_ptr * HZ); 1001 - } else { 1002 - int val = READ_ONCE(*k_ptr); 1003 - unsigned long lval; 1004 - if (val < 0) { 1005 - *negp = true; 1006 - lval = -(unsigned long)val; 1007 - } else { 1008 - *negp = false; 1009 - lval = (unsigned long)val; 1010 - } 1011 - *u_ptr = lval / HZ; 960 + return sysctl_user_to_kern_int_conv_hz(negp, u_ptr, k_ptr); 1012 961 } 1013 - return 0; 962 + return sysctl_kern_to_user_int_conv_hz(negp, u_ptr, k_ptr); 1014 963 } 1015 964 1016 965 static int do_proc_dointvec_userhz_jiffies_conv(bool *negp, unsigned long *u_ptr, ··· 1001 984 const struct ctl_table *table) 1002 985 { 1003 986 if (SYSCTL_USER_TO_KERN(dir)) { 1004 - if (USER_HZ < HZ && (LONG_MAX / HZ) * USER_HZ < *u_ptr) 1005 - return 1; 1006 - *k_ptr = clock_t_to_jiffies(*negp ? -*u_ptr : *u_ptr); 1007 - } else { 1008 - int val = *k_ptr; 1009 - unsigned long lval; 1010 - if (val < 0) { 1011 - *negp = true; 1012 - lval = -(unsigned long)val; 1013 - } else { 1014 - *negp = false; 1015 - lval = (unsigned long)val; 1016 - } 1017 - *u_ptr = jiffies_to_clock_t(lval); 987 + if (USER_HZ < HZ) 988 + return -EINVAL; 989 + return sysctl_user_to_kern_int_conv_userhz(negp, u_ptr, k_ptr); 1018 990 } 1019 - return 0; 991 + return sysctl_kern_to_user_int_conv_userhz(negp, u_ptr, k_ptr); 1020 992 } 1021 993 1022 994 static int do_proc_dointvec_ms_jiffies_conv(bool *negp, unsigned long *u_ptr, ··· 1013 1007 const struct ctl_table *table) 1014 1008 { 1015 1009 if (SYSCTL_USER_TO_KERN(dir)) { 1016 - unsigned long jif = msecs_to_jiffies(*negp ? -*u_ptr : *u_ptr); 1017 - 1018 - if (jif > INT_MAX) 1019 - return 1; 1020 - WRITE_ONCE(*k_ptr, (int)jif); 1021 - } else { 1022 - int val = READ_ONCE(*k_ptr); 1023 - unsigned long lval; 1024 - if (val < 0) { 1025 - *negp = true; 1026 - lval = -(unsigned long)val; 1027 - } else { 1028 - *negp = false; 1029 - lval = (unsigned long)val; 1030 - } 1031 - *u_ptr = jiffies_to_msecs(lval); 1010 + return sysctl_user_to_kern_int_conv_ms(negp, u_ptr, k_ptr); 1032 1011 } 1033 - return 0; 1012 + return sysctl_kern_to_user_int_conv_ms(negp, u_ptr, k_ptr); 1034 1013 } 1035 1014 1036 1015 static int do_proc_dointvec_ms_jiffies_minmax_conv(bool *negp, unsigned long *u_ptr,