diff options
Diffstat (limited to 'kernel/sysctl.c')
| -rw-r--r-- | kernel/sysctl.c | 79 | 
1 files changed, 28 insertions, 51 deletions
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index dc6858d6639e..5faf89ac9ec0 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -2047,9 +2047,8 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,  		  void *data)  {  	int *i, vleft, first = 1, err = 0; -	unsigned long page = 0;  	size_t left; -	char *kbuf; +	char *kbuf = NULL, *p;  	if (!tbl_data || !table->maxlen || !*lenp || (*ppos && !write)) {  		*lenp = 0; @@ -2078,15 +2077,9 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,  		if (left > PAGE_SIZE - 1)  			left = PAGE_SIZE - 1; -		page = __get_free_page(GFP_TEMPORARY); -		kbuf = (char *) page; -		if (!kbuf) -			return -ENOMEM; -		if (copy_from_user(kbuf, buffer, left)) { -			err = -EFAULT; -			goto free; -		} -		kbuf[left] = 0; +		p = kbuf = memdup_user_nul(buffer, left); +		if (IS_ERR(kbuf)) +			return PTR_ERR(kbuf);  	}  	for (; left && vleft--; i++, first=0) { @@ -2094,11 +2087,11 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,  		bool neg;  		if (write) { -			left -= proc_skip_spaces(&kbuf); +			left -= proc_skip_spaces(&p);  			if (!left)  				break; -			err = proc_get_long(&kbuf, &left, &lval, &neg, +			err = proc_get_long(&p, &left, &lval, &neg,  					     proc_wspace_sep,  					     sizeof(proc_wspace_sep), NULL);  			if (err) @@ -2125,10 +2118,9 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,  	if (!write && !first && left && !err)  		err = proc_put_char(&buffer, &left, '\n');  	if (write && !err && left) -		left -= proc_skip_spaces(&kbuf); -free: +		left -= proc_skip_spaces(&p);  	if (write) { -		free_page(page); +		kfree(kbuf);  		if (first)  			return err ? : -EINVAL;  	} @@ -2310,9 +2302,8 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int  {  	unsigned long *i, *min, *max;  	int vleft, first = 1, err = 0; -	unsigned long page = 0;  	size_t left; -	char *kbuf; +	char *kbuf = NULL, *p;  	if (!data || !table->maxlen || !*lenp || (*ppos && !write)) {  		*lenp = 0; @@ -2340,15 +2331,9 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int  		if (left > PAGE_SIZE - 1)  			left = PAGE_SIZE - 1; -		page = __get_free_page(GFP_TEMPORARY); -		kbuf = (char *) page; -		if (!kbuf) -			return -ENOMEM; -		if (copy_from_user(kbuf, buffer, left)) { -			err = -EFAULT; -			goto free; -		} -		kbuf[left] = 0; +		p = kbuf = memdup_user_nul(buffer, left); +		if (IS_ERR(kbuf)) +			return PTR_ERR(kbuf);  	}  	for (; left && vleft--; i++, first = 0) { @@ -2357,9 +2342,9 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int  		if (write) {  			bool neg; -			left -= proc_skip_spaces(&kbuf); +			left -= proc_skip_spaces(&p); -			err = proc_get_long(&kbuf, &left, &val, &neg, +			err = proc_get_long(&p, &left, &val, &neg,  					     proc_wspace_sep,  					     sizeof(proc_wspace_sep), NULL);  			if (err) @@ -2385,10 +2370,9 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int  	if (!write && !first && left && !err)  		err = proc_put_char(&buffer, &left, '\n');  	if (write && !err) -		left -= proc_skip_spaces(&kbuf); -free: +		left -= proc_skip_spaces(&p);  	if (write) { -		free_page(page); +		kfree(kbuf);  		if (first)  			return err ? : -EINVAL;  	} @@ -2650,34 +2634,27 @@ int proc_do_large_bitmap(struct ctl_table *table, int write,  	}  	if (write) { -		unsigned long page = 0; -		char *kbuf; +		char *kbuf, *p;  		if (left > PAGE_SIZE - 1)  			left = PAGE_SIZE - 1; -		page = __get_free_page(GFP_TEMPORARY); -		kbuf = (char *) page; -		if (!kbuf) -			return -ENOMEM; -		if (copy_from_user(kbuf, buffer, left)) { -			free_page(page); -			return -EFAULT; -                } -		kbuf[left] = 0; +		p = kbuf = memdup_user_nul(buffer, left); +		if (IS_ERR(kbuf)) +			return PTR_ERR(kbuf);  		tmp_bitmap = kzalloc(BITS_TO_LONGS(bitmap_len) * sizeof(unsigned long),  				     GFP_KERNEL);  		if (!tmp_bitmap) { -			free_page(page); +			kfree(kbuf);  			return -ENOMEM;  		} -		proc_skip_char(&kbuf, &left, '\n'); +		proc_skip_char(&p, &left, '\n');  		while (!err && left) {  			unsigned long val_a, val_b;  			bool neg; -			err = proc_get_long(&kbuf, &left, &val_a, &neg, tr_a, +			err = proc_get_long(&p, &left, &val_a, &neg, tr_a,  					     sizeof(tr_a), &c);  			if (err)  				break; @@ -2688,12 +2665,12 @@ int proc_do_large_bitmap(struct ctl_table *table, int write,  			val_b = val_a;  			if (left) { -				kbuf++; +				p++;  				left--;  			}  			if (c == '-') { -				err = proc_get_long(&kbuf, &left, &val_b, +				err = proc_get_long(&p, &left, &val_b,  						     &neg, tr_b, sizeof(tr_b),  						     &c);  				if (err) @@ -2704,16 +2681,16 @@ int proc_do_large_bitmap(struct ctl_table *table, int write,  					break;  				}  				if (left) { -					kbuf++; +					p++;  					left--;  				}  			}  			bitmap_set(tmp_bitmap, val_a, val_b - val_a + 1);  			first = 0; -			proc_skip_char(&kbuf, &left, '\n'); +			proc_skip_char(&p, &left, '\n');  		} -		free_page(page); +		kfree(kbuf);  	} else {  		unsigned long bit_a, bit_b = 0;  | 
