aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/uapi/linux/bpf.h22
-rw-r--r--kernel/bpf/cgroup.c70
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. */
2685enum bpf_adj_room_mode { 2705enum 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}
807EXPORT_SYMBOL(__cgroup_bpf_run_filter_sysctl); 808EXPORT_SYMBOL(__cgroup_bpf_run_filter_sysctl);
808 809
810static 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
841BPF_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
862static 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
809static const struct bpf_func_proto * 872static const struct bpf_func_proto *
810sysctl_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) 873sysctl_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
815static bool sysctl_is_valid_access(int off, int size, enum bpf_access_type type, 883static bool sysctl_is_valid_access(int off, int size, enum bpf_access_type type,