aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorMartin KaFai Lau <kafai@fb.com>2019-02-10 02:22:24 -0500
committerAlexei Starovoitov <ast@kernel.org>2019-02-10 22:46:17 -0500
commit655a51e536c09d15ffa3603b1b6fce2b45b85a1f (patch)
treec918f6f95d890735a86370630fd7791f2a5a5360 /kernel
parent9b1f3d6e5af295a72deb5e3f04db07a6a58be72e (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.c31
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)
334static bool type_is_sk_pointer(enum bpf_reg_type type) 334static 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
340static bool reg_type_may_be_null(enum bpf_reg_type type) 341static 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
347static bool type_is_refcounted(enum bpf_reg_type type) 349static 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
412static char slot_type_char[] = { 416static 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 }