diff options
| author | Martin KaFai Lau <kafai@fb.com> | 2019-02-10 02:22:24 -0500 |
|---|---|---|
| committer | Alexei Starovoitov <ast@kernel.org> | 2019-02-10 22:46:17 -0500 |
| commit | 655a51e536c09d15ffa3603b1b6fce2b45b85a1f (patch) | |
| tree | c918f6f95d890735a86370630fd7791f2a5a5360 /kernel | |
| parent | 9b1f3d6e5af295a72deb5e3f04db07a6a58be72e (diff) | |
bpf: Add struct bpf_tcp_sock and BPF_FUNC_tcp_sock
This patch adds a helper function BPF_FUNC_tcp_sock and it
is currently available for cg_skb and sched_(cls|act):
struct bpf_tcp_sock *bpf_tcp_sock(struct bpf_sock *sk);
int cg_skb_foo(struct __sk_buff *skb) {
struct bpf_tcp_sock *tp;
struct bpf_sock *sk;
__u32 snd_cwnd;
sk = skb->sk;
if (!sk)
return 1;
tp = bpf_tcp_sock(sk);
if (!tp)
return 1;
snd_cwnd = tp->snd_cwnd;
/* ... */
return 1;
}
A 'struct bpf_tcp_sock' is also added to the uapi bpf.h to provide
read-only access. bpf_tcp_sock has all the existing tcp_sock's fields
that has already been exposed by the bpf_sock_ops.
i.e. no new tcp_sock's fields are exposed in bpf.h.
This helper returns a pointer to the tcp_sock. If it is not a tcp_sock
or it cannot be traced back to a tcp_sock by sk_to_full_sk(), it
returns NULL. Hence, the caller needs to check for NULL before
accessing it.
The current use case is to expose members from tcp_sock
to allow a cg_skb_bpf_prog to provide per cgroup traffic
policing/shaping.
Acked-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/bpf/verifier.c | 31 |
1 files changed, 29 insertions, 2 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index b755d55a3791..1b9496c41383 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c | |||
| @@ -334,14 +334,16 @@ static bool type_is_pkt_pointer(enum bpf_reg_type type) | |||
| 334 | static bool type_is_sk_pointer(enum bpf_reg_type type) | 334 | static bool type_is_sk_pointer(enum bpf_reg_type type) |
| 335 | { | 335 | { |
| 336 | return type == PTR_TO_SOCKET || | 336 | return type == PTR_TO_SOCKET || |
| 337 | type == PTR_TO_SOCK_COMMON; | 337 | type == PTR_TO_SOCK_COMMON || |
| 338 | type == PTR_TO_TCP_SOCK; | ||
| 338 | } | 339 | } |
| 339 | 340 | ||
| 340 | static bool reg_type_may_be_null(enum bpf_reg_type type) | 341 | static bool reg_type_may_be_null(enum bpf_reg_type type) |
| 341 | { | 342 | { |
| 342 | return type == PTR_TO_MAP_VALUE_OR_NULL || | 343 | return type == PTR_TO_MAP_VALUE_OR_NULL || |
| 343 | type == PTR_TO_SOCKET_OR_NULL || | 344 | type == PTR_TO_SOCKET_OR_NULL || |
| 344 | type == PTR_TO_SOCK_COMMON_OR_NULL; | 345 | type == PTR_TO_SOCK_COMMON_OR_NULL || |
| 346 | type == PTR_TO_TCP_SOCK_OR_NULL; | ||
| 345 | } | 347 | } |
| 346 | 348 | ||
| 347 | static bool type_is_refcounted(enum bpf_reg_type type) | 349 | static bool type_is_refcounted(enum bpf_reg_type type) |
| @@ -407,6 +409,8 @@ static const char * const reg_type_str[] = { | |||
| 407 | [PTR_TO_SOCKET_OR_NULL] = "sock_or_null", | 409 | [PTR_TO_SOCKET_OR_NULL] = "sock_or_null", |
| 408 | [PTR_TO_SOCK_COMMON] = "sock_common", | 410 | [PTR_TO_SOCK_COMMON] = "sock_common", |
| 409 | [PTR_TO_SOCK_COMMON_OR_NULL] = "sock_common_or_null", | 411 | [PTR_TO_SOCK_COMMON_OR_NULL] = "sock_common_or_null", |
| 412 | [PTR_TO_TCP_SOCK] = "tcp_sock", | ||
| 413 | [PTR_TO_TCP_SOCK_OR_NULL] = "tcp_sock_or_null", | ||
| 410 | }; | 414 | }; |
| 411 | 415 | ||
| 412 | static char slot_type_char[] = { | 416 | static char slot_type_char[] = { |
| @@ -1209,6 +1213,8 @@ static bool is_spillable_regtype(enum bpf_reg_type type) | |||
| 1209 | case PTR_TO_SOCKET_OR_NULL: | 1213 | case PTR_TO_SOCKET_OR_NULL: |
| 1210 | case PTR_TO_SOCK_COMMON: | 1214 | case PTR_TO_SOCK_COMMON: |
| 1211 | case PTR_TO_SOCK_COMMON_OR_NULL: | 1215 | case PTR_TO_SOCK_COMMON_OR_NULL: |
| 1216 | case PTR_TO_TCP_SOCK: | ||
| 1217 | case PTR_TO_TCP_SOCK_OR_NULL: | ||
| 1212 | return true; | 1218 | return true; |
| 1213 | default: | 1219 | default: |
| 1214 | return false; | 1220 | return false; |
| @@ -1662,6 +1668,9 @@ static int check_sock_access(struct bpf_verifier_env *env, int insn_idx, | |||
| 1662 | case PTR_TO_SOCKET: | 1668 | case PTR_TO_SOCKET: |
| 1663 | valid = bpf_sock_is_valid_access(off, size, t, &info); | 1669 | valid = bpf_sock_is_valid_access(off, size, t, &info); |
| 1664 | break; | 1670 | break; |
| 1671 | case PTR_TO_TCP_SOCK: | ||
| 1672 | valid = bpf_tcp_sock_is_valid_access(off, size, t, &info); | ||
| 1673 | break; | ||
| 1665 | default: | 1674 | default: |
| 1666 | valid = false; | 1675 | valid = false; |
| 1667 | } | 1676 | } |
| @@ -1823,6 +1832,9 @@ static int check_ptr_alignment(struct bpf_verifier_env *env, | |||
| 1823 | case PTR_TO_SOCK_COMMON: | 1832 | case PTR_TO_SOCK_COMMON: |
| 1824 | pointer_desc = "sock_common "; | 1833 | pointer_desc = "sock_common "; |
| 1825 | break; | 1834 | break; |
| 1835 | case PTR_TO_TCP_SOCK: | ||
| 1836 | pointer_desc = "tcp_sock "; | ||
| 1837 | break; | ||
| 1826 | default: | 1838 | default: |
| 1827 | break; | 1839 | break; |
| 1828 | } | 1840 | } |
| @@ -3148,6 +3160,10 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn | |||
| 3148 | /* For mark_ptr_or_null_reg() */ | 3160 | /* For mark_ptr_or_null_reg() */ |
| 3149 | regs[BPF_REG_0].id = ++env->id_gen; | 3161 | regs[BPF_REG_0].id = ++env->id_gen; |
| 3150 | } | 3162 | } |
| 3163 | } else if (fn->ret_type == RET_PTR_TO_TCP_SOCK_OR_NULL) { | ||
| 3164 | mark_reg_known_zero(env, regs, BPF_REG_0); | ||
| 3165 | regs[BPF_REG_0].type = PTR_TO_TCP_SOCK_OR_NULL; | ||
| 3166 | regs[BPF_REG_0].id = ++env->id_gen; | ||
| 3151 | } else { | 3167 | } else { |
| 3152 | verbose(env, "unknown return type %d of func %s#%d\n", | 3168 | verbose(env, "unknown return type %d of func %s#%d\n", |
| 3153 | fn->ret_type, func_id_name(func_id), func_id); | 3169 | fn->ret_type, func_id_name(func_id), func_id); |
| @@ -3409,6 +3425,8 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, | |||
| 3409 | case PTR_TO_SOCKET_OR_NULL: | 3425 | case PTR_TO_SOCKET_OR_NULL: |
| 3410 | case PTR_TO_SOCK_COMMON: | 3426 | case PTR_TO_SOCK_COMMON: |
| 3411 | case PTR_TO_SOCK_COMMON_OR_NULL: | 3427 | case PTR_TO_SOCK_COMMON_OR_NULL: |
| 3428 | case PTR_TO_TCP_SOCK: | ||
| 3429 | case PTR_TO_TCP_SOCK_OR_NULL: | ||
| 3412 | verbose(env, "R%d pointer arithmetic on %s prohibited\n", | 3430 | verbose(env, "R%d pointer arithmetic on %s prohibited\n", |
| 3413 | dst, reg_type_str[ptr_reg->type]); | 3431 | dst, reg_type_str[ptr_reg->type]); |
| 3414 | return -EACCES; | 3432 | return -EACCES; |
| @@ -4644,6 +4662,8 @@ static void mark_ptr_or_null_reg(struct bpf_func_state *state, | |||
| 4644 | reg->type = PTR_TO_SOCKET; | 4662 | reg->type = PTR_TO_SOCKET; |
| 4645 | } else if (reg->type == PTR_TO_SOCK_COMMON_OR_NULL) { | 4663 | } else if (reg->type == PTR_TO_SOCK_COMMON_OR_NULL) { |
| 4646 | reg->type = PTR_TO_SOCK_COMMON; | 4664 | reg->type = PTR_TO_SOCK_COMMON; |
| 4665 | } else if (reg->type == PTR_TO_TCP_SOCK_OR_NULL) { | ||
| 4666 | reg->type = PTR_TO_TCP_SOCK; | ||
| 4647 | } | 4667 | } |
| 4648 | if (is_null || !(reg_is_refcounted(reg) || | 4668 | if (is_null || !(reg_is_refcounted(reg) || |
| 4649 | reg_may_point_to_spin_lock(reg))) { | 4669 | reg_may_point_to_spin_lock(reg))) { |
| @@ -5839,6 +5859,8 @@ static bool regsafe(struct bpf_reg_state *rold, struct bpf_reg_state *rcur, | |||
| 5839 | case PTR_TO_SOCKET_OR_NULL: | 5859 | case PTR_TO_SOCKET_OR_NULL: |
| 5840 | case PTR_TO_SOCK_COMMON: | 5860 | case PTR_TO_SOCK_COMMON: |
| 5841 | case PTR_TO_SOCK_COMMON_OR_NULL: | 5861 | case PTR_TO_SOCK_COMMON_OR_NULL: |
| 5862 | case PTR_TO_TCP_SOCK: | ||
| 5863 | case PTR_TO_TCP_SOCK_OR_NULL: | ||
| 5842 | /* Only valid matches are exact, which memcmp() above | 5864 | /* Only valid matches are exact, which memcmp() above |
| 5843 | * would have accepted | 5865 | * would have accepted |
| 5844 | */ | 5866 | */ |
| @@ -6161,6 +6183,8 @@ static bool reg_type_mismatch_ok(enum bpf_reg_type type) | |||
| 6161 | case PTR_TO_SOCKET_OR_NULL: | 6183 | case PTR_TO_SOCKET_OR_NULL: |
| 6162 | case PTR_TO_SOCK_COMMON: | 6184 | case PTR_TO_SOCK_COMMON: |
| 6163 | case PTR_TO_SOCK_COMMON_OR_NULL: | 6185 | case PTR_TO_SOCK_COMMON_OR_NULL: |
| 6186 | case PTR_TO_TCP_SOCK: | ||
| 6187 | case PTR_TO_TCP_SOCK_OR_NULL: | ||
| 6164 | return false; | 6188 | return false; |
| 6165 | default: | 6189 | default: |
| 6166 | return true; | 6190 | return true; |
| @@ -7166,6 +7190,9 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env) | |||
| 7166 | case PTR_TO_SOCK_COMMON: | 7190 | case PTR_TO_SOCK_COMMON: |
| 7167 | convert_ctx_access = bpf_sock_convert_ctx_access; | 7191 | convert_ctx_access = bpf_sock_convert_ctx_access; |
| 7168 | break; | 7192 | break; |
| 7193 | case PTR_TO_TCP_SOCK: | ||
| 7194 | convert_ctx_access = bpf_tcp_sock_convert_ctx_access; | ||
| 7195 | break; | ||
| 7169 | default: | 7196 | default: |
| 7170 | continue; | 7197 | continue; |
| 7171 | } | 7198 | } |
