aboutsummaryrefslogtreecommitdiffstats
path: root/fs/proc/proc_sysctl.c
diff options
context:
space:
mode:
authorAndrey Ignatov <rdna@fb.com>2019-03-07 21:38:43 -0500
committerAlexei Starovoitov <ast@kernel.org>2019-04-12 16:54:58 -0400
commit4e63acdff864654cee0ac5aaeda3913798ee78f6 (patch)
tree85e2cff7f791e8e98dfcca646211ccc1278de61e /fs/proc/proc_sysctl.c
parent1d11b3016cec4ed9770b98e82a61708c8f4926e7 (diff)
bpf: Introduce bpf_sysctl_{get,set}_new_value helpers
Add helpers to work with new value being written to sysctl by user space. bpf_sysctl_get_new_value() copies value being written to sysctl into provided buffer. bpf_sysctl_set_new_value() overrides new value being written by user space with a one from provided buffer. Buffer should contain string representation of the value, similar to what can be seen in /proc/sys/. Both helpers can be used only on sysctl write. File position matters and can be managed by an interface that will be introduced separately. E.g. if user space calls sys_write to a file in /proc/sys/ at file position = X, where X > 0, then the value set by bpf_sysctl_set_new_value() will be written starting from X. If program wants to override whole value with specified buffer, file position has to be set to zero. Documentation for the new helpers is provided in bpf.h UAPI. Signed-off-by: Andrey Ignatov <rdna@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'fs/proc/proc_sysctl.c')
-rw-r--r--fs/proc/proc_sysctl.c22
1 files changed, 17 insertions, 5 deletions
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index e01b02150340..023101c6f0d7 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -570,8 +570,8 @@ static ssize_t proc_sys_call_handler(struct file *filp, void __user *buf,
570 struct inode *inode = file_inode(filp); 570 struct inode *inode = file_inode(filp);
571 struct ctl_table_header *head = grab_header(inode); 571 struct ctl_table_header *head = grab_header(inode);
572 struct ctl_table *table = PROC_I(inode)->sysctl_entry; 572 struct ctl_table *table = PROC_I(inode)->sysctl_entry;
573 void *new_buf = NULL;
573 ssize_t error; 574 ssize_t error;
574 size_t res;
575 575
576 if (IS_ERR(head)) 576 if (IS_ERR(head))
577 return PTR_ERR(head); 577 return PTR_ERR(head);
@@ -589,15 +589,27 @@ static ssize_t proc_sys_call_handler(struct file *filp, void __user *buf,
589 if (!table->proc_handler) 589 if (!table->proc_handler)
590 goto out; 590 goto out;
591 591
592 error = BPF_CGROUP_RUN_PROG_SYSCTL(head, table, write); 592 error = BPF_CGROUP_RUN_PROG_SYSCTL(head, table, write, buf, &count,
593 &new_buf);
593 if (error) 594 if (error)
594 goto out; 595 goto out;
595 596
596 /* careful: calling conventions are nasty here */ 597 /* careful: calling conventions are nasty here */
597 res = count; 598 if (new_buf) {
598 error = table->proc_handler(table, write, buf, &res, ppos); 599 mm_segment_t old_fs;
600
601 old_fs = get_fs();
602 set_fs(KERNEL_DS);
603 error = table->proc_handler(table, write, (void __user *)new_buf,
604 &count, ppos);
605 set_fs(old_fs);
606 kfree(new_buf);
607 } else {
608 error = table->proc_handler(table, write, buf, &count, ppos);
609 }
610
599 if (!error) 611 if (!error)
600 error = res; 612 error = count;
601out: 613out:
602 sysctl_head_finish(head); 614 sysctl_head_finish(head);
603 615