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

sysctl: Replace UINT converter macros with functions

Replace the SYSCTL_USER_TO_KERN_UINT_CONV and SYSCTL_UINT_CONV_CUSTOM
macros with functions with the same logic. This makes debugging easier
and aligns with the functions preference described in coding-style.rst.
Update the only user of this API: pipe.c.

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

+148 -77
+18 -4
fs/pipe.c
··· 1481 1481 }; 1482 1482 1483 1483 #ifdef CONFIG_SYSCTL 1484 - static SYSCTL_USER_TO_KERN_UINT_CONV(_pipe_maxsz, round_pipe_size) 1485 - static SYSCTL_UINT_CONV_CUSTOM(_pipe_maxsz, 1486 - sysctl_user_to_kern_uint_conv_pipe_maxsz, 1487 - sysctl_kern_to_user_uint_conv, true) 1484 + 1485 + static ulong round_pipe_size_ul(ulong size) 1486 + { 1487 + return round_pipe_size(size); 1488 + } 1489 + 1490 + static int u2k_pipe_maxsz(const ulong *u_ptr, uint *k_ptr) 1491 + { 1492 + return proc_uint_u2k_conv_uop(u_ptr, k_ptr, round_pipe_size_ul); 1493 + } 1494 + 1495 + static int do_proc_uint_conv_pipe_maxsz(ulong *u_ptr, uint *k_ptr, 1496 + int dir, const struct ctl_table *table) 1497 + { 1498 + return proc_uint_conv(u_ptr, k_ptr, dir, table, true, 1499 + u2k_pipe_maxsz, 1500 + proc_uint_k2u_conv); 1501 + } 1488 1502 1489 1503 static int proc_dopipe_max_size(const struct ctl_table *table, int write, 1490 1504 void *buffer, size_t *lenp, loff_t *ppos)
+7 -56
include/linux/sysctl.h
··· 135 135 return user_to_kern(negp, u_ptr, k_ptr); \ 136 136 return 0; \ 137 137 } 138 - 139 - #define SYSCTL_USER_TO_KERN_UINT_CONV(name, u_ptr_op) \ 140 - int sysctl_user_to_kern_uint_conv##name(const unsigned long *u_ptr,\ 141 - unsigned int *k_ptr) \ 142 - { \ 143 - unsigned long u = u_ptr_op(*u_ptr); \ 144 - if (u > UINT_MAX) \ 145 - return -EINVAL; \ 146 - WRITE_ONCE(*k_ptr, u); \ 147 - return 0; \ 148 - } 149 - 150 - #define SYSCTL_UINT_CONV_CUSTOM(name, user_to_kern, kern_to_user, \ 151 - k_ptr_range_check) \ 152 - int do_proc_uint_conv##name(unsigned long *u_ptr, unsigned int *k_ptr, \ 153 - int dir, const struct ctl_table *tbl) \ 154 - { \ 155 - if (SYSCTL_KERN_TO_USER(dir)) \ 156 - return kern_to_user(u_ptr, k_ptr); \ 157 - \ 158 - if (k_ptr_range_check) { \ 159 - unsigned int tmp_k; \ 160 - int ret; \ 161 - if (!tbl) \ 162 - return -EINVAL; \ 163 - ret = user_to_kern(u_ptr, &tmp_k); \ 164 - if (ret) \ 165 - return ret; \ 166 - if ((tbl->extra1 && \ 167 - *(unsigned int *)tbl->extra1 > tmp_k) || \ 168 - (tbl->extra2 && \ 169 - *(unsigned int *)tbl->extra2 < tmp_k)) \ 170 - return -ERANGE; \ 171 - WRITE_ONCE(*k_ptr, tmp_k); \ 172 - } else \ 173 - return user_to_kern(u_ptr, k_ptr); \ 174 - return 0; \ 175 - } 176 - 177 138 #else // CONFIG_PROC_SYSCTL 178 139 #define SYSCTL_USER_TO_KERN_INT_CONV(name, u_ptr_op) \ 179 140 int sysctl_user_to_kern_int_conv##name(const bool *negp, \ ··· 160 199 return -ENOSYS; \ 161 200 } 162 201 163 - #define SYSCTL_USER_TO_KERN_UINT_CONV(name, u_ptr_op) \ 164 - int sysctl_user_to_kern_uint_conv##name(const unsigned long *u_ptr,\ 165 - unsigned int *k_ptr) \ 166 - { \ 167 - return -ENOSYS; \ 168 - } 169 - 170 - #define SYSCTL_UINT_CONV_CUSTOM(name, user_to_kern, kern_to_user, \ 171 - k_ptr_range_check) \ 172 - int do_proc_uint_conv##name(unsigned long *u_ptr, unsigned int *k_ptr, \ 173 - int dir, const struct ctl_table *tbl) \ 174 - { \ 175 - return -ENOSYS; \ 176 - } 177 - 178 202 #endif // CONFIG_PROC_SYSCTL 179 - 180 203 181 204 extern const unsigned long sysctl_long_vals[]; 182 205 ··· 184 239 size_t *lenp, loff_t *ppos, 185 240 int (*conv)(unsigned long *lvalp, unsigned int *valp, 186 241 int write, const struct ctl_table *table)); 242 + int proc_uint_k2u_conv(ulong *u_ptr, const uint *k_ptr); 243 + int proc_uint_u2k_conv_uop(const ulong *u_ptr, uint *k_ptr, 244 + ulong (*u_ptr_op)(const ulong)); 245 + int proc_uint_conv(ulong *u_ptr, uint *k_ptr, int dir, 246 + const struct ctl_table *tbl, bool k_ptr_range_check, 247 + int (*user_to_kern)(const ulong *u_ptr, uint *k_ptr), 248 + int (*kern_to_user)(ulong *u_ptr, const uint *k_ptr)); 187 249 188 250 int proc_dou8vec_minmax(const struct ctl_table *table, int write, void *buffer, 189 251 size_t *lenp, loff_t *ppos); ··· 201 249 int proc_do_large_bitmap(const struct ctl_table *, int, void *, size_t *, loff_t *); 202 250 int proc_do_static_key(const struct ctl_table *table, int write, void *buffer, 203 251 size_t *lenp, loff_t *ppos); 204 - int sysctl_kern_to_user_uint_conv(unsigned long *u_ptr, const unsigned int *k_ptr); 205 252 206 253 /* 207 254 * Register a set of sysctl names by calling register_sysctl
+123 -17
kernel/sysctl.c
··· 354 354 } 355 355 } 356 356 357 + /** 358 + * proc_uint_u2k_conv_uop - Assign user value to a kernel pointer 359 + * 360 + * @u_ptr: pointer to user space variable 361 + * @k_ptr: pointer to kernel variable 362 + * @u_ptr_op: execute this function before assigning to k_ptr 363 + * 364 + * Uses WRITE_ONCE to assign value to k_ptr. Executes u_ptr_op if 365 + * not NULL. Check that the values are less than UINT_MAX to avoid 366 + * having to support wrap around from userspace. 367 + * 368 + * returns 0 on success. 369 + */ 370 + int proc_uint_u2k_conv_uop(const ulong *u_ptr, uint *k_ptr, 371 + ulong (*u_ptr_op)(const ulong)) 372 + { 373 + ulong u = u_ptr_op ? u_ptr_op(*u_ptr) : *u_ptr; 374 + 375 + if (u > UINT_MAX) 376 + return -EINVAL; 377 + WRITE_ONCE(*k_ptr, u); 378 + return 0; 379 + } 380 + 381 + /** 382 + * proc_uint_k2u_conv - Assign kernel value to a user space pointer 383 + * 384 + * @u_ptr: pointer to user space variable 385 + * @k_ptr: pointer to kernel variable 386 + * 387 + * Uses READ_ONCE to assign value to u_ptr. 388 + * 389 + * returns 0 on success. 390 + */ 391 + int proc_uint_k2u_conv(ulong *u_ptr, const uint *k_ptr) 392 + { 393 + uint val = READ_ONCE(*k_ptr); 394 + *u_ptr = (ulong)val; 395 + return 0; 396 + } 397 + 398 + /** 399 + * proc_uint_conv - Change user or kernel pointer based on direction 400 + * 401 + * @u_ptr: pointer to user variable 402 + * @k_ptr: pointer to kernel variable 403 + * @dir: %TRUE if this is a write to the sysctl file 404 + * @tbl: the sysctl table 405 + * @k_ptr_range_check: Check range for k_ptr when %TRUE 406 + * @user_to_kern: Callback used to assign value from user to kernel var 407 + * @kern_to_user: Callback used to assign value from kernel to user var 408 + * 409 + * When direction is kernel to user, then the u_ptr is modified. 410 + * When direction is user to kernel, then the k_ptr is modified. 411 + * 412 + * Returns 0 on success 413 + */ 414 + int proc_uint_conv(ulong *u_ptr, uint *k_ptr, int dir, 415 + const struct ctl_table *tbl, bool k_ptr_range_check, 416 + int (*user_to_kern)(const ulong *u_ptr, uint *k_ptr), 417 + int (*kern_to_user)(ulong *u_ptr, const uint *k_ptr)) 418 + { 419 + if (SYSCTL_KERN_TO_USER(dir)) 420 + return kern_to_user(u_ptr, k_ptr); 421 + 422 + if (k_ptr_range_check) { 423 + uint tmp_k; 424 + int ret; 425 + 426 + if (!tbl) 427 + return -EINVAL; 428 + ret = user_to_kern(u_ptr, &tmp_k); 429 + if (ret) 430 + return ret; 431 + if ((tbl->extra1 && 432 + *(uint *)tbl->extra1 > tmp_k) || 433 + (tbl->extra2 && 434 + *(uint *)tbl->extra2 < tmp_k)) 435 + return -ERANGE; 436 + WRITE_ONCE(*k_ptr, tmp_k); 437 + } else 438 + return user_to_kern(u_ptr, k_ptr); 439 + return 0; 440 + } 441 + 442 + static int proc_uint_u2k_conv(const ulong *u_ptr, uint *k_ptr) 443 + { 444 + return proc_uint_u2k_conv_uop(u_ptr, k_ptr, NULL); 445 + } 446 + 447 + static int do_proc_uint_conv(ulong *u_ptr, uint *k_ptr, int dir, 448 + const struct ctl_table *tbl) 449 + { 450 + return proc_uint_conv(u_ptr, k_ptr, dir, tbl, false, 451 + proc_uint_u2k_conv, proc_uint_k2u_conv); 452 + } 453 + 454 + static int do_proc_uint_conv_minmax(ulong *u_ptr, uint *k_ptr, int dir, 455 + const struct ctl_table *tbl) 456 + { 457 + return proc_uint_conv(u_ptr, k_ptr, dir, tbl, true, 458 + proc_uint_u2k_conv, proc_uint_k2u_conv); 459 + } 460 + 357 461 static SYSCTL_USER_TO_KERN_INT_CONV(, SYSCTL_CONV_IDENTITY) 358 462 static SYSCTL_KERN_TO_USER_INT_CONV(, SYSCTL_CONV_IDENTITY) 359 463 ··· 465 361 sysctl_kern_to_user_int_conv, false) 466 362 static SYSCTL_INT_CONV_CUSTOM(_minmax, sysctl_user_to_kern_int_conv, 467 363 sysctl_kern_to_user_int_conv, true) 468 - 469 - 470 - static SYSCTL_USER_TO_KERN_UINT_CONV(, SYSCTL_CONV_IDENTITY) 471 - 472 - int sysctl_kern_to_user_uint_conv(unsigned long *u_ptr, 473 - const unsigned int *k_ptr) 474 - { 475 - unsigned int val = READ_ONCE(*k_ptr); 476 - *u_ptr = (unsigned long)val; 477 - return 0; 478 - } 479 - 480 - static SYSCTL_UINT_CONV_CUSTOM(, sysctl_user_to_kern_uint_conv, 481 - sysctl_kern_to_user_uint_conv, false) 482 - static SYSCTL_UINT_CONV_CUSTOM(_minmax, sysctl_user_to_kern_uint_conv, 483 - sysctl_kern_to_user_uint_conv, true) 484 364 485 365 static const char proc_wspace_sep[] = { ' ', '\t', '\n' }; 486 366 ··· 663 575 { 664 576 return do_proc_douintvec(table, dir, buffer, lenp, ppos, conv); 665 577 } 666 - 667 578 668 579 /** 669 580 * proc_dobool - read/write a bool ··· 1162 1075 size_t *lenp, loff_t *ppos, 1163 1076 int (*conv)(unsigned long *lvalp, unsigned int *valp, 1164 1077 int write, const struct ctl_table *table)) 1078 + { 1079 + return -ENOSYS; 1080 + } 1081 + 1082 + int proc_uint_k2u_conv(ulong *u_ptr, const uint *k_ptr) 1083 + { 1084 + return -ENOSYS; 1085 + } 1086 + 1087 + int proc_uint_u2k_conv_uop(const ulong *u_ptr, uint *k_ptr, 1088 + ulong (*u_ptr_op)(const ulong)) 1089 + { 1090 + return -ENOSYS; 1091 + } 1092 + 1093 + int proc_uint_conv(ulong *u_ptr, uint *k_ptr, int dir, 1094 + const struct ctl_table *tbl, bool k_ptr_range_check, 1095 + int (*user_to_kern)(const ulong *u_ptr, uint *k_ptr), 1096 + int (*kern_to_user)(ulong *u_ptr, const uint *k_ptr)) 1165 1097 { 1166 1098 return -ENOSYS; 1167 1099 }