3416 lines · 80.0 KB · C
RawDownload
 		*valp = tmp;	} 	return 0;} /** * proc_douintvec_minmax - read a vector of unsigned ints with min/max values * @table: the sysctl table * @write: %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 int) unsigned integer * values from/to the user buffer, treated as an ASCII string. Negative * strings are not allowed. * * This routine will ensure the values are within the range specified by * table->extra1 (min) and table->extra2 (max). There is a final sanity * check for UINT_MAX to avoid having to support wrap around uses from * userspace. * * Returns 0 on success or -ERANGE on write when the range check fails. */int proc_douintvec_minmax(struct ctl_table *table, int write,			  void *buffer, size_t *lenp, loff_t *ppos){	struct do_proc_douintvec_minmax_conv_param param = {		.min = (unsigned int *) table->extra1,		.max = (unsigned int *) table->extra2,	};	return do_proc_douintvec(table, write, buffer, lenp, ppos,				 do_proc_douintvec_minmax_conv, &param);} static int do_proc_dopipe_max_size_conv(unsigned long *lvalp,					unsigned int *valp,					int write, void *data){	if (write) {		unsigned int val; 		val = round_pipe_size(*lvalp);		if (val == 0)			return -EINVAL; 		*valp = val;	} else {		unsigned int val = *valp;		*lvalp = (unsigned long) val;	} 	return 0;} static int proc_dopipe_max_size(struct ctl_table *table, int write,				void *buffer, size_t *lenp, loff_t *ppos){	return do_proc_douintvec(table, write, buffer, lenp, ppos,				 do_proc_dopipe_max_size_conv, NULL);} static void validate_coredump_safety(void){#ifdef CONFIG_COREDUMP	if (suid_dumpable == SUID_DUMP_ROOT &&	    core_pattern[0] != '/' && core_pattern[0] != '|') {		printk(KERN_WARNING"Unsafe core_pattern used with fs.suid_dumpable=2.\n""Pipe handler or fully qualified core dump path required.\n""Set kernel.core_pattern before fs.suid_dumpable.\n"		);	}#endif} static int proc_dointvec_minmax_coredump(struct ctl_table *table, int write,		void *buffer, size_t *lenp, loff_t *ppos){	int error = proc_dointvec_minmax(table, write, buffer, lenp, ppos);	if (!error)		validate_coredump_safety();	return error;} #ifdef CONFIG_COREDUMPstatic int proc_dostring_coredump(struct ctl_table *table, int write,		  void *buffer, size_t *lenp, loff_t *ppos){	int error = proc_dostring(table, write, buffer, lenp, ppos);	if (!error)		validate_coredump_safety();	return error;}#endif #ifdef CONFIG_MAGIC_SYSRQstatic int sysrq_sysctl_handler(struct ctl_table *table, int write,				void *buffer, size_t *lenp, loff_t *ppos){	int tmp, ret; 	tmp = sysrq_mask(); 	ret = __do_proc_dointvec(&tmp, table, write, buffer,			       lenp, ppos, NULL, NULL);	if (ret || !write)		return ret; 	if (write)		sysrq_toggle_support(tmp); 	return 0;}#endif static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table,		int write, void *buffer, size_t *lenp, loff_t *ppos,		unsigned long convmul, unsigned long convdiv){	unsigned long *i, *min, *max;	int vleft, first = 1, err = 0;	size_t left;	char *p; 	if (!data || !table->maxlen || !*lenp || (*ppos && !write)) {		*lenp = 0;		return 0;	} 	i = (unsigned long *) data;	min = (unsigned long *) table->extra1;	max = (unsigned long *) table->extra2;	vleft = table->maxlen / sizeof(unsigned long);	left = *lenp; 	if (write) {		if (proc_first_pos_non_zero_ignore(ppos, table))			goto out; 		if (left > PAGE_SIZE - 1)			left = PAGE_SIZE - 1;		p = buffer;	} 	for (; left && vleft--; i++, first = 0) {		unsigned long val; 		if (write) {			bool neg; 			left -= proc_skip_spaces(&p);			if (!left)				break; 			err = proc_get_long(&p, &left, &val, &neg,					     proc_wspace_sep,					     sizeof(proc_wspace_sep), NULL);			if (err)				break;			if (neg)				continue;			val = convmul * val / convdiv;			if ((min && val < *min) || (max && val > *max)) {				err = -EINVAL;				break;			}			*i = val;		} else {			val = convdiv * (*i) / convmul;			if (!first)				proc_put_char(&buffer, &left, '\t');			proc_put_long(&buffer, &left, val, false);		}	} 	if (!write && !first && left && !err)		proc_put_char(&buffer, &left, '\n');	if (write && !err)		left -= proc_skip_spaces(&p);	if (write && first)		return err ? : -EINVAL;	*lenp -= left;out:	*ppos += *lenp;	return err;} static int do_proc_doulongvec_minmax(struct ctl_table *table, int write,		void *buffer, size_t *lenp, loff_t *ppos, unsigned long convmul,		unsigned long convdiv){	return __do_proc_doulongvec_minmax(table->data, table, write,			buffer, lenp, ppos, convmul, convdiv);} /** * proc_doulongvec_minmax - read a vector of long integers with min/max values * @table: the sysctl table * @write: %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(struct ctl_table *table, int write,			   void *buffer, size_t *lenp, loff_t *ppos){    return do_proc_doulongvec_minmax(table, write, buffer, lenp, ppos, 1l, 1l);} /** * proc_doulongvec_ms_jiffies_minmax - read a vector of millisecond values with min/max values * @table: the sysctl table * @write: %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. The values * are treated as milliseconds, and converted to jiffies when they are stored. * * 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_ms_jiffies_minmax(struct ctl_table *table, int write,				      void *buffer, size_t *lenp, loff_t *ppos){    return do_proc_doulongvec_minmax(table, write, buffer,				     lenp, ppos, HZ, 1000l);}  static int do_proc_dointvec_jiffies_conv(bool *negp, unsigned long *lvalp,					 int *valp,					 int write, void *data){	if (write) {		if (*lvalp > INT_MAX / HZ)			return 1;		*valp = *negp ? -(*lvalp*HZ) : (*lvalp*HZ);	} else {		int val = *valp;		unsigned long lval;		if (val < 0) {			*negp = true;			lval = -(unsigned long)val;		} else {			*negp = false;			lval = (unsigned long)val;		}		*lvalp = lval / HZ;	}	return 0;} static int do_proc_dointvec_userhz_jiffies_conv(bool *negp, unsigned long *lvalp,						int *valp,						int write, void *data){	if (write) {		if (USER_HZ < HZ && *lvalp > (LONG_MAX / HZ) * USER_HZ)			return 1;		*valp = clock_t_to_jiffies(*negp ? -*lvalp : *lvalp);	} else {		int val = *valp;		unsigned long lval;		if (val < 0) {			*negp = true;			lval = -(unsigned long)val;		} else {			*negp = false;			lval = (unsigned long)val;		}		*lvalp = jiffies_to_clock_t(lval);	}	return 0;} static int do_proc_dointvec_ms_jiffies_conv(bool *negp, unsigned long *lvalp,					    int *valp,					    int write, void *data){	if (write) {		unsigned long jif = msecs_to_jiffies(*negp ? -*lvalp : *lvalp); 		if (jif > INT_MAX)			return 1;		*valp = (int)jif;	} else {		int val = *valp;		unsigned long lval;		if (val < 0) {			*negp = true;			lval = -(unsigned long)val;		} else {			*negp = false;			lval = (unsigned long)val;		}		*lvalp = jiffies_to_msecs(lval);	}	return 0;} /** * proc_dointvec_jiffies - read a vector of integers as seconds * @table: the sysctl table * @write: %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 int) integer * values from/to the user buffer, treated as an ASCII string.  * The values read are assumed to be in seconds, and are converted into * jiffies. * * Returns 0 on success. */int proc_dointvec_jiffies(struct ctl_table *table, int write,			  void *buffer, size_t *lenp, loff_t *ppos){    return do_proc_dointvec(table,write,buffer,lenp,ppos,		    	    do_proc_dointvec_jiffies_conv,NULL);} /** * proc_dointvec_userhz_jiffies - read a vector of integers as 1/USER_HZ seconds * @table: the sysctl table * @write: %TRUE if this is a write to the sysctl file * @buffer: the user buffer * @lenp: the size of the user buffer * @ppos: pointer to the file position * * Reads/writes up to table->maxlen/sizeof(unsigned int) integer * values from/to the user buffer, treated as an ASCII string.  * The values read are assumed to be in 1/USER_HZ seconds, and  * are converted into jiffies. * * Returns 0 on success. */int proc_dointvec_userhz_jiffies(struct ctl_table *table, int write,				 void *buffer, size_t *lenp, loff_t *ppos){    return do_proc_dointvec(table,write,buffer,lenp,ppos,		    	    do_proc_dointvec_userhz_jiffies_conv,NULL);} /** * proc_dointvec_ms_jiffies - read a vector of integers as 1 milliseconds * @table: the sysctl table * @write: %TRUE if this is a write to the sysctl file * @buffer: the user buffer * @lenp: the size of the user buffer * @ppos: file position * @ppos: the current position in the file * * Reads/writes up to table->maxlen/sizeof(unsigned int) integer * values from/to the user buffer, treated as an ASCII string.  * The values read are assumed to be in 1/1000 seconds, and  * are converted into jiffies. * * Returns 0 on success. */int proc_dointvec_ms_jiffies(struct ctl_table *table, int write, void *buffer,		size_t *lenp, loff_t *ppos){	return do_proc_dointvec(table, write, buffer, lenp, ppos,				do_proc_dointvec_ms_jiffies_conv, NULL);} static int proc_do_cad_pid(struct ctl_table *table, int write, void *buffer,		size_t *lenp, loff_t *ppos){	struct pid *new_pid;	pid_t tmp;	int r; 	tmp = pid_vnr(cad_pid); 	r = __do_proc_dointvec(&tmp, table, write, buffer,			       lenp, ppos, NULL, NULL);	if (r || !write)		return r; 	new_pid = find_get_pid(tmp);	if (!new_pid)		return -ESRCH; 	put_pid(xchg(&cad_pid, new_pid));	return 0;} /** * proc_do_large_bitmap - read/write from/to a large bitmap * @table: the sysctl table * @write: %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(struct ctl_table *table, int write,			 void *buffer, size_t *lenp, loff_t *ppos){	int err = 0;	bool first = 1;	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; 	if (!bitmap || !bitmap_len || !left || (*ppos && !write)) {		*lenp = 0;		return 0;	} 	if (write) {		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 ||

Lines 1001–1500 of 3416. Previous lines