diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/core/filter.c | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/net/core/filter.c b/net/core/filter.c index b39c869d22e3..1f6a26c4f8b9 100644 --- a/net/core/filter.c +++ b/net/core/filter.c | |||
@@ -3110,6 +3110,36 @@ void bpf_warn_invalid_xdp_action(u32 act) | |||
3110 | } | 3110 | } |
3111 | EXPORT_SYMBOL_GPL(bpf_warn_invalid_xdp_action); | 3111 | EXPORT_SYMBOL_GPL(bpf_warn_invalid_xdp_action); |
3112 | 3112 | ||
3113 | static bool __is_valid_sock_ops_access(int off, int size) | ||
3114 | { | ||
3115 | if (off < 0 || off >= sizeof(struct bpf_sock_ops)) | ||
3116 | return false; | ||
3117 | /* The verifier guarantees that size > 0. */ | ||
3118 | if (off % size != 0) | ||
3119 | return false; | ||
3120 | if (size != sizeof(__u32)) | ||
3121 | return false; | ||
3122 | |||
3123 | return true; | ||
3124 | } | ||
3125 | |||
3126 | static bool sock_ops_is_valid_access(int off, int size, | ||
3127 | enum bpf_access_type type, | ||
3128 | struct bpf_insn_access_aux *info) | ||
3129 | { | ||
3130 | if (type == BPF_WRITE) { | ||
3131 | switch (off) { | ||
3132 | case offsetof(struct bpf_sock_ops, op) ... | ||
3133 | offsetof(struct bpf_sock_ops, replylong[3]): | ||
3134 | break; | ||
3135 | default: | ||
3136 | return false; | ||
3137 | } | ||
3138 | } | ||
3139 | |||
3140 | return __is_valid_sock_ops_access(off, size); | ||
3141 | } | ||
3142 | |||
3113 | static u32 bpf_convert_ctx_access(enum bpf_access_type type, | 3143 | static u32 bpf_convert_ctx_access(enum bpf_access_type type, |
3114 | const struct bpf_insn *si, | 3144 | const struct bpf_insn *si, |
3115 | struct bpf_insn *insn_buf, | 3145 | struct bpf_insn *insn_buf, |
@@ -3379,6 +3409,138 @@ static u32 xdp_convert_ctx_access(enum bpf_access_type type, | |||
3379 | return insn - insn_buf; | 3409 | return insn - insn_buf; |
3380 | } | 3410 | } |
3381 | 3411 | ||
3412 | static u32 sock_ops_convert_ctx_access(enum bpf_access_type type, | ||
3413 | const struct bpf_insn *si, | ||
3414 | struct bpf_insn *insn_buf, | ||
3415 | struct bpf_prog *prog) | ||
3416 | { | ||
3417 | struct bpf_insn *insn = insn_buf; | ||
3418 | int off; | ||
3419 | |||
3420 | switch (si->off) { | ||
3421 | case offsetof(struct bpf_sock_ops, op) ... | ||
3422 | offsetof(struct bpf_sock_ops, replylong[3]): | ||
3423 | BUILD_BUG_ON(FIELD_SIZEOF(struct bpf_sock_ops, op) != | ||
3424 | FIELD_SIZEOF(struct bpf_sock_ops_kern, op)); | ||
3425 | BUILD_BUG_ON(FIELD_SIZEOF(struct bpf_sock_ops, reply) != | ||
3426 | FIELD_SIZEOF(struct bpf_sock_ops_kern, reply)); | ||
3427 | BUILD_BUG_ON(FIELD_SIZEOF(struct bpf_sock_ops, replylong) != | ||
3428 | FIELD_SIZEOF(struct bpf_sock_ops_kern, replylong)); | ||
3429 | off = si->off; | ||
3430 | off -= offsetof(struct bpf_sock_ops, op); | ||
3431 | off += offsetof(struct bpf_sock_ops_kern, op); | ||
3432 | if (type == BPF_WRITE) | ||
3433 | *insn++ = BPF_STX_MEM(BPF_W, si->dst_reg, si->src_reg, | ||
3434 | off); | ||
3435 | else | ||
3436 | *insn++ = BPF_LDX_MEM(BPF_W, si->dst_reg, si->src_reg, | ||
3437 | off); | ||
3438 | break; | ||
3439 | |||
3440 | case offsetof(struct bpf_sock_ops, family): | ||
3441 | BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common, skc_family) != 2); | ||
3442 | |||
3443 | *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF( | ||
3444 | struct bpf_sock_ops_kern, sk), | ||
3445 | si->dst_reg, si->src_reg, | ||
3446 | offsetof(struct bpf_sock_ops_kern, sk)); | ||
3447 | *insn++ = BPF_LDX_MEM(BPF_H, si->dst_reg, si->dst_reg, | ||
3448 | offsetof(struct sock_common, skc_family)); | ||
3449 | break; | ||
3450 | |||
3451 | case offsetof(struct bpf_sock_ops, remote_ip4): | ||
3452 | BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common, skc_daddr) != 4); | ||
3453 | |||
3454 | *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF( | ||
3455 | struct bpf_sock_ops_kern, sk), | ||
3456 | si->dst_reg, si->src_reg, | ||
3457 | offsetof(struct bpf_sock_ops_kern, sk)); | ||
3458 | *insn++ = BPF_LDX_MEM(BPF_W, si->dst_reg, si->dst_reg, | ||
3459 | offsetof(struct sock_common, skc_daddr)); | ||
3460 | break; | ||
3461 | |||
3462 | case offsetof(struct bpf_sock_ops, local_ip4): | ||
3463 | BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common, skc_rcv_saddr) != 4); | ||
3464 | |||
3465 | *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF( | ||
3466 | struct bpf_sock_ops_kern, sk), | ||
3467 | si->dst_reg, si->src_reg, | ||
3468 | offsetof(struct bpf_sock_ops_kern, sk)); | ||
3469 | *insn++ = BPF_LDX_MEM(BPF_W, si->dst_reg, si->dst_reg, | ||
3470 | offsetof(struct sock_common, | ||
3471 | skc_rcv_saddr)); | ||
3472 | break; | ||
3473 | |||
3474 | case offsetof(struct bpf_sock_ops, remote_ip6[0]) ... | ||
3475 | offsetof(struct bpf_sock_ops, remote_ip6[3]): | ||
3476 | #if IS_ENABLED(CONFIG_IPV6) | ||
3477 | BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common, | ||
3478 | skc_v6_daddr.s6_addr32[0]) != 4); | ||
3479 | |||
3480 | off = si->off; | ||
3481 | off -= offsetof(struct bpf_sock_ops, remote_ip6[0]); | ||
3482 | *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF( | ||
3483 | struct bpf_sock_ops_kern, sk), | ||
3484 | si->dst_reg, si->src_reg, | ||
3485 | offsetof(struct bpf_sock_ops_kern, sk)); | ||
3486 | *insn++ = BPF_LDX_MEM(BPF_W, si->dst_reg, si->dst_reg, | ||
3487 | offsetof(struct sock_common, | ||
3488 | skc_v6_daddr.s6_addr32[0]) + | ||
3489 | off); | ||
3490 | #else | ||
3491 | *insn++ = BPF_MOV32_IMM(si->dst_reg, 0); | ||
3492 | #endif | ||
3493 | break; | ||
3494 | |||
3495 | case offsetof(struct bpf_sock_ops, local_ip6[0]) ... | ||
3496 | offsetof(struct bpf_sock_ops, local_ip6[3]): | ||
3497 | #if IS_ENABLED(CONFIG_IPV6) | ||
3498 | BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common, | ||
3499 | skc_v6_rcv_saddr.s6_addr32[0]) != 4); | ||
3500 | |||
3501 | off = si->off; | ||
3502 | off -= offsetof(struct bpf_sock_ops, local_ip6[0]); | ||
3503 | *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF( | ||
3504 | struct bpf_sock_ops_kern, sk), | ||
3505 | si->dst_reg, si->src_reg, | ||
3506 | offsetof(struct bpf_sock_ops_kern, sk)); | ||
3507 | *insn++ = BPF_LDX_MEM(BPF_W, si->dst_reg, si->dst_reg, | ||
3508 | offsetof(struct sock_common, | ||
3509 | skc_v6_rcv_saddr.s6_addr32[0]) + | ||
3510 | off); | ||
3511 | #else | ||
3512 | *insn++ = BPF_MOV32_IMM(si->dst_reg, 0); | ||
3513 | #endif | ||
3514 | break; | ||
3515 | |||
3516 | case offsetof(struct bpf_sock_ops, remote_port): | ||
3517 | BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common, skc_dport) != 2); | ||
3518 | |||
3519 | *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF( | ||
3520 | struct bpf_sock_ops_kern, sk), | ||
3521 | si->dst_reg, si->src_reg, | ||
3522 | offsetof(struct bpf_sock_ops_kern, sk)); | ||
3523 | *insn++ = BPF_LDX_MEM(BPF_H, si->dst_reg, si->dst_reg, | ||
3524 | offsetof(struct sock_common, skc_dport)); | ||
3525 | #ifndef __BIG_ENDIAN_BITFIELD | ||
3526 | *insn++ = BPF_ALU32_IMM(BPF_LSH, si->dst_reg, 16); | ||
3527 | #endif | ||
3528 | break; | ||
3529 | |||
3530 | case offsetof(struct bpf_sock_ops, local_port): | ||
3531 | BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common, skc_num) != 2); | ||
3532 | |||
3533 | *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF( | ||
3534 | struct bpf_sock_ops_kern, sk), | ||
3535 | si->dst_reg, si->src_reg, | ||
3536 | offsetof(struct bpf_sock_ops_kern, sk)); | ||
3537 | *insn++ = BPF_LDX_MEM(BPF_H, si->dst_reg, si->dst_reg, | ||
3538 | offsetof(struct sock_common, skc_num)); | ||
3539 | break; | ||
3540 | } | ||
3541 | return insn - insn_buf; | ||
3542 | } | ||
3543 | |||
3382 | const struct bpf_verifier_ops sk_filter_prog_ops = { | 3544 | const struct bpf_verifier_ops sk_filter_prog_ops = { |
3383 | .get_func_proto = sk_filter_func_proto, | 3545 | .get_func_proto = sk_filter_func_proto, |
3384 | .is_valid_access = sk_filter_is_valid_access, | 3546 | .is_valid_access = sk_filter_is_valid_access, |
@@ -3428,6 +3590,12 @@ const struct bpf_verifier_ops cg_sock_prog_ops = { | |||
3428 | .convert_ctx_access = sock_filter_convert_ctx_access, | 3590 | .convert_ctx_access = sock_filter_convert_ctx_access, |
3429 | }; | 3591 | }; |
3430 | 3592 | ||
3593 | const struct bpf_verifier_ops sock_ops_prog_ops = { | ||
3594 | .get_func_proto = bpf_base_func_proto, | ||
3595 | .is_valid_access = sock_ops_is_valid_access, | ||
3596 | .convert_ctx_access = sock_ops_convert_ctx_access, | ||
3597 | }; | ||
3598 | |||
3431 | int sk_detach_filter(struct sock *sk) | 3599 | int sk_detach_filter(struct sock *sk) |
3432 | { | 3600 | { |
3433 | int ret = -ENOENT; | 3601 | int ret = -ENOENT; |