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/limits.h> 17 #include <linux/syscalls.h> 18 #include <linux/capability.h> 19 20 #include "../lib/kstrtox.h" 21 22 #include <linux/uaccess.h> 23 #include <asm/processor.h> 24 25 /* shared constants to be used in various sysctls */ 26 const int sysctl_vals[] = { 0, 1, 2, 3, 4, 100, 200, 1000, 3000, INT_MAX, 65535, -1 }; 27 EXPORT_SYMBOL(sysctl_vals); 28 29 const unsigned long sysctl_long_vals[] = { 0, 1, LONG_MAX }; 30 EXPORT_SYMBOL_GPL(sysctl_long_vals); 31 32 #if defined(CONFIG_SYSCTL) 33 34 /* Constants used for minimum and maximum */ 35 static const int ngroups_max = NGROUPS_MAX; 36 static const int cap_last_cap = CAP_LAST_CAP; 37 38 #ifdef CONFIG_PROC_SYSCTL 39 40 /** 41 * enum sysctl_writes_mode - supported sysctl write modes 42 * 43 * @SYSCTL_WRITES_LEGACY: each write syscall must fully contain the sysctl value 44 * to be written, and multiple writes on the same sysctl file descriptor 45 * will rewrite the sysctl value, regardless of file position. No warning 46 * is issued when the initial position is not 0. 47 * @SYSCTL_WRITES_WARN: same as above but warn when the initial file position is 48 * not 0. 49 * @SYSCTL_WRITES_STRICT: writes to numeric sysctl entries must always be at 50 * file position 0 and the value must be fully contained in the buffer 51 * sent to the write syscall. If dealing with strings respect the file 52 * position, but restrict this to the max length of the buffer, anything 53 * passed the max length will be ignored. Multiple writes will append 54 * to the buffer. 55 * 56 * These write modes control how current file position affects the behavior of 57 * updating internal kernel (SYSCTL_USER_TO_KERN) sysctl values through the proc 58 * 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 dir, 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 (SYSCTL_USER_TO_KERN(dir)) { 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 * @dir: %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 dir, 190 void *buffer, size_t *lenp, loff_t *ppos) 191 { 192 if (SYSCTL_USER_TO_KERN(dir)) 193 proc_first_pos_non_zero_ignore(ppos, table); 194 195 return _proc_do_string(table->data, table->maxlen, dir, 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 /** 358 * proc_uint_u2k_conv_uop - Assign user value to a kernel pointer 359 * 360 * @u_ptr: pointer to user space variable 361 * @k_ptr: pointer to kernel variable 362 * @u_ptr_op: execute this function before assigning to k_ptr 363 * 364 * Uses WRITE_ONCE to assign value to k_ptr. Executes u_ptr_op if 365 * not NULL. Check that the values are less than UINT_MAX to avoid 366 * having to support wrap around from userspace. 367 * 368 * returns 0 on success. 369 */ 370 int proc_uint_u2k_conv_uop(const ulong *u_ptr, uint *k_ptr, 371 ulong (*u_ptr_op)(const ulong)) 372 { 373 ulong u = u_ptr_op ? u_ptr_op(*u_ptr) : *u_ptr; 374 375 if (u > UINT_MAX) 376 return -EINVAL; 377 WRITE_ONCE(*k_ptr, u); 378 return 0; 379 } 380 381 /** 382 * proc_uint_k2u_conv - Assign kernel value to a user space pointer 383 * 384 * @u_ptr: pointer to user space variable 385 * @k_ptr: pointer to kernel variable 386 * 387 * Uses READ_ONCE to assign value to u_ptr. 388 * 389 * returns 0 on success. 390 */ 391 int proc_uint_k2u_conv(ulong *u_ptr, const uint *k_ptr) 392 { 393 uint val = READ_ONCE(*k_ptr); 394 *u_ptr = (ulong)val; 395 return 0; 396 } 397 398 /** 399 * proc_uint_conv - Change user or kernel pointer based on direction 400 * 401 * @u_ptr: pointer to user variable 402 * @k_ptr: pointer to kernel variable 403 * @dir: %TRUE if this is a write to the sysctl file 404 * @tbl: the sysctl table 405 * @k_ptr_range_check: Check range for k_ptr when %TRUE 406 * @user_to_kern: Callback used to assign value from user to kernel var 407 * @kern_to_user: Callback used to assign value from kernel to user var 408 * 409 * When direction is kernel to user, then the u_ptr is modified. 410 * When direction is user to kernel, then the k_ptr is modified. 411 * 412 * Returns 0 on success 413 */ 414 int proc_uint_conv(ulong *u_ptr, uint *k_ptr, int dir, 415 const struct ctl_table *tbl, bool k_ptr_range_check, 416 int (*user_to_kern)(const ulong *u_ptr, uint *k_ptr), 417 int (*kern_to_user)(ulong *u_ptr, const uint *k_ptr)) 418 { 419 if (SYSCTL_KERN_TO_USER(dir)) 420 return kern_to_user(u_ptr, k_ptr); 421 422 if (k_ptr_range_check) { 423 uint tmp_k; 424 int ret; 425 426 if (!tbl) 427 return -EINVAL; 428 ret = user_to_kern(u_ptr, &tmp_k); 429 if (ret) 430 return ret; 431 if ((tbl->extra1 && 432 *(uint *)tbl->extra1 > tmp_k) || 433 (tbl->extra2 && 434 *(uint *)tbl->extra2 < tmp_k)) 435 return -ERANGE; 436 WRITE_ONCE(*k_ptr, tmp_k); 437 } else 438 return user_to_kern(u_ptr, k_ptr); 439 return 0; 440 } 441 442 static int proc_uint_u2k_conv(const ulong *u_ptr, uint *k_ptr) 443 { 444 return proc_uint_u2k_conv_uop(u_ptr, k_ptr, NULL); 445 } 446 447 static int do_proc_uint_conv(ulong *u_ptr, uint *k_ptr, int dir, 448 const struct ctl_table *tbl) 449 { 450 return proc_uint_conv(u_ptr, k_ptr, dir, tbl, false, 451 proc_uint_u2k_conv, proc_uint_k2u_conv); 452 } 453 454 static int do_proc_uint_conv_minmax(ulong *u_ptr, uint *k_ptr, int dir, 455 const struct ctl_table *tbl) 456 { 457 return proc_uint_conv(u_ptr, k_ptr, dir, tbl, true, 458 proc_uint_u2k_conv, proc_uint_k2u_conv); 459 } 460 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 } 572 573 static const char proc_wspace_sep[] = { ' ', '\t', '\n' }; 574 575 static int do_proc_dointvec(const struct ctl_table *table, int dir, 576 void *buffer, size_t *lenp, loff_t *ppos, 577 int (*conv)(bool *negp, unsigned long *u_ptr, int *k_ptr, 578 int dir, const struct ctl_table *table)) 579 { 580 int *i, vleft, first = 1, err = 0; 581 size_t left; 582 char *p; 583 584 if (!table->data || !table->maxlen || !*lenp || 585 (*ppos && SYSCTL_KERN_TO_USER(dir))) { 586 *lenp = 0; 587 return 0; 588 } 589 590 i = (int *) table->data; 591 vleft = table->maxlen / sizeof(*i); 592 left = *lenp; 593 594 if (!conv) 595 conv = do_proc_int_conv; 596 597 if (SYSCTL_USER_TO_KERN(dir)) { 598 if (proc_first_pos_non_zero_ignore(ppos, table)) 599 goto out; 600 601 if (left > PAGE_SIZE - 1) 602 left = PAGE_SIZE - 1; 603 p = buffer; 604 } 605 606 for (; left && vleft--; i++, first=0) { 607 unsigned long lval; 608 bool neg; 609 610 if (SYSCTL_USER_TO_KERN(dir)) { 611 proc_skip_spaces(&p, &left); 612 613 if (!left) 614 break; 615 err = proc_get_long(&p, &left, &lval, &neg, 616 proc_wspace_sep, 617 sizeof(proc_wspace_sep), NULL); 618 if (err) 619 break; 620 if (conv(&neg, &lval, i, 1, table)) { 621 err = -EINVAL; 622 break; 623 } 624 } else { 625 if (conv(&neg, &lval, i, 0, table)) { 626 err = -EINVAL; 627 break; 628 } 629 if (!first) 630 proc_put_char(&buffer, &left, '\t'); 631 proc_put_long(&buffer, &left, lval, neg); 632 } 633 } 634 635 if (SYSCTL_KERN_TO_USER(dir) && !first && left && !err) 636 proc_put_char(&buffer, &left, '\n'); 637 if (SYSCTL_USER_TO_KERN(dir) && !err && left) 638 proc_skip_spaces(&p, &left); 639 if (SYSCTL_USER_TO_KERN(dir) && first) 640 return err ? : -EINVAL; 641 *lenp -= left; 642 out: 643 *ppos += *lenp; 644 return err; 645 } 646 647 static int do_proc_douintvec_w(const struct ctl_table *table, void *buffer, 648 size_t *lenp, loff_t *ppos, 649 int (*conv)(unsigned long *u_ptr, 650 unsigned int *k_ptr, int dir, 651 const struct ctl_table *table)) 652 { 653 unsigned long lval; 654 int err = 0; 655 size_t left; 656 bool neg; 657 char *p = buffer; 658 659 left = *lenp; 660 661 if (proc_first_pos_non_zero_ignore(ppos, table)) 662 goto bail_early; 663 664 if (left > PAGE_SIZE - 1) 665 left = PAGE_SIZE - 1; 666 667 proc_skip_spaces(&p, &left); 668 if (!left) { 669 err = -EINVAL; 670 goto out_free; 671 } 672 673 err = proc_get_long(&p, &left, &lval, &neg, 674 proc_wspace_sep, 675 sizeof(proc_wspace_sep), NULL); 676 if (err || neg) { 677 err = -EINVAL; 678 goto out_free; 679 } 680 681 if (conv(&lval, (unsigned int *) table->data, 1, table)) { 682 err = -EINVAL; 683 goto out_free; 684 } 685 686 if (!err && left) 687 proc_skip_spaces(&p, &left); 688 689 out_free: 690 if (err) 691 return -EINVAL; 692 693 return 0; 694 695 bail_early: 696 *ppos += *lenp; 697 return err; 698 } 699 700 static int do_proc_douintvec_r(const struct ctl_table *table, void *buffer, 701 size_t *lenp, loff_t *ppos, 702 int (*conv)(unsigned long *u_ptr, 703 unsigned int *k_ptr, int dir, 704 const struct ctl_table *table)) 705 { 706 unsigned long lval; 707 int err = 0; 708 size_t left; 709 710 left = *lenp; 711 712 if (conv(&lval, (unsigned int *) table->data, 0, table)) { 713 err = -EINVAL; 714 goto out; 715 } 716 717 proc_put_long(&buffer, &left, lval, false); 718 if (!left) 719 goto out; 720 721 proc_put_char(&buffer, &left, '\n'); 722 723 out: 724 *lenp -= left; 725 *ppos += *lenp; 726 727 return err; 728 } 729 730 static int do_proc_douintvec(const struct ctl_table *table, int dir, 731 void *buffer, size_t *lenp, loff_t *ppos, 732 int (*conv)(unsigned long *u_ptr, 733 unsigned int *k_ptr, int dir, 734 const struct ctl_table *table)) 735 { 736 unsigned int vleft; 737 738 if (!table->data || !table->maxlen || !*lenp || 739 (*ppos && SYSCTL_KERN_TO_USER(dir))) { 740 *lenp = 0; 741 return 0; 742 } 743 744 vleft = table->maxlen / sizeof(unsigned int); 745 746 /* 747 * Arrays are not supported, keep this simple. *Do not* add 748 * support for them. 749 */ 750 if (vleft != 1) { 751 *lenp = 0; 752 return -EINVAL; 753 } 754 755 if (!conv) 756 conv = do_proc_uint_conv; 757 758 if (SYSCTL_USER_TO_KERN(dir)) 759 return do_proc_douintvec_w(table, buffer, lenp, ppos, conv); 760 return do_proc_douintvec_r(table, buffer, lenp, ppos, conv); 761 } 762 763 /** 764 * proc_douintvec_conv - read a vector of unsigned ints with a custom converter 765 * 766 * @table: the sysctl table 767 * @dir: %TRUE if this is a write to the sysctl file 768 * @buffer: the user buffer 769 * @lenp: the size of the user buffer 770 * @ppos: file position 771 * @conv: Custom converter call back 772 * 773 * Reads/writes up to table->maxlen/sizeof(unsigned int) unsigned integer 774 * values from/to the user buffer, treated as an ASCII string. Negative 775 * strings are not allowed. 776 * 777 * Returns 0 on success 778 */ 779 int proc_douintvec_conv(const struct ctl_table *table, int dir, void *buffer, 780 size_t *lenp, loff_t *ppos, 781 int (*conv)(unsigned long *u_ptr, unsigned int *k_ptr, 782 int dir, const struct ctl_table *table)) 783 { 784 return do_proc_douintvec(table, dir, buffer, lenp, ppos, conv); 785 } 786 787 /** 788 * proc_dobool - read/write a bool 789 * @table: the sysctl table 790 * @dir: %TRUE if this is a write to the sysctl file 791 * @buffer: the user buffer 792 * @lenp: the size of the user buffer 793 * @ppos: file position 794 * 795 * Reads/writes one integer value from/to the user buffer, 796 * treated as an ASCII string. 797 * 798 * table->data must point to a bool variable and table->maxlen must 799 * be sizeof(bool). 800 * 801 * Returns 0 on success. 802 */ 803 int proc_dobool(const struct ctl_table *table, int dir, void *buffer, 804 size_t *lenp, loff_t *ppos) 805 { 806 struct ctl_table tmp; 807 bool *data = table->data; 808 int res, val; 809 810 /* Do not support arrays yet. */ 811 if (table->maxlen != sizeof(bool)) 812 return -EINVAL; 813 814 tmp = *table; 815 tmp.maxlen = sizeof(val); 816 tmp.data = &val; 817 818 val = READ_ONCE(*data); 819 res = proc_dointvec(&tmp, dir, buffer, lenp, ppos); 820 if (res) 821 return res; 822 if (SYSCTL_USER_TO_KERN(dir)) 823 WRITE_ONCE(*data, val); 824 return 0; 825 } 826 827 /** 828 * proc_dointvec - read a vector of integers 829 * @table: the sysctl table 830 * @dir: %TRUE if this is a write to the sysctl file 831 * @buffer: the user buffer 832 * @lenp: the size of the user buffer 833 * @ppos: file position 834 * 835 * Reads/writes up to table->maxlen/sizeof(unsigned int) integer 836 * values from/to the user buffer, treated as an ASCII string. 837 * 838 * Returns 0 on success. 839 */ 840 int proc_dointvec(const struct ctl_table *table, int dir, void *buffer, 841 size_t *lenp, loff_t *ppos) 842 { 843 return do_proc_dointvec(table, dir, buffer, lenp, ppos, NULL); 844 } 845 846 /** 847 * proc_douintvec - read a vector of unsigned integers 848 * @table: the sysctl table 849 * @dir: %TRUE if this is a write to the sysctl file 850 * @buffer: the user buffer 851 * @lenp: the size of the user buffer 852 * @ppos: file position 853 * 854 * Reads/writes up to table->maxlen/sizeof(unsigned int) unsigned integer 855 * values from/to the user buffer, treated as an ASCII string. 856 * 857 * Returns 0 on success. 858 */ 859 int proc_douintvec(const struct ctl_table *table, int dir, void *buffer, 860 size_t *lenp, loff_t *ppos) 861 { 862 return do_proc_douintvec(table, dir, buffer, lenp, ppos, 863 do_proc_uint_conv); 864 } 865 866 /** 867 * proc_dointvec_minmax - read a vector of integers with min/max values 868 * @table: the sysctl table 869 * @dir: %TRUE if this is a write to the sysctl file 870 * @buffer: the user buffer 871 * @lenp: the size of the user buffer 872 * @ppos: file position 873 * 874 * Reads/writes up to table->maxlen/sizeof(unsigned int) integer 875 * values from/to the user buffer, treated as an ASCII string. 876 * 877 * This routine will ensure the values are within the range specified by 878 * table->extra1 (min) and table->extra2 (max). 879 * 880 * Returns 0 on success or -EINVAL when the range check fails and 881 * SYSCTL_USER_TO_KERN(dir) == true 882 */ 883 int proc_dointvec_minmax(const struct ctl_table *table, int dir, 884 void *buffer, size_t *lenp, loff_t *ppos) 885 { 886 return do_proc_dointvec(table, dir, buffer, lenp, ppos, 887 do_proc_int_conv_minmax); 888 } 889 890 /** 891 * proc_douintvec_minmax - read a vector of unsigned ints with min/max values 892 * @table: the sysctl table 893 * @dir: %TRUE if this is a write to the sysctl file 894 * @buffer: the user buffer 895 * @lenp: the size of the user buffer 896 * @ppos: file position 897 * 898 * Reads/writes up to table->maxlen/sizeof(unsigned int) unsigned integer 899 * values from/to the user buffer, treated as an ASCII string. Negative 900 * strings are not allowed. 901 * 902 * When changing the kernel variable, this routine will ensure the values 903 * are within the range specified by table->extra1 (min) and table->extra2 904 * (max). And Check that the values are less than UINT_MAX to avoid having to 905 * support wrap around uses from userspace. 906 * 907 * Returns 0 on success or -ERANGE when range check failes and 908 * SYSCTL_USER_TO_KERN(dir) == true 909 */ 910 int proc_douintvec_minmax(const struct ctl_table *table, int dir, 911 void *buffer, size_t *lenp, loff_t *ppos) 912 { 913 return do_proc_douintvec(table, dir, buffer, lenp, ppos, 914 do_proc_uint_conv_minmax); 915 } 916 917 /** 918 * proc_dou8vec_minmax - read a vector of unsigned chars with min/max values 919 * @table: the sysctl table 920 * @dir: %TRUE if this is a write to the sysctl file 921 * @buffer: the user buffer 922 * @lenp: the size of the user buffer 923 * @ppos: file position 924 * 925 * Reads/writes up to table->maxlen/sizeof(u8) unsigned chars 926 * values from/to the user buffer, treated as an ASCII string. Negative 927 * strings are not allowed. 928 * 929 * This routine will ensure the values are within the range specified by 930 * table->extra1 (min) and table->extra2 (max). 931 * 932 * Returns 0 on success or an error on SYSCTL_USER_TO_KERN(dir) == true 933 * and the range check fails. 934 */ 935 int proc_dou8vec_minmax(const struct ctl_table *table, int dir, 936 void *buffer, size_t *lenp, loff_t *ppos) 937 { 938 struct ctl_table tmp; 939 unsigned int min = 0, max = 255U, val; 940 u8 *data = table->data; 941 int res; 942 943 /* Do not support arrays yet. */ 944 if (table->maxlen != sizeof(u8)) 945 return -EINVAL; 946 947 tmp = *table; 948 949 tmp.maxlen = sizeof(val); 950 tmp.data = &val; 951 if (!tmp.extra1) 952 tmp.extra1 = (unsigned int *) &min; 953 if (!tmp.extra2) 954 tmp.extra2 = (unsigned int *) &max; 955 956 val = READ_ONCE(*data); 957 res = do_proc_douintvec(&tmp, dir, buffer, lenp, ppos, 958 do_proc_uint_conv_minmax); 959 if (res) 960 return res; 961 if (SYSCTL_USER_TO_KERN(dir)) 962 WRITE_ONCE(*data, val); 963 return 0; 964 } 965 EXPORT_SYMBOL_GPL(proc_dou8vec_minmax); 966 967 static int do_proc_doulongvec_minmax(const struct ctl_table *table, int dir, 968 void *buffer, size_t *lenp, loff_t *ppos, 969 unsigned long convmul, 970 unsigned long convdiv) 971 { 972 unsigned long *i, *min, *max; 973 int vleft, first = 1, err = 0; 974 size_t left; 975 char *p; 976 977 if (!table->data || !table->maxlen || !*lenp || 978 (*ppos && SYSCTL_KERN_TO_USER(dir))) { 979 *lenp = 0; 980 return 0; 981 } 982 983 i = table->data; 984 min = table->extra1; 985 max = table->extra2; 986 vleft = table->maxlen / sizeof(unsigned long); 987 left = *lenp; 988 989 if (SYSCTL_USER_TO_KERN(dir)) { 990 if (proc_first_pos_non_zero_ignore(ppos, table)) 991 goto out; 992 993 if (left > PAGE_SIZE - 1) 994 left = PAGE_SIZE - 1; 995 p = buffer; 996 } 997 998 for (; left && vleft--; i++, first = 0) { 999 unsigned long val; 1000 1001 if (SYSCTL_USER_TO_KERN(dir)) { 1002 bool neg; 1003 1004 proc_skip_spaces(&p, &left); 1005 if (!left) 1006 break; 1007 1008 err = proc_get_long(&p, &left, &val, &neg, 1009 proc_wspace_sep, 1010 sizeof(proc_wspace_sep), NULL); 1011 if (err || neg) { 1012 err = -EINVAL; 1013 break; 1014 } 1015 1016 val = convmul * val / convdiv; 1017 if ((min && val < *min) || (max && val > *max)) { 1018 err = -EINVAL; 1019 break; 1020 } 1021 WRITE_ONCE(*i, val); 1022 } else { 1023 val = convdiv * READ_ONCE(*i) / convmul; 1024 if (!first) 1025 proc_put_char(&buffer, &left, '\t'); 1026 proc_put_long(&buffer, &left, val, false); 1027 } 1028 } 1029 1030 if (SYSCTL_KERN_TO_USER(dir) && !first && left && !err) 1031 proc_put_char(&buffer, &left, '\n'); 1032 if (SYSCTL_USER_TO_KERN(dir) && !err) 1033 proc_skip_spaces(&p, &left); 1034 if (SYSCTL_USER_TO_KERN(dir) && first) 1035 return err ? : -EINVAL; 1036 *lenp -= left; 1037 out: 1038 *ppos += *lenp; 1039 return err; 1040 } 1041 1042 int proc_doulongvec_minmax_conv(const struct ctl_table *table, int dir, 1043 void *buffer, size_t *lenp, loff_t *ppos, 1044 unsigned long convmul, unsigned long convdiv) 1045 { 1046 return do_proc_doulongvec_minmax(table, dir, buffer, lenp, ppos, 1047 convmul, convdiv); 1048 } 1049 1050 /** 1051 * proc_doulongvec_minmax - read a vector of long integers with min/max values 1052 * @table: the sysctl table 1053 * @dir: %TRUE if this is a write to the sysctl file 1054 * @buffer: the user buffer 1055 * @lenp: the size of the user buffer 1056 * @ppos: file position 1057 * 1058 * Reads/writes up to table->maxlen/sizeof(unsigned long) unsigned long 1059 * values from/to the user buffer, treated as an ASCII string. 1060 * 1061 * This routine will ensure the values are within the range specified by 1062 * table->extra1 (min) and table->extra2 (max). 1063 * 1064 * Returns 0 on success. 1065 */ 1066 int proc_doulongvec_minmax(const struct ctl_table *table, int dir, 1067 void *buffer, size_t *lenp, loff_t *ppos) 1068 { 1069 return proc_doulongvec_minmax_conv(table, dir, buffer, lenp, ppos, 1l, 1l); 1070 } 1071 1072 /** 1073 * proc_dointvec_conv - read a vector of ints with a custom converter 1074 * @table: the sysctl table 1075 * @dir: %TRUE if this is a write to the sysctl file 1076 * @buffer: the user buffer 1077 * @lenp: the size of the user buffer 1078 * @ppos: file position 1079 * @conv: Custom converter call back 1080 * 1081 * Reads/writes up to table->maxlen/sizeof(unsigned int) unsigned integer 1082 * values from/to the user buffer, treated as an ASCII string. Negative 1083 * strings are not allowed. 1084 * 1085 * Returns: 0 on success 1086 */ 1087 1088 int proc_dointvec_conv(const struct ctl_table *table, int dir, void *buffer, 1089 size_t *lenp, loff_t *ppos, 1090 int (*conv)(bool *negp, unsigned long *u_ptr, int *k_ptr, 1091 int dir, const struct ctl_table *table)) 1092 { 1093 return do_proc_dointvec(table, dir, buffer, lenp, ppos, conv); 1094 } 1095 1096 /** 1097 * proc_do_large_bitmap - read/write from/to a large bitmap 1098 * @table: the sysctl table 1099 * @dir: %TRUE if this is a write to the sysctl file 1100 * @buffer: the user buffer 1101 * @lenp: the size of the user buffer 1102 * @ppos: file position 1103 * 1104 * The bitmap is stored at table->data and the bitmap length (in bits) 1105 * in table->maxlen. 1106 * 1107 * We use a range comma separated format (e.g. 1,3-4,10-10) so that 1108 * large bitmaps may be represented in a compact manner. Writing into 1109 * the file will clear the bitmap then update it with the given input. 1110 * 1111 * Returns 0 on success. 1112 */ 1113 int proc_do_large_bitmap(const struct ctl_table *table, int dir, 1114 void *buffer, size_t *lenp, loff_t *ppos) 1115 { 1116 int err = 0; 1117 size_t left = *lenp; 1118 unsigned long bitmap_len = table->maxlen; 1119 unsigned long *bitmap = *(unsigned long **) table->data; 1120 unsigned long *tmp_bitmap = NULL; 1121 char tr_a[] = { '-', ',', '\n' }, tr_b[] = { ',', '\n', 0 }, c; 1122 1123 if (!bitmap || !bitmap_len || !left || (*ppos && SYSCTL_KERN_TO_USER(dir))) { 1124 *lenp = 0; 1125 return 0; 1126 } 1127 1128 if (SYSCTL_USER_TO_KERN(dir)) { 1129 char *p = buffer; 1130 size_t skipped = 0; 1131 1132 if (left > PAGE_SIZE - 1) { 1133 left = PAGE_SIZE - 1; 1134 /* How much of the buffer we'll skip this pass */ 1135 skipped = *lenp - left; 1136 } 1137 1138 tmp_bitmap = bitmap_zalloc(bitmap_len, GFP_KERNEL); 1139 if (!tmp_bitmap) 1140 return -ENOMEM; 1141 proc_skip_char(&p, &left, '\n'); 1142 while (!err && left) { 1143 unsigned long val_a, val_b; 1144 bool neg; 1145 size_t saved_left; 1146 1147 /* In case we stop parsing mid-number, we can reset */ 1148 saved_left = left; 1149 err = proc_get_long(&p, &left, &val_a, &neg, tr_a, 1150 sizeof(tr_a), &c); 1151 /* 1152 * If we consumed the entirety of a truncated buffer or 1153 * only one char is left (may be a "-"), then stop here, 1154 * reset, & come back for more. 1155 */ 1156 if ((left <= 1) && skipped) { 1157 left = saved_left; 1158 break; 1159 } 1160 1161 if (err) 1162 break; 1163 if (val_a >= bitmap_len || neg) { 1164 err = -EINVAL; 1165 break; 1166 } 1167 1168 val_b = val_a; 1169 if (left) { 1170 p++; 1171 left--; 1172 } 1173 1174 if (c == '-') { 1175 err = proc_get_long(&p, &left, &val_b, 1176 &neg, tr_b, sizeof(tr_b), 1177 &c); 1178 /* 1179 * If we consumed all of a truncated buffer or 1180 * then stop here, reset, & come back for more. 1181 */ 1182 if (!left && skipped) { 1183 left = saved_left; 1184 break; 1185 } 1186 1187 if (err) 1188 break; 1189 if (val_b >= bitmap_len || neg || 1190 val_a > val_b) { 1191 err = -EINVAL; 1192 break; 1193 } 1194 if (left) { 1195 p++; 1196 left--; 1197 } 1198 } 1199 1200 bitmap_set(tmp_bitmap, val_a, val_b - val_a + 1); 1201 proc_skip_char(&p, &left, '\n'); 1202 } 1203 left += skipped; 1204 } else { 1205 unsigned long bit_a, bit_b = 0; 1206 bool first = 1; 1207 1208 while (left) { 1209 bit_a = find_next_bit(bitmap, bitmap_len, bit_b); 1210 if (bit_a >= bitmap_len) 1211 break; 1212 bit_b = find_next_zero_bit(bitmap, bitmap_len, 1213 bit_a + 1) - 1; 1214 1215 if (!first) 1216 proc_put_char(&buffer, &left, ','); 1217 proc_put_long(&buffer, &left, bit_a, false); 1218 if (bit_a != bit_b) { 1219 proc_put_char(&buffer, &left, '-'); 1220 proc_put_long(&buffer, &left, bit_b, false); 1221 } 1222 1223 first = 0; bit_b++; 1224 } 1225 proc_put_char(&buffer, &left, '\n'); 1226 } 1227 1228 if (!err) { 1229 if (SYSCTL_USER_TO_KERN(dir)) { 1230 if (*ppos) 1231 bitmap_or(bitmap, bitmap, tmp_bitmap, bitmap_len); 1232 else 1233 bitmap_copy(bitmap, tmp_bitmap, bitmap_len); 1234 } 1235 *lenp -= left; 1236 *ppos += *lenp; 1237 } 1238 1239 bitmap_free(tmp_bitmap); 1240 return err; 1241 } 1242 1243 #else /* CONFIG_PROC_SYSCTL */ 1244 1245 int proc_dostring(const struct ctl_table *table, int dir, 1246 void *buffer, size_t *lenp, loff_t *ppos) 1247 { 1248 return -ENOSYS; 1249 } 1250 1251 int proc_dobool(const struct ctl_table *table, int dir, 1252 void *buffer, size_t *lenp, loff_t *ppos) 1253 { 1254 return -ENOSYS; 1255 } 1256 1257 int proc_dointvec(const struct ctl_table *table, int dir, 1258 void *buffer, size_t *lenp, loff_t *ppos) 1259 { 1260 return -ENOSYS; 1261 } 1262 1263 int proc_douintvec(const struct ctl_table *table, int dir, 1264 void *buffer, size_t *lenp, loff_t *ppos) 1265 { 1266 return -ENOSYS; 1267 } 1268 1269 int proc_dointvec_minmax(const struct ctl_table *table, int dir, 1270 void *buffer, size_t *lenp, loff_t *ppos) 1271 { 1272 return -ENOSYS; 1273 } 1274 1275 int proc_douintvec_minmax(const struct ctl_table *table, int dir, 1276 void *buffer, size_t *lenp, loff_t *ppos) 1277 { 1278 return -ENOSYS; 1279 } 1280 1281 int proc_douintvec_conv(const struct ctl_table *table, int write, void *buffer, 1282 size_t *lenp, loff_t *ppos, 1283 int (*conv)(unsigned long *lvalp, unsigned int *valp, 1284 int write, const struct ctl_table *table)) 1285 { 1286 return -ENOSYS; 1287 } 1288 1289 int proc_uint_k2u_conv(ulong *u_ptr, const uint *k_ptr) 1290 { 1291 return -ENOSYS; 1292 } 1293 1294 int proc_uint_u2k_conv_uop(const ulong *u_ptr, uint *k_ptr, 1295 ulong (*u_ptr_op)(const ulong)) 1296 { 1297 return -ENOSYS; 1298 } 1299 1300 int proc_uint_conv(ulong *u_ptr, uint *k_ptr, int dir, 1301 const struct ctl_table *tbl, bool k_ptr_range_check, 1302 int (*user_to_kern)(const ulong *u_ptr, uint *k_ptr), 1303 int (*kern_to_user)(ulong *u_ptr, const uint *k_ptr)) 1304 { 1305 return -ENOSYS; 1306 } 1307 1308 int proc_dou8vec_minmax(const struct ctl_table *table, int dir, 1309 void *buffer, size_t *lenp, loff_t *ppos) 1310 { 1311 return -ENOSYS; 1312 } 1313 1314 int proc_doulongvec_minmax(const struct ctl_table *table, int dir, 1315 void *buffer, size_t *lenp, loff_t *ppos) 1316 { 1317 return -ENOSYS; 1318 } 1319 1320 int proc_doulongvec_minmax_conv(const struct ctl_table *table, int dir, 1321 void *buffer, size_t *lenp, loff_t *ppos, 1322 unsigned long convmul, unsigned long convdiv) 1323 { 1324 return -ENOSYS; 1325 } 1326 1327 int proc_dointvec_conv(const struct ctl_table *table, int dir, void *buffer, 1328 size_t *lenp, loff_t *ppos, 1329 int (*conv)(bool *negp, unsigned long *u_ptr, int *k_ptr, 1330 int dir, const struct ctl_table *table)) 1331 { 1332 return -ENOSYS; 1333 } 1334 1335 int proc_do_large_bitmap(const struct ctl_table *table, int dir, 1336 void *buffer, size_t *lenp, loff_t *ppos) 1337 { 1338 return -ENOSYS; 1339 } 1340 1341 #endif /* CONFIG_PROC_SYSCTL */ 1342 1343 #if defined(CONFIG_SYSCTL) 1344 int proc_do_static_key(const struct ctl_table *table, int dir, 1345 void *buffer, size_t *lenp, loff_t *ppos) 1346 { 1347 struct static_key *key = (struct static_key *)table->data; 1348 static DEFINE_MUTEX(static_key_mutex); 1349 int val, ret; 1350 struct ctl_table tmp = { 1351 .data = &val, 1352 .maxlen = sizeof(val), 1353 .mode = table->mode, 1354 .extra1 = SYSCTL_ZERO, 1355 .extra2 = SYSCTL_ONE, 1356 }; 1357 1358 if (SYSCTL_USER_TO_KERN(dir) && !capable(CAP_SYS_ADMIN)) 1359 return -EPERM; 1360 1361 mutex_lock(&static_key_mutex); 1362 val = static_key_enabled(key); 1363 ret = proc_dointvec_minmax(&tmp, dir, buffer, lenp, ppos); 1364 if (SYSCTL_USER_TO_KERN(dir) && !ret) { 1365 if (val) 1366 static_key_enable(key); 1367 else 1368 static_key_disable(key); 1369 } 1370 mutex_unlock(&static_key_mutex); 1371 return ret; 1372 } 1373 1374 static const struct ctl_table sysctl_subsys_table[] = { 1375 #ifdef CONFIG_PROC_SYSCTL 1376 { 1377 .procname = "sysctl_writes_strict", 1378 .data = &sysctl_writes_strict, 1379 .maxlen = sizeof(int), 1380 .mode = 0644, 1381 .proc_handler = proc_dointvec_minmax, 1382 .extra1 = SYSCTL_NEG_ONE, 1383 .extra2 = SYSCTL_ONE, 1384 }, 1385 #endif 1386 { 1387 .procname = "ngroups_max", 1388 .data = (void *)&ngroups_max, 1389 .maxlen = sizeof (int), 1390 .mode = 0444, 1391 .proc_handler = proc_dointvec, 1392 }, 1393 { 1394 .procname = "cap_last_cap", 1395 .data = (void *)&cap_last_cap, 1396 .maxlen = sizeof(int), 1397 .mode = 0444, 1398 .proc_handler = proc_dointvec, 1399 }, 1400 #ifdef CONFIG_SYSCTL_ARCH_UNALIGN_ALLOW 1401 { 1402 .procname = "unaligned-trap", 1403 .data = &unaligned_enabled, 1404 .maxlen = sizeof(int), 1405 .mode = 0644, 1406 .proc_handler = proc_dointvec, 1407 }, 1408 #endif 1409 #ifdef CONFIG_SYSCTL_ARCH_UNALIGN_NO_WARN 1410 { 1411 .procname = "ignore-unaligned-usertrap", 1412 .data = &no_unaligned_warning, 1413 .maxlen = sizeof (int), 1414 .mode = 0644, 1415 .proc_handler = proc_dointvec, 1416 }, 1417 #endif 1418 }; 1419 1420 int __init sysctl_init_bases(void) 1421 { 1422 register_sysctl_init("kernel", sysctl_subsys_table); 1423 1424 return 0; 1425 } 1426 #endif /* CONFIG_SYSCTL */ 1427 /* 1428 * No sense putting this after each symbol definition, twice, 1429 * exception granted :-) 1430 */ 1431 EXPORT_SYMBOL(proc_dobool); 1432 EXPORT_SYMBOL(proc_dointvec); 1433 EXPORT_SYMBOL(proc_douintvec); 1434 EXPORT_SYMBOL(proc_dointvec_minmax); 1435 EXPORT_SYMBOL_GPL(proc_douintvec_minmax); 1436 EXPORT_SYMBOL(proc_dostring); 1437 EXPORT_SYMBOL(proc_doulongvec_minmax); 1438 EXPORT_SYMBOL(proc_do_large_bitmap); 1439