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.

Merge tag 'sysctl-7.00-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/sysctl/sysctl

Pull sysctl updates from Joel Granados:

- Remove macros from proc handler converters

Replace the proc converter macros with "regular" functions. Though it
is more verbose than the macro version, it helps when debugging and
better aligns with coding-style.rst.

- General cleanup

Remove superfluous ctl_table forward declarations. Const qualify the
memory_allocation_profiling_sysctl and loadpin_sysctl_table arrays.
Add missing kernel doc to proc_dointvec_conv.

- Testing

This series was run through sysctl selftests/kunit test suite in
x86_64. And went into linux-next after rc4, giving it a good 3 weeks
of testing

* tag 'sysctl-7.00-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/sysctl/sysctl:
sysctl: replace SYSCTL_INT_CONV_CUSTOM macro with functions
sysctl: Replace unidirectional INT converter macros with functions
sysctl: Add kernel doc to proc_douintvec_conv
sysctl: Replace UINT converter macros with functions
sysctl: Add CONFIG_PROC_SYSCTL guards for converter macros
sysctl: clarify proc_douintvec_minmax doc
sysctl: Return -ENOSYS from proc_douintvec_conv when CONFIG_PROC_SYSCTL=n
sysctl: Remove unused ctl_table forward declarations
loadpin: Implement custom proc_handler for enforce
alloc_tag: move memory_allocation_profiling_sysctls into .rodata
sysctl: Add missing kernel-doc for proc_dointvec_conv

+438 -178
+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)
-1
include/linux/fs.h
··· 3525 3525 ssize_t simple_attr_write_signed(struct file *file, const char __user *buf, 3526 3526 size_t len, loff_t *ppos); 3527 3527 3528 - struct ctl_table; 3529 3528 int __init list_bdev_fs_names(char *buf, size_t size); 3530 3529 3531 3530 #define __FMODE_EXEC ((__force int) FMODE_EXEC)
-2
include/linux/hugetlb.h
··· 16 16 #include <linux/userfaultfd_k.h> 17 17 #include <linux/nodemask.h> 18 18 19 - struct ctl_table; 20 - struct user_struct; 21 19 struct mmu_gather; 22 20 struct node; 23 21
-1
include/linux/printk.h
··· 78 78 /* strlen("ratelimit") + 1 */ 79 79 #define DEVKMSG_STR_MAX_SIZE 10 80 80 extern char devkmsg_log_str[DEVKMSG_STR_MAX_SIZE]; 81 - struct ctl_table; 82 81 83 82 extern int suppress_printk; 84 83
+17 -103
include/linux/sysctl.h
··· 59 59 #define SYSCTL_LONG_ONE ((void *)&sysctl_long_vals[1]) 60 60 #define SYSCTL_LONG_MAX ((void *)&sysctl_long_vals[2]) 61 61 62 - #define SYSCTL_CONV_IDENTITY(val) (val) 63 62 /** 64 63 * 65 64 * "dir" originates from read_iter (dir = 0) or write_iter (dir = 1) ··· 72 73 #define SYSCTL_USER_TO_KERN(dir) (!!(dir)) 73 74 #define SYSCTL_KERN_TO_USER(dir) (!dir) 74 75 75 - #define SYSCTL_USER_TO_KERN_INT_CONV(name, u_ptr_op) \ 76 - int sysctl_user_to_kern_int_conv##name(const bool *negp, \ 77 - const unsigned long *u_ptr,\ 78 - int *k_ptr) \ 79 - { \ 80 - unsigned long u = u_ptr_op(*u_ptr); \ 81 - if (*negp) { \ 82 - if (u > (unsigned long) INT_MAX + 1) \ 83 - return -EINVAL; \ 84 - WRITE_ONCE(*k_ptr, -u); \ 85 - } else { \ 86 - if (u > (unsigned long) INT_MAX) \ 87 - return -EINVAL; \ 88 - WRITE_ONCE(*k_ptr, u); \ 89 - } \ 90 - return 0; \ 91 - } 92 - 93 - #define SYSCTL_KERN_TO_USER_INT_CONV(name, k_ptr_op) \ 94 - int sysctl_kern_to_user_int_conv##name(bool *negp, \ 95 - unsigned long *u_ptr, \ 96 - const int *k_ptr) \ 97 - { \ 98 - int val = READ_ONCE(*k_ptr); \ 99 - if (val < 0) { \ 100 - *negp = true; \ 101 - *u_ptr = -k_ptr_op((unsigned long)val); \ 102 - } else { \ 103 - *negp = false; \ 104 - *u_ptr = k_ptr_op((unsigned long)val); \ 105 - } \ 106 - return 0; \ 107 - } 108 - 109 - /** 110 - * To range check on a converted value, use a temp k_ptr 111 - * When checking range, value should be within (tbl->extra1, tbl->extra2) 112 - */ 113 - #define SYSCTL_INT_CONV_CUSTOM(name, user_to_kern, kern_to_user, \ 114 - k_ptr_range_check) \ 115 - int do_proc_int_conv##name(bool *negp, unsigned long *u_ptr, int *k_ptr,\ 116 - int dir, const struct ctl_table *tbl) \ 117 - { \ 118 - if (SYSCTL_KERN_TO_USER(dir)) \ 119 - return kern_to_user(negp, u_ptr, k_ptr); \ 120 - \ 121 - if (k_ptr_range_check) { \ 122 - int tmp_k, ret; \ 123 - if (!tbl) \ 124 - return -EINVAL; \ 125 - ret = user_to_kern(negp, u_ptr, &tmp_k); \ 126 - if (ret) \ 127 - return ret; \ 128 - if ((tbl->extra1 && *(int *)tbl->extra1 > tmp_k) || \ 129 - (tbl->extra2 && *(int *)tbl->extra2 < tmp_k)) \ 130 - return -EINVAL; \ 131 - WRITE_ONCE(*k_ptr, tmp_k); \ 132 - } else \ 133 - return user_to_kern(negp, u_ptr, k_ptr); \ 134 - return 0; \ 135 - } 136 - 137 - #define SYSCTL_USER_TO_KERN_UINT_CONV(name, u_ptr_op) \ 138 - int sysctl_user_to_kern_uint_conv##name(const unsigned long *u_ptr,\ 139 - unsigned int *k_ptr) \ 140 - { \ 141 - unsigned long u = u_ptr_op(*u_ptr); \ 142 - if (u > UINT_MAX) \ 143 - return -EINVAL; \ 144 - WRITE_ONCE(*k_ptr, u); \ 145 - return 0; \ 146 - } 147 - 148 - #define SYSCTL_UINT_CONV_CUSTOM(name, user_to_kern, kern_to_user, \ 149 - k_ptr_range_check) \ 150 - int do_proc_uint_conv##name(unsigned long *u_ptr, unsigned int *k_ptr, \ 151 - int dir, const struct ctl_table *tbl) \ 152 - { \ 153 - if (SYSCTL_KERN_TO_USER(dir)) \ 154 - return kern_to_user(u_ptr, k_ptr); \ 155 - \ 156 - if (k_ptr_range_check) { \ 157 - unsigned int tmp_k; \ 158 - int ret; \ 159 - if (!tbl) \ 160 - return -EINVAL; \ 161 - ret = user_to_kern(u_ptr, &tmp_k); \ 162 - if (ret) \ 163 - return ret; \ 164 - if ((tbl->extra1 && \ 165 - *(unsigned int *)tbl->extra1 > tmp_k) || \ 166 - (tbl->extra2 && \ 167 - *(unsigned int *)tbl->extra2 < tmp_k)) \ 168 - return -ERANGE; \ 169 - WRITE_ONCE(*k_ptr, tmp_k); \ 170 - } else \ 171 - return user_to_kern(u_ptr, k_ptr); \ 172 - return 0; \ 173 - } 174 - 175 - 176 76 extern const unsigned long sysctl_long_vals[]; 177 77 178 78 typedef int proc_handler(const struct ctl_table *ctl, int write, void *buffer, ··· 80 182 int proc_dostring(const struct ctl_table *, int, void *, size_t *, loff_t *); 81 183 int proc_dobool(const struct ctl_table *table, int write, void *buffer, 82 184 size_t *lenp, loff_t *ppos); 185 + 83 186 int proc_dointvec(const struct ctl_table *, int, void *, size_t *, loff_t *); 84 187 int proc_dointvec_minmax(const struct ctl_table *table, int dir, void *buffer, 85 188 size_t *lenp, loff_t *ppos); ··· 88 189 size_t *lenp, loff_t *ppos, 89 190 int (*conv)(bool *negp, unsigned long *u_ptr, int *k_ptr, 90 191 int dir, const struct ctl_table *table)); 192 + int proc_int_k2u_conv_kop(ulong *u_ptr, const int *k_ptr, bool *negp, 193 + ulong (*k_ptr_op)(const ulong)); 194 + int proc_int_u2k_conv_uop(const ulong *u_ptr, int *k_ptr, const bool *negp, 195 + ulong (*u_ptr_op)(const ulong)); 196 + int proc_int_conv(bool *negp, ulong *u_ptr, int *k_ptr, int dir, 197 + const struct ctl_table *tbl, bool k_ptr_range_check, 198 + int (*user_to_kern)(const bool *negp, const ulong *u_ptr, int *k_ptr), 199 + int (*kern_to_user)(bool *negp, ulong *u_ptr, const int *k_ptr)); 200 + 91 201 int proc_douintvec(const struct ctl_table *, int, void *, size_t *, loff_t *); 92 202 int proc_douintvec_minmax(const struct ctl_table *table, int write, void *buffer, 93 203 size_t *lenp, loff_t *ppos); ··· 104 196 size_t *lenp, loff_t *ppos, 105 197 int (*conv)(unsigned long *lvalp, unsigned int *valp, 106 198 int write, const struct ctl_table *table)); 199 + int proc_uint_k2u_conv(ulong *u_ptr, const uint *k_ptr); 200 + int proc_uint_u2k_conv_uop(const ulong *u_ptr, uint *k_ptr, 201 + ulong (*u_ptr_op)(const ulong)); 202 + int proc_uint_conv(ulong *u_ptr, uint *k_ptr, int dir, 203 + const struct ctl_table *tbl, bool k_ptr_range_check, 204 + int (*user_to_kern)(const ulong *u_ptr, uint *k_ptr), 205 + int (*kern_to_user)(ulong *u_ptr, const uint *k_ptr)); 107 206 108 207 int proc_dou8vec_minmax(const struct ctl_table *table, int write, void *buffer, 109 208 size_t *lenp, loff_t *ppos); ··· 121 206 int proc_do_large_bitmap(const struct ctl_table *, int, void *, size_t *, loff_t *); 122 207 int proc_do_static_key(const struct ctl_table *table, int write, void *buffer, 123 208 size_t *lenp, loff_t *ppos); 124 - int sysctl_kern_to_user_uint_conv(unsigned long *u_ptr, const unsigned int *k_ptr); 125 209 126 210 /* 127 211 * Register a set of sysctl names by calling register_sysctl
-2
include/net/ax25.h
··· 211 211 unsigned short slave_timeout; /* when? */ 212 212 } ax25_dama_info; 213 213 214 - struct ctl_table; 215 - 216 214 typedef struct ax25_dev { 217 215 struct list_head list; 218 216
+1 -1
kernel/printk/internal.h
··· 4 4 */ 5 5 #include <linux/console.h> 6 6 #include <linux/types.h> 7 + #include <linux/sysctl.h> 7 8 8 9 #if defined(CONFIG_PRINTK) && defined(CONFIG_SYSCTL) 9 - struct ctl_table; 10 10 void __init printk_sysctl_init(void); 11 11 int devkmsg_sysctl_set_loglvl(const struct ctl_table *table, int write, 12 12 void *buffer, size_t *lenp, loff_t *ppos);
-1
kernel/printk/sysctl.c
··· 3 3 * sysctl.c: General linux system control interface 4 4 */ 5 5 6 - #include <linux/sysctl.h> 7 6 #include <linux/printk.h> 8 7 #include <linux/capability.h> 9 8 #include <linux/ratelimit.h>
+274 -24
kernel/sysctl.c
··· 354 354 } 355 355 } 356 356 357 - static SYSCTL_USER_TO_KERN_INT_CONV(, SYSCTL_CONV_IDENTITY) 358 - static SYSCTL_KERN_TO_USER_INT_CONV(, SYSCTL_CONV_IDENTITY) 359 - 360 - static SYSCTL_INT_CONV_CUSTOM(, sysctl_user_to_kern_int_conv, 361 - sysctl_kern_to_user_int_conv, false) 362 - static SYSCTL_INT_CONV_CUSTOM(_minmax, sysctl_user_to_kern_int_conv, 363 - sysctl_kern_to_user_int_conv, true) 364 - 365 - 366 - static SYSCTL_USER_TO_KERN_UINT_CONV(, SYSCTL_CONV_IDENTITY) 367 - 368 - int sysctl_kern_to_user_uint_conv(unsigned long *u_ptr, 369 - const unsigned int *k_ptr) 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)) 370 372 { 371 - unsigned int val = READ_ONCE(*k_ptr); 372 - *u_ptr = (unsigned long)val; 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); 373 378 return 0; 374 379 } 375 380 376 - static SYSCTL_UINT_CONV_CUSTOM(, sysctl_user_to_kern_uint_conv, 377 - sysctl_kern_to_user_uint_conv, false) 378 - static SYSCTL_UINT_CONV_CUSTOM(_minmax, sysctl_user_to_kern_uint_conv, 379 - sysctl_kern_to_user_uint_conv, true) 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 + 461 + /** 462 + * proc_int_k2u_conv_kop - Assign kernel value to a user space pointer 463 + * @u_ptr: pointer to user space variable 464 + * @k_ptr: pointer to kernel variable 465 + * @negp: assigned %TRUE if the converted kernel value is negative; 466 + * %FALSE otherweise 467 + * @k_ptr_op: execute this function before assigning to u_ptr 468 + * 469 + * Uses READ_ONCE to get value from k_ptr. Executes k_ptr_op before assigning 470 + * to u_ptr if not NULL. Does **not** check for overflow. 471 + * 472 + * Returns: 0 on success. 473 + */ 474 + int proc_int_k2u_conv_kop(ulong *u_ptr, const int *k_ptr, bool *negp, 475 + ulong (*k_ptr_op)(const ulong)) 476 + { 477 + int val = READ_ONCE(*k_ptr); 478 + 479 + if (val < 0) { 480 + *negp = true; 481 + *u_ptr = k_ptr_op ? -k_ptr_op((ulong)val) : -(ulong)val; 482 + } else { 483 + *negp = false; 484 + *u_ptr = k_ptr_op ? k_ptr_op((ulong)val) : (ulong) val; 485 + } 486 + return 0; 487 + } 488 + 489 + /** 490 + * proc_int_u2k_conv_uop - Assign user value to a kernel pointer 491 + * @u_ptr: pointer to user space variable 492 + * @k_ptr: pointer to kernel variable 493 + * @negp: If %TRUE, the converted user value is made negative. 494 + * @u_ptr_op: execute this function before assigning to k_ptr 495 + * 496 + * Uses WRITE_ONCE to assign value to k_ptr. Executes u_ptr_op if 497 + * not NULL. Check for overflow with UINT_MAX. 498 + * 499 + * Returns: 0 on success. 500 + */ 501 + int proc_int_u2k_conv_uop(const ulong *u_ptr, int *k_ptr, const bool *negp, 502 + ulong (*u_ptr_op)(const ulong)) 503 + { 504 + ulong u = u_ptr_op ? u_ptr_op(*u_ptr) : *u_ptr; 505 + 506 + if (*negp) { 507 + if (u > (ulong) INT_MAX + 1) 508 + return -EINVAL; 509 + WRITE_ONCE(*k_ptr, -u); 510 + } else { 511 + if (u > (ulong) INT_MAX) 512 + return -EINVAL; 513 + WRITE_ONCE(*k_ptr, u); 514 + } 515 + return 0; 516 + } 517 + 518 + int proc_int_conv(bool *negp, ulong *u_ptr, int *k_ptr, int dir, 519 + const struct ctl_table *tbl, bool k_ptr_range_check, 520 + int (*user_to_kern)(const bool *negp, const ulong *u_ptr, int *k_ptr), 521 + int (*kern_to_user)(bool *negp, ulong *u_ptr, const int *k_ptr)) 522 + { 523 + if (SYSCTL_KERN_TO_USER(dir)) 524 + return kern_to_user(negp, u_ptr, k_ptr); 525 + 526 + if (k_ptr_range_check) { 527 + int tmp_k, ret; 528 + 529 + if (!tbl) 530 + return -EINVAL; 531 + ret = user_to_kern(negp, u_ptr, &tmp_k); 532 + if (ret) 533 + return ret; 534 + if ((tbl->extra1 && *(int *)tbl->extra1 > tmp_k) || 535 + (tbl->extra2 && *(int *)tbl->extra2 < tmp_k)) 536 + return -EINVAL; 537 + WRITE_ONCE(*k_ptr, tmp_k); 538 + } else 539 + return user_to_kern(negp, u_ptr, k_ptr); 540 + return 0; 541 + } 542 + 543 + 544 + 545 + static int sysctl_user_to_kern_int_conv(const bool *negp, const ulong *u_ptr, 546 + int *k_ptr) 547 + { 548 + return proc_int_u2k_conv_uop(u_ptr, k_ptr, negp, NULL); 549 + } 550 + 551 + static int sysctl_kern_to_user_int_conv(bool *negp, ulong *u_ptr, const int *k_ptr) 552 + { 553 + return proc_int_k2u_conv_kop(u_ptr, k_ptr, negp, NULL); 554 + } 555 + 556 + static int do_proc_int_conv(bool *negp, unsigned long *u_ptr, int *k_ptr, 557 + int dir, const struct ctl_table *tbl) 558 + { 559 + return proc_int_conv(negp, u_ptr, k_ptr, dir, tbl, false, 560 + sysctl_user_to_kern_int_conv, 561 + sysctl_kern_to_user_int_conv); 562 + 563 + } 564 + 565 + static int do_proc_int_conv_minmax(bool *negp, unsigned long *u_ptr, int *k_ptr, 566 + int dir, const struct ctl_table *tbl) 567 + { 568 + return proc_int_conv(negp, u_ptr, k_ptr, dir, tbl, true, 569 + sysctl_user_to_kern_int_conv, 570 + sysctl_kern_to_user_int_conv); 571 + } 380 572 381 573 static const char proc_wspace_sep[] = { ' ', '\t', '\n' }; 382 574 ··· 760 568 return do_proc_douintvec_r(table, buffer, lenp, ppos, conv); 761 569 } 762 570 571 + /** 572 + * proc_douintvec_conv - read a vector of unsigned ints with a custom converter 573 + * 574 + * @table: the sysctl table 575 + * @dir: %TRUE if this is a write to the sysctl file 576 + * @buffer: the user buffer 577 + * @lenp: the size of the user buffer 578 + * @ppos: file position 579 + * @conv: Custom converter call back 580 + * 581 + * Reads/writes up to table->maxlen/sizeof(unsigned int) unsigned integer 582 + * values from/to the user buffer, treated as an ASCII string. Negative 583 + * strings are not allowed. 584 + * 585 + * Returns 0 on success 586 + */ 763 587 int proc_douintvec_conv(const struct ctl_table *table, int dir, void *buffer, 764 588 size_t *lenp, loff_t *ppos, 765 589 int (*conv)(unsigned long *u_ptr, unsigned int *k_ptr, ··· 783 575 { 784 576 return do_proc_douintvec(table, dir, buffer, lenp, ppos, conv); 785 577 } 786 - 787 578 788 579 /** 789 580 * proc_dobool - read/write a bool ··· 899 692 * values from/to the user buffer, treated as an ASCII string. Negative 900 693 * strings are not allowed. 901 694 * 902 - * This routine will ensure the values are within the range specified by 903 - * table->extra1 (min) and table->extra2 (max). There is a final sanity 904 - * check for UINT_MAX to avoid having to support wrap around uses from 905 - * userspace. 695 + * When changing the kernel variable, this routine will ensure the values 696 + * are within the range specified by table->extra1 (min) and table->extra2 697 + * (max). And Check that the values are less than UINT_MAX to avoid having to 698 + * support wrap around uses from userspace. 906 699 * 907 700 * Returns 0 on success or -ERANGE when range check failes and 908 701 * SYSCTL_USER_TO_KERN(dir) == true ··· 1068 861 { 1069 862 return proc_doulongvec_minmax_conv(table, dir, buffer, lenp, ppos, 1l, 1l); 1070 863 } 864 + 865 + /** 866 + * proc_dointvec_conv - read a vector of ints with a custom converter 867 + * @table: the sysctl table 868 + * @dir: %TRUE if this is a write to the sysctl file 869 + * @buffer: the user buffer 870 + * @lenp: the size of the user buffer 871 + * @ppos: file position 872 + * @conv: Custom converter call back 873 + * 874 + * Reads/writes up to table->maxlen/sizeof(unsigned int) unsigned integer 875 + * values from/to the user buffer, treated as an ASCII string. Negative 876 + * strings are not allowed. 877 + * 878 + * Returns: 0 on success 879 + */ 1071 880 1072 881 int proc_dointvec_conv(const struct ctl_table *table, int dir, void *buffer, 1073 882 size_t *lenp, loff_t *ppos, ··· 1274 1051 1275 1052 int proc_douintvec_minmax(const struct ctl_table *table, int dir, 1276 1053 void *buffer, size_t *lenp, loff_t *ppos) 1054 + { 1055 + return -ENOSYS; 1056 + } 1057 + 1058 + int proc_douintvec_conv(const struct ctl_table *table, int write, void *buffer, 1059 + size_t *lenp, loff_t *ppos, 1060 + int (*conv)(unsigned long *lvalp, unsigned int *valp, 1061 + int write, const struct ctl_table *table)) 1062 + { 1063 + return -ENOSYS; 1064 + } 1065 + 1066 + int proc_uint_k2u_conv(ulong *u_ptr, const uint *k_ptr) 1067 + { 1068 + return -ENOSYS; 1069 + } 1070 + 1071 + int proc_uint_u2k_conv_uop(const ulong *u_ptr, uint *k_ptr, 1072 + ulong (*u_ptr_op)(const ulong)) 1073 + { 1074 + return -ENOSYS; 1075 + } 1076 + 1077 + int proc_uint_conv(ulong *u_ptr, uint *k_ptr, int dir, 1078 + const struct ctl_table *tbl, bool k_ptr_range_check, 1079 + int (*user_to_kern)(const ulong *u_ptr, uint *k_ptr), 1080 + int (*kern_to_user)(ulong *u_ptr, const uint *k_ptr)) 1277 1081 { 1278 1082 return -ENOSYS; 1279 1083 }
+112 -18
kernel/time/jiffies.c
··· 100 100 __clocksource_register(&refined_jiffies); 101 101 } 102 102 103 - #define SYSCTL_CONV_MULT_HZ(val) ((val) * HZ) 104 - #define SYSCTL_CONV_DIV_HZ(val) ((val) / HZ) 103 + #ifdef CONFIG_PROC_SYSCTL 104 + static ulong mult_hz(const ulong val) 105 + { 106 + return val * HZ; 107 + } 105 108 106 - static SYSCTL_USER_TO_KERN_INT_CONV(_hz, SYSCTL_CONV_MULT_HZ) 107 - static SYSCTL_KERN_TO_USER_INT_CONV(_hz, SYSCTL_CONV_DIV_HZ) 108 - static SYSCTL_USER_TO_KERN_INT_CONV(_userhz, clock_t_to_jiffies) 109 - static SYSCTL_KERN_TO_USER_INT_CONV(_userhz, jiffies_to_clock_t) 110 - static SYSCTL_USER_TO_KERN_INT_CONV(_ms, msecs_to_jiffies) 111 - static SYSCTL_KERN_TO_USER_INT_CONV(_ms, jiffies_to_msecs) 109 + static ulong div_hz(const ulong val) 110 + { 111 + return val / HZ; 112 + } 112 113 113 - static SYSCTL_INT_CONV_CUSTOM(_jiffies, sysctl_user_to_kern_int_conv_hz, 114 - sysctl_kern_to_user_int_conv_hz, false) 115 - static SYSCTL_INT_CONV_CUSTOM(_userhz_jiffies, 116 - sysctl_user_to_kern_int_conv_userhz, 117 - sysctl_kern_to_user_int_conv_userhz, false) 118 - static SYSCTL_INT_CONV_CUSTOM(_ms_jiffies, sysctl_user_to_kern_int_conv_ms, 119 - sysctl_kern_to_user_int_conv_ms, false) 120 - static SYSCTL_INT_CONV_CUSTOM(_ms_jiffies_minmax, 121 - sysctl_user_to_kern_int_conv_ms, 122 - sysctl_kern_to_user_int_conv_ms, true) 114 + static int sysctl_u2k_int_conv_hz(const bool *negp, const ulong *u_ptr, int *k_ptr) 115 + { 116 + return proc_int_u2k_conv_uop(u_ptr, k_ptr, negp, mult_hz); 117 + } 118 + 119 + static int sysctl_k2u_int_conv_hz(bool *negp, ulong *u_ptr, const int *k_ptr) 120 + { 121 + return proc_int_k2u_conv_kop(u_ptr, k_ptr, negp, div_hz); 122 + } 123 + 124 + static int sysctl_u2k_int_conv_userhz(const bool *negp, const ulong *u_ptr, int *k_ptr) 125 + { 126 + return proc_int_u2k_conv_uop(u_ptr, k_ptr, negp, clock_t_to_jiffies); 127 + } 128 + 129 + static ulong sysctl_jiffies_to_clock_t(const ulong val) 130 + { 131 + return jiffies_to_clock_t(val); 132 + } 133 + 134 + static int sysctl_k2u_int_conv_userhz(bool *negp, ulong *u_ptr, const int *k_ptr) 135 + { 136 + return proc_int_k2u_conv_kop(u_ptr, k_ptr, negp, sysctl_jiffies_to_clock_t); 137 + } 138 + 139 + static ulong sysctl_msecs_to_jiffies(const ulong val) 140 + { 141 + return msecs_to_jiffies(val); 142 + } 143 + 144 + static int sysctl_u2k_int_conv_ms(const bool *negp, const ulong *u_ptr, int *k_ptr) 145 + { 146 + return proc_int_u2k_conv_uop(u_ptr, k_ptr, negp, sysctl_msecs_to_jiffies); 147 + } 148 + 149 + static ulong sysctl_jiffies_to_msecs(const ulong val) 150 + { 151 + return jiffies_to_msecs(val); 152 + } 153 + 154 + static int sysctl_k2u_int_conv_ms(bool *negp, ulong *u_ptr, const int *k_ptr) 155 + { 156 + return proc_int_k2u_conv_kop(u_ptr, k_ptr, negp, sysctl_jiffies_to_msecs); 157 + } 158 + 159 + static int do_proc_int_conv_jiffies(bool *negp, ulong *u_ptr, int *k_ptr, 160 + int dir, const struct ctl_table *tbl) 161 + { 162 + return proc_int_conv(negp, u_ptr, k_ptr, dir, tbl, false, 163 + sysctl_u2k_int_conv_hz, sysctl_k2u_int_conv_hz); 164 + } 165 + 166 + static int do_proc_int_conv_userhz_jiffies(bool *negp, ulong *u_ptr, 167 + int *k_ptr, int dir, 168 + const struct ctl_table *tbl) 169 + { 170 + return proc_int_conv(negp, u_ptr, k_ptr, dir, tbl, false, 171 + sysctl_u2k_int_conv_userhz, 172 + sysctl_k2u_int_conv_userhz); 173 + } 174 + 175 + static int do_proc_int_conv_ms_jiffies(bool *negp, ulong *u_ptr, int *k_ptr, 176 + int dir, const struct ctl_table *tbl) 177 + { 178 + return proc_int_conv(negp, u_ptr, k_ptr, dir, tbl, false, 179 + sysctl_u2k_int_conv_ms, sysctl_k2u_int_conv_ms); 180 + } 181 + 182 + static int do_proc_int_conv_ms_jiffies_minmax(bool *negp, ulong *u_ptr, 183 + int *k_ptr, int dir, 184 + const struct ctl_table *tbl) 185 + { 186 + return proc_int_conv(negp, u_ptr, k_ptr, dir, tbl, false, 187 + sysctl_u2k_int_conv_ms, sysctl_k2u_int_conv_ms); 188 + } 189 + 190 + #else // CONFIG_PROC_SYSCTL 191 + static int do_proc_int_conv_jiffies(bool *negp, ulong *u_ptr, int *k_ptr, 192 + int dir, const struct ctl_table *tbl) 193 + { 194 + return -ENOSYS; 195 + } 196 + 197 + static int do_proc_int_conv_userhz_jiffies(bool *negp, ulong *u_ptr, 198 + int *k_ptr, int dir, 199 + const struct ctl_table *tbl) 200 + { 201 + return -ENOSYS; 202 + } 203 + 204 + static int do_proc_int_conv_ms_jiffies(bool *negp, ulong *u_ptr, int *k_ptr, 205 + int dir, const struct ctl_table *tbl) 206 + { 207 + return -ENOSYS; 208 + } 209 + 210 + static int do_proc_int_conv_ms_jiffies_minmax(bool *negp, ulong *u_ptr, 211 + int *k_ptr, int dir, 212 + const struct ctl_table *tbl) 213 + { 214 + return -ENOSYS; 215 + } 216 + #endif 123 217 124 218 /** 125 219 * proc_dointvec_jiffies - read a vector of integers as seconds
+16 -21
security/loadpin/loadpin.c
··· 53 53 static bool deny_reading_verity_digests; 54 54 #endif 55 55 56 + // initialized to false 57 + static bool loadpin_root_writable; 56 58 #ifdef CONFIG_SYSCTL 57 - static struct ctl_table loadpin_sysctl_table[] = { 59 + 60 + static int proc_handler_loadpin(const struct ctl_table *table, int dir, 61 + void *buffer, size_t *lenp, loff_t *ppos) 62 + { 63 + if (!loadpin_root_writable && SYSCTL_USER_TO_KERN(dir)) 64 + return -EINVAL; 65 + return proc_dointvec_minmax(table, dir, buffer, lenp, ppos); 66 + } 67 + 68 + static const struct ctl_table loadpin_sysctl_table[] = { 58 69 { 59 70 .procname = "enforce", 60 71 .data = &enforce, 61 72 .maxlen = sizeof(int), 62 73 .mode = 0644, 63 - .proc_handler = proc_dointvec_minmax, 64 - .extra1 = SYSCTL_ONE, 74 + .proc_handler = proc_handler_loadpin, 75 + .extra1 = SYSCTL_ZERO, 65 76 .extra2 = SYSCTL_ONE, 66 77 }, 67 78 }; 68 - 69 - static void set_sysctl(bool is_writable) 70 - { 71 - /* 72 - * If load pinning is not enforced via a read-only block 73 - * device, allow sysctl to change modes for testing. 74 - */ 75 - if (is_writable) 76 - loadpin_sysctl_table[0].extra1 = SYSCTL_ZERO; 77 - else 78 - loadpin_sysctl_table[0].extra1 = SYSCTL_ONE; 79 - } 80 - #else 81 - static inline void set_sysctl(bool is_writable) { } 82 79 #endif 83 80 84 81 static void report_writable(struct super_block *mnt_sb, bool writable) ··· 129 132 struct super_block *load_root; 130 133 const char *origin = kernel_read_file_id_str(id); 131 134 bool first_root_pin = false; 132 - bool load_root_writable; 133 135 134 136 /* If the file id is excluded, ignore the pinning. */ 135 137 if ((unsigned int)id < ARRAY_SIZE(ignore_read_file_id) && ··· 149 153 } 150 154 151 155 load_root = file->f_path.mnt->mnt_sb; 152 - load_root_writable = sb_is_writable(load_root); 153 156 154 157 /* First loaded module/firmware defines the root for all others. */ 155 158 spin_lock(&pinned_root_spinlock); ··· 164 169 spin_unlock(&pinned_root_spinlock); 165 170 166 171 if (first_root_pin) { 167 - report_writable(pinned_root, load_root_writable); 168 - set_sysctl(load_root_writable); 172 + loadpin_root_writable = sb_is_writable(pinned_root); 173 + report_writable(pinned_root, loadpin_root_writable); 169 174 report_load(origin, file, "pinned"); 170 175 } 171 176