diff options
author | Andrey Ignatov <rdna@fb.com> | 2019-02-27 16:28:48 -0500 |
---|---|---|
committer | Alexei Starovoitov <ast@kernel.org> | 2019-04-12 16:54:58 -0400 |
commit | 808649fb787d918a48a360a668ee4ee9023f0c11 (patch) | |
tree | a58fb657373b8886c6ddf715476f62484edc233d /kernel/bpf | |
parent | 7b146cebe30cb481b0f70d85779da938da818637 (diff) |
bpf: Introduce bpf_sysctl_get_name helper
Add bpf_sysctl_get_name() helper to copy sysctl name (/proc/sys/ entry)
into provided by BPF_PROG_TYPE_CGROUP_SYSCTL program buffer.
By default full name (w/o /proc/sys/) is copied, e.g. "net/ipv4/tcp_mem".
If BPF_F_SYSCTL_BASE_NAME flag is set, only base name will be copied,
e.g. "tcp_mem".
Documentation for the new helper 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 'kernel/bpf')
-rw-r--r-- | kernel/bpf/cgroup.c | 70 |
1 files changed, 69 insertions, 1 deletions
diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c index 610491b5f0aa..a68387043244 100644 --- a/kernel/bpf/cgroup.c +++ b/kernel/bpf/cgroup.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/filter.h> | 14 | #include <linux/filter.h> |
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/sysctl.h> | 16 | #include <linux/sysctl.h> |
17 | #include <linux/string.h> | ||
17 | #include <linux/bpf.h> | 18 | #include <linux/bpf.h> |
18 | #include <linux/bpf-cgroup.h> | 19 | #include <linux/bpf-cgroup.h> |
19 | #include <net/sock.h> | 20 | #include <net/sock.h> |
@@ -806,10 +807,77 @@ int __cgroup_bpf_run_filter_sysctl(struct ctl_table_header *head, | |||
806 | } | 807 | } |
807 | EXPORT_SYMBOL(__cgroup_bpf_run_filter_sysctl); | 808 | EXPORT_SYMBOL(__cgroup_bpf_run_filter_sysctl); |
808 | 809 | ||
810 | static ssize_t sysctl_cpy_dir(const struct ctl_dir *dir, char **bufp, | ||
811 | size_t *lenp) | ||
812 | { | ||
813 | ssize_t tmp_ret = 0, ret; | ||
814 | |||
815 | if (dir->header.parent) { | ||
816 | tmp_ret = sysctl_cpy_dir(dir->header.parent, bufp, lenp); | ||
817 | if (tmp_ret < 0) | ||
818 | return tmp_ret; | ||
819 | } | ||
820 | |||
821 | ret = strscpy(*bufp, dir->header.ctl_table[0].procname, *lenp); | ||
822 | if (ret < 0) | ||
823 | return ret; | ||
824 | *bufp += ret; | ||
825 | *lenp -= ret; | ||
826 | ret += tmp_ret; | ||
827 | |||
828 | /* Avoid leading slash. */ | ||
829 | if (!ret) | ||
830 | return ret; | ||
831 | |||
832 | tmp_ret = strscpy(*bufp, "/", *lenp); | ||
833 | if (tmp_ret < 0) | ||
834 | return tmp_ret; | ||
835 | *bufp += tmp_ret; | ||
836 | *lenp -= tmp_ret; | ||
837 | |||
838 | return ret + tmp_ret; | ||
839 | } | ||
840 | |||
841 | BPF_CALL_4(bpf_sysctl_get_name, struct bpf_sysctl_kern *, ctx, char *, buf, | ||
842 | size_t, buf_len, u64, flags) | ||
843 | { | ||
844 | ssize_t tmp_ret = 0, ret; | ||
845 | |||
846 | if (!buf) | ||
847 | return -EINVAL; | ||
848 | |||
849 | if (!(flags & BPF_F_SYSCTL_BASE_NAME)) { | ||
850 | if (!ctx->head) | ||
851 | return -EINVAL; | ||
852 | tmp_ret = sysctl_cpy_dir(ctx->head->parent, &buf, &buf_len); | ||
853 | if (tmp_ret < 0) | ||
854 | return tmp_ret; | ||
855 | } | ||
856 | |||
857 | ret = strscpy(buf, ctx->table->procname, buf_len); | ||
858 | |||
859 | return ret < 0 ? ret : tmp_ret + ret; | ||
860 | } | ||
861 | |||
862 | static const struct bpf_func_proto bpf_sysctl_get_name_proto = { | ||
863 | .func = bpf_sysctl_get_name, | ||
864 | .gpl_only = false, | ||
865 | .ret_type = RET_INTEGER, | ||
866 | .arg1_type = ARG_PTR_TO_CTX, | ||
867 | .arg2_type = ARG_PTR_TO_MEM, | ||
868 | .arg3_type = ARG_CONST_SIZE, | ||
869 | .arg4_type = ARG_ANYTHING, | ||
870 | }; | ||
871 | |||
809 | static const struct bpf_func_proto * | 872 | static const struct bpf_func_proto * |
810 | sysctl_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) | 873 | sysctl_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) |
811 | { | 874 | { |
812 | return cgroup_base_func_proto(func_id, prog); | 875 | switch (func_id) { |
876 | case BPF_FUNC_sysctl_get_name: | ||
877 | return &bpf_sysctl_get_name_proto; | ||
878 | default: | ||
879 | return cgroup_base_func_proto(func_id, prog); | ||
880 | } | ||
813 | } | 881 | } |
814 | 882 | ||
815 | static bool sysctl_is_valid_access(int off, int size, enum bpf_access_type type, | 883 | static bool sysctl_is_valid_access(int off, int size, enum bpf_access_type type, |