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: Indicate the direction of operation with macro names

Replace the "write" integer parameter with SYSCTL_USER_TO_KERN() and
SYSCTL_KERN_TO_USER() that clearly indicate data flow direction in
sysctl operations.

"write" originates in proc_sysctl.c (proc_sys_{read,write}) and can take
one of two values: "0" or "1" when called from proc_sys_read and
proc_sys_write respectively. When write has a value of zero, data is
"written" to a user space buffer from a kernel variable (usually
ctl_table->data). Whereas when write has a value greater than zero, data
is "written" to an internal kernel variable from a user space buffer.
Remove this ambiguity by introducing macros that clearly indicate the
direction of the "write".

The write mode names in sysctl_writes_mode are left unchanged as these
directly relate to the sysctl_write_strict file in /proc/sys where the
word "write" unambiguously refers to writing to a file.

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

+136 -116
+136 -116
kernel/sysctl.c
··· 30 30 const unsigned long sysctl_long_vals[] = { 0, 1, LONG_MAX }; 31 31 EXPORT_SYMBOL_GPL(sysctl_long_vals); 32 32 33 + /** 34 + * 35 + * "dir" originates from read_iter (dir = 0) or write_iter (dir = 1) 36 + * in the file_operations struct at proc/proc_sysctl.c. Its value means 37 + * one of two things for sysctl: 38 + * 1. SYSCTL_USER_TO_KERN(dir) Writing to an internal kernel variable from user 39 + * space (dir > 0) 40 + * 2. SYSCTL_KERN_TO_USER(dir) Writing to a user space buffer from a kernel 41 + * variable (dir == 0). 42 + */ 43 + #define SYSCTL_USER_TO_KERN(dir) (!!(dir)) 44 + #define SYSCTL_KERN_TO_USER(dir) (!dir) 45 + 33 46 #if defined(CONFIG_SYSCTL) 34 47 35 48 /* Constants used for minimum and maximum */ ··· 68 55 * to the buffer. 69 56 * 70 57 * These write modes control how current file position affects the behavior of 71 - * updating sysctl values through the proc interface on each write. 58 + * updating internal kernel (SYSCTL_USER_TO_KERN) sysctl values through the proc 59 + * interface on each write. 72 60 */ 73 61 enum sysctl_writes_mode { 74 62 SYSCTL_WRITES_LEGACY = -1, ··· 87 73 88 74 #ifdef CONFIG_PROC_SYSCTL 89 75 90 - static int _proc_do_string(char *data, int maxlen, int write, 76 + static int _proc_do_string(char *data, int maxlen, int dir, 91 77 char *buffer, size_t *lenp, loff_t *ppos) 92 78 { 93 79 size_t len; ··· 98 84 return 0; 99 85 } 100 86 101 - if (write) { 87 + if (SYSCTL_USER_TO_KERN(dir)) { 102 88 if (sysctl_writes_strict == SYSCTL_WRITES_STRICT) { 103 89 /* Only continue writes not past the end of buffer. */ 104 90 len = strlen(data); ··· 186 172 /** 187 173 * proc_dostring - read a string sysctl 188 174 * @table: the sysctl table 189 - * @write: %TRUE if this is a write to the sysctl file 175 + * @dir: %TRUE if this is a write to the sysctl file 190 176 * @buffer: the user buffer 191 177 * @lenp: the size of the user buffer 192 178 * @ppos: file position ··· 200 186 * 201 187 * Returns 0 on success. 202 188 */ 203 - int proc_dostring(const struct ctl_table *table, int write, 189 + int proc_dostring(const struct ctl_table *table, int dir, 204 190 void *buffer, size_t *lenp, loff_t *ppos) 205 191 { 206 - if (write) 192 + if (SYSCTL_USER_TO_KERN(dir)) 207 193 proc_first_pos_non_zero_ignore(ppos, table); 208 194 209 - return _proc_do_string(table->data, table->maxlen, write, buffer, lenp, 195 + return _proc_do_string(table->data, table->maxlen, dir, buffer, lenp, 210 196 ppos); 211 197 } 212 198 ··· 369 355 } 370 356 371 357 static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp, 372 - int *valp, int write, 358 + int *valp, int dir, 373 359 const struct ctl_table *table) 374 360 { 375 - if (write) { 361 + if (SYSCTL_USER_TO_KERN(dir)) { 376 362 if (*negp) { 377 363 if (*lvalp > (unsigned long) INT_MAX + 1) 378 364 return -EINVAL; ··· 396 382 } 397 383 398 384 static int do_proc_douintvec_conv(unsigned long *lvalp, 399 - unsigned int *valp, int write, 385 + unsigned int *valp, int dir, 400 386 const struct ctl_table *table) 401 387 { 402 - if (write) { 388 + if (SYSCTL_USER_TO_KERN(dir)) { 403 389 if (*lvalp > UINT_MAX) 404 390 return -EINVAL; 405 391 WRITE_ONCE(*valp, *lvalp); ··· 413 399 static const char proc_wspace_sep[] = { ' ', '\t', '\n' }; 414 400 415 401 416 - static int do_proc_dointvec(const struct ctl_table *table, int write, 402 + static int do_proc_dointvec(const struct ctl_table *table, int dir, 417 403 void *buffer, size_t *lenp, loff_t *ppos, 418 404 int (*conv)(bool *negp, unsigned long *lvalp, int *valp, 419 - int write, const struct ctl_table *table)) 405 + int dir, const struct ctl_table *table)) 420 406 { 421 407 int *i, vleft, first = 1, err = 0; 422 408 size_t left; 423 409 char *p; 424 410 425 - if (!table->data || !table->maxlen || !*lenp || (*ppos && !write)) { 411 + if (!table->data || !table->maxlen || !*lenp || 412 + (*ppos && SYSCTL_KERN_TO_USER(dir))) { 426 413 *lenp = 0; 427 414 return 0; 428 415 } ··· 435 420 if (!conv) 436 421 conv = do_proc_dointvec_conv; 437 422 438 - if (write) { 423 + if (SYSCTL_USER_TO_KERN(dir)) { 439 424 if (proc_first_pos_non_zero_ignore(ppos, table)) 440 425 goto out; 441 426 ··· 448 433 unsigned long lval; 449 434 bool neg; 450 435 451 - if (write) { 436 + if (SYSCTL_USER_TO_KERN(dir)) { 452 437 proc_skip_spaces(&p, &left); 453 438 454 439 if (!left) ··· 473 458 } 474 459 } 475 460 476 - if (!write && !first && left && !err) 461 + if (SYSCTL_KERN_TO_USER(dir) && !first && left && !err) 477 462 proc_put_char(&buffer, &left, '\n'); 478 - if (write && !err && left) 463 + if (SYSCTL_USER_TO_KERN(dir) && !err && left) 479 464 proc_skip_spaces(&p, &left); 480 - if (write && first) 465 + if (SYSCTL_USER_TO_KERN(dir) && first) 481 466 return err ? : -EINVAL; 482 467 *lenp -= left; 483 468 out: ··· 488 473 static int do_proc_douintvec_w(const struct ctl_table *table, void *buffer, 489 474 size_t *lenp, loff_t *ppos, 490 475 int (*conv)(unsigned long *lvalp, 491 - unsigned int *valp, int write, 476 + unsigned int *valp, int dir, 492 477 const struct ctl_table *table)) 493 478 { 494 479 unsigned long lval; ··· 541 526 static int do_proc_douintvec_r(const struct ctl_table *table, void *buffer, 542 527 size_t *lenp, loff_t *ppos, 543 528 int (*conv)(unsigned long *lvalp, 544 - unsigned int *valp, int write, 529 + unsigned int *valp, int dir, 545 530 const struct ctl_table *table)) 546 531 { 547 532 unsigned long lval; ··· 568 553 return err; 569 554 } 570 555 571 - int do_proc_douintvec(const struct ctl_table *table, int write, void *buffer, 556 + int do_proc_douintvec(const struct ctl_table *table, int dir, void *buffer, 572 557 size_t *lenp, loff_t *ppos, 573 558 int (*conv)(unsigned long *lvalp, unsigned int *valp, 574 - int write, const struct ctl_table *table)) 559 + int dir, const struct ctl_table *table)) 575 560 { 576 561 unsigned int vleft; 577 562 578 - if (!table->data || !table->maxlen || !*lenp || (*ppos && !write)) { 563 + if (!table->data || !table->maxlen || !*lenp || 564 + (*ppos && SYSCTL_KERN_TO_USER(dir))) { 579 565 *lenp = 0; 580 566 return 0; 581 567 } ··· 595 579 if (!conv) 596 580 conv = do_proc_douintvec_conv; 597 581 598 - if (write) 582 + if (SYSCTL_USER_TO_KERN(dir)) 599 583 return do_proc_douintvec_w(table, buffer, lenp, ppos, conv); 600 584 return do_proc_douintvec_r(table, buffer, lenp, ppos, conv); 601 585 } ··· 603 587 /** 604 588 * proc_dobool - read/write a bool 605 589 * @table: the sysctl table 606 - * @write: %TRUE if this is a write to the sysctl file 590 + * @dir: %TRUE if this is a write to the sysctl file 607 591 * @buffer: the user buffer 608 592 * @lenp: the size of the user buffer 609 593 * @ppos: file position ··· 616 600 * 617 601 * Returns 0 on success. 618 602 */ 619 - int proc_dobool(const struct ctl_table *table, int write, void *buffer, 603 + int proc_dobool(const struct ctl_table *table, int dir, void *buffer, 620 604 size_t *lenp, loff_t *ppos) 621 605 { 622 606 struct ctl_table tmp; ··· 632 616 tmp.data = &val; 633 617 634 618 val = READ_ONCE(*data); 635 - res = proc_dointvec(&tmp, write, buffer, lenp, ppos); 619 + res = proc_dointvec(&tmp, dir, buffer, lenp, ppos); 636 620 if (res) 637 621 return res; 638 - if (write) 622 + if (SYSCTL_USER_TO_KERN(dir)) 639 623 WRITE_ONCE(*data, val); 640 624 return 0; 641 625 } ··· 643 627 /** 644 628 * proc_dointvec - read a vector of integers 645 629 * @table: the sysctl table 646 - * @write: %TRUE if this is a write to the sysctl file 630 + * @dir: %TRUE if this is a write to the sysctl file 647 631 * @buffer: the user buffer 648 632 * @lenp: the size of the user buffer 649 633 * @ppos: file position ··· 653 637 * 654 638 * Returns 0 on success. 655 639 */ 656 - int proc_dointvec(const struct ctl_table *table, int write, void *buffer, 640 + int proc_dointvec(const struct ctl_table *table, int dir, void *buffer, 657 641 size_t *lenp, loff_t *ppos) 658 642 { 659 - return do_proc_dointvec(table, write, buffer, lenp, ppos, NULL); 643 + return do_proc_dointvec(table, dir, buffer, lenp, ppos, NULL); 660 644 } 661 645 662 646 /** 663 647 * proc_douintvec - read a vector of unsigned integers 664 648 * @table: the sysctl table 665 - * @write: %TRUE if this is a write to the sysctl file 649 + * @dir: %TRUE if this is a write to the sysctl file 666 650 * @buffer: the user buffer 667 651 * @lenp: the size of the user buffer 668 652 * @ppos: file position ··· 672 656 * 673 657 * Returns 0 on success. 674 658 */ 675 - int proc_douintvec(const struct ctl_table *table, int write, void *buffer, 659 + int proc_douintvec(const struct ctl_table *table, int dir, void *buffer, 676 660 size_t *lenp, loff_t *ppos) 677 661 { 678 - return do_proc_douintvec(table, write, buffer, lenp, ppos, 662 + return do_proc_douintvec(table, dir, buffer, lenp, ppos, 679 663 do_proc_douintvec_conv); 680 664 } 681 665 682 666 static int do_proc_dointvec_minmax_conv(bool *negp, unsigned long *lvalp, 683 - int *valp, int write, 667 + int *valp, int dir, 684 668 const struct ctl_table *table) 685 669 { 686 670 int tmp, ret, *min, *max; ··· 688 672 * If writing, first do so via a temporary local int so we can 689 673 * bounds-check it before touching *valp. 690 674 */ 691 - int *ip = write ? &tmp : valp; 675 + int *ip = SYSCTL_USER_TO_KERN(dir) ? &tmp : valp; 692 676 693 - ret = do_proc_dointvec_conv(negp, lvalp, ip, write, table); 677 + ret = do_proc_dointvec_conv(negp, lvalp, ip, dir, table); 694 678 if (ret) 695 679 return ret; 696 680 697 - if (write) { 681 + if (SYSCTL_USER_TO_KERN(dir)) { 698 682 min = (int *) table->extra1; 699 683 max = (int *) table->extra2; 700 684 if ((min && *min > tmp) || (max && *max < tmp)) ··· 708 692 /** 709 693 * proc_dointvec_minmax - read a vector of integers with min/max values 710 694 * @table: the sysctl table 711 - * @write: %TRUE if this is a write to the sysctl file 695 + * @dir: %TRUE if this is a write to the sysctl file 712 696 * @buffer: the user buffer 713 697 * @lenp: the size of the user buffer 714 698 * @ppos: file position ··· 719 703 * This routine will ensure the values are within the range specified by 720 704 * table->extra1 (min) and table->extra2 (max). 721 705 * 722 - * Returns 0 on success or -EINVAL on write when the range check fails. 706 + * Returns 0 on success or -EINVAL when the range check fails and 707 + * SYSCTL_USER_TO_KERN(dir) == true 723 708 */ 724 - int proc_dointvec_minmax(const struct ctl_table *table, int write, 709 + int proc_dointvec_minmax(const struct ctl_table *table, int dir, 725 710 void *buffer, size_t *lenp, loff_t *ppos) 726 711 { 727 - return do_proc_dointvec(table, write, buffer, lenp, ppos, 712 + return do_proc_dointvec(table, dir, buffer, lenp, ppos, 728 713 do_proc_dointvec_minmax_conv); 729 714 } 730 715 731 716 static int do_proc_douintvec_minmax_conv(unsigned long *lvalp, 732 - unsigned int *valp, int write, 717 + unsigned int *valp, int dir, 733 718 const struct ctl_table *table) 734 719 { 735 720 int ret; 736 721 unsigned int tmp, *min, *max; 737 - /* write via temporary local uint for bounds-checking */ 738 - unsigned int *up = write ? &tmp : valp; 722 + /* When writing to the kernel use a temp local uint for bounds-checking */ 723 + unsigned int *up = SYSCTL_USER_TO_KERN(dir) ? &tmp : valp; 739 724 740 - ret = do_proc_douintvec_conv(lvalp, up, write, table); 725 + ret = do_proc_douintvec_conv(lvalp, up, dir, table); 741 726 if (ret) 742 727 return ret; 743 728 744 - if (write) { 729 + if (SYSCTL_USER_TO_KERN(dir)) { 745 730 min = (unsigned int *) table->extra1; 746 731 max = (unsigned int *) table->extra2; 747 732 if ((min && *min > tmp) || (max && *max < tmp)) ··· 757 740 /** 758 741 * proc_douintvec_minmax - read a vector of unsigned ints with min/max values 759 742 * @table: the sysctl table 760 - * @write: %TRUE if this is a write to the sysctl file 743 + * @dir: %TRUE if this is a write to the sysctl file 761 744 * @buffer: the user buffer 762 745 * @lenp: the size of the user buffer 763 746 * @ppos: file position ··· 771 754 * check for UINT_MAX to avoid having to support wrap around uses from 772 755 * userspace. 773 756 * 774 - * Returns 0 on success or -ERANGE on write when the range check fails. 757 + * Returns 0 on success or -ERANGE when range check failes and 758 + * SYSCTL_USER_TO_KERN(dir) == true 775 759 */ 776 - int proc_douintvec_minmax(const struct ctl_table *table, int write, 760 + int proc_douintvec_minmax(const struct ctl_table *table, int dir, 777 761 void *buffer, size_t *lenp, loff_t *ppos) 778 762 { 779 - return do_proc_douintvec(table, write, buffer, lenp, ppos, 763 + return do_proc_douintvec(table, dir, buffer, lenp, ppos, 780 764 do_proc_douintvec_minmax_conv); 781 765 } 782 766 783 767 /** 784 768 * proc_dou8vec_minmax - read a vector of unsigned chars with min/max values 785 769 * @table: the sysctl table 786 - * @write: %TRUE if this is a write to the sysctl file 770 + * @dir: %TRUE if this is a write to the sysctl file 787 771 * @buffer: the user buffer 788 772 * @lenp: the size of the user buffer 789 773 * @ppos: file position ··· 796 778 * This routine will ensure the values are within the range specified by 797 779 * table->extra1 (min) and table->extra2 (max). 798 780 * 799 - * Returns 0 on success or an error on write when the range check fails. 781 + * Returns 0 on success or an error on SYSCTL_USER_TO_KERN(dir) == true 782 + * and the range check fails. 800 783 */ 801 - int proc_dou8vec_minmax(const struct ctl_table *table, int write, 784 + int proc_dou8vec_minmax(const struct ctl_table *table, int dir, 802 785 void *buffer, size_t *lenp, loff_t *ppos) 803 786 { 804 787 struct ctl_table tmp; ··· 821 802 tmp.extra2 = (unsigned int *) &max; 822 803 823 804 val = READ_ONCE(*data); 824 - res = do_proc_douintvec(&tmp, write, buffer, lenp, ppos, 805 + res = do_proc_douintvec(&tmp, dir, buffer, lenp, ppos, 825 806 do_proc_douintvec_minmax_conv); 826 807 if (res) 827 808 return res; 828 - if (write) 809 + if (SYSCTL_USER_TO_KERN(dir)) 829 810 WRITE_ONCE(*data, val); 830 811 return 0; 831 812 } 832 813 EXPORT_SYMBOL_GPL(proc_dou8vec_minmax); 833 814 834 - static int do_proc_doulongvec_minmax(const struct ctl_table *table, int write, 815 + static int do_proc_doulongvec_minmax(const struct ctl_table *table, int dir, 835 816 void *buffer, size_t *lenp, loff_t *ppos, 836 817 unsigned long convmul, 837 818 unsigned long convdiv) ··· 841 822 size_t left; 842 823 char *p; 843 824 844 - if (!table->data || !table->maxlen || !*lenp || (*ppos && !write)) { 825 + if (!table->data || !table->maxlen || !*lenp || 826 + (*ppos && SYSCTL_KERN_TO_USER(dir))) { 845 827 *lenp = 0; 846 828 return 0; 847 829 } ··· 853 833 vleft = table->maxlen / sizeof(unsigned long); 854 834 left = *lenp; 855 835 856 - if (write) { 836 + if (SYSCTL_USER_TO_KERN(dir)) { 857 837 if (proc_first_pos_non_zero_ignore(ppos, table)) 858 838 goto out; 859 839 ··· 865 845 for (; left && vleft--; i++, first = 0) { 866 846 unsigned long val; 867 847 868 - if (write) { 848 + if (SYSCTL_USER_TO_KERN(dir)) { 869 849 bool neg; 870 850 871 851 proc_skip_spaces(&p, &left); ··· 894 874 } 895 875 } 896 876 897 - if (!write && !first && left && !err) 877 + if (SYSCTL_KERN_TO_USER(dir) && !first && left && !err) 898 878 proc_put_char(&buffer, &left, '\n'); 899 - if (write && !err) 879 + if (SYSCTL_USER_TO_KERN(dir) && !err) 900 880 proc_skip_spaces(&p, &left); 901 - if (write && first) 881 + if (SYSCTL_USER_TO_KERN(dir) && first) 902 882 return err ? : -EINVAL; 903 883 *lenp -= left; 904 884 out: ··· 909 889 /** 910 890 * proc_doulongvec_minmax - read a vector of long integers with min/max values 911 891 * @table: the sysctl table 912 - * @write: %TRUE if this is a write to the sysctl file 892 + * @dir: %TRUE if this is a write to the sysctl file 913 893 * @buffer: the user buffer 914 894 * @lenp: the size of the user buffer 915 895 * @ppos: file position ··· 922 902 * 923 903 * Returns 0 on success. 924 904 */ 925 - int proc_doulongvec_minmax(const struct ctl_table *table, int write, 905 + int proc_doulongvec_minmax(const struct ctl_table *table, int dir, 926 906 void *buffer, size_t *lenp, loff_t *ppos) 927 907 { 928 - return do_proc_doulongvec_minmax(table, write, buffer, lenp, ppos, 1l, 1l); 908 + return do_proc_doulongvec_minmax(table, dir, buffer, lenp, ppos, 1l, 1l); 929 909 } 930 910 931 911 /** 932 912 * proc_doulongvec_ms_jiffies_minmax - read a vector of millisecond values with min/max values 933 913 * @table: the sysctl table 934 - * @write: %TRUE if this is a write to the sysctl file 914 + * @dir: %TRUE if this is a write to the sysctl file 935 915 * @buffer: the user buffer 936 916 * @lenp: the size of the user buffer 937 917 * @ppos: file position ··· 945 925 * 946 926 * Returns 0 on success. 947 927 */ 948 - int proc_doulongvec_ms_jiffies_minmax(const struct ctl_table *table, int write, 928 + int proc_doulongvec_ms_jiffies_minmax(const struct ctl_table *table, int dir, 949 929 void *buffer, size_t *lenp, loff_t *ppos) 950 930 { 951 - return do_proc_doulongvec_minmax(table, write, buffer, 952 - lenp, ppos, HZ, 1000l); 931 + return do_proc_doulongvec_minmax(table, dir, buffer, 932 + lenp, ppos, HZ, 1000l); 953 933 } 954 934 955 935 956 936 static int do_proc_dointvec_jiffies_conv(bool *negp, unsigned long *lvalp, 957 - int *valp, int write, 937 + int *valp, int dir, 958 938 const struct ctl_table *table) 959 939 { 960 - if (write) { 940 + if (SYSCTL_USER_TO_KERN(dir)) { 961 941 if (*lvalp > INT_MAX / HZ) 962 942 return 1; 963 943 if (*negp) ··· 980 960 } 981 961 982 962 static int do_proc_dointvec_userhz_jiffies_conv(bool *negp, unsigned long *lvalp, 983 - int *valp, int write, 963 + int *valp, int dir, 984 964 const struct ctl_table *table) 985 965 { 986 - if (write) { 966 + if (SYSCTL_USER_TO_KERN(dir)) { 987 967 if (USER_HZ < HZ && *lvalp > (LONG_MAX / HZ) * USER_HZ) 988 968 return 1; 989 969 *valp = clock_t_to_jiffies(*negp ? -*lvalp : *lvalp); ··· 1003 983 } 1004 984 1005 985 static int do_proc_dointvec_ms_jiffies_conv(bool *negp, unsigned long *lvalp, 1006 - int *valp, int write, 986 + int *valp, int dir, 1007 987 const struct ctl_table *table) 1008 988 { 1009 - if (write) { 989 + if (SYSCTL_USER_TO_KERN(dir)) { 1010 990 unsigned long jif = msecs_to_jiffies(*negp ? -*lvalp : *lvalp); 1011 991 1012 992 if (jif > INT_MAX) ··· 1028 1008 } 1029 1009 1030 1010 static int do_proc_dointvec_ms_jiffies_minmax_conv(bool *negp, unsigned long *lvalp, 1031 - int *valp, int write, 1011 + int *valp, int dir, 1032 1012 const struct ctl_table *table) 1033 1013 { 1034 1014 int tmp, ret, *min, *max; ··· 1036 1016 * If writing, first do so via a temporary local int so we can 1037 1017 * bounds-check it before touching *valp. 1038 1018 */ 1039 - int *ip = write ? &tmp : valp; 1019 + int *ip = SYSCTL_USER_TO_KERN(dir) ? &tmp : valp; 1040 1020 1041 - ret = do_proc_dointvec_ms_jiffies_conv(negp, lvalp, ip, write, table); 1021 + ret = do_proc_dointvec_ms_jiffies_conv(negp, lvalp, ip, dir, table); 1042 1022 if (ret) 1043 1023 return ret; 1044 1024 1045 - if (write) { 1025 + if (SYSCTL_USER_TO_KERN(dir)) { 1046 1026 min = (int *) table->extra1; 1047 1027 max = (int *) table->extra2; 1048 1028 if ((min && *min > tmp) || (max && *max < tmp)) ··· 1055 1035 /** 1056 1036 * proc_dointvec_jiffies - read a vector of integers as seconds 1057 1037 * @table: the sysctl table 1058 - * @write: %TRUE if this is a write to the sysctl file 1038 + * @dir: %TRUE if this is a write to the sysctl file 1059 1039 * @buffer: the user buffer 1060 1040 * @lenp: the size of the user buffer 1061 1041 * @ppos: file position ··· 1067 1047 * 1068 1048 * Returns 0 on success. 1069 1049 */ 1070 - int proc_dointvec_jiffies(const struct ctl_table *table, int write, 1050 + int proc_dointvec_jiffies(const struct ctl_table *table, int dir, 1071 1051 void *buffer, size_t *lenp, loff_t *ppos) 1072 1052 { 1073 - return do_proc_dointvec(table,write,buffer,lenp,ppos, 1074 - do_proc_dointvec_jiffies_conv); 1053 + return do_proc_dointvec(table, dir, buffer, lenp, ppos, 1054 + do_proc_dointvec_jiffies_conv); 1075 1055 } 1076 1056 1077 - int proc_dointvec_ms_jiffies_minmax(const struct ctl_table *table, int write, 1057 + int proc_dointvec_ms_jiffies_minmax(const struct ctl_table *table, int dir, 1078 1058 void *buffer, size_t *lenp, loff_t *ppos) 1079 1059 { 1080 - return do_proc_dointvec(table, write, buffer, lenp, ppos, 1060 + return do_proc_dointvec(table, dir, buffer, lenp, ppos, 1081 1061 do_proc_dointvec_ms_jiffies_minmax_conv); 1082 1062 } 1083 1063 1084 1064 /** 1085 1065 * proc_dointvec_userhz_jiffies - read a vector of integers as 1/USER_HZ seconds 1086 1066 * @table: the sysctl table 1087 - * @write: %TRUE if this is a write to the sysctl file 1067 + * @dir: %TRUE if this is a write to the sysctl file 1088 1068 * @buffer: the user buffer 1089 1069 * @lenp: the size of the user buffer 1090 1070 * @ppos: pointer to the file position ··· 1096 1076 * 1097 1077 * Returns 0 on success. 1098 1078 */ 1099 - int proc_dointvec_userhz_jiffies(const struct ctl_table *table, int write, 1079 + int proc_dointvec_userhz_jiffies(const struct ctl_table *table, int dir, 1100 1080 void *buffer, size_t *lenp, loff_t *ppos) 1101 1081 { 1102 - return do_proc_dointvec(table, write, buffer, lenp, ppos, 1082 + return do_proc_dointvec(table, dir, buffer, lenp, ppos, 1103 1083 do_proc_dointvec_userhz_jiffies_conv); 1104 1084 } 1105 1085 1106 1086 /** 1107 1087 * proc_dointvec_ms_jiffies - read a vector of integers as 1 milliseconds 1108 1088 * @table: the sysctl table 1109 - * @write: %TRUE if this is a write to the sysctl file 1089 + * @dir: %TRUE if this is a write to the sysctl file 1110 1090 * @buffer: the user buffer 1111 1091 * @lenp: the size of the user buffer 1112 1092 * @ppos: the current position in the file ··· 1118 1098 * 1119 1099 * Returns 0 on success. 1120 1100 */ 1121 - int proc_dointvec_ms_jiffies(const struct ctl_table *table, int write, void *buffer, 1101 + int proc_dointvec_ms_jiffies(const struct ctl_table *table, int dir, void *buffer, 1122 1102 size_t *lenp, loff_t *ppos) 1123 1103 { 1124 - return do_proc_dointvec(table, write, buffer, lenp, ppos, 1104 + return do_proc_dointvec(table, dir, buffer, lenp, ppos, 1125 1105 do_proc_dointvec_ms_jiffies_conv); 1126 1106 } 1127 1107 1128 1108 /** 1129 1109 * proc_do_large_bitmap - read/write from/to a large bitmap 1130 1110 * @table: the sysctl table 1131 - * @write: %TRUE if this is a write to the sysctl file 1111 + * @dir: %TRUE if this is a write to the sysctl file 1132 1112 * @buffer: the user buffer 1133 1113 * @lenp: the size of the user buffer 1134 1114 * @ppos: file position ··· 1142 1122 * 1143 1123 * Returns 0 on success. 1144 1124 */ 1145 - int proc_do_large_bitmap(const struct ctl_table *table, int write, 1125 + int proc_do_large_bitmap(const struct ctl_table *table, int dir, 1146 1126 void *buffer, size_t *lenp, loff_t *ppos) 1147 1127 { 1148 1128 int err = 0; ··· 1152 1132 unsigned long *tmp_bitmap = NULL; 1153 1133 char tr_a[] = { '-', ',', '\n' }, tr_b[] = { ',', '\n', 0 }, c; 1154 1134 1155 - if (!bitmap || !bitmap_len || !left || (*ppos && !write)) { 1135 + if (!bitmap || !bitmap_len || !left || (*ppos && SYSCTL_KERN_TO_USER(dir))) { 1156 1136 *lenp = 0; 1157 1137 return 0; 1158 1138 } 1159 1139 1160 - if (write) { 1140 + if (SYSCTL_USER_TO_KERN(dir)) { 1161 1141 char *p = buffer; 1162 1142 size_t skipped = 0; 1163 1143 ··· 1258 1238 } 1259 1239 1260 1240 if (!err) { 1261 - if (write) { 1241 + if (SYSCTL_USER_TO_KERN(dir)) { 1262 1242 if (*ppos) 1263 1243 bitmap_or(bitmap, bitmap, tmp_bitmap, bitmap_len); 1264 1244 else ··· 1274 1254 1275 1255 #else /* CONFIG_PROC_SYSCTL */ 1276 1256 1277 - int proc_dostring(const struct ctl_table *table, int write, 1257 + int proc_dostring(const struct ctl_table *table, int dir, 1278 1258 void *buffer, size_t *lenp, loff_t *ppos) 1279 1259 { 1280 1260 return -ENOSYS; 1281 1261 } 1282 1262 1283 - int proc_dobool(const struct ctl_table *table, int write, 1263 + int proc_dobool(const struct ctl_table *table, int dir, 1284 1264 void *buffer, size_t *lenp, loff_t *ppos) 1285 1265 { 1286 1266 return -ENOSYS; 1287 1267 } 1288 1268 1289 - int proc_dointvec(const struct ctl_table *table, int write, 1269 + int proc_dointvec(const struct ctl_table *table, int dir, 1290 1270 void *buffer, size_t *lenp, loff_t *ppos) 1291 1271 { 1292 1272 return -ENOSYS; 1293 1273 } 1294 1274 1295 - int proc_douintvec(const struct ctl_table *table, int write, 1275 + int proc_douintvec(const struct ctl_table *table, int dir, 1296 1276 void *buffer, size_t *lenp, loff_t *ppos) 1297 1277 { 1298 1278 return -ENOSYS; 1299 1279 } 1300 1280 1301 - int proc_dointvec_minmax(const struct ctl_table *table, int write, 1281 + int proc_dointvec_minmax(const struct ctl_table *table, int dir, 1302 1282 void *buffer, size_t *lenp, loff_t *ppos) 1303 1283 { 1304 1284 return -ENOSYS; 1305 1285 } 1306 1286 1307 - int proc_douintvec_minmax(const struct ctl_table *table, int write, 1287 + int proc_douintvec_minmax(const struct ctl_table *table, int dir, 1308 1288 void *buffer, size_t *lenp, loff_t *ppos) 1309 1289 { 1310 1290 return -ENOSYS; 1311 1291 } 1312 1292 1313 - int proc_dou8vec_minmax(const struct ctl_table *table, int write, 1293 + int proc_dou8vec_minmax(const struct ctl_table *table, int dir, 1314 1294 void *buffer, size_t *lenp, loff_t *ppos) 1315 1295 { 1316 1296 return -ENOSYS; 1317 1297 } 1318 1298 1319 - int proc_dointvec_jiffies(const struct ctl_table *table, int write, 1299 + int proc_dointvec_jiffies(const struct ctl_table *table, int dir, 1320 1300 void *buffer, size_t *lenp, loff_t *ppos) 1321 1301 { 1322 1302 return -ENOSYS; 1323 1303 } 1324 1304 1325 - int proc_dointvec_ms_jiffies_minmax(const struct ctl_table *table, int write, 1305 + int proc_dointvec_ms_jiffies_minmax(const struct ctl_table *table, int dir, 1326 1306 void *buffer, size_t *lenp, loff_t *ppos) 1327 1307 { 1328 1308 return -ENOSYS; 1329 1309 } 1330 1310 1331 - int proc_dointvec_userhz_jiffies(const struct ctl_table *table, int write, 1311 + int proc_dointvec_userhz_jiffies(const struct ctl_table *table, int dir, 1332 1312 void *buffer, size_t *lenp, loff_t *ppos) 1333 1313 { 1334 1314 return -ENOSYS; 1335 1315 } 1336 1316 1337 - int proc_dointvec_ms_jiffies(const struct ctl_table *table, int write, 1317 + int proc_dointvec_ms_jiffies(const struct ctl_table *table, int dir, 1338 1318 void *buffer, size_t *lenp, loff_t *ppos) 1339 1319 { 1340 1320 return -ENOSYS; 1341 1321 } 1342 1322 1343 - int proc_doulongvec_minmax(const struct ctl_table *table, int write, 1323 + int proc_doulongvec_minmax(const struct ctl_table *table, int dir, 1344 1324 void *buffer, size_t *lenp, loff_t *ppos) 1345 1325 { 1346 1326 return -ENOSYS; 1347 1327 } 1348 1328 1349 - int proc_doulongvec_ms_jiffies_minmax(const struct ctl_table *table, int write, 1329 + int proc_doulongvec_ms_jiffies_minmax(const struct ctl_table *table, int dir, 1350 1330 void *buffer, size_t *lenp, loff_t *ppos) 1351 1331 { 1352 1332 return -ENOSYS; 1353 1333 } 1354 1334 1355 - int proc_do_large_bitmap(const struct ctl_table *table, int write, 1335 + int proc_do_large_bitmap(const struct ctl_table *table, int dir, 1356 1336 void *buffer, size_t *lenp, loff_t *ppos) 1357 1337 { 1358 1338 return -ENOSYS; ··· 1361 1341 #endif /* CONFIG_PROC_SYSCTL */ 1362 1342 1363 1343 #if defined(CONFIG_SYSCTL) 1364 - int proc_do_static_key(const struct ctl_table *table, int write, 1344 + int proc_do_static_key(const struct ctl_table *table, int dir, 1365 1345 void *buffer, size_t *lenp, loff_t *ppos) 1366 1346 { 1367 1347 struct static_key *key = (struct static_key *)table->data; ··· 1375 1355 .extra2 = SYSCTL_ONE, 1376 1356 }; 1377 1357 1378 - if (write && !capable(CAP_SYS_ADMIN)) 1358 + if (SYSCTL_USER_TO_KERN(dir) && !capable(CAP_SYS_ADMIN)) 1379 1359 return -EPERM; 1380 1360 1381 1361 mutex_lock(&static_key_mutex); 1382 1362 val = static_key_enabled(key); 1383 - ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); 1384 - if (write && !ret) { 1363 + ret = proc_dointvec_minmax(&tmp, dir, buffer, lenp, ppos); 1364 + if (SYSCTL_USER_TO_KERN(dir) && !ret) { 1385 1365 if (val) 1386 1366 static_key_enable(key); 1387 1367 else