1438 lines · 35.4 KB · C
RawDownload
		if (SYSCTL_USER_TO_KERN(dir)) {			bool neg; 			proc_skip_spaces(&p, &left);			if (!left)				break; 			err = proc_get_long(&p, &left, &val, &neg,					     proc_wspace_sep,					     sizeof(proc_wspace_sep), NULL);			if (err || neg) {				err = -EINVAL;				break;			} 			val = convmul * val / convdiv;			if ((min && val < *min) || (max && val > *max)) {				err = -EINVAL;				break;			}			WRITE_ONCE(*i, val);		} else {			val = convdiv * READ_ONCE(*i) / convmul;			if (!first)				proc_put_char(&buffer, &left, '\t');			proc_put_long(&buffer, &left, val, false);		}	} 	if (SYSCTL_KERN_TO_USER(dir) && !first && left && !err)		proc_put_char(&buffer, &left, '\n');	if (SYSCTL_USER_TO_KERN(dir) && !err)		proc_skip_spaces(&p, &left);	if (SYSCTL_USER_TO_KERN(dir) && first)		return err ? : -EINVAL;	*lenp -= left;out:	*ppos += *lenp;	return err;} int proc_doulongvec_minmax_conv(const struct ctl_table *table, int dir,				void *buffer, size_t *lenp, loff_t *ppos,				unsigned long convmul, unsigned long convdiv){	return do_proc_doulongvec_minmax(table, dir, buffer, lenp, ppos,					 convmul, convdiv);} /** * proc_doulongvec_minmax - read a vector of long integers with min/max values * @table: the sysctl table * @dir: %TRUE if this is a write to the sysctl file * @buffer: the user buffer * @lenp: the size of the user buffer * @ppos: file position * * Reads/writes up to table->maxlen/sizeof(unsigned long) unsigned long * values from/to the user buffer, treated as an ASCII string. * * This routine will ensure the values are within the range specified by * table->extra1 (min) and table->extra2 (max). * * Returns 0 on success. */int proc_doulongvec_minmax(const struct ctl_table *table, int dir,			   void *buffer, size_t *lenp, loff_t *ppos){	return proc_doulongvec_minmax_conv(table, dir, buffer, lenp, ppos, 1l, 1l);} /** * proc_dointvec_conv - read a vector of ints with a custom converter * @table: the sysctl table * @dir: %TRUE if this is a write to the sysctl file * @buffer: the user buffer * @lenp: the size of the user buffer * @ppos: file position * @conv: Custom converter call back * * Reads/writes up to table->maxlen/sizeof(unsigned int) unsigned integer * values from/to the user buffer, treated as an ASCII string. Negative * strings are not allowed. * * Returns: 0 on success */ int proc_dointvec_conv(const struct ctl_table *table, int dir, void *buffer,		       size_t *lenp, loff_t *ppos,		       int (*conv)(bool *negp, unsigned long *u_ptr, int *k_ptr,				   int dir, const struct ctl_table *table)){	return do_proc_dointvec(table, dir, buffer, lenp, ppos, conv);} /** * proc_do_large_bitmap - read/write from/to a large bitmap * @table: the sysctl table * @dir: %TRUE if this is a write to the sysctl file * @buffer: the user buffer * @lenp: the size of the user buffer * @ppos: file position * * The bitmap is stored at table->data and the bitmap length (in bits) * in table->maxlen. * * We use a range comma separated format (e.g. 1,3-4,10-10) so that * large bitmaps may be represented in a compact manner. Writing into * the file will clear the bitmap then update it with the given input. * * Returns 0 on success. */int proc_do_large_bitmap(const struct ctl_table *table, int dir,			 void *buffer, size_t *lenp, loff_t *ppos){	int err = 0;	size_t left = *lenp;	unsigned long bitmap_len = table->maxlen;	unsigned long *bitmap = *(unsigned long **) table->data;	unsigned long *tmp_bitmap = NULL;	char tr_a[] = { '-', ',', '\n' }, tr_b[] = { ',', '\n', 0 }, c = 0; 	if (!bitmap || !bitmap_len || !left || (*ppos && SYSCTL_KERN_TO_USER(dir))) {		*lenp = 0;		return 0;	} 	if (SYSCTL_USER_TO_KERN(dir)) {		char *p = buffer;		size_t skipped = 0; 		if (left > PAGE_SIZE - 1) {			left = PAGE_SIZE - 1;			/* How much of the buffer we'll skip this pass */			skipped = *lenp - left;		} 		tmp_bitmap = bitmap_zalloc(bitmap_len, GFP_KERNEL);		if (!tmp_bitmap)			return -ENOMEM;		proc_skip_char(&p, &left, '\n');		while (!err && left) {			unsigned long val_a, val_b;			bool neg;			size_t saved_left; 			/* In case we stop parsing mid-number, we can reset */			saved_left = left;			err = proc_get_long(&p, &left, &val_a, &neg, tr_a,					     sizeof(tr_a), &c);			/*			 * If we consumed the entirety of a truncated buffer or			 * only one char is left (may be a "-"), then stop here,			 * reset, & come back for more.			 */			if ((left <= 1) && skipped) {				left = saved_left;				break;			} 			if (err)				break;			if (val_a >= bitmap_len || neg) {				err = -EINVAL;				break;			} 			val_b = val_a;			if (left) {				p++;				left--;			} 			if (c == '-') {				err = proc_get_long(&p, &left, &val_b,						     &neg, tr_b, sizeof(tr_b),						     &c);				/*				 * If we consumed all of a truncated buffer or				 * then stop here, reset, & come back for more.				 */				if (!left && skipped) {					left = saved_left;					break;				} 				if (err)					break;				if (val_b >= bitmap_len || neg ||				    val_a > val_b) {					err = -EINVAL;					break;				}				if (left) {					p++;					left--;				}			} 			bitmap_set(tmp_bitmap, val_a, val_b - val_a + 1);			proc_skip_char(&p, &left, '\n');		}		left += skipped;	} else {		unsigned long bit_a, bit_b = 0;		bool first = 1; 		while (left) {			bit_a = find_next_bit(bitmap, bitmap_len, bit_b);			if (bit_a >= bitmap_len)				break;			bit_b = find_next_zero_bit(bitmap, bitmap_len,						   bit_a + 1) - 1; 			if (!first)				proc_put_char(&buffer, &left, ',');			proc_put_long(&buffer, &left, bit_a, false);			if (bit_a != bit_b) {				proc_put_char(&buffer, &left, '-');				proc_put_long(&buffer, &left, bit_b, false);			} 			first = 0; bit_b++;		}		proc_put_char(&buffer, &left, '\n');	} 	if (!err) {		if (SYSCTL_USER_TO_KERN(dir)) {			if (*ppos)				bitmap_or(bitmap, bitmap, tmp_bitmap, bitmap_len);			else				bitmap_copy(bitmap, tmp_bitmap, bitmap_len);		}		*lenp -= left;		*ppos += *lenp;	} 	bitmap_free(tmp_bitmap);	return err;} #else /* CONFIG_PROC_SYSCTL */ int proc_dostring(const struct ctl_table *table, int dir,		  void *buffer, size_t *lenp, loff_t *ppos){	return -ENOSYS;} int proc_dobool(const struct ctl_table *table, int dir,		void *buffer, size_t *lenp, loff_t *ppos){	return -ENOSYS;} int proc_dointvec(const struct ctl_table *table, int dir,		  void *buffer, size_t *lenp, loff_t *ppos){	return -ENOSYS;} int proc_douintvec(const struct ctl_table *table, int dir,		  void *buffer, size_t *lenp, loff_t *ppos){	return -ENOSYS;} int proc_dointvec_minmax(const struct ctl_table *table, int dir,		    void *buffer, size_t *lenp, loff_t *ppos){	return -ENOSYS;} int proc_douintvec_minmax(const struct ctl_table *table, int dir,			  void *buffer, size_t *lenp, loff_t *ppos){	return -ENOSYS;} int proc_douintvec_conv(const struct ctl_table *table, int write, void *buffer,			size_t *lenp, loff_t *ppos,			int (*conv)(unsigned long *lvalp, unsigned int *valp,				    int write, const struct ctl_table *table)){	return -ENOSYS;} int proc_uint_k2u_conv(ulong *u_ptr, const uint *k_ptr){	return -ENOSYS;} int proc_uint_u2k_conv_uop(const ulong *u_ptr, uint *k_ptr,			   ulong (*u_ptr_op)(const ulong)){	return -ENOSYS;} int proc_uint_conv(ulong *u_ptr, uint *k_ptr, int dir,		   const struct ctl_table *tbl, bool k_ptr_range_check,		   int (*user_to_kern)(const ulong *u_ptr, uint *k_ptr),		   int (*kern_to_user)(ulong *u_ptr, const uint *k_ptr)){	return -ENOSYS;} int proc_dou8vec_minmax(const struct ctl_table *table, int dir,			void *buffer, size_t *lenp, loff_t *ppos){	return -ENOSYS;} int proc_doulongvec_minmax(const struct ctl_table *table, int dir,		    void *buffer, size_t *lenp, loff_t *ppos){	return -ENOSYS;} int proc_doulongvec_minmax_conv(const struct ctl_table *table, int dir,				void *buffer, size_t *lenp, loff_t *ppos,				unsigned long convmul, unsigned long convdiv){	return -ENOSYS;} int proc_dointvec_conv(const struct ctl_table *table, int dir, void *buffer,		       size_t *lenp, loff_t *ppos,		       int (*conv)(bool *negp, unsigned long *u_ptr, int *k_ptr,				   int dir, const struct ctl_table *table)){	return -ENOSYS;} int proc_do_large_bitmap(const struct ctl_table *table, int dir,			 void *buffer, size_t *lenp, loff_t *ppos){	return -ENOSYS;} #endif /* CONFIG_PROC_SYSCTL */ #if defined(CONFIG_SYSCTL)int proc_do_static_key(const struct ctl_table *table, int dir,		       void *buffer, size_t *lenp, loff_t *ppos){	struct static_key *key = (struct static_key *)table->data;	static DEFINE_MUTEX(static_key_mutex);	int val, ret;	struct ctl_table tmp = {		.data   = &val,		.maxlen = sizeof(val),		.mode   = table->mode,		.extra1 = SYSCTL_ZERO,		.extra2 = SYSCTL_ONE,	}; 	if (SYSCTL_USER_TO_KERN(dir) && !capable(CAP_SYS_ADMIN))		return -EPERM; 	mutex_lock(&static_key_mutex);	val = static_key_enabled(key);	ret = proc_dointvec_minmax(&tmp, dir, buffer, lenp, ppos);	if (SYSCTL_USER_TO_KERN(dir) && !ret) {		if (val)			static_key_enable(key);		else			static_key_disable(key);	}	mutex_unlock(&static_key_mutex);	return ret;} static const struct ctl_table sysctl_subsys_table[] = {#ifdef CONFIG_PROC_SYSCTL	{		.procname	= "sysctl_writes_strict",		.data		= &sysctl_writes_strict,		.maxlen		= sizeof(int),		.mode		= 0644,		.proc_handler	= proc_dointvec_minmax,		.extra1		= SYSCTL_NEG_ONE,		.extra2		= SYSCTL_ONE,	},#endif	{		.procname	= "ngroups_max",		.data		= (void *)&ngroups_max,		.maxlen		= sizeof (int),		.mode		= 0444,		.proc_handler	= proc_dointvec,	},	{		.procname	= "cap_last_cap",		.data		= (void *)&cap_last_cap,		.maxlen		= sizeof(int),		.mode		= 0444,		.proc_handler	= proc_dointvec,	},#ifdef CONFIG_SYSCTL_ARCH_UNALIGN_ALLOW	{		.procname	= "unaligned-trap",		.data		= &unaligned_enabled,		.maxlen		= sizeof(int),		.mode		= 0644,		.proc_handler	= proc_dointvec,	},#endif#ifdef CONFIG_SYSCTL_ARCH_UNALIGN_NO_WARN	{		.procname	= "ignore-unaligned-usertrap",		.data		= &no_unaligned_warning,		.maxlen		= sizeof (int),		.mode		= 0644,		.proc_handler	= proc_dointvec,	},#endif}; int __init sysctl_init_bases(void){	register_sysctl_init("kernel", sysctl_subsys_table); 	return 0;}#endif /* CONFIG_SYSCTL *//* * No sense putting this after each symbol definition, twice, * exception granted :-) */EXPORT_SYMBOL(proc_dobool);EXPORT_SYMBOL(proc_dointvec);EXPORT_SYMBOL(proc_douintvec);EXPORT_SYMBOL(proc_dointvec_minmax);EXPORT_SYMBOL_GPL(proc_douintvec_minmax);EXPORT_SYMBOL(proc_dostring);EXPORT_SYMBOL(proc_doulongvec_minmax);EXPORT_SYMBOL(proc_do_large_bitmap);

Lines 1001–1438 of 1438. Previous lines