This allows the sysctl handler to safely take kernel space pointers, as required for the new code to set sysctl parameters at boot time. Signed-off-by: Christoph Hellwig <hch@xxxxxx> --- fs/proc/proc_sysctl.c | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 42c5128c7d1c76..dd5eb693bd00df 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -540,7 +540,7 @@ static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry, return err; } -static ssize_t proc_sys_call_handler(struct file *filp, void __user *ubuf, +static ssize_t proc_sys_call_handler(struct file *filp, uptr_t buf, size_t count, loff_t *ppos, int write) { struct inode *inode = file_inode(filp); @@ -566,20 +566,21 @@ static ssize_t proc_sys_call_handler(struct file *filp, void __user *ubuf, goto out; /* don't even try if the size is too large */ - if (count > KMALLOC_MAX_SIZE) + if (count >= KMALLOC_MAX_SIZE) return -ENOMEM; + error = -ENOMEM; + + /* allow for NULL termination on writes */ + kbuf = kzalloc(count + (write ? 1 : 0), GFP_KERNEL); + if (!kbuf) + goto out; + if (write) { - kbuf = memdup_user_nul(ubuf, count); - if (IS_ERR(kbuf)) { - error = PTR_ERR(kbuf); - goto out; - } - } else { - error = -ENOMEM; - kbuf = kzalloc(count, GFP_KERNEL); - if (!kbuf) - goto out; + error = -EFAULT; + if (copy_from_uptr(kbuf, buf, count)) + goto out_free_buf; + ((char *)kbuf)[count] = '\0'; } error = BPF_CGROUP_RUN_PROG_SYSCTL(head, table, write, &kbuf, &count, @@ -594,7 +595,7 @@ static ssize_t proc_sys_call_handler(struct file *filp, void __user *ubuf, if (!write) { error = -EFAULT; - if (copy_to_user(ubuf, kbuf, count)) + if (copy_to_uptr(buf, kbuf, count)) goto out_free_buf; } @@ -607,16 +608,16 @@ static ssize_t proc_sys_call_handler(struct file *filp, void __user *ubuf, return error; } -static ssize_t proc_sys_read(struct file *filp, char __user *buf, +static ssize_t proc_sys_read(struct file *filp, uptr_t buf, size_t count, loff_t *ppos) { - return proc_sys_call_handler(filp, (void __user *)buf, count, ppos, 0); + return proc_sys_call_handler(filp, buf, count, ppos, 0); } -static ssize_t proc_sys_write(struct file *filp, const char __user *buf, +static ssize_t proc_sys_write(struct file *filp, uptr_t buf, size_t count, loff_t *ppos) { - return proc_sys_call_handler(filp, (void __user *)buf, count, ppos, 1); + return proc_sys_call_handler(filp, buf, count, ppos, 1); } static int proc_sys_open(struct inode *inode, struct file *filp) @@ -853,8 +854,8 @@ static int proc_sys_getattr(const struct path *path, struct kstat *stat, static const struct file_operations proc_sys_file_operations = { .open = proc_sys_open, .poll = proc_sys_poll, - .read = proc_sys_read, - .write = proc_sys_write, + .read_uptr = proc_sys_read, + .write_uptr = proc_sys_write, .llseek = default_llseek, }; -- 2.26.2