1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * sysctl.c: General linux system control interface 4 */ 5 6 #include <linux/sysctl.h> 7 #include <linux/bitmap.h> 8 #include <linux/proc_fs.h> 9 #include <linux/ctype.h> 10 #include <linux/init.h> 11 #include <linux/kernel.h> 12 #include <linux/kobject.h> 13 #include <linux/highuid.h> 14 #include <linux/writeback.h> 15 #include <linux/initrd.h> 16 #include <linux/times.h> 17 #include <linux/limits.h> 18 #include <linux/syscalls.h> 19 #include <linux/capability.h> 20 21 #include "../lib/kstrtox.h" 22 23 #include <linux/uaccess.h> 24 #include <asm/processor.h> 25 26 /* shared constants to be used in various sysctls */ 27 const int sysctl_vals[] = { 0, 1, 2, 3, 4, 100, 200, 1000, 3000, INT_MAX, 65535, -1 }; 28 EXPORT_SYMBOL(sysctl_vals); 29 30 const unsigned long sysctl_long_vals[] = { 0, 1, LONG_MAX }; 31 EXPORT_SYMBOL_GPL(sysctl_long_vals); 32 33 #if defined(CONFIG_SYSCTL) 34 35 /* Constants used for minimum and maximum */ 36 static const int ngroups_max = NGROUPS_MAX; 37 static const int cap_last_cap = CAP_LAST_CAP; 38 39 #ifdef CONFIG_PROC_SYSCTL 40 41 /** 42 * enum sysctl_writes_mode - supported sysctl write modes 43 * 44 * @SYSCTL_WRITES_LEGACY: each write syscall must fully contain the sysctl value 45 * to be written, and multiple writes on the same sysctl file descriptor 46 * will rewrite the sysctl value, regardless of file position. No warning 47 * is issued when the initial position is not 0. 48 * @SYSCTL_WRITES_WARN: same as above but warn when the initial file position is 49 * not 0. 50 * @SYSCTL_WRITES_STRICT: writes to numeric sysctl entries must always be at 51 * file position 0 and the value must be fully contained in the buffer 52 * sent to the write syscall. If dealing with strings respect the file 53 * position, but restrict this to the max length of the buffer, anything 54 * passed the max length will be ignored. Multiple writes will append 55 * to the buffer. 56 * 57 * These write modes control how current file position affects the behavior of 58 * updating sysctl values through the proc interface on each write. 59 */ 60 enum sysctl_writes_mode { 61 SYSCTL_WRITES_LEGACY = -1, 62 SYSCTL_WRITES_WARN = 0, 63 SYSCTL_WRITES_STRICT = 1, 64 }; 65 66 static enum sysctl_writes_mode sysctl_writes_strict = SYSCTL_WRITES_STRICT; 67 #endif /* CONFIG_PROC_SYSCTL */ 68 #endif /* CONFIG_SYSCTL */ 69 70 /* 71 * /proc/sys support 72 */ 73 74 #ifdef CONFIG_PROC_SYSCTL 75 76 static int _proc_do_string(char *data, int maxlen, int write, 77 char *buffer, size_t *lenp, loff_t *ppos) 78 { 79 size_t len; 80 char c, *p; 81 82 if (!data || !maxlen || !*lenp) { 83 *lenp = 0; 84 return 0; 85 } 86 87 if (write) { 88 if (sysctl_writes_strict == SYSCTL_WRITES_STRICT) { 89 /* Only continue writes not past the end of buffer. */ 90 len = strlen(data); 91 if (len > maxlen - 1) 92 len = maxlen - 1; 93 94 if (*ppos > len) 95 return 0; 96 len = *ppos; 97 } else { 98 /* Start writing from beginning of buffer. */ 99 len = 0; 100 } 101 102 *ppos += *lenp; 103 p = buffer; 104 while ((p - buffer) < *lenp && len < maxlen - 1) { 105 c = *(p++); 106 if (c == 0 || c == '\n') 107 break; 108 data[len++] = c; 109 } 110 data[len] = 0; 111 } else { 112 len = strlen(data); 113 if (len > maxlen) 114 len = maxlen; 115 116 if (*ppos > len) { 117 *lenp = 0; 118 return 0; 119 } 120 121 data += *ppos; 122 len -= *ppos; 123 124 if (len > *lenp) 125 len = *lenp; 126 if (len) 127 memcpy(buffer, data, len); 128 if (len < *lenp) { 129 buffer[len] = '\n'; 130 len++; 131 } 132 *lenp = len; 133 *ppos += len; 134 } 135 return 0; 136 } 137 138 static void warn_sysctl_write(const struct ctl_table *table) 139 { 140 pr_warn_once("%s wrote to %s when file position was not 0!\n" 141 "This will not be supported in the future. To silence this\n" 142 "warning, set kernel.sysctl_writes_strict = -1\n", 143 current->comm, table->procname); 144 } 145 146 /** 147 * proc_first_pos_non_zero_ignore - check if first position is allowed 148 * @ppos: file position 149 * @table: the sysctl table 150 * 151 * Returns true if the first position is non-zero and the sysctl_writes_strict 152 * mode indicates this is not allowed for numeric input types. String proc 153 * handlers can ignore the return value. 154 */ 155 static bool proc_first_pos_non_zero_ignore(loff_t *ppos, 156 const struct ctl_table *table) 157 { 158 if (!*ppos) 159 return false; 160 161 switch (sysctl_writes_strict) { 162 case SYSCTL_WRITES_STRICT: 163 return true; 164 case SYSCTL_WRITES_WARN: 165 warn_sysctl_write(table); 166 return false; 167 default: 168 return false; 169 } 170 } 171 172 /** 173 * proc_dostring - read a string sysctl 174 * @table: the sysctl table 175 * @write: %TRUE if this is a write to the sysctl file 176 * @buffer: the user buffer 177 * @lenp: the size of the user buffer 178 * @ppos: file position 179 * 180 * Reads/writes a string from/to the user buffer. If the kernel 181 * buffer provided is not large enough to hold the string, the 182 * string is truncated. The copied string is %NULL-terminated. 183 * If the string is being read by the user process, it is copied 184 * and a newline '\n' is added. It is truncated if the buffer is 185 * not large enough. 186 * 187 * Returns 0 on success. 188 */ 189 int proc_dostring(const struct ctl_table *table, int write, 190 void *buffer, size_t *lenp, loff_t *ppos) 191 { 192 if (write) 193 proc_first_pos_non_zero_ignore(ppos, table); 194 195 return _proc_do_string(table->data, table->maxlen, write, buffer, lenp, 196 ppos); 197 } 198 199 static void proc_skip_spaces(char **buf, size_t *size) 200 { 201 while (*size) { 202 if (!isspace(**buf)) 203 break; 204 (*size)--; 205 (*buf)++; 206 } 207 } 208 209 static void proc_skip_char(char **buf, size_t *size, const char v) 210 { 211 while (*size) { 212 if (**buf != v) 213 break; 214 (*size)--; 215 (*buf)++; 216 } 217 } 218 219 /** 220 * strtoul_lenient - parse an ASCII formatted integer from a buffer and only 221 * fail on overflow 222 * 223 * @cp: kernel buffer containing the string to parse 224 * @endp: pointer to store the trailing characters 225 * @base: the base to use 226 * @res: where the parsed integer will be stored 227 * 228 * In case of success 0 is returned and @res will contain the parsed integer, 229 * @endp will hold any trailing characters. 230 * This function will fail the parse on overflow. If there wasn't an overflow 231 * the function will defer the decision what characters count as invalid to the 232 * caller. 233 */ 234 static int strtoul_lenient(const char *cp, char **endp, unsigned int base, 235 unsigned long *res) 236 { 237 unsigned long long result; 238 unsigned int rv; 239 240 cp = _parse_integer_fixup_radix(cp, &base); 241 rv = _parse_integer(cp, base, &result); 242 if ((rv & KSTRTOX_OVERFLOW) || (result != (unsigned long)result)) 243 return -ERANGE; 244 245 cp += rv; 246 247 if (endp) 248 *endp = (char *)cp; 249 250 *res = (unsigned long)result; 251 return 0; 252 } 253 254 #define TMPBUFLEN 22 255 /** 256 * proc_get_long - reads an ASCII formatted integer from a user buffer 257 * 258 * @buf: a kernel buffer 259 * @size: size of the kernel buffer 260 * @val: this is where the number will be stored 261 * @neg: set to %TRUE if number is negative 262 * @perm_tr: a vector which contains the allowed trailers 263 * @perm_tr_len: size of the perm_tr vector 264 * @tr: pointer to store the trailer character 265 * 266 * In case of success %0 is returned and @buf and @size are updated with 267 * the amount of bytes read. If @tr is non-NULL and a trailing 268 * character exists (size is non-zero after returning from this 269 * function), @tr is updated with the trailing character. 270 */ 271 static int proc_get_long(char **buf, size_t *size, 272 unsigned long *val, bool *neg, 273 const char *perm_tr, unsigned perm_tr_len, char *tr) 274 { 275 char *p, tmp[TMPBUFLEN]; 276 ssize_t len = *size; 277 278 if (len <= 0) 279 return -EINVAL; 280 281 if (len > TMPBUFLEN - 1) 282 len = TMPBUFLEN - 1; 283 284 memcpy(tmp, *buf, len); 285 286 tmp[len] = 0; 287 p = tmp; 288 if (*p == '-' && *size > 1) { 289 *neg = true; 290 p++; 291 } else 292 *neg = false; 293 if (!isdigit(*p)) 294 return -EINVAL; 295 296 if (strtoul_lenient(p, &p, 0, val)) 297 return -EINVAL; 298 299 len = p - tmp; 300 301 /* We don't know if the next char is whitespace thus we may accept 302 * invalid integers (e.g. 1234...a) or two integers instead of one 303 * (e.g. 123...1). So lets not allow such large numbers. */ 304 if (len == TMPBUFLEN - 1) 305 return -EINVAL; 306 307 if (len < *size && perm_tr_len && !memchr(perm_tr, *p, perm_tr_len)) 308 return -EINVAL; 309 310 if (tr && (len < *size)) 311 *tr = *p; 312 313 *buf += len; 314 *size -= len; 315 316 return 0; 317 } 318 319 /** 320 * proc_put_long - converts an integer to a decimal ASCII formatted string 321 * 322 * @buf: the user buffer 323 * @size: the size of the user buffer 324 * @val: the integer to be converted 325 * @neg: sign of the number, %TRUE for negative 326 * 327 * In case of success @buf and @size are updated with the amount of bytes 328 * written. 329 */ 330 static void proc_put_long(void **buf, size_t *size, unsigned long val, bool neg) 331 { 332 int len; 333 char tmp[TMPBUFLEN], *p = tmp; 334 335 sprintf(p, "%s%lu", neg ? "-" : "", val); 336 len = strlen(tmp); 337 if (len > *size) 338 len = *size; 339 memcpy(*buf, tmp, len); 340 *size -= len; 341 *buf += len; 342 } 343 #undef TMPBUFLEN 344 345 static void proc_put_char(void **buf, size_t *size, char c) 346 { 347 if (*size) { 348 char **buffer = (char **)buf; 349 **buffer = c; 350 351 (*size)--; 352 (*buffer)++; 353 *buf = *buffer; 354 } 355 } 356 357 static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp, 358 int *valp, 359 int write, void *data) 360 { 361 if (write) { 362 if (*negp) { 363 if (*lvalp > (unsigned long) INT_MAX + 1) 364 return -EINVAL; 365 WRITE_ONCE(*valp, -*lvalp); 366 } else { 367 if (*lvalp > (unsigned long) INT_MAX) 368 return -EINVAL; 369 WRITE_ONCE(*valp, *lvalp); 370 } 371 } else { 372 int val = READ_ONCE(*valp); 373 if (val < 0) { 374 *negp = true; 375 *lvalp = -(unsigned long)val; 376 } else { 377 *negp = false; 378 *lvalp = (unsigned long)val; 379 } 380 } 381 return 0; 382 } 383 384 static int do_proc_douintvec_conv(unsigned long *lvalp, 385 unsigned int *valp, 386 int write, void *data) 387 { 388 if (write) { 389 if (*lvalp > UINT_MAX) 390 return -EINVAL; 391 WRITE_ONCE(*valp, *lvalp); 392 } else { 393 unsigned int val = READ_ONCE(*valp); 394 *lvalp = (unsigned long)val; 395 } 396 return 0; 397 } 398 399 static const char proc_wspace_sep[] = { ' ', '\t', '\n' }; 400 401 static int __do_proc_dointvec(void *tbl_data, const struct ctl_table *table, 402 int write, void *buffer, 403 size_t *lenp, loff_t *ppos, 404 int (*conv)(bool *negp, unsigned long *lvalp, int *valp, 405 int write, void *data), 406 void *data) 407 { 408 int *i, vleft, first = 1, err = 0; 409 size_t left; 410 char *p; 411 412 if (!tbl_data || !table->maxlen || !*lenp || (*ppos && !write)) { 413 *lenp = 0; 414 return 0; 415 } 416 417 i = (int *) tbl_data; 418 vleft = table->maxlen / sizeof(*i); 419 left = *lenp; 420 421 if (!conv) 422 conv = do_proc_dointvec_conv; 423 424 if (write) { 425 if (proc_first_pos_non_zero_ignore(ppos, table)) 426 goto out; 427 428 if (left > PAGE_SIZE - 1) 429 left = PAGE_SIZE - 1; 430 p = buffer; 431 } 432 433 for (; left && vleft--; i++, first=0) { 434 unsigned long lval; 435 bool neg; 436 437 if (write) { 438 proc_skip_spaces(&p, &left); 439 440 if (!left) 441 break; 442 err = proc_get_long(&p, &left, &lval, &neg, 443 proc_wspace_sep, 444 sizeof(proc_wspace_sep), NULL); 445 if (err) 446 break; 447 if (conv(&neg, &lval, i, 1, data)) { 448 err = -EINVAL; 449 break; 450 } 451 } else { 452 if (conv(&neg, &lval, i, 0, data)) { 453 err = -EINVAL; 454 break; 455 } 456 if (!first) 457 proc_put_char(&buffer, &left, '\t'); 458 proc_put_long(&buffer, &left, lval, neg); 459 } 460 } 461 462 if (!write && !first && left && !err) 463 proc_put_char(&buffer, &left, '\n'); 464 if (write && !err && left) 465 proc_skip_spaces(&p, &left); 466 if (write && first) 467 return err ? : -EINVAL; 468 *lenp -= left; 469 out: 470 *ppos += *lenp; 471 return err; 472 } 473 474 static int do_proc_dointvec(const struct ctl_table *table, int write, 475 void *buffer, size_t *lenp, loff_t *ppos, 476 int (*conv)(bool *negp, unsigned long *lvalp, int *valp, 477 int write, void *data), 478 void *data) 479 { 480 return __do_proc_dointvec(table->data, table, write, 481 buffer, lenp, ppos, conv, data); 482 } 483 484 static int do_proc_douintvec_w(unsigned int *tbl_data, 485 const struct ctl_table *table, 486 void *buffer, 487 size_t *lenp, loff_t *ppos, 488 int (*conv)(unsigned long *lvalp, 489 unsigned int *valp, 490 int write, void *data), 491 void *data) 492 { 493 unsigned long lval; 494 int err = 0; 495 size_t left; 496 bool neg; 497 char *p = buffer; 498 499 left = *lenp; 500 501 if (proc_first_pos_non_zero_ignore(ppos, table)) 502 goto bail_early; 503 504 if (left > PAGE_SIZE - 1) 505 left = PAGE_SIZE - 1; 506 507 proc_skip_spaces(&p, &left); 508 if (!left) { 509 err = -EINVAL; 510 goto out_free; 511 } 512 513 err = proc_get_long(&p, &left, &lval, &neg, 514 proc_wspace_sep, 515 sizeof(proc_wspace_sep), NULL); 516 if (err || neg) { 517 err = -EINVAL; 518 goto out_free; 519 } 520 521 if (conv(&lval, tbl_data, 1, data)) { 522 err = -EINVAL; 523 goto out_free; 524 } 525 526 if (!err && left) 527 proc_skip_spaces(&p, &left); 528 529 out_free: 530 if (err) 531 return -EINVAL; 532 533 return 0; 534 535 /* This is in keeping with old __do_proc_dointvec() */ 536 bail_early: 537 *ppos += *lenp; 538 return err; 539 } 540 541 static int do_proc_douintvec_r(unsigned int *tbl_data, void *buffer, 542 size_t *lenp, loff_t *ppos, 543 int (*conv)(unsigned long *lvalp, 544 unsigned int *valp, 545 int write, void *data), 546 void *data) 547 { 548 unsigned long lval; 549 int err = 0; 550 size_t left; 551 552 left = *lenp; 553 554 if (conv(&lval, tbl_data, 0, data)) { 555 err = -EINVAL; 556 goto out; 557 } 558 559 proc_put_long(&buffer, &left, lval, false); 560 if (!left) 561 goto out; 562 563 proc_put_char(&buffer, &left, '\n'); 564 565 out: 566 *lenp -= left; 567 *ppos += *lenp; 568 569 return err; 570 } 571 572 static int __do_proc_douintvec(void *tbl_data, const struct ctl_table *table, 573 int write, void *buffer, 574 size_t *lenp, loff_t *ppos, 575 int (*conv)(unsigned long *lvalp, 576 unsigned int *valp, 577 int write, void *data), 578 void *data) 579 { 580 unsigned int *i, vleft; 581 582 if (!tbl_data || !table->maxlen || !*lenp || (*ppos && !write)) { 583 *lenp = 0; 584 return 0; 585 } 586 587 i = (unsigned int *) tbl_data; 588 vleft = table->maxlen / sizeof(*i); 589 590 /* 591 * Arrays are not supported, keep this simple. *Do not* add 592 * support for them. 593 */ 594 if (vleft != 1) { 595 *lenp = 0; 596 return -EINVAL; 597 } 598 599 if (!conv) 600 conv = do_proc_douintvec_conv; 601 602 if (write) 603 return do_proc_douintvec_w(i, table, buffer, lenp, ppos, 604 conv, data); 605 return do_proc_douintvec_r(i, buffer, lenp, ppos, conv, data); 606 } 607 608 int do_proc_douintvec(const struct ctl_table *table, int write, 609 void *buffer, size_t *lenp, loff_t *ppos, 610 int (*conv)(unsigned long *lvalp, 611 unsigned int *valp, 612 int write, void *data), 613 void *data) 614 { 615 return __do_proc_douintvec(table->data, table, write, 616 buffer, lenp, ppos, conv, data); 617 } 618 619 /** 620 * proc_dobool - read/write a bool 621 * @table: the sysctl table 622 * @write: %TRUE if this is a write to the sysctl file 623 * @buffer: the user buffer 624 * @lenp: the size of the user buffer 625 * @ppos: file position 626 * 627 * Reads/writes one integer value from/to the user buffer, 628 * treated as an ASCII string. 629 * 630 * table->data must point to a bool variable and table->maxlen must 631 * be sizeof(bool). 632 * 633 * Returns 0 on success. 634 */ 635 int proc_dobool(const struct ctl_table *table, int write, void *buffer, 636 size_t *lenp, loff_t *ppos) 637 { 638 struct ctl_table tmp; 639 bool *data = table->data; 640 int res, val; 641 642 /* Do not support arrays yet. */ 643 if (table->maxlen != sizeof(bool)) 644 return -EINVAL; 645 646 tmp = *table; 647 tmp.maxlen = sizeof(val); 648 tmp.data = &val; 649 650 val = READ_ONCE(*data); 651 res = proc_dointvec(&tmp, write, buffer, lenp, ppos); 652 if (res) 653 return res; 654 if (write) 655 WRITE_ONCE(*data, val); 656 return 0; 657 } 658 659 /** 660 * proc_dointvec - read a vector of integers 661 * @table: the sysctl table 662 * @write: %TRUE if this is a write to the sysctl file 663 * @buffer: the user buffer 664 * @lenp: the size of the user buffer 665 * @ppos: file position 666 * 667 * Reads/writes up to table->maxlen/sizeof(unsigned int) integer 668 * values from/to the user buffer, treated as an ASCII string. 669 * 670 * Returns 0 on success. 671 */ 672 int proc_dointvec(const struct ctl_table *table, int write, void *buffer, 673 size_t *lenp, loff_t *ppos) 674 { 675 return do_proc_dointvec(table, write, buffer, lenp, ppos, NULL, NULL); 676 } 677 678 /** 679 * proc_douintvec - read a vector of unsigned integers 680 * @table: the sysctl table 681 * @write: %TRUE if this is a write to the sysctl file 682 * @buffer: the user buffer 683 * @lenp: the size of the user buffer 684 * @ppos: file position 685 * 686 * Reads/writes up to table->maxlen/sizeof(unsigned int) unsigned integer 687 * values from/to the user buffer, treated as an ASCII string. 688 * 689 * Returns 0 on success. 690 */ 691 int proc_douintvec(const struct ctl_table *table, int write, void *buffer, 692 size_t *lenp, loff_t *ppos) 693 { 694 return do_proc_douintvec(table, write, buffer, lenp, ppos, 695 do_proc_douintvec_conv, NULL); 696 } 697 698 /** 699 * struct do_proc_dointvec_minmax_conv_param - proc_dointvec_minmax() range checking structure 700 * @min: pointer to minimum allowable value 701 * @max: pointer to maximum allowable value 702 * 703 * The do_proc_dointvec_minmax_conv_param structure provides the 704 * minimum and maximum values for doing range checking for those sysctl 705 * parameters that use the proc_dointvec_minmax() handler. 706 */ 707 struct do_proc_dointvec_minmax_conv_param { 708 int *min; 709 int *max; 710 }; 711 712 static int do_proc_dointvec_minmax_conv(bool *negp, unsigned long *lvalp, 713 int *valp, 714 int write, void *data) 715 { 716 int tmp, ret; 717 struct do_proc_dointvec_minmax_conv_param *param = data; 718 /* 719 * If writing, first do so via a temporary local int so we can 720 * bounds-check it before touching *valp. 721 */ 722 int *ip = write ? &tmp : valp; 723 724 ret = do_proc_dointvec_conv(negp, lvalp, ip, write, data); 725 if (ret) 726 return ret; 727 728 if (write) { 729 if ((param->min && *param->min > tmp) || 730 (param->max && *param->max < tmp)) 731 return -EINVAL; 732 WRITE_ONCE(*valp, tmp); 733 } 734 735 return 0; 736 } 737 738 /** 739 * proc_dointvec_minmax - read a vector of integers with min/max values 740 * @table: the sysctl table 741 * @write: %TRUE if this is a write to the sysctl file 742 * @buffer: the user buffer 743 * @lenp: the size of the user buffer 744 * @ppos: file position 745 * 746 * Reads/writes up to table->maxlen/sizeof(unsigned int) integer 747 * values from/to the user buffer, treated as an ASCII string. 748 * 749 * This routine will ensure the values are within the range specified by 750 * table->extra1 (min) and table->extra2 (max). 751 * 752 * Returns 0 on success or -EINVAL on write when the range check fails. 753 */ 754 int proc_dointvec_minmax(const struct ctl_table *table, int write, 755 void *buffer, size_t *lenp, loff_t *ppos) 756 { 757 struct do_proc_dointvec_minmax_conv_param param = { 758 .min = (int *) table->extra1, 759 .max = (int *) table->extra2, 760 }; 761 return do_proc_dointvec(table, write, buffer, lenp, ppos, 762 do_proc_dointvec_minmax_conv, ¶m); 763 } 764 765 /** 766 * struct do_proc_douintvec_minmax_conv_param - proc_douintvec_minmax() range checking structure 767 * @min: pointer to minimum allowable value 768 * @max: pointer to maximum allowable value 769 * 770 * The do_proc_douintvec_minmax_conv_param structure provides the 771 * minimum and maximum values for doing range checking for those sysctl 772 * parameters that use the proc_douintvec_minmax() handler. 773 */ 774 struct do_proc_douintvec_minmax_conv_param { 775 unsigned int *min; 776 unsigned int *max; 777 }; 778 779 static int do_proc_douintvec_minmax_conv(unsigned long *lvalp, 780 unsigned int *valp, 781 int write, void *data) 782 { 783 int ret; 784 unsigned int tmp; 785 struct do_proc_douintvec_minmax_conv_param *param = data; 786 /* write via temporary local uint for bounds-checking */ 787 unsigned int *up = write ? &tmp : valp; 788 789 ret = do_proc_douintvec_conv(lvalp, up, write, data); 790 if (ret) 791 return ret; 792 793 if (write) { 794 if ((param->min && *param->min > tmp) || 795 (param->max && *param->max < tmp)) 796 return -ERANGE; 797 798 WRITE_ONCE(*valp, tmp); 799 } 800 801 return 0; 802 } 803 804 /** 805 * proc_douintvec_minmax - read a vector of unsigned ints with min/max values 806 * @table: the sysctl table 807 * @write: %TRUE if this is a write to the sysctl file 808 * @buffer: the user buffer 809 * @lenp: the size of the user buffer 810 * @ppos: file position 811 * 812 * Reads/writes up to table->maxlen/sizeof(unsigned int) unsigned integer 813 * values from/to the user buffer, treated as an ASCII string. Negative 814 * strings are not allowed. 815 * 816 * This routine will ensure the values are within the range specified by 817 * table->extra1 (min) and table->extra2 (max). There is a final sanity 818 * check for UINT_MAX to avoid having to support wrap around uses from 819 * userspace. 820 * 821 * Returns 0 on success or -ERANGE on write when the range check fails. 822 */ 823 int proc_douintvec_minmax(const struct ctl_table *table, int write, 824 void *buffer, size_t *lenp, loff_t *ppos) 825 { 826 struct do_proc_douintvec_minmax_conv_param param = { 827 .min = (unsigned int *) table->extra1, 828 .max = (unsigned int *) table->extra2, 829 }; 830 return do_proc_douintvec(table, write, buffer, lenp, ppos, 831 do_proc_douintvec_minmax_conv, ¶m); 832 } 833 834 /** 835 * proc_dou8vec_minmax - read a vector of unsigned chars with min/max values 836 * @table: the sysctl table 837 * @write: %TRUE if this is a write to the sysctl file 838 * @buffer: the user buffer 839 * @lenp: the size of the user buffer 840 * @ppos: file position 841 * 842 * Reads/writes up to table->maxlen/sizeof(u8) unsigned chars 843 * values from/to the user buffer, treated as an ASCII string. Negative 844 * strings are not allowed. 845 * 846 * This routine will ensure the values are within the range specified by 847 * table->extra1 (min) and table->extra2 (max). 848 * 849 * Returns 0 on success or an error on write when the range check fails. 850 */ 851 int proc_dou8vec_minmax(const struct ctl_table *table, int write, 852 void *buffer, size_t *lenp, loff_t *ppos) 853 { 854 struct ctl_table tmp; 855 unsigned int min = 0, max = 255U, val; 856 u8 *data = table->data; 857 struct do_proc_douintvec_minmax_conv_param param = { 858 .min = &min, 859 .max = &max, 860 }; 861 int res; 862 863 /* Do not support arrays yet. */ 864 if (table->maxlen != sizeof(u8)) 865 return -EINVAL; 866 867 if (table->extra1) 868 min = *(unsigned int *) table->extra1; 869 if (table->extra2) 870 max = *(unsigned int *) table->extra2; 871 872 tmp = *table; 873 874 tmp.maxlen = sizeof(val); 875 tmp.data = &val; 876 val = READ_ONCE(*data); 877 res = do_proc_douintvec(&tmp, write, buffer, lenp, ppos, 878 do_proc_douintvec_minmax_conv, ¶m); 879 if (res) 880 return res; 881 if (write) 882 WRITE_ONCE(*data, val); 883 return 0; 884 } 885 EXPORT_SYMBOL_GPL(proc_dou8vec_minmax); 886 887 static int __do_proc_doulongvec_minmax(void *data, 888 const struct ctl_table *table, int write, 889 void *buffer, size_t *lenp, loff_t *ppos, 890 unsigned long convmul, unsigned long convdiv) 891 { 892 unsigned long *i, *min, *max; 893 int vleft, first = 1, err = 0; 894 size_t left; 895 char *p; 896 897 if (!data || !table->maxlen || !*lenp || (*ppos && !write)) { 898 *lenp = 0; 899 return 0; 900 } 901 902 i = data; 903 min = table->extra1; 904 max = table->extra2; 905 vleft = table->maxlen / sizeof(unsigned long); 906 left = *lenp; 907 908 if (write) { 909 if (proc_first_pos_non_zero_ignore(ppos, table)) 910 goto out; 911 912 if (left > PAGE_SIZE - 1) 913 left = PAGE_SIZE - 1; 914 p = buffer; 915 } 916 917 for (; left && vleft--; i++, first = 0) { 918 unsigned long val; 919 920 if (write) { 921 bool neg; 922 923 proc_skip_spaces(&p, &left); 924 if (!left) 925 break; 926 927 err = proc_get_long(&p, &left, &val, &neg, 928 proc_wspace_sep, 929 sizeof(proc_wspace_sep), NULL); 930 if (err || neg) { 931 err = -EINVAL; 932 break; 933 } 934 935 val = convmul * val / convdiv; 936 if ((min && val < *min) || (max && val > *max)) { 937 err = -EINVAL; 938 break; 939 } 940 WRITE_ONCE(*i, val); 941 } else { 942 val = convdiv * READ_ONCE(*i) / convmul; 943 if (!first) 944 proc_put_char(&buffer, &left, '\t'); 945 proc_put_long(&buffer, &left, val, false); 946 } 947 } 948 949 if (!write && !first && left && !err) 950 proc_put_char(&buffer, &left, '\n'); 951 if (write && !err) 952 proc_skip_spaces(&p, &left); 953 if (write && first) 954 return err ? : -EINVAL; 955 *lenp -= left; 956 out: 957 *ppos += *lenp; 958 return err; 959 } 960 961 static int do_proc_doulongvec_minmax(const struct ctl_table *table, int write, 962 void *buffer, size_t *lenp, loff_t *ppos, unsigned long convmul, 963 unsigned long convdiv) 964 { 965 return __do_proc_doulongvec_minmax(table->data, table, write, 966 buffer, lenp, ppos, convmul, convdiv); 967 } 968 969 /** 970 * proc_doulongvec_minmax - read a vector of long integers with min/max values 971 * @table: the sysctl table 972 * @write: %TRUE if this is a write to the sysctl file 973 * @buffer: the user buffer 974 * @lenp: the size of the user buffer 975 * @ppos: file position 976 * 977 * Reads/writes up to table->maxlen/sizeof(unsigned long) unsigned long 978 * values from/to the user buffer, treated as an ASCII string. 979 * 980 * This routine will ensure the values are within the range specified by 981 * table->extra1 (min) and table->extra2 (max). 982 * 983 * Returns 0 on success. 984 */ 985 int proc_doulongvec_minmax(const struct ctl_table *table, int write, 986 void *buffer, size_t *lenp, loff_t *ppos) 987 { 988 return do_proc_doulongvec_minmax(table, write, buffer, lenp, ppos, 1l, 1l); 989 } 990 991 /** 992 * proc_doulongvec_ms_jiffies_minmax - read a vector of millisecond values with min/max values 993 * @table: the sysctl table 994 * @write: %TRUE if this is a write to the sysctl file 995 * @buffer: the user buffer 996 * @lenp: the size of the user buffer 997 * @ppos: file position 998 * 999 * Reads/writes up to table->maxlen/sizeof(unsigned long) unsigned long 1000 * values from/to the user buffer, treated as an ASCII string. The values 1001 * are treated as milliseconds, and converted to jiffies when they are stored. 1002 * 1003 * This routine will ensure the values are within the range specified by 1004 * table->extra1 (min) and table->extra2 (max). 1005 * 1006 * Returns 0 on success. 1007 */ 1008 int proc_doulongvec_ms_jiffies_minmax(const struct ctl_table *table, int write, 1009 void *buffer, size_t *lenp, loff_t *ppos) 1010 { 1011 return do_proc_doulongvec_minmax(table, write, buffer, 1012 lenp, ppos, HZ, 1000l); 1013 } 1014 1015 1016 static int do_proc_dointvec_jiffies_conv(bool *negp, unsigned long *lvalp, 1017 int *valp, 1018 int write, void *data) 1019 { 1020 if (write) { 1021 if (*lvalp > INT_MAX / HZ) 1022 return 1; 1023 if (*negp) 1024 WRITE_ONCE(*valp, -*lvalp * HZ); 1025 else 1026 WRITE_ONCE(*valp, *lvalp * HZ); 1027 } else { 1028 int val = READ_ONCE(*valp); 1029 unsigned long lval; 1030 if (val < 0) { 1031 *negp = true; 1032 lval = -(unsigned long)val; 1033 } else { 1034 *negp = false; 1035 lval = (unsigned long)val; 1036 } 1037 *lvalp = lval / HZ; 1038 } 1039 return 0; 1040 } 1041 1042 static int do_proc_dointvec_userhz_jiffies_conv(bool *negp, unsigned long *lvalp, 1043 int *valp, 1044 int write, void *data) 1045 { 1046 if (write) { 1047 if (USER_HZ < HZ && *lvalp > (LONG_MAX / HZ) * USER_HZ) 1048 return 1; 1049 *valp = clock_t_to_jiffies(*negp ? -*lvalp : *lvalp); 1050 } else { 1051 int val = *valp; 1052 unsigned long lval; 1053 if (val < 0) { 1054 *negp = true; 1055 lval = -(unsigned long)val; 1056 } else { 1057 *negp = false; 1058 lval = (unsigned long)val; 1059 } 1060 *lvalp = jiffies_to_clock_t(lval); 1061 } 1062 return 0; 1063 } 1064 1065 static int do_proc_dointvec_ms_jiffies_conv(bool *negp, unsigned long *lvalp, 1066 int *valp, 1067 int write, void *data) 1068 { 1069 if (write) { 1070 unsigned long jif = msecs_to_jiffies(*negp ? -*lvalp : *lvalp); 1071 1072 if (jif > INT_MAX) 1073 return 1; 1074 WRITE_ONCE(*valp, (int)jif); 1075 } else { 1076 int val = READ_ONCE(*valp); 1077 unsigned long lval; 1078 if (val < 0) { 1079 *negp = true; 1080 lval = -(unsigned long)val; 1081 } else { 1082 *negp = false; 1083 lval = (unsigned long)val; 1084 } 1085 *lvalp = jiffies_to_msecs(lval); 1086 } 1087 return 0; 1088 } 1089 1090 static int do_proc_dointvec_ms_jiffies_minmax_conv(bool *negp, unsigned long *lvalp, 1091 int *valp, int write, void *data) 1092 { 1093 int tmp, ret; 1094 struct do_proc_dointvec_minmax_conv_param *param = data; 1095 /* 1096 * If writing, first do so via a temporary local int so we can 1097 * bounds-check it before touching *valp. 1098 */ 1099 int *ip = write ? &tmp : valp; 1100 1101 ret = do_proc_dointvec_ms_jiffies_conv(negp, lvalp, ip, write, data); 1102 if (ret) 1103 return ret; 1104 1105 if (write) { 1106 if ((param->min && *param->min > tmp) || 1107 (param->max && *param->max < tmp)) 1108 return -EINVAL; 1109 *valp = tmp; 1110 } 1111 return 0; 1112 } 1113 1114 /** 1115 * proc_dointvec_jiffies - read a vector of integers as seconds 1116 * @table: the sysctl table 1117 * @write: %TRUE if this is a write to the sysctl file 1118 * @buffer: the user buffer 1119 * @lenp: the size of the user buffer 1120 * @ppos: file position 1121 * 1122 * Reads/writes up to table->maxlen/sizeof(unsigned int) integer 1123 * values from/to the user buffer, treated as an ASCII string. 1124 * The values read are assumed to be in seconds, and are converted into 1125 * jiffies. 1126 * 1127 * Returns 0 on success. 1128 */ 1129 int proc_dointvec_jiffies(const struct ctl_table *table, int write, 1130 void *buffer, size_t *lenp, loff_t *ppos) 1131 { 1132 return do_proc_dointvec(table,write,buffer,lenp,ppos, 1133 do_proc_dointvec_jiffies_conv,NULL); 1134 } 1135 1136 int proc_dointvec_ms_jiffies_minmax(const struct ctl_table *table, int write, 1137 void *buffer, size_t *lenp, loff_t *ppos) 1138 { 1139 struct do_proc_dointvec_minmax_conv_param param = { 1140 .min = (int *) table->extra1, 1141 .max = (int *) table->extra2, 1142 }; 1143 return do_proc_dointvec(table, write, buffer, lenp, ppos, 1144 do_proc_dointvec_ms_jiffies_minmax_conv, ¶m); 1145 } 1146 1147 /** 1148 * proc_dointvec_userhz_jiffies - read a vector of integers as 1/USER_HZ seconds 1149 * @table: the sysctl table 1150 * @write: %TRUE if this is a write to the sysctl file 1151 * @buffer: the user buffer 1152 * @lenp: the size of the user buffer 1153 * @ppos: pointer to the file position 1154 * 1155 * Reads/writes up to table->maxlen/sizeof(unsigned int) integer 1156 * values from/to the user buffer, treated as an ASCII string. 1157 * The values read are assumed to be in 1/USER_HZ seconds, and 1158 * are converted into jiffies. 1159 * 1160 * Returns 0 on success. 1161 */ 1162 int proc_dointvec_userhz_jiffies(const struct ctl_table *table, int write, 1163 void *buffer, size_t *lenp, loff_t *ppos) 1164 { 1165 return do_proc_dointvec(table, write, buffer, lenp, ppos, 1166 do_proc_dointvec_userhz_jiffies_conv, NULL); 1167 } 1168 1169 /** 1170 * proc_dointvec_ms_jiffies - read a vector of integers as 1 milliseconds 1171 * @table: the sysctl table 1172 * @write: %TRUE if this is a write to the sysctl file 1173 * @buffer: the user buffer 1174 * @lenp: the size of the user buffer 1175 * @ppos: the current position in the file 1176 * 1177 * Reads/writes up to table->maxlen/sizeof(unsigned int) integer 1178 * values from/to the user buffer, treated as an ASCII string. 1179 * The values read are assumed to be in 1/1000 seconds, and 1180 * are converted into jiffies. 1181 * 1182 * Returns 0 on success. 1183 */ 1184 int proc_dointvec_ms_jiffies(const struct ctl_table *table, int write, void *buffer, 1185 size_t *lenp, loff_t *ppos) 1186 { 1187 return do_proc_dointvec(table, write, buffer, lenp, ppos, 1188 do_proc_dointvec_ms_jiffies_conv, NULL); 1189 } 1190 1191 /** 1192 * proc_do_large_bitmap - read/write from/to a large bitmap 1193 * @table: the sysctl table 1194 * @write: %TRUE if this is a write to the sysctl file 1195 * @buffer: the user buffer 1196 * @lenp: the size of the user buffer 1197 * @ppos: file position 1198 * 1199 * The bitmap is stored at table->data and the bitmap length (in bits) 1200 * in table->maxlen. 1201 * 1202 * We use a range comma separated format (e.g. 1,3-4,10-10) so that 1203 * large bitmaps may be represented in a compact manner. Writing into 1204 * the file will clear the bitmap then update it with the given input. 1205 * 1206 * Returns 0 on success. 1207 */ 1208 int proc_do_large_bitmap(const struct ctl_table *table, int write, 1209 void *buffer, size_t *lenp, loff_t *ppos) 1210 { 1211 int err = 0; 1212 size_t left = *lenp; 1213 unsigned long bitmap_len = table->maxlen; 1214 unsigned long *bitmap = *(unsigned long **) table->data; 1215 unsigned long *tmp_bitmap = NULL; 1216 char tr_a[] = { '-', ',', '\n' }, tr_b[] = { ',', '\n', 0 }, c; 1217 1218 if (!bitmap || !bitmap_len || !left || (*ppos && !write)) { 1219 *lenp = 0; 1220 return 0; 1221 } 1222 1223 if (write) { 1224 char *p = buffer; 1225 size_t skipped = 0; 1226 1227 if (left > PAGE_SIZE - 1) { 1228 left = PAGE_SIZE - 1; 1229 /* How much of the buffer we'll skip this pass */ 1230 skipped = *lenp - left; 1231 } 1232 1233 tmp_bitmap = bitmap_zalloc(bitmap_len, GFP_KERNEL); 1234 if (!tmp_bitmap) 1235 return -ENOMEM; 1236 proc_skip_char(&p, &left, '\n'); 1237 while (!err && left) { 1238 unsigned long val_a, val_b; 1239 bool neg; 1240 size_t saved_left; 1241 1242 /* In case we stop parsing mid-number, we can reset */ 1243 saved_left = left; 1244 err = proc_get_long(&p, &left, &val_a, &neg, tr_a, 1245 sizeof(tr_a), &c); 1246 /* 1247 * If we consumed the entirety of a truncated buffer or 1248 * only one char is left (may be a "-"), then stop here, 1249 * reset, & come back for more. 1250 */ 1251 if ((left <= 1) && skipped) { 1252 left = saved_left; 1253 break; 1254 } 1255 1256 if (err) 1257 break; 1258 if (val_a >= bitmap_len || neg) { 1259 err = -EINVAL; 1260 break; 1261 } 1262 1263 val_b = val_a; 1264 if (left) { 1265 p++; 1266 left--; 1267 } 1268 1269 if (c == '-') { 1270 err = proc_get_long(&p, &left, &val_b, 1271 &neg, tr_b, sizeof(tr_b), 1272 &c); 1273 /* 1274 * If we consumed all of a truncated buffer or 1275 * then stop here, reset, & come back for more. 1276 */ 1277 if (!left && skipped) { 1278 left = saved_left; 1279 break; 1280 } 1281 1282 if (err) 1283 break; 1284 if (val_b >= bitmap_len || neg || 1285 val_a > val_b) { 1286 err = -EINVAL; 1287 break; 1288 } 1289 if (left) { 1290 p++; 1291 left--; 1292 } 1293 } 1294 1295 bitmap_set(tmp_bitmap, val_a, val_b - val_a + 1); 1296 proc_skip_char(&p, &left, '\n'); 1297 } 1298 left += skipped; 1299 } else { 1300 unsigned long bit_a, bit_b = 0; 1301 bool first = 1; 1302 1303 while (left) { 1304 bit_a = find_next_bit(bitmap, bitmap_len, bit_b); 1305 if (bit_a >= bitmap_len) 1306 break; 1307 bit_b = find_next_zero_bit(bitmap, bitmap_len, 1308 bit_a + 1) - 1; 1309 1310 if (!first) 1311 proc_put_char(&buffer, &left, ','); 1312 proc_put_long(&buffer, &left, bit_a, false); 1313 if (bit_a != bit_b) { 1314 proc_put_char(&buffer, &left, '-'); 1315 proc_put_long(&buffer, &left, bit_b, false); 1316 } 1317 1318 first = 0; bit_b++; 1319 } 1320 proc_put_char(&buffer, &left, '\n'); 1321 } 1322 1323 if (!err) { 1324 if (write) { 1325 if (*ppos) 1326 bitmap_or(bitmap, bitmap, tmp_bitmap, bitmap_len); 1327 else 1328 bitmap_copy(bitmap, tmp_bitmap, bitmap_len); 1329 } 1330 *lenp -= left; 1331 *ppos += *lenp; 1332 } 1333 1334 bitmap_free(tmp_bitmap); 1335 return err; 1336 } 1337 1338 #else /* CONFIG_PROC_SYSCTL */ 1339 1340 int proc_dostring(const struct ctl_table *table, int write, 1341 void *buffer, size_t *lenp, loff_t *ppos) 1342 { 1343 return -ENOSYS; 1344 } 1345 1346 int proc_dobool(const struct ctl_table *table, int write, 1347 void *buffer, size_t *lenp, loff_t *ppos) 1348 { 1349 return -ENOSYS; 1350 } 1351 1352 int proc_dointvec(const struct ctl_table *table, int write, 1353 void *buffer, size_t *lenp, loff_t *ppos) 1354 { 1355 return -ENOSYS; 1356 } 1357 1358 int proc_douintvec(const struct ctl_table *table, int write, 1359 void *buffer, size_t *lenp, loff_t *ppos) 1360 { 1361 return -ENOSYS; 1362 } 1363 1364 int proc_dointvec_minmax(const struct ctl_table *table, int write, 1365 void *buffer, size_t *lenp, loff_t *ppos) 1366 { 1367 return -ENOSYS; 1368 } 1369 1370 int proc_douintvec_minmax(const struct ctl_table *table, int write, 1371 void *buffer, size_t *lenp, loff_t *ppos) 1372 { 1373 return -ENOSYS; 1374 } 1375 1376 int proc_dou8vec_minmax(const struct ctl_table *table, int write, 1377 void *buffer, size_t *lenp, loff_t *ppos) 1378 { 1379 return -ENOSYS; 1380 } 1381 1382 int proc_dointvec_jiffies(const struct ctl_table *table, int write, 1383 void *buffer, size_t *lenp, loff_t *ppos) 1384 { 1385 return -ENOSYS; 1386 } 1387 1388 int proc_dointvec_ms_jiffies_minmax(const struct ctl_table *table, int write, 1389 void *buffer, size_t *lenp, loff_t *ppos) 1390 { 1391 return -ENOSYS; 1392 } 1393 1394 int proc_dointvec_userhz_jiffies(const struct ctl_table *table, int write, 1395 void *buffer, size_t *lenp, loff_t *ppos) 1396 { 1397 return -ENOSYS; 1398 } 1399 1400 int proc_dointvec_ms_jiffies(const struct ctl_table *table, int write, 1401 void *buffer, size_t *lenp, loff_t *ppos) 1402 { 1403 return -ENOSYS; 1404 } 1405 1406 int proc_doulongvec_minmax(const struct ctl_table *table, int write, 1407 void *buffer, size_t *lenp, loff_t *ppos) 1408 { 1409 return -ENOSYS; 1410 } 1411 1412 int proc_doulongvec_ms_jiffies_minmax(const struct ctl_table *table, int write, 1413 void *buffer, size_t *lenp, loff_t *ppos) 1414 { 1415 return -ENOSYS; 1416 } 1417 1418 int proc_do_large_bitmap(const struct ctl_table *table, int write, 1419 void *buffer, size_t *lenp, loff_t *ppos) 1420 { 1421 return -ENOSYS; 1422 } 1423 1424 #endif /* CONFIG_PROC_SYSCTL */ 1425 1426 #if defined(CONFIG_SYSCTL) 1427 int proc_do_static_key(const struct ctl_table *table, int write, 1428 void *buffer, size_t *lenp, loff_t *ppos) 1429 { 1430 struct static_key *key = (struct static_key *)table->data; 1431 static DEFINE_MUTEX(static_key_mutex); 1432 int val, ret; 1433 struct ctl_table tmp = { 1434 .data = &val, 1435 .maxlen = sizeof(val), 1436 .mode = table->mode, 1437 .extra1 = SYSCTL_ZERO, 1438 .extra2 = SYSCTL_ONE, 1439 }; 1440 1441 if (write && !capable(CAP_SYS_ADMIN)) 1442 return -EPERM; 1443 1444 mutex_lock(&static_key_mutex); 1445 val = static_key_enabled(key); 1446 ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); 1447 if (write && !ret) { 1448 if (val) 1449 static_key_enable(key); 1450 else 1451 static_key_disable(key); 1452 } 1453 mutex_unlock(&static_key_mutex); 1454 return ret; 1455 } 1456 1457 static const struct ctl_table sysctl_subsys_table[] = { 1458 #ifdef CONFIG_PROC_SYSCTL 1459 { 1460 .procname = "sysctl_writes_strict", 1461 .data = &sysctl_writes_strict, 1462 .maxlen = sizeof(int), 1463 .mode = 0644, 1464 .proc_handler = proc_dointvec_minmax, 1465 .extra1 = SYSCTL_NEG_ONE, 1466 .extra2 = SYSCTL_ONE, 1467 }, 1468 #endif 1469 { 1470 .procname = "ngroups_max", 1471 .data = (void *)&ngroups_max, 1472 .maxlen = sizeof (int), 1473 .mode = 0444, 1474 .proc_handler = proc_dointvec, 1475 }, 1476 { 1477 .procname = "cap_last_cap", 1478 .data = (void *)&cap_last_cap, 1479 .maxlen = sizeof(int), 1480 .mode = 0444, 1481 .proc_handler = proc_dointvec, 1482 }, 1483 #ifdef CONFIG_SYSCTL_ARCH_UNALIGN_ALLOW 1484 { 1485 .procname = "unaligned-trap", 1486 .data = &unaligned_enabled, 1487 .maxlen = sizeof(int), 1488 .mode = 0644, 1489 .proc_handler = proc_dointvec, 1490 }, 1491 #endif 1492 #ifdef CONFIG_SYSCTL_ARCH_UNALIGN_NO_WARN 1493 { 1494 .procname = "ignore-unaligned-usertrap", 1495 .data = &no_unaligned_warning, 1496 .maxlen = sizeof (int), 1497 .mode = 0644, 1498 .proc_handler = proc_dointvec, 1499 }, 1500 #endif 1501 }; 1502 1503 int __init sysctl_init_bases(void) 1504 { 1505 register_sysctl_init("kernel", sysctl_subsys_table); 1506 1507 return 0; 1508 } 1509 #endif /* CONFIG_SYSCTL */ 1510 /* 1511 * No sense putting this after each symbol definition, twice, 1512 * exception granted :-) 1513 */ 1514 EXPORT_SYMBOL(proc_dobool); 1515 EXPORT_SYMBOL(proc_dointvec); 1516 EXPORT_SYMBOL(proc_douintvec); 1517 EXPORT_SYMBOL(proc_dointvec_jiffies); 1518 EXPORT_SYMBOL(proc_dointvec_minmax); 1519 EXPORT_SYMBOL_GPL(proc_douintvec_minmax); 1520 EXPORT_SYMBOL(proc_dointvec_userhz_jiffies); 1521 EXPORT_SYMBOL(proc_dointvec_ms_jiffies); 1522 EXPORT_SYMBOL(proc_dostring); 1523 EXPORT_SYMBOL(proc_doulongvec_minmax); 1524 EXPORT_SYMBOL(proc_doulongvec_ms_jiffies_minmax); 1525 EXPORT_SYMBOL(proc_do_large_bitmap); 1526