diff options
-rw-r--r-- | include/uapi/linux/bpf.h | 22 | ||||
-rw-r--r-- | kernel/bpf/cgroup.c | 70 |
2 files changed, 90 insertions, 2 deletions
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index cc2a2466d5f3..9c8a2f3ccb9b 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h | |||
@@ -2506,6 +2506,22 @@ union bpf_attr { | |||
2506 | * Return | 2506 | * Return |
2507 | * 0 if iph and th are a valid SYN cookie ACK, or a negative error | 2507 | * 0 if iph and th are a valid SYN cookie ACK, or a negative error |
2508 | * otherwise. | 2508 | * otherwise. |
2509 | * | ||
2510 | * int bpf_sysctl_get_name(struct bpf_sysctl *ctx, char *buf, size_t buf_len, u64 flags) | ||
2511 | * Description | ||
2512 | * Get name of sysctl in /proc/sys/ and copy it into provided by | ||
2513 | * program buffer *buf* of size *buf_len*. | ||
2514 | * | ||
2515 | * The buffer is always NUL terminated, unless it's zero-sized. | ||
2516 | * | ||
2517 | * If *flags* is zero, full name (e.g. "net/ipv4/tcp_mem") is | ||
2518 | * copied. Use **BPF_F_SYSCTL_BASE_NAME** flag to copy base name | ||
2519 | * only (e.g. "tcp_mem"). | ||
2520 | * Return | ||
2521 | * Number of character copied (not including the trailing NUL). | ||
2522 | * | ||
2523 | * **-E2BIG** if the buffer wasn't big enough (*buf* will contain | ||
2524 | * truncated name in this case). | ||
2509 | */ | 2525 | */ |
2510 | #define __BPF_FUNC_MAPPER(FN) \ | 2526 | #define __BPF_FUNC_MAPPER(FN) \ |
2511 | FN(unspec), \ | 2527 | FN(unspec), \ |
@@ -2608,7 +2624,8 @@ union bpf_attr { | |||
2608 | FN(skb_ecn_set_ce), \ | 2624 | FN(skb_ecn_set_ce), \ |
2609 | FN(get_listener_sock), \ | 2625 | FN(get_listener_sock), \ |
2610 | FN(skc_lookup_tcp), \ | 2626 | FN(skc_lookup_tcp), \ |
2611 | FN(tcp_check_syncookie), | 2627 | FN(tcp_check_syncookie), \ |
2628 | FN(sysctl_get_name), | ||
2612 | 2629 | ||
2613 | /* integer value in 'imm' field of BPF_CALL instruction selects which helper | 2630 | /* integer value in 'imm' field of BPF_CALL instruction selects which helper |
2614 | * function eBPF program intends to call | 2631 | * function eBPF program intends to call |
@@ -2681,6 +2698,9 @@ enum bpf_func_id { | |||
2681 | BPF_ADJ_ROOM_ENCAP_L2_MASK) \ | 2698 | BPF_ADJ_ROOM_ENCAP_L2_MASK) \ |
2682 | << BPF_ADJ_ROOM_ENCAP_L2_SHIFT) | 2699 | << BPF_ADJ_ROOM_ENCAP_L2_SHIFT) |
2683 | 2700 | ||
2701 | /* BPF_FUNC_sysctl_get_name flags. */ | ||
2702 | #define BPF_F_SYSCTL_BASE_NAME (1ULL << 0) | ||
2703 | |||
2684 | /* Mode for BPF_FUNC_skb_adjust_room helper. */ | 2704 | /* Mode for BPF_FUNC_skb_adjust_room helper. */ |
2685 | enum bpf_adj_room_mode { | 2705 | enum bpf_adj_room_mode { |
2686 | BPF_ADJ_ROOM_NET, | 2706 | BPF_ADJ_ROOM_NET, |
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, |