File Index
Files and directories
Sign in
FILE

sysctl.c

File preview with syntax highlighting.

linux-6.19.14/kernel/sysctl.c C
   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 */
  26const int sysctl_vals[] = { 0, 1, 2, 3, 4, 100, 200, 1000, 3000, INT_MAX, 65535, -1 };
  27EXPORT_SYMBOL(sysctl_vals);
  28
  29const unsigned long sysctl_long_vals[] = { 0, 1, LONG_MAX };
  30EXPORT_SYMBOL_GPL(sysctl_long_vals);
  31
  32#if defined(CONFIG_SYSCTL)
  33
  34/* Constants used for minimum and maximum */
  35static const int ngroups_max = NGROUPS_MAX;
  36static 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 */
  60enum sysctl_writes_mode {
  61	SYSCTL_WRITES_LEGACY		= -1,
  62	SYSCTL_WRITES_WARN		= 0,
  63	SYSCTL_WRITES_STRICT		= 1,
  64};
  65
  66static 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
  76static 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
 138static 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 */
 155static 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 */
 189int 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
 199static 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
 209static 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 */
 234static 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 */
 271static 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 */
 330static 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
 345static 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
 357static SYSCTL_USER_TO_KERN_INT_CONV(, SYSCTL_CONV_IDENTITY)
 358static SYSCTL_KERN_TO_USER_INT_CONV(, SYSCTL_CONV_IDENTITY)
 359
 360static SYSCTL_INT_CONV_CUSTOM(, sysctl_user_to_kern_int_conv,
 361			      sysctl_kern_to_user_int_conv, false)
 362static SYSCTL_INT_CONV_CUSTOM(_minmax, sysctl_user_to_kern_int_conv,
 363			      sysctl_kern_to_user_int_conv, true)
 364
 365
 366static SYSCTL_USER_TO_KERN_UINT_CONV(, SYSCTL_CONV_IDENTITY)
 367
 368int sysctl_kern_to_user_uint_conv(unsigned long *u_ptr,
 369				  const unsigned int *k_ptr)
 370{
 371	unsigned int val = READ_ONCE(*k_ptr);
 372	*u_ptr = (unsigned long)val;
 373	return 0;
 374}
 375
 376static SYSCTL_UINT_CONV_CUSTOM(, sysctl_user_to_kern_uint_conv,
 377			       sysctl_kern_to_user_uint_conv, false)
 378static SYSCTL_UINT_CONV_CUSTOM(_minmax, sysctl_user_to_kern_uint_conv,
 379			       sysctl_kern_to_user_uint_conv, true)
 380
 381static const char proc_wspace_sep[] = { ' ', '\t', '\n' };
 382
 383static int do_proc_dointvec(const struct ctl_table *table, int dir,
 384		  void *buffer, size_t *lenp, loff_t *ppos,
 385		  int (*conv)(bool *negp, unsigned long *u_ptr, int *k_ptr,
 386			      int dir, const struct ctl_table *table))
 387{
 388	int *i, vleft, first = 1, err = 0;
 389	size_t left;
 390	char *p;
 391
 392	if (!table->data || !table->maxlen || !*lenp ||
 393	    (*ppos && SYSCTL_KERN_TO_USER(dir))) {
 394		*lenp = 0;
 395		return 0;
 396	}
 397
 398	i = (int *) table->data;
 399	vleft = table->maxlen / sizeof(*i);
 400	left = *lenp;
 401
 402	if (!conv)
 403		conv = do_proc_int_conv;
 404
 405	if (SYSCTL_USER_TO_KERN(dir)) {
 406		if (proc_first_pos_non_zero_ignore(ppos, table))
 407			goto out;
 408
 409		if (left > PAGE_SIZE - 1)
 410			left = PAGE_SIZE - 1;
 411		p = buffer;
 412	}
 413
 414	for (; left && vleft--; i++, first=0) {
 415		unsigned long lval;
 416		bool neg;
 417
 418		if (SYSCTL_USER_TO_KERN(dir)) {
 419			proc_skip_spaces(&p, &left);
 420
 421			if (!left)
 422				break;
 423			err = proc_get_long(&p, &left, &lval, &neg,
 424					     proc_wspace_sep,
 425					     sizeof(proc_wspace_sep), NULL);
 426			if (err)
 427				break;
 428			if (conv(&neg, &lval, i, 1, table)) {
 429				err = -EINVAL;
 430				break;
 431			}
 432		} else {
 433			if (conv(&neg, &lval, i, 0, table)) {
 434				err = -EINVAL;
 435				break;
 436			}
 437			if (!first)
 438				proc_put_char(&buffer, &left, '\t');
 439			proc_put_long(&buffer, &left, lval, neg);
 440		}
 441	}
 442
 443	if (SYSCTL_KERN_TO_USER(dir) && !first && left && !err)
 444		proc_put_char(&buffer, &left, '\n');
 445	if (SYSCTL_USER_TO_KERN(dir) && !err && left)
 446		proc_skip_spaces(&p, &left);
 447	if (SYSCTL_USER_TO_KERN(dir) && first)
 448		return err ? : -EINVAL;
 449	*lenp -= left;
 450out:
 451	*ppos += *lenp;
 452	return err;
 453}
 454
 455static int do_proc_douintvec_w(const struct ctl_table *table, void *buffer,
 456			       size_t *lenp, loff_t *ppos,
 457			       int (*conv)(unsigned long *u_ptr,
 458					   unsigned int *k_ptr, int dir,
 459					   const struct ctl_table *table))
 460{
 461	unsigned long lval;
 462	int err = 0;
 463	size_t left;
 464	bool neg;
 465	char *p = buffer;
 466
 467	left = *lenp;
 468
 469	if (proc_first_pos_non_zero_ignore(ppos, table))
 470		goto bail_early;
 471
 472	if (left > PAGE_SIZE - 1)
 473		left = PAGE_SIZE - 1;
 474
 475	proc_skip_spaces(&p, &left);
 476	if (!left) {
 477		err = -EINVAL;
 478		goto out_free;
 479	}
 480
 481	err = proc_get_long(&p, &left, &lval, &neg,
 482			     proc_wspace_sep,
 483			     sizeof(proc_wspace_sep), NULL);
 484	if (err || neg) {
 485		err = -EINVAL;
 486		goto out_free;
 487	}
 488
 489	if (conv(&lval, (unsigned int *) table->data, 1, table)) {
 490		err = -EINVAL;
 491		goto out_free;
 492	}
 493
 494	if (!err && left)
 495		proc_skip_spaces(&p, &left);
 496
 497out_free:
 498	if (err)
 499		return -EINVAL;
 500
 501	return 0;
 502
 503bail_early:
 504	*ppos += *lenp;
 505	return err;
 506}
 507
 508static int do_proc_douintvec_r(const struct ctl_table *table, void *buffer,
 509			       size_t *lenp, loff_t *ppos,
 510			       int (*conv)(unsigned long *u_ptr,
 511					   unsigned int *k_ptr, int dir,
 512					   const struct ctl_table *table))
 513{
 514	unsigned long lval;
 515	int err = 0;
 516	size_t left;
 517
 518	left = *lenp;
 519
 520	if (conv(&lval, (unsigned int *) table->data, 0, table)) {
 521		err = -EINVAL;
 522		goto out;
 523	}
 524
 525	proc_put_long(&buffer, &left, lval, false);
 526	if (!left)
 527		goto out;
 528
 529	proc_put_char(&buffer, &left, '\n');
 530
 531out:
 532	*lenp -= left;
 533	*ppos += *lenp;
 534
 535	return err;
 536}
 537
 538static int do_proc_douintvec(const struct ctl_table *table, int dir,
 539			     void *buffer, size_t *lenp, loff_t *ppos,
 540			      int (*conv)(unsigned long *u_ptr,
 541					  unsigned int *k_ptr, int dir,
 542					  const struct ctl_table *table))
 543{
 544	unsigned int vleft;
 545
 546	if (!table->data || !table->maxlen || !*lenp ||
 547	    (*ppos && SYSCTL_KERN_TO_USER(dir))) {
 548		*lenp = 0;
 549		return 0;
 550	}
 551
 552	vleft = table->maxlen / sizeof(unsigned int);
 553
 554	/*
 555	 * Arrays are not supported, keep this simple. *Do not* add
 556	 * support for them.
 557	 */
 558	if (vleft != 1) {
 559		*lenp = 0;
 560		return -EINVAL;
 561	}
 562
 563	if (!conv)
 564		conv = do_proc_uint_conv;
 565
 566	if (SYSCTL_USER_TO_KERN(dir))
 567		return do_proc_douintvec_w(table, buffer, lenp, ppos, conv);
 568	return do_proc_douintvec_r(table, buffer, lenp, ppos, conv);
 569}
 570
 571int proc_douintvec_conv(const struct ctl_table *table, int dir, void *buffer,
 572			size_t *lenp, loff_t *ppos,
 573			int (*conv)(unsigned long *u_ptr, unsigned int *k_ptr,
 574				    int dir, const struct ctl_table *table))
 575{
 576	return do_proc_douintvec(table, dir, buffer, lenp, ppos, conv);
 577}
 578
 579
 580/**
 581 * proc_dobool - read/write a bool
 582 * @table: the sysctl table
 583 * @dir: %TRUE if this is a write to the sysctl file
 584 * @buffer: the user buffer
 585 * @lenp: the size of the user buffer
 586 * @ppos: file position
 587 *
 588 * Reads/writes one integer value from/to the user buffer,
 589 * treated as an ASCII string.
 590 *
 591 * table->data must point to a bool variable and table->maxlen must
 592 * be sizeof(bool).
 593 *
 594 * Returns 0 on success.
 595 */
 596int proc_dobool(const struct ctl_table *table, int dir, void *buffer,
 597		size_t *lenp, loff_t *ppos)
 598{
 599	struct ctl_table tmp;
 600	bool *data = table->data;
 601	int res, val;
 602
 603	/* Do not support arrays yet. */
 604	if (table->maxlen != sizeof(bool))
 605		return -EINVAL;
 606
 607	tmp = *table;
 608	tmp.maxlen = sizeof(val);
 609	tmp.data = &val;
 610
 611	val = READ_ONCE(*data);
 612	res = proc_dointvec(&tmp, dir, buffer, lenp, ppos);
 613	if (res)
 614		return res;
 615	if (SYSCTL_USER_TO_KERN(dir))
 616		WRITE_ONCE(*data, val);
 617	return 0;
 618}
 619
 620/**
 621 * proc_dointvec - read a vector of integers
 622 * @table: the sysctl table
 623 * @dir: %TRUE if this is a write to the sysctl file
 624 * @buffer: the user buffer
 625 * @lenp: the size of the user buffer
 626 * @ppos: file position
 627 *
 628 * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
 629 * values from/to the user buffer, treated as an ASCII string.
 630 *
 631 * Returns 0 on success.
 632 */
 633int proc_dointvec(const struct ctl_table *table, int dir, void *buffer,
 634		  size_t *lenp, loff_t *ppos)
 635{
 636	return do_proc_dointvec(table, dir, buffer, lenp, ppos, NULL);
 637}
 638
 639/**
 640 * proc_douintvec - read a vector of unsigned integers
 641 * @table: the sysctl table
 642 * @dir: %TRUE if this is a write to the sysctl file
 643 * @buffer: the user buffer
 644 * @lenp: the size of the user buffer
 645 * @ppos: file position
 646 *
 647 * Reads/writes up to table->maxlen/sizeof(unsigned int) unsigned integer
 648 * values from/to the user buffer, treated as an ASCII string.
 649 *
 650 * Returns 0 on success.
 651 */
 652int proc_douintvec(const struct ctl_table *table, int dir, void *buffer,
 653		size_t *lenp, loff_t *ppos)
 654{
 655	return do_proc_douintvec(table, dir, buffer, lenp, ppos,
 656				 do_proc_uint_conv);
 657}
 658
 659/**
 660 * proc_dointvec_minmax - read a vector of integers with min/max values
 661 * @table: the sysctl table
 662 * @dir: %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 * This routine will ensure the values are within the range specified by
 671 * table->extra1 (min) and table->extra2 (max).
 672 *
 673 * Returns 0 on success or -EINVAL when the range check fails and
 674 * SYSCTL_USER_TO_KERN(dir) == true
 675 */
 676int proc_dointvec_minmax(const struct ctl_table *table, int dir,
 677		  void *buffer, size_t *lenp, loff_t *ppos)
 678{
 679	return do_proc_dointvec(table, dir, buffer, lenp, ppos,
 680				do_proc_int_conv_minmax);
 681}
 682
 683/**
 684 * proc_douintvec_minmax - read a vector of unsigned ints with min/max values
 685 * @table: the sysctl table
 686 * @dir: %TRUE if this is a write to the sysctl file
 687 * @buffer: the user buffer
 688 * @lenp: the size of the user buffer
 689 * @ppos: file position
 690 *
 691 * Reads/writes up to table->maxlen/sizeof(unsigned int) unsigned integer
 692 * values from/to the user buffer, treated as an ASCII string. Negative
 693 * strings are not allowed.
 694 *
 695 * This routine will ensure the values are within the range specified by
 696 * table->extra1 (min) and table->extra2 (max). There is a final sanity
 697 * check for UINT_MAX to avoid having to support wrap around uses from
 698 * userspace.
 699 *
 700 * Returns 0 on success or -ERANGE when range check failes and
 701 * SYSCTL_USER_TO_KERN(dir) == true
 702 */
 703int proc_douintvec_minmax(const struct ctl_table *table, int dir,
 704			  void *buffer, size_t *lenp, loff_t *ppos)
 705{
 706	return do_proc_douintvec(table, dir, buffer, lenp, ppos,
 707				 do_proc_uint_conv_minmax);
 708}
 709
 710/**
 711 * proc_dou8vec_minmax - read a vector of unsigned chars with min/max values
 712 * @table: the sysctl table
 713 * @dir: %TRUE if this is a write to the sysctl file
 714 * @buffer: the user buffer
 715 * @lenp: the size of the user buffer
 716 * @ppos: file position
 717 *
 718 * Reads/writes up to table->maxlen/sizeof(u8) unsigned chars
 719 * values from/to the user buffer, treated as an ASCII string. Negative
 720 * strings are not allowed.
 721 *
 722 * This routine will ensure the values are within the range specified by
 723 * table->extra1 (min) and table->extra2 (max).
 724 *
 725 * Returns 0 on success or an error on SYSCTL_USER_TO_KERN(dir) == true
 726 * and the range check fails.
 727 */
 728int proc_dou8vec_minmax(const struct ctl_table *table, int dir,
 729			void *buffer, size_t *lenp, loff_t *ppos)
 730{
 731	struct ctl_table tmp;
 732	unsigned int min = 0, max = 255U, val;
 733	u8 *data = table->data;
 734	int res;
 735
 736	/* Do not support arrays yet. */
 737	if (table->maxlen != sizeof(u8))
 738		return -EINVAL;
 739
 740	tmp = *table;
 741
 742	tmp.maxlen = sizeof(val);
 743	tmp.data = &val;
 744	if (!tmp.extra1)
 745		tmp.extra1 = (unsigned int *) &min;
 746	if (!tmp.extra2)
 747		tmp.extra2 = (unsigned int *) &max;
 748
 749	val = READ_ONCE(*data);
 750	res = do_proc_douintvec(&tmp, dir, buffer, lenp, ppos,
 751				do_proc_uint_conv_minmax);
 752	if (res)
 753		return res;
 754	if (SYSCTL_USER_TO_KERN(dir))
 755		WRITE_ONCE(*data, val);
 756	return 0;
 757}
 758EXPORT_SYMBOL_GPL(proc_dou8vec_minmax);
 759
 760static int do_proc_doulongvec_minmax(const struct ctl_table *table, int dir,
 761				     void *buffer, size_t *lenp, loff_t *ppos,
 762				     unsigned long convmul,
 763				     unsigned long convdiv)
 764{
 765	unsigned long *i, *min, *max;
 766	int vleft, first = 1, err = 0;
 767	size_t left;
 768	char *p;
 769
 770	if (!table->data || !table->maxlen || !*lenp ||
 771	    (*ppos && SYSCTL_KERN_TO_USER(dir))) {
 772		*lenp = 0;
 773		return 0;
 774	}
 775
 776	i = table->data;
 777	min = table->extra1;
 778	max = table->extra2;
 779	vleft = table->maxlen / sizeof(unsigned long);
 780	left = *lenp;
 781
 782	if (SYSCTL_USER_TO_KERN(dir)) {
 783		if (proc_first_pos_non_zero_ignore(ppos, table))
 784			goto out;
 785
 786		if (left > PAGE_SIZE - 1)
 787			left = PAGE_SIZE - 1;
 788		p = buffer;
 789	}
 790
 791	for (; left && vleft--; i++, first = 0) {
 792		unsigned long val;
 793
 794		if (SYSCTL_USER_TO_KERN(dir)) {
 795			bool neg;
 796
 797			proc_skip_spaces(&p, &left);
 798			if (!left)
 799				break;
 800
 801			err = proc_get_long(&p, &left, &val, &neg,
 802					     proc_wspace_sep,
 803					     sizeof(proc_wspace_sep), NULL);
 804			if (err || neg) {
 805				err = -EINVAL;
 806				break;
 807			}
 808
 809			val = convmul * val / convdiv;
 810			if ((min && val < *min) || (max && val > *max)) {
 811				err = -EINVAL;
 812				break;
 813			}
 814			WRITE_ONCE(*i, val);
 815		} else {
 816			val = convdiv * READ_ONCE(*i) / convmul;
 817			if (!first)
 818				proc_put_char(&buffer, &left, '\t');
 819			proc_put_long(&buffer, &left, val, false);
 820		}
 821	}
 822
 823	if (SYSCTL_KERN_TO_USER(dir) && !first && left && !err)
 824		proc_put_char(&buffer, &left, '\n');
 825	if (SYSCTL_USER_TO_KERN(dir) && !err)
 826		proc_skip_spaces(&p, &left);
 827	if (SYSCTL_USER_TO_KERN(dir) && first)
 828		return err ? : -EINVAL;
 829	*lenp -= left;
 830out:
 831	*ppos += *lenp;
 832	return err;
 833}
 834
 835int proc_doulongvec_minmax_conv(const struct ctl_table *table, int dir,
 836				void *buffer, size_t *lenp, loff_t *ppos,
 837				unsigned long convmul, unsigned long convdiv)
 838{
 839	return do_proc_doulongvec_minmax(table, dir, buffer, lenp, ppos,
 840					 convmul, convdiv);
 841}
 842
 843/**
 844 * proc_doulongvec_minmax - read a vector of long integers with min/max values
 845 * @table: the sysctl table
 846 * @dir: %TRUE if this is a write to the sysctl file
 847 * @buffer: the user buffer
 848 * @lenp: the size of the user buffer
 849 * @ppos: file position
 850 *
 851 * Reads/writes up to table->maxlen/sizeof(unsigned long) unsigned long
 852 * values from/to the user buffer, treated as an ASCII string.
 853 *
 854 * This routine will ensure the values are within the range specified by
 855 * table->extra1 (min) and table->extra2 (max).
 856 *
 857 * Returns 0 on success.
 858 */
 859int proc_doulongvec_minmax(const struct ctl_table *table, int dir,
 860			   void *buffer, size_t *lenp, loff_t *ppos)
 861{
 862	return proc_doulongvec_minmax_conv(table, dir, buffer, lenp, ppos, 1l, 1l);
 863}
 864
 865int proc_dointvec_conv(const struct ctl_table *table, int dir, void *buffer,
 866		       size_t *lenp, loff_t *ppos,
 867		       int (*conv)(bool *negp, unsigned long *u_ptr, int *k_ptr,
 868				   int dir, const struct ctl_table *table))
 869{
 870	return do_proc_dointvec(table, dir, buffer, lenp, ppos, conv);
 871}
 872
 873/**
 874 * proc_do_large_bitmap - read/write from/to a large bitmap
 875 * @table: the sysctl table
 876 * @dir: %TRUE if this is a write to the sysctl file
 877 * @buffer: the user buffer
 878 * @lenp: the size of the user buffer
 879 * @ppos: file position
 880 *
 881 * The bitmap is stored at table->data and the bitmap length (in bits)
 882 * in table->maxlen.
 883 *
 884 * We use a range comma separated format (e.g. 1,3-4,10-10) so that
 885 * large bitmaps may be represented in a compact manner. Writing into
 886 * the file will clear the bitmap then update it with the given input.
 887 *
 888 * Returns 0 on success.
 889 */
 890int proc_do_large_bitmap(const struct ctl_table *table, int dir,
 891			 void *buffer, size_t *lenp, loff_t *ppos)
 892{
 893	int err = 0;
 894	size_t left = *lenp;
 895	unsigned long bitmap_len = table->maxlen;
 896	unsigned long *bitmap = *(unsigned long **) table->data;
 897	unsigned long *tmp_bitmap = NULL;
 898	char tr_a[] = { '-', ',', '\n' }, tr_b[] = { ',', '\n', 0 }, c = 0;
 899
 900	if (!bitmap || !bitmap_len || !left || (*ppos && SYSCTL_KERN_TO_USER(dir))) {
 901		*lenp = 0;
 902		return 0;
 903	}
 904
 905	if (SYSCTL_USER_TO_KERN(dir)) {
 906		char *p = buffer;
 907		size_t skipped = 0;
 908
 909		if (left > PAGE_SIZE - 1) {
 910			left = PAGE_SIZE - 1;
 911			/* How much of the buffer we'll skip this pass */
 912			skipped = *lenp - left;
 913		}
 914
 915		tmp_bitmap = bitmap_zalloc(bitmap_len, GFP_KERNEL);
 916		if (!tmp_bitmap)
 917			return -ENOMEM;
 918		proc_skip_char(&p, &left, '\n');
 919		while (!err && left) {
 920			unsigned long val_a, val_b;
 921			bool neg;
 922			size_t saved_left;
 923
 924			/* In case we stop parsing mid-number, we can reset */
 925			saved_left = left;
 926			err = proc_get_long(&p, &left, &val_a, &neg, tr_a,
 927					     sizeof(tr_a), &c);
 928			/*
 929			 * If we consumed the entirety of a truncated buffer or
 930			 * only one char is left (may be a "-"), then stop here,
 931			 * reset, & come back for more.
 932			 */
 933			if ((left <= 1) && skipped) {
 934				left = saved_left;
 935				break;
 936			}
 937
 938			if (err)
 939				break;
 940			if (val_a >= bitmap_len || neg) {
 941				err = -EINVAL;
 942				break;
 943			}
 944
 945			val_b = val_a;
 946			if (left) {
 947				p++;
 948				left--;
 949			}
 950
 951			if (c == '-') {
 952				err = proc_get_long(&p, &left, &val_b,
 953						     &neg, tr_b, sizeof(tr_b),
 954						     &c);
 955				/*
 956				 * If we consumed all of a truncated buffer or
 957				 * then stop here, reset, & come back for more.
 958				 */
 959				if (!left && skipped) {
 960					left = saved_left;
 961					break;
 962				}
 963
 964				if (err)
 965					break;
 966				if (val_b >= bitmap_len || neg ||
 967				    val_a > val_b) {
 968					err = -EINVAL;
 969					break;
 970				}
 971				if (left) {
 972					p++;
 973					left--;
 974				}
 975			}
 976
 977			bitmap_set(tmp_bitmap, val_a, val_b - val_a + 1);
 978			proc_skip_char(&p, &left, '\n');
 979		}
 980		left += skipped;
 981	} else {
 982		unsigned long bit_a, bit_b = 0;
 983		bool first = 1;
 984
 985		while (left) {
 986			bit_a = find_next_bit(bitmap, bitmap_len, bit_b);
 987			if (bit_a >= bitmap_len)
 988				break;
 989			bit_b = find_next_zero_bit(bitmap, bitmap_len,
 990						   bit_a + 1) - 1;
 991
 992			if (!first)
 993				proc_put_char(&buffer, &left, ',');
 994			proc_put_long(&buffer, &left, bit_a, false);
 995			if (bit_a != bit_b) {
 996				proc_put_char(&buffer, &left, '-');
 997				proc_put_long(&buffer, &left, bit_b, false);
 998			}
 999
1000			first = 0; bit_b++;
1001		}
1002		proc_put_char(&buffer, &left, '\n');
1003	}
1004
1005	if (!err) {
1006		if (SYSCTL_USER_TO_KERN(dir)) {
1007			if (*ppos)
1008				bitmap_or(bitmap, bitmap, tmp_bitmap, bitmap_len);
1009			else
1010				bitmap_copy(bitmap, tmp_bitmap, bitmap_len);
1011		}
1012		*lenp -= left;
1013		*ppos += *lenp;
1014	}
1015
1016	bitmap_free(tmp_bitmap);
1017	return err;
1018}
1019
1020#else /* CONFIG_PROC_SYSCTL */
1021
1022int proc_dostring(const struct ctl_table *table, int dir,
1023		  void *buffer, size_t *lenp, loff_t *ppos)
1024{
1025	return -ENOSYS;
1026}
1027
1028int proc_dobool(const struct ctl_table *table, int dir,
1029		void *buffer, size_t *lenp, loff_t *ppos)
1030{
1031	return -ENOSYS;
1032}
1033
1034int proc_dointvec(const struct ctl_table *table, int dir,
1035		  void *buffer, size_t *lenp, loff_t *ppos)
1036{
1037	return -ENOSYS;
1038}
1039
1040int proc_douintvec(const struct ctl_table *table, int dir,
1041		  void *buffer, size_t *lenp, loff_t *ppos)
1042{
1043	return -ENOSYS;
1044}
1045
1046int proc_dointvec_minmax(const struct ctl_table *table, int dir,
1047		    void *buffer, size_t *lenp, loff_t *ppos)
1048{
1049	return -ENOSYS;
1050}
1051
1052int proc_douintvec_minmax(const struct ctl_table *table, int dir,
1053			  void *buffer, size_t *lenp, loff_t *ppos)
1054{
1055	return -ENOSYS;
1056}
1057
1058int proc_dou8vec_minmax(const struct ctl_table *table, int dir,
1059			void *buffer, size_t *lenp, loff_t *ppos)
1060{
1061	return -ENOSYS;
1062}
1063
1064int proc_doulongvec_minmax(const struct ctl_table *table, int dir,
1065		    void *buffer, size_t *lenp, loff_t *ppos)
1066{
1067	return -ENOSYS;
1068}
1069
1070int proc_doulongvec_minmax_conv(const struct ctl_table *table, int dir,
1071				void *buffer, size_t *lenp, loff_t *ppos,
1072				unsigned long convmul, unsigned long convdiv)
1073{
1074	return -ENOSYS;
1075}
1076
1077int proc_dointvec_conv(const struct ctl_table *table, int dir, void *buffer,
1078		       size_t *lenp, loff_t *ppos,
1079		       int (*conv)(bool *negp, unsigned long *u_ptr, int *k_ptr,
1080				   int dir, const struct ctl_table *table))
1081{
1082	return -ENOSYS;
1083}
1084
1085int proc_do_large_bitmap(const struct ctl_table *table, int dir,
1086			 void *buffer, size_t *lenp, loff_t *ppos)
1087{
1088	return -ENOSYS;
1089}
1090
1091#endif /* CONFIG_PROC_SYSCTL */
1092
1093#if defined(CONFIG_SYSCTL)
1094int proc_do_static_key(const struct ctl_table *table, int dir,
1095		       void *buffer, size_t *lenp, loff_t *ppos)
1096{
1097	struct static_key *key = (struct static_key *)table->data;
1098	static DEFINE_MUTEX(static_key_mutex);
1099	int val, ret;
1100	struct ctl_table tmp = {
1101		.data   = &val,
1102		.maxlen = sizeof(val),
1103		.mode   = table->mode,
1104		.extra1 = SYSCTL_ZERO,
1105		.extra2 = SYSCTL_ONE,
1106	};
1107
1108	if (SYSCTL_USER_TO_KERN(dir) && !capable(CAP_SYS_ADMIN))
1109		return -EPERM;
1110
1111	mutex_lock(&static_key_mutex);
1112	val = static_key_enabled(key);
1113	ret = proc_dointvec_minmax(&tmp, dir, buffer, lenp, ppos);
1114	if (SYSCTL_USER_TO_KERN(dir) && !ret) {
1115		if (val)
1116			static_key_enable(key);
1117		else
1118			static_key_disable(key);
1119	}
1120	mutex_unlock(&static_key_mutex);
1121	return ret;
1122}
1123
1124static const struct ctl_table sysctl_subsys_table[] = {
1125#ifdef CONFIG_PROC_SYSCTL
1126	{
1127		.procname	= "sysctl_writes_strict",
1128		.data		= &sysctl_writes_strict,
1129		.maxlen		= sizeof(int),
1130		.mode		= 0644,
1131		.proc_handler	= proc_dointvec_minmax,
1132		.extra1		= SYSCTL_NEG_ONE,
1133		.extra2		= SYSCTL_ONE,
1134	},
1135#endif
1136	{
1137		.procname	= "ngroups_max",
1138		.data		= (void *)&ngroups_max,
1139		.maxlen		= sizeof (int),
1140		.mode		= 0444,
1141		.proc_handler	= proc_dointvec,
1142	},
1143	{
1144		.procname	= "cap_last_cap",
1145		.data		= (void *)&cap_last_cap,
1146		.maxlen		= sizeof(int),
1147		.mode		= 0444,
1148		.proc_handler	= proc_dointvec,
1149	},
1150#ifdef CONFIG_SYSCTL_ARCH_UNALIGN_ALLOW
1151	{
1152		.procname	= "unaligned-trap",
1153		.data		= &unaligned_enabled,
1154		.maxlen		= sizeof(int),
1155		.mode		= 0644,
1156		.proc_handler	= proc_dointvec,
1157	},
1158#endif
1159#ifdef CONFIG_SYSCTL_ARCH_UNALIGN_NO_WARN
1160	{
1161		.procname	= "ignore-unaligned-usertrap",
1162		.data		= &no_unaligned_warning,
1163		.maxlen		= sizeof (int),
1164		.mode		= 0644,
1165		.proc_handler	= proc_dointvec,
1166	},
1167#endif
1168};
1169
1170int __init sysctl_init_bases(void)
1171{
1172	register_sysctl_init("kernel", sysctl_subsys_table);
1173
1174	return 0;
1175}
1176#endif /* CONFIG_SYSCTL */
1177/*
1178 * No sense putting this after each symbol definition, twice,
1179 * exception granted :-)
1180 */
1181EXPORT_SYMBOL(proc_dobool);
1182EXPORT_SYMBOL(proc_dointvec);
1183EXPORT_SYMBOL(proc_douintvec);
1184EXPORT_SYMBOL(proc_dointvec_minmax);
1185EXPORT_SYMBOL_GPL(proc_douintvec_minmax);
1186EXPORT_SYMBOL(proc_dostring);
1187EXPORT_SYMBOL(proc_doulongvec_minmax);
1188EXPORT_SYMBOL(proc_do_large_bitmap);
~/ Read-only file preview.