History

Merge tag 'bpf-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf

Pull BPF fixes from Daniel Borkmann: - Fix BPF verifier to preserve full pointer state for commuted scalar += pointer arithmetic (Yiyang Chen, Eduard Zingerman) - Fix a use-after-free of request sockets in the BPF TCP iterator batching (Jose Fernandez) - Fix a use-after-free of sk_redir in the BPF sockmap send verdict path (Chengfeng Ye) - Fix a netns reference imbalance in the BPF conntrack kfuncs (Chengfeng Ye) - Fix bpf_get_fsverity_digest() dynptr assumptions and silent digest truncation (Eric Biggers) - Fix bpf_tcp_{gen,check}_syncookie to check sk_state before sk_protocol to make sure it is a full socket (Luxiao Xu) - Fix rqspinlock to reset the tail when preserving the queue on deadlock (Kumar Kartikeya Dwivedi) * tag 'bpf-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf: rqspinlock: Reset tail when preserving queue on deadlock bpf: Check sk_state before sk_protocol in bpf_tcp_*_syncookie fsverity: Fix silent truncation in bpf_get_fsverity_digest() fsverity: Fix bpf_get_fsverity_digest() dynptr assumptions bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch() bpf: Fix netns reference imbalance in conntrack kfuncs bpf, sockmap: Fix sk_redir use-after-free in send verdict selftests/bpf: Cover commuted pointer state propagation bpf: Propagate untrusted pointer state in commuted arithmetic bpf: Preserve pointer state for commuted arithmetic bpf: Simplify sanitize_err() signature

Linus Torvalds committed 3 months ago

Commit a13307e2 parents 0150da6 7a3c02810 files · +198 −76Browse files

Unified · Split

10 files
  1. fs/verity/measure.c +9 −6
  2. kernel/bpf/rqspinlock.c +3 −2
  3. kernel/bpf/verifier.c +22 −23
  4. net/core/filter.c +2 −2
  5. net/ipv4/tcp_bpf.c +2 −0
  6. net/ipv4/tcp_ipv4.c +24 −19
  7. net/netfilter/nf_conntrack_bpf.c +48 −24
  8. tools/testing/selftests/bpf/progs/dynptr_fail.c +30 −0
  9. tools/testing/selftests/bpf/progs/mem_rdonly_untrusted.c +17 −0
  10. tools/testing/selftests/bpf/progs/verifier_basic_stack.c +41 −0
fs/verity/measure.c+9−6
@@ -122,11 +122,11 @@ __bpf_kfunc int bpf_get_fsverity_digest(struct file *file, const struct bpf_dynp · 121 unmodified lines
122{122{
123 const struct bpf_dynptr_kern *digest_ptr = (struct bpf_dynptr_kern *)digest_p;123 const struct bpf_dynptr_kern *digest_ptr = (struct bpf_dynptr_kern *)digest_p;
124 const struct inode *inode = file_inode(file);124 const struct inode *inode = file_inode(file);
125 u32 dynptr_sz = __bpf_dynptr_size(digest_ptr);125 u64 dynptr_sz = __bpf_dynptr_size(digest_ptr);
126 struct fsverity_digest *arg;126 struct fsverity_digest *arg;
127 const struct fsverity_info *vi;127 const struct fsverity_info *vi;
128 const struct fsverity_hash_alg *hash_alg;128 const struct fsverity_hash_alg *hash_alg;
129 int out_digest_sz;129 u64 out_digest_sz;
130 130
131 if (dynptr_sz < sizeof(struct fsverity_digest))131 if (dynptr_sz < sizeof(struct fsverity_digest))
132 return -EINVAL;132 return -EINVAL;
@@ -144,17 +144,20 @@ __bpf_kfunc int bpf_get_fsverity_digest(struct file *file, const struct bpf_dynp · 11 unmodified lines
144 144
145 hash_alg = vi->tree_params.hash_alg;145 hash_alg = vi->tree_params.hash_alg;
146 146
147 out_digest_sz = dynptr_sz - sizeof(struct fsverity_digest);
148 if (out_digest_sz < hash_alg->digest_size)
149 return -EOVERFLOW;
150
147 arg->digest_algorithm = hash_alg - fsverity_hash_algs;151 arg->digest_algorithm = hash_alg - fsverity_hash_algs;
148 arg->digest_size = hash_alg->digest_size;152 arg->digest_size = hash_alg->digest_size;
149 153
150 out_digest_sz = dynptr_sz - sizeof(struct fsverity_digest);
151
152 /* copy digest */154 /* copy digest */
153 memcpy(arg->digest, vi->file_digest, min_t(int, hash_alg->digest_size, out_digest_sz));155 memcpy(arg->digest, vi->file_digest, hash_alg->digest_size);
154 156
155 /* fill the extra buffer with zeros */157 /* fill the extra buffer with zeros */
156 if (out_digest_sz > hash_alg->digest_size)158 if (out_digest_sz > hash_alg->digest_size)
157 memset(arg->digest + arg->digest_size, 0, out_digest_sz - hash_alg->digest_size);159 memset(arg->digest + hash_alg->digest_size, 0,
160 out_digest_sz - hash_alg->digest_size);
158 161
159 return 0;162 return 0;
160}163}
kernel/bpf/rqspinlock.c+3−2
@@ -572,9 +572,10 @@ queue: · 571 unmodified lines
572 572
573 /* Disable queue destruction when we detect deadlocks. */573 /* Disable queue destruction when we detect deadlocks. */
574 if (ret == -EDEADLK) {574 if (ret == -EDEADLK) {
575 if (!next)575 if (!try_cmpxchg_tail(lock, tail, 0)) {
576 next = smp_cond_load_relaxed(&node->next, (VAL));576 next = smp_cond_load_relaxed(&node->next, (VAL));
577 arch_mcs_spin_unlock_contended(&next->locked);577 arch_mcs_spin_unlock_contended(&next->locked);
578 }
578 goto err_release_node;579 goto err_release_node;
579 }580 }
580 581
kernel/bpf/verifier.c+22−23
@@ -13557,23 +13557,21 @@ static void sanitize_mark_insn_seen(struct bpf_verifier_env *env) · 13556 unmodified lines
13557 env->insn_aux_data[env->insn_idx].seen = env->pass_cnt;13557 env->insn_aux_data[env->insn_idx].seen = env->pass_cnt;
13558}13558}
13559 13559
13560static int sanitize_err(struct bpf_verifier_env *env,13560static int sanitize_err(struct bpf_verifier_env *env, const struct bpf_insn *insn, int reason)
13561 const struct bpf_insn *insn, int reason,
13562 const struct bpf_reg_state *off_reg,
13563 const struct bpf_reg_state *dst_reg)
13564{13561{
13565 static const char *err = "pointer arithmetic with it prohibited for !root";13562 static const char *err = "pointer arithmetic with it prohibited for !root";
13566 const char *op = BPF_OP(insn->code) == BPF_ADD ? "add" : "sub";13563 const char *op = BPF_OP(insn->code) == BPF_ADD ? "add" : "sub";
13567 u32 dst = insn->dst_reg, src = insn->src_reg;13564 u32 dst = insn->dst_reg, src = insn->src_reg;
13565 struct bpf_reg_state *regs = cur_regs(env);
13568 13566
13569 switch (reason) {13567 switch (reason) {
13570 case REASON_BOUNDS:13568 case REASON_BOUNDS:
13571 verbose(env, "R%d has unknown scalar with mixed signed bounds, %s\n",13569 verbose(env, "R%d has unknown scalar with mixed signed bounds, %s\n",
13572 off_reg == dst_reg ? dst : src, err);13570 regs[src].type == SCALAR_VALUE ? src : dst, err);
13573 break;13571 break;
13574 case REASON_TYPE:13572 case REASON_TYPE:
13575 verbose(env, "R%d has pointer with unsupported alu operation, %s\n",13573 verbose(env, "R%d has pointer with unsupported alu operation, %s\n",
13576 off_reg == dst_reg ? src : dst, err);13574 regs[src].type == SCALAR_VALUE ? dst : src, err);
13577 break;13575 break;
13578 case REASON_PATHS:13576 case REASON_PATHS:
13579 verbose(env, "R%d tried to %s from different maps, paths or scalars, %s\n",13577 verbose(env, "R%d tried to %s from different maps, paths or scalars, %s\n",
@@ -13709,13 +13707,6 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, · 129 unmodified lines
13709 return -EACCES;13707 return -EACCES;
13710 }13708 }
13711 13709
13712 /*
13713 * Accesses to untrusted PTR_TO_MEM are done through probe
13714 * instructions, hence no need to track offsets.
13715 */
13716 if (base_type(ptr_reg->type) == PTR_TO_MEM && (ptr_reg->type & PTR_UNTRUSTED))
13717 return 0;
13718
13719 switch (base_type(ptr_reg->type)) {13710 switch (base_type(ptr_reg->type)) {
13720 case PTR_TO_CTX:13711 case PTR_TO_CTX:
13721 case PTR_TO_MAP_VALUE:13712 case PTR_TO_MAP_VALUE:
@@ -13745,11 +13736,19 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, · 23 unmodified lines
13745 return -EACCES;13736 return -EACCES;
13746 }13737 }
13747 13738
13748 /* In case of 'scalar += pointer', dst_reg inherits pointer type and id.13739 /* For 'scalar += pointer', dst_reg inherits the complete pointer
13749 * The id may be overwritten later if we create a new variable offset.13740 * register state. Individual fields may be adjusted later by pointer
13741 * arithmetic. Callers guarantee that below does not overwrite off_reg.
13750 */13742 */
13751 dst_reg->type = ptr_reg->type;13743 if (dst_reg != ptr_reg)
13752 dst_reg->id = ptr_reg->id;13744 *dst_reg = *ptr_reg;
13745
13746 /*
13747 * Accesses to untrusted PTR_TO_MEM are done through probe
13748 * instructions, hence no need to track offsets.
13749 */
13750 if (base_type(ptr_reg->type) == PTR_TO_MEM && (ptr_reg->type & PTR_UNTRUSTED))
13751 return 0;
13753 13752
13754 if (!check_reg_sane_offset_scalar(env, off_reg, ptr_reg->type) ||13753 if (!check_reg_sane_offset_scalar(env, off_reg, ptr_reg->type) ||
13755 !check_reg_sane_offset_ptr(env, ptr_reg, ptr_reg->type))13754 !check_reg_sane_offset_ptr(env, ptr_reg, ptr_reg->type))
@@ -13762,7 +13761,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, · 6 unmodified lines
13762 ret = sanitize_ptr_alu(env, insn, ptr_reg, off_reg, dst_reg,13761 ret = sanitize_ptr_alu(env, insn, ptr_reg, off_reg, dst_reg,
13763 &info, false);13762 &info, false);
13764 if (ret < 0)13763 if (ret < 0)
13765 return sanitize_err(env, insn, ret, off_reg, dst_reg);13764 return sanitize_err(env, insn, ret);
13766 }13765 }
13767 13766
13768 switch (opcode) {13767 switch (opcode) {
@@ -13792,7 +13791,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, · 23 unmodified lines
13792 }13791 }
13793 break;13792 break;
13794 case BPF_SUB:13793 case BPF_SUB:
13795 if (dst_reg == off_reg) {13794 if (dst_reg != ptr_reg) {
13796 /* scalar -= pointer. Creates an unknown scalar */13795 /* scalar -= pointer. Creates an unknown scalar */
13797 verbose(env, "R%d tried to subtract pointer from scalar\n",13796 verbose(env, "R%d tried to subtract pointer from scalar\n",
13798 dst);13797 dst);
@@ -13855,7 +13854,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, · 56 unmodified lines
13855 return -EFAULT;13854 return -EFAULT;
13856 }13855 }
13857 if (ret < 0)13856 if (ret < 0)
13858 return sanitize_err(env, insn, ret, off_reg, dst_reg);13857 return sanitize_err(env, insn, ret);
13859 }13858 }
13860 13859
13861 return 0;13860 return 0;
@@ -14607,7 +14606,7 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env, · 745 unmodified lines
14607 if (sanitize_needed(opcode)) {14606 if (sanitize_needed(opcode)) {
14608 ret = sanitize_val_alu(env, insn);14607 ret = sanitize_val_alu(env, insn);
14609 if (ret < 0)14608 if (ret < 0)
14610 return sanitize_err(env, insn, ret, NULL, NULL);14609 return sanitize_err(env, insn, ret);
14611 }14610 }
14612 14611
14613 /* Calculate sign/unsigned bounds and tnum for alu32 and alu64 bit ops.14612 /* Calculate sign/unsigned bounds and tnum for alu32 and alu64 bit ops.
@@ -14810,8 +14809,8 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env, · 196 unmodified lines
14810 err = mark_chain_precision(env, insn->dst_reg);14809 err = mark_chain_precision(env, insn->dst_reg);
14811 if (err)14810 if (err)
14812 return err;14811 return err;
14813 return adjust_ptr_min_max_vals(env, insn,14812 off_reg = *dst_reg;
14814 src_reg, dst_reg);14813 return adjust_ptr_min_max_vals(env, insn, src_reg, &off_reg);
14815 }14814 }
14816 } else if (ptr_reg) {14815 } else if (ptr_reg) {
14817 /* pointer += scalar */14816 /* pointer += scalar */
net/core/filter.c+2−2
@@ -7684,7 +7684,7 @@ BPF_CALL_5(bpf_tcp_check_syncookie, struct sock *, sk, void *, iph, u32, iph_len · 7683 unmodified lines
7684 return -EINVAL;7684 return -EINVAL;
7685 7685
7686 /* sk_listener() allows TCP_NEW_SYN_RECV, which makes no sense here. */7686 /* sk_listener() allows TCP_NEW_SYN_RECV, which makes no sense here. */
7687 if (sk->sk_protocol != IPPROTO_TCP || sk->sk_state != TCP_LISTEN)7687 if (sk->sk_state != TCP_LISTEN || sk->sk_protocol != IPPROTO_TCP)
7688 return -EINVAL;7688 return -EINVAL;
7689 7689
7690 if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_syncookies))7690 if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_syncookies))
@@ -7757,7 +7757,7 @@ BPF_CALL_5(bpf_tcp_gen_syncookie, struct sock *, sk, void *, iph, u32, iph_len, · 66 unmodified lines
7757 if (unlikely(!sk || th_len < sizeof(*th) || th_len != th->doff * 4))7757 if (unlikely(!sk || th_len < sizeof(*th) || th_len != th->doff * 4))
7758 return -EINVAL;7758 return -EINVAL;
7759 7759
7760 if (sk->sk_protocol != IPPROTO_TCP || sk->sk_state != TCP_LISTEN)7760 if (sk->sk_state != TCP_LISTEN || sk->sk_protocol != IPPROTO_TCP)
7761 return -EINVAL;7761 return -EINVAL;
7762 7762
7763 if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_syncookies))7763 if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_syncookies))
net/ipv4/tcp_bpf.c+2−0
@@ -469,6 +469,7 @@ more_data: · 468 unmodified lines
469 case __SK_REDIRECT:469 case __SK_REDIRECT:
470 redir_ingress = psock->redir_ingress;470 redir_ingress = psock->redir_ingress;
471 sk_redir = psock->sk_redir;471 sk_redir = psock->sk_redir;
472 sock_hold(sk_redir);
472 sk_msg_apply_bytes(psock, tosend);473 sk_msg_apply_bytes(psock, tosend);
473 if (!psock->apply_bytes) {474 if (!psock->apply_bytes) {
474 /* Clean up before releasing the sock lock. */475 /* Clean up before releasing the sock lock. */
@@ -489,6 +490,7 @@ more_data: · 14 unmodified lines
489 490
490 if (eval == __SK_REDIRECT)491 if (eval == __SK_REDIRECT)
491 sock_put(sk_redir);492 sock_put(sk_redir);
493 sock_put(sk_redir);
492 494
493 lock_sock(sk);495 lock_sock(sk);
494 sk_mem_uncharge(sk, sent);496 sk_mem_uncharge(sk, sent);
net/ipv4/tcp_ipv4.c+24−19
@@ -3078,24 +3078,24 @@ static unsigned int bpf_iter_tcp_established_batch(struct seq_file *seq, · 3077 unmodified lines
3078{3078{
3079 struct bpf_tcp_iter_state *iter = seq->private;3079 struct bpf_tcp_iter_state *iter = seq->private;
3080 struct hlist_nulls_node *node;3080 struct hlist_nulls_node *node;
3081 unsigned int expected = 1;3081 struct sock *sk = *start_sk;
3082 struct sock *sk;3082 unsigned int expected = 0;
3083
3084 sock_hold(*start_sk);
3085 iter->batch[iter->end_sk++].sk = *start_sk;
3086 3083
3087 sk = sk_nulls_next(*start_sk);
3088 *start_sk = NULL;3084 *start_sk = NULL;
3089 sk_nulls_for_each_from(sk, node) {3085 sk_nulls_for_each_from(sk, node) {
3090 if (seq_sk_match(seq, sk)) {3086 if (!seq_sk_match(seq, sk))
3091 if (iter->end_sk < iter->max_sk) {3087 continue;
3092 sock_hold(sk);3088 expected++;
3093 iter->batch[iter->end_sk++].sk = sk;3089 if (iter->end_sk < iter->max_sk) {
3094 } else if (!*start_sk) {3090 /* reqsk_queue_hash_req() inserts with sk_refcnt == 0
3095 /* Remember where we left off. */3091 * and refcount_set()s it after the bucket lock drops.
3096 *start_sk = sk;3092 */
3097 }3093 if (unlikely(!refcount_inc_not_zero(&sk->sk_refcnt)))
3098 expected++;3094 continue;
3095 iter->batch[iter->end_sk++].sk = sk;
3096 } else if (!*start_sk) {
3097 /* Remember where we left off. */
3098 *start_sk = sk;
3099 }3099 }
3100 }3100 }
3101 3101
@@ -3133,12 +3133,13 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq) · 31 unmodified lines
3133 struct sock *sk;3133 struct sock *sk;
3134 int err;3134 int err;
3135 3135
3136again:
3136 sk = bpf_iter_tcp_resume(seq);3137 sk = bpf_iter_tcp_resume(seq);
3137 if (!sk)3138 if (!sk)
3138 return NULL; /* Done */3139 return NULL; /* Done */
3139 3140
3140 expected = bpf_iter_fill_batch(seq, &sk);3141 expected = bpf_iter_fill_batch(seq, &sk);
3141 if (likely(iter->end_sk == expected))3142 if (likely(!sk))
3142 goto done;3143 goto done;
3143 3144
3144 /* Batch size was too small. */3145 /* Batch size was too small. */
@@ -3157,7 +3158,7 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq) · 12 unmodified lines
3157 return NULL; /* Done */3158 return NULL; /* Done */
3158 3159
3159 expected = bpf_iter_fill_batch(seq, &sk);3160 expected = bpf_iter_fill_batch(seq, &sk);
3160 if (likely(iter->end_sk == expected))3161 if (likely(!sk))
3161 goto done;3162 goto done;
3162 3163
3163 /* Batch size was still too small. Hold onto the lock while we try3164 /* Batch size was still too small. Hold onto the lock while we try
@@ -3170,10 +3171,14 @@ static struct sock *bpf_iter_tcp_batch(struct seq_file *seq) · 6 unmodified lines
3170 return ERR_PTR(err);3171 return ERR_PTR(err);
3171 }3172 }
3172 3173
3173 expected = bpf_iter_fill_batch(seq, &sk);3174 bpf_iter_fill_batch(seq, &sk);
3174 WARN_ON_ONCE(iter->end_sk != expected);3175 WARN_ON_ONCE(sk);
3175done:3176done:
3176 bpf_iter_tcp_unlock_bucket(seq);3177 bpf_iter_tcp_unlock_bucket(seq);
3178 if (unlikely(!iter->end_sk)) {
3179 ++iter->state.bucket;
3180 goto again;
3181 }
3177 return iter->batch[0].sk;3182 return iter->batch[0].sk;
3178}3183}
3179 3184
net/netfilter/nf_conntrack_bpf.c+48−24
@@ -122,42 +122,54 @@ __bpf_nf_ct_alloc_entry(struct net *net, struct bpf_sock_tuple *bpf_tuple, · 121 unmodified lines
122 struct nf_conntrack_tuple otuple, rtuple;122 struct nf_conntrack_tuple otuple, rtuple;
123 struct nf_conntrack_zone ct_zone;123 struct nf_conntrack_zone ct_zone;
124 struct nf_conn *ct;124 struct nf_conn *ct;
125 u8 ct_zone_dir = 0;
126 u16 ct_zone_id;
127 s32 netns_id;
128 u8 l4proto;
125 int err;129 int err;
126 130
127 if (!(opts_len == NF_BPF_CT_OPTS_SZ || opts_len == 12))131 if (!(opts_len == NF_BPF_CT_OPTS_SZ || opts_len == 12))
128 return ERR_PTR(-EINVAL);132 return ERR_PTR(-EINVAL);
133
134 netns_id = READ_ONCE(opts->netns_id);
135 l4proto = READ_ONCE(opts->l4proto);
136 ct_zone_id = READ_ONCE(opts->ct_zone_id);
129 if (opts_len == NF_BPF_CT_OPTS_SZ) {137 if (opts_len == NF_BPF_CT_OPTS_SZ) {
130 if (opts->reserved[0] || opts->reserved[1] || opts->reserved[2])138 ct_zone_dir = READ_ONCE(opts->ct_zone_dir);
139 if (READ_ONCE(opts->reserved[0]) ||
140 READ_ONCE(opts->reserved[1]) ||
141 READ_ONCE(opts->reserved[2]))
131 return ERR_PTR(-EINVAL);142 return ERR_PTR(-EINVAL);
132 } else {143 } else {
133 if (opts->ct_zone_id)144 if (ct_zone_id)
134 return ERR_PTR(-EINVAL);145 return ERR_PTR(-EINVAL);
135 }146 }
136 147
137 if (unlikely(opts->netns_id < BPF_F_CURRENT_NETNS))148 if (unlikely(netns_id < BPF_F_CURRENT_NETNS))
138 return ERR_PTR(-EINVAL);149 return ERR_PTR(-EINVAL);
139 150
140 err = bpf_nf_ct_tuple_parse(bpf_tuple, tuple_len, opts->l4proto,151 err = bpf_nf_ct_tuple_parse(bpf_tuple, tuple_len, l4proto,
141 IP_CT_DIR_ORIGINAL, &otuple);152 IP_CT_DIR_ORIGINAL, &otuple);
142 if (err < 0)153 if (err < 0)
143 return ERR_PTR(err);154 return ERR_PTR(err);
144 155
145 err = bpf_nf_ct_tuple_parse(bpf_tuple, tuple_len, opts->l4proto,156 err = bpf_nf_ct_tuple_parse(bpf_tuple, tuple_len, l4proto,
146 IP_CT_DIR_REPLY, &rtuple);157 IP_CT_DIR_REPLY, &rtuple);
147 if (err < 0)158 if (err < 0)
148 return ERR_PTR(err);159 return ERR_PTR(err);
149 160
150 if (opts->netns_id >= 0) {161 if (netns_id >= 0) {
151 net = get_net_ns_by_id(net, opts->netns_id);162 net = get_net_ns_by_id(net, netns_id);
152 if (unlikely(!net))163 if (unlikely(!net))
153 return ERR_PTR(-ENONET);164 return ERR_PTR(-ENONET);
154 }165 }
155 166
156 if (opts_len == NF_BPF_CT_OPTS_SZ) {167 if (opts_len == NF_BPF_CT_OPTS_SZ) {
157 if (opts->ct_zone_dir == 0)168 if (ct_zone_dir == 0) {
158 opts->ct_zone_dir = NF_CT_DEFAULT_ZONE_DIR;169 ct_zone_dir = NF_CT_DEFAULT_ZONE_DIR;
159 nf_ct_zone_init(&ct_zone,170 opts->ct_zone_dir = ct_zone_dir;
160 opts->ct_zone_id, opts->ct_zone_dir, 0);171 }
172 nf_ct_zone_init(&ct_zone, ct_zone_id, ct_zone_dir, 0);
161 } else {173 } else {
162 ct_zone = nf_ct_zone_dflt;174 ct_zone = nf_ct_zone_dflt;
163 }175 }
@@ -171,7 +183,7 @@ __bpf_nf_ct_alloc_entry(struct net *net, struct bpf_sock_tuple *bpf_tuple, · 7 unmodified lines
171 __nf_ct_set_timeout(ct, timeout * HZ);183 __nf_ct_set_timeout(ct, timeout * HZ);
172 184
173out:185out:
174 if (opts->netns_id >= 0)186 if (netns_id >= 0)
175 put_net(net);187 put_net(net);
176 188
177 return ct;189 return ct;
@@ -186,46 +198,58 @@ static struct nf_conn *__bpf_nf_ct_lookup(struct net *net, · 8 unmodified lines
186 struct nf_conntrack_tuple tuple;198 struct nf_conntrack_tuple tuple;
187 struct nf_conntrack_zone ct_zone;199 struct nf_conntrack_zone ct_zone;
188 struct nf_conn *ct;200 struct nf_conn *ct;
201 u8 ct_zone_dir = 0;
202 u16 ct_zone_id;
203 s32 netns_id;
204 u8 l4proto;
189 int err;205 int err;
190 206
191 if (!opts || !bpf_tuple)207 if (!opts || !bpf_tuple)
192 return ERR_PTR(-EINVAL);208 return ERR_PTR(-EINVAL);
193 if (!(opts_len == NF_BPF_CT_OPTS_SZ || opts_len == 12))209 if (!(opts_len == NF_BPF_CT_OPTS_SZ || opts_len == 12))
194 return ERR_PTR(-EINVAL);210 return ERR_PTR(-EINVAL);
211
212 netns_id = READ_ONCE(opts->netns_id);
213 l4proto = READ_ONCE(opts->l4proto);
214 ct_zone_id = READ_ONCE(opts->ct_zone_id);
195 if (opts_len == NF_BPF_CT_OPTS_SZ) {215 if (opts_len == NF_BPF_CT_OPTS_SZ) {
196 if (opts->reserved[0] || opts->reserved[1] || opts->reserved[2])216 ct_zone_dir = READ_ONCE(opts->ct_zone_dir);
217 if (READ_ONCE(opts->reserved[0]) ||
218 READ_ONCE(opts->reserved[1]) ||
219 READ_ONCE(opts->reserved[2]))
197 return ERR_PTR(-EINVAL);220 return ERR_PTR(-EINVAL);
198 } else {221 } else {
199 if (opts->ct_zone_id)222 if (ct_zone_id)
200 return ERR_PTR(-EINVAL);223 return ERR_PTR(-EINVAL);
201 }224 }
202 if (unlikely(opts->l4proto != IPPROTO_TCP && opts->l4proto != IPPROTO_UDP))225 if (unlikely(l4proto != IPPROTO_TCP && l4proto != IPPROTO_UDP))
203 return ERR_PTR(-EPROTO);226 return ERR_PTR(-EPROTO);
204 if (unlikely(opts->netns_id < BPF_F_CURRENT_NETNS))227 if (unlikely(netns_id < BPF_F_CURRENT_NETNS))
205 return ERR_PTR(-EINVAL);228 return ERR_PTR(-EINVAL);
206 229
207 err = bpf_nf_ct_tuple_parse(bpf_tuple, tuple_len, opts->l4proto,230 err = bpf_nf_ct_tuple_parse(bpf_tuple, tuple_len, l4proto,
208 IP_CT_DIR_ORIGINAL, &tuple);231 IP_CT_DIR_ORIGINAL, &tuple);
209 if (err < 0)232 if (err < 0)
210 return ERR_PTR(err);233 return ERR_PTR(err);
211 234
212 if (opts->netns_id >= 0) {235 if (netns_id >= 0) {
213 net = get_net_ns_by_id(net, opts->netns_id);236 net = get_net_ns_by_id(net, netns_id);
214 if (unlikely(!net))237 if (unlikely(!net))
215 return ERR_PTR(-ENONET);238 return ERR_PTR(-ENONET);
216 }239 }
217 240
218 if (opts_len == NF_BPF_CT_OPTS_SZ) {241 if (opts_len == NF_BPF_CT_OPTS_SZ) {
219 if (opts->ct_zone_dir == 0)242 if (ct_zone_dir == 0) {
220 opts->ct_zone_dir = NF_CT_DEFAULT_ZONE_DIR;243 ct_zone_dir = NF_CT_DEFAULT_ZONE_DIR;
221 nf_ct_zone_init(&ct_zone,244 opts->ct_zone_dir = ct_zone_dir;
222 opts->ct_zone_id, opts->ct_zone_dir, 0);245 }
246 nf_ct_zone_init(&ct_zone, ct_zone_id, ct_zone_dir, 0);
223 } else {247 } else {
224 ct_zone = nf_ct_zone_dflt;248 ct_zone = nf_ct_zone_dflt;
225 }249 }
226 250
227 hash = nf_conntrack_find_get(net, &ct_zone, &tuple);251 hash = nf_conntrack_find_get(net, &ct_zone, &tuple);
228 if (opts->netns_id >= 0)252 if (netns_id >= 0)
229 put_net(net);253 put_net(net);
230 if (!hash)254 if (!hash)
231 return ERR_PTR(-ENOENT);255 return ERR_PTR(-ENOENT);
tools/testing/selftests/bpf/progs/dynptr_fail.c+30−0
@@ -1635,6 +1635,36 @@ static int callback(__u32 index, void *data) · 1634 unmodified lines
1635 return 0;1635 return 0;
1636}1636}
1637 1637
1638/* A commuted add should preserve the parent id of a dynptr data slice. */
1639SEC("?raw_tp")
1640__failure __msg("invalid mem access 'scalar'")
1641int dynptr_slice_commuted_invalidate(void *ctx)
1642{
1643 struct bpf_dynptr ptr;
1644 __u32 *slice, *derived;
1645
1646 bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(__u32), 0, &ptr);
1647
1648 slice = bpf_dynptr_data(&ptr, 0, sizeof(__u32));
1649 if (!slice)
1650 goto done;
1651
1652 asm volatile ("%[dst] = 0;"
1653 "%[dst] += %[src];"
1654 "%[src] = 0;"
1655 : [dst]"=&r"(derived), [src]"+r"(slice)
1656 :
1657 : "memory");
1658
1659 bpf_ringbuf_discard_dynptr(&ptr, 0);
1660 val = *derived;
1661 return 0;
1662
1663done:
1664 bpf_ringbuf_discard_dynptr(&ptr, 0);
1665 return 0;
1666}
1667
1638/* If the dynptr is written into in a callback function, its data1668/* If the dynptr is written into in a callback function, its data
1639 * slices should be invalidated as well.1669 * slices should be invalidated as well.
1640 */1670 */
tools/testing/selftests/bpf/progs/mem_rdonly_untrusted.c+17−0
@@ -226,4 +226,21 @@ int null_check(void *ctx) · 225 unmodified lines
226 return 0;226 return 0;
227}227}
228 228
229SEC("socket")
230__success
231__retval(1)
232int ldx_is_ok_commuted_addr(void *ctx)
233{
234 int v, *p, *derived;
235
236 v = 1;
237 p = bpf_rdonly_cast(&v, 0);
238 asm volatile ("%[dst] = 0;"
239 "%[dst] += %[src];"
240 : [dst]"=&r"(derived)
241 : [src]"r"(p)
242 : "memory");
243 return *derived;
244}
245
229char _license[] SEC("license") = "GPL";246char _license[] SEC("license") = "GPL";
tools/testing/selftests/bpf/progs/verifier_basic_stack.c+41−0
@@ -97,4 +97,45 @@ __naked void misaligned_read_from_stack(void) · 96 unmodified lines
97" ::: __clobber_all);97" ::: __clobber_all);
98}98}
99 99
100SEC("socket")
101__description("stack pointer arithmetic preserves frame number")
102__failure __msg("R7 invalid mem access 'scalar'")
103__naked void stack_ptr_arith_preserves_frameno(void)
104{
105 asm volatile ("\
106 r3 = 0; \
107 *(u64 *)(r10 - 8) = r3; \
108 r1 = %[map_hash_8b] ll; \
109 r2 = r10; \
110 r2 += -8; \
111 call %[bpf_map_lookup_elem]; \
112 if r0 != 0 goto +2; \
113 r0 = 0; \
114 exit; \
115 r1 = r0; \
116 r2 = 0; \
117 r3 = 0; \
118 call stack_ptr_arith_preserves_frameno_subprog;\
119 r0 = 0; \
120 exit; \
121 ":
122 : __imm(bpf_map_lookup_elem),
123 __imm_addr(map_hash_8b)
124 : __clobber_all);
125}
126
127static __used __naked void stack_ptr_arith_preserves_frameno_subprog(void)
128{
129 asm volatile ("\
130 *(u64 *)(r10 - 8) = r1; \
131 r6 = -8; \
132 r6 += r10; \
133 *(u64 *)(r6 + 0) = r2; \
134 r7 = *(u64 *)(r10 - 8); \
135 *(u64 *)(r7 + 0) = r3; \
136 r0 = 0; \
137 exit; \
138 "::: __clobber_all);
139}
140
100char _license[] SEC("license") = "GPL";141char _license[] SEC("license") = "GPL";