Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion drivers/net/ethernet/broadcom/bnxt/bnxt.c
Original file line number Diff line number Diff line change
Expand Up @@ -1440,8 +1440,8 @@ static struct sk_buff *bnxt_copy_xdp(struct bnxt_napi *bnapi,
return skb;

if (metasize) {
skb_metadata_set(skb, metasize);
__skb_pull(skb, metasize);
skb_metadata_set(skb, metasize);
}

return skb;
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/ethernet/intel/i40e/i40e_xsk.c
Original file line number Diff line number Diff line change
Expand Up @@ -310,8 +310,8 @@ static struct sk_buff *i40e_construct_skb_zc(struct i40e_ring *rx_ring,
ALIGN(totalsize, sizeof(long)));

if (metasize) {
skb_metadata_set(skb, metasize);
__skb_pull(skb, metasize);
skb_metadata_set(skb, metasize);
}

if (likely(!xdp_buff_has_frags(xdp)))
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/ethernet/intel/igb/igb_xsk.c
Original file line number Diff line number Diff line change
Expand Up @@ -284,8 +284,8 @@ static struct sk_buff *igb_construct_skb_zc(struct igb_ring *rx_ring,
ALIGN(totalsize, sizeof(long)));

if (metasize) {
skb_metadata_set(skb, metasize);
__skb_pull(skb, metasize);
skb_metadata_set(skb, metasize);
}

return skb;
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/ethernet/intel/igc/igc_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -2024,8 +2024,8 @@ static struct sk_buff *igc_construct_skb(struct igc_ring *rx_ring,
ALIGN(headlen + metasize, sizeof(long)));

if (metasize) {
skb_metadata_set(skb, metasize);
__skb_pull(skb, metasize);
skb_metadata_set(skb, metasize);
}

/* update all of the pointers */
Expand Down Expand Up @@ -2752,8 +2752,8 @@ static struct sk_buff *igc_construct_skb_zc(struct igc_ring *ring,
ALIGN(totalsize, sizeof(long)));

if (metasize) {
skb_metadata_set(skb, metasize);
__skb_pull(skb, metasize);
skb_metadata_set(skb, metasize);
}

if (ctx->rx_ts) {
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,8 @@ static struct sk_buff *ixgbe_construct_skb_zc(struct ixgbe_ring *rx_ring,
ALIGN(totalsize, sizeof(long)));

if (metasize) {
skb_metadata_set(skb, metasize);
__skb_pull(skb, metasize);
skb_metadata_set(skb, metasize);
}

return skb;
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.c
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,8 @@ static struct sk_buff *mlx5e_xsk_construct_skb(struct mlx5e_rq *rq, struct xdp_b
skb_put_data(skb, xdp->data_meta, totallen);

if (metalen) {
skb_metadata_set(skb, metalen);
__skb_pull(skb, metalen);
skb_metadata_set(skb, metalen);
}

return skb;
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/veth.c
Original file line number Diff line number Diff line change
Expand Up @@ -876,11 +876,11 @@ static struct sk_buff *veth_xdp_rcv_skb(struct veth_rq *rq,
else
skb->data_len = 0;

skb->protocol = eth_type_trans(skb, rq->dev);

metalen = xdp->data - xdp->data_meta;
if (metalen)
skb_metadata_set(skb, metalen);

skb->protocol = eth_type_trans(skb, rq->dev);
out:
return skb;
drop:
Expand Down
2 changes: 1 addition & 1 deletion include/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -1076,7 +1076,7 @@ struct bpf_verifier_ops {
bool (*is_valid_access)(int off, int size, enum bpf_access_type type,
const struct bpf_prog *prog,
struct bpf_insn_access_aux *info);
int (*gen_prologue)(struct bpf_insn *insn, bool direct_write,
int (*gen_prologue)(struct bpf_insn *insn, u32 pkt_access_flags,
const struct bpf_prog *prog);
int (*gen_epilogue)(struct bpf_insn *insn, const struct bpf_prog *prog,
s16 ctx_stack_off);
Expand Down
7 changes: 6 additions & 1 deletion include/linux/bpf_verifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,11 @@ enum priv_stack_mode {
PRIV_STACK_ADAPTIVE,
};

enum packet_access_flags {
PA_F_DIRECT_WRITE = BIT(0),
PA_F_DATA_META_LOAD = BIT(1),
};

struct bpf_subprog_info {
/* 'start' has to be the first field otherwise find_subprog() won't work */
u32 start; /* insn idx of function entry point */
Expand Down Expand Up @@ -760,7 +765,7 @@ struct bpf_verifier_env {
bool bpf_capable;
bool bypass_spec_v1;
bool bypass_spec_v4;
bool seen_direct_write;
u8 seen_packet_access; /* combination of enum packet_access_flags */
bool seen_exception;
struct bpf_insn_aux_data *insn_aux_data; /* array of per-insn state */
const struct bpf_line_info *prev_linfo;
Expand Down
37 changes: 28 additions & 9 deletions include/linux/skbuff.h
Original file line number Diff line number Diff line change
Expand Up @@ -595,15 +595,16 @@ struct skb_shared_info {
__u8 meta_len;
__u8 nr_frags;
__u8 tx_flags;
u16 meta_end;
unsigned short gso_size;
/* Warning: this field is not always filled in (UFO)! */
unsigned short gso_segs;
unsigned int gso_type;
struct sk_buff *frag_list;
union {
struct skb_shared_hwtstamps hwtstamps;
struct xsk_tx_metadata_compl xsk_meta;
};
unsigned int gso_type;
u32 tskey;

/*
Expand Down Expand Up @@ -4499,7 +4500,7 @@ static inline u8 skb_metadata_len(const struct sk_buff *skb)

static inline void *skb_metadata_end(const struct sk_buff *skb)
{
return skb_mac_header(skb);
return skb->head + skb_shinfo(skb)->meta_end;
}

static inline bool __skb_metadata_differs(const struct sk_buff *skb_a,
Expand Down Expand Up @@ -4554,8 +4555,16 @@ static inline bool skb_metadata_differs(const struct sk_buff *skb_a,
true : __skb_metadata_differs(skb_a, skb_b, len_a);
}

/**
* skb_metadata_set - Record packet metadata length and location.
* @skb: packet carrying the metadata
* @meta_len: number of bytes of metadata preceding skb->data
*
* Must be called when skb->data already points past the metadata area.
*/
static inline void skb_metadata_set(struct sk_buff *skb, u8 meta_len)
{
skb_shinfo(skb)->meta_end = skb_headroom(skb);
skb_shinfo(skb)->meta_len = meta_len;
}

Expand Down Expand Up @@ -4591,18 +4600,28 @@ static inline void skb_data_move(struct sk_buff *skb, const int len,
if (!meta_len)
goto no_metadata;

meta_end = skb_metadata_end(skb);
meta = meta_end - meta_len;

if (WARN_ON_ONCE(meta_end + len != skb->data ||
meta_len > skb_headroom(skb))) {
/* Not enough headroom left for metadata. Drop it. */
if (WARN_ONCE(meta_len > skb_headroom(skb),
"skb headroom smaller than metadata")) {
skb_metadata_clear(skb);
goto no_metadata;
}

memmove(meta + len, meta, meta_len + n);
return;
meta_end = skb_metadata_end(skb);
meta = meta_end - meta_len;

/* Metadata in front of data before push/pull. Keep it that way. */
if (meta_end == skb->data - len) {
memmove(meta + len, meta, meta_len + n);
skb_shinfo(skb)->meta_end += len;
return;
}

if (len < 0) {
/* Data pushed. Move metadata to the top. */
memmove(skb->head, meta, meta_len);
skb_shinfo(skb)->meta_end = meta_len;
}
no_metadata:
memmove(skb->data, skb->data - len, n);
}
Expand Down
2 changes: 1 addition & 1 deletion kernel/bpf/cgroup.c
Original file line number Diff line number Diff line change
Expand Up @@ -2694,7 +2694,7 @@ static u32 cg_sockopt_convert_ctx_access(enum bpf_access_type type,
}

static int cg_sockopt_get_prologue(struct bpf_insn *insn_buf,
bool direct_write,
u32 pkt_access_flags,
const struct bpf_prog *prog)
{
/* Nothing to do for sockopt argument. The data is kzalloc'ated.
Expand Down
42 changes: 18 additions & 24 deletions kernel/bpf/verifier.c
Original file line number Diff line number Diff line change
Expand Up @@ -6085,13 +6085,9 @@ static bool may_access_direct_pkt_data(struct bpf_verifier_env *env,
if (meta)
return meta->pkt_access;

env->seen_direct_write = true;
return true;

case BPF_PROG_TYPE_CGROUP_SOCKOPT:
if (t == BPF_WRITE)
env->seen_direct_write = true;

return true;

default:
Expand Down Expand Up @@ -6164,6 +6160,10 @@ static int check_ctx_access(struct bpf_verifier_env *env, int insn_idx, int off,
} else {
env->insn_aux_data[insn_idx].ctx_field_size = info->ctx_field_size;
}

if (base_type(info->reg_type) == PTR_TO_PACKET_META)
env->seen_packet_access |= PA_F_DATA_META_LOAD;

/* remember the offset of last byte accessed in ctx */
if (env->prog->aux->max_ctx_offset < off + size)
env->prog->aux->max_ctx_offset = off + size;
Expand Down Expand Up @@ -7619,15 +7619,17 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
err = check_stack_write(env, regno, off, size,
value_regno, insn_idx);
} else if (reg_is_pkt_pointer(reg)) {
if (t == BPF_WRITE && !may_access_direct_pkt_data(env, NULL, t)) {
verbose(env, "cannot write into packet\n");
return -EACCES;
}
if (t == BPF_WRITE && value_regno >= 0 &&
is_pointer_value(env, value_regno)) {
verbose(env, "R%d leaks addr into packet\n",
value_regno);
return -EACCES;
if (t == BPF_WRITE) {
if (!may_access_direct_pkt_data(env, NULL, BPF_WRITE)) {
verbose(env, "cannot write into packet\n");
return -EACCES;
}
if (value_regno >= 0 && is_pointer_value(env, value_regno)) {
verbose(env, "R%d leaks addr into packet\n",
value_regno);
return -EACCES;
}
env->seen_packet_access |= PA_F_DIRECT_WRITE;
}
err = check_packet_access(env, regno, off, size, false);
if (!err && t == BPF_READ && value_regno >= 0)
Expand Down Expand Up @@ -13766,11 +13768,11 @@ static int check_special_kfunc(struct bpf_verifier_env *env, struct bpf_kfunc_ca
if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_slice]) {
regs[BPF_REG_0].type |= MEM_RDONLY;
} else {
/* this will set env->seen_direct_write to true */
if (!may_access_direct_pkt_data(env, NULL, BPF_WRITE)) {
verbose(env, "the prog does not allow writes to packet data\n");
return -EINVAL;
}
env->seen_packet_access |= PA_F_DIRECT_WRITE;
}

if (!meta->initialized_dynptr.id) {
Expand Down Expand Up @@ -21229,13 +21231,12 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
}
}

if (ops->gen_prologue || env->seen_direct_write) {
if (ops->gen_prologue || (env->seen_packet_access & PA_F_DIRECT_WRITE)) {
if (!ops->gen_prologue) {
verifier_bug(env, "gen_prologue is null");
return -EFAULT;
}
cnt = ops->gen_prologue(insn_buf, env->seen_direct_write,
env->prog);
cnt = ops->gen_prologue(insn_buf, env->seen_packet_access, env->prog);
if (cnt >= INSN_BUF_SIZE) {
verifier_bug(env, "prologue is too long");
return -EFAULT;
Expand Down Expand Up @@ -21810,7 +21811,6 @@ static void specialize_kfunc(struct bpf_verifier_env *env,
u32 func_id, u16 offset, unsigned long *addr)
{
struct bpf_prog *prog = env->prog;
bool seen_direct_write;
void *xdp_kfunc;
bool is_rdonly;

Expand All @@ -21827,16 +21827,10 @@ static void specialize_kfunc(struct bpf_verifier_env *env,
return;

if (func_id == special_kfunc_list[KF_bpf_dynptr_from_skb]) {
seen_direct_write = env->seen_direct_write;
is_rdonly = !may_access_direct_pkt_data(env, NULL, BPF_WRITE);

if (is_rdonly)
*addr = (unsigned long)bpf_dynptr_from_skb_rdonly;

/* restore env->seen_direct_write to its original value, since
* may_access_direct_pkt_data mutates it
*/
env->seen_direct_write = seen_direct_write;
}

if (func_id == special_kfunc_list[KF_bpf_set_dentry_xattr] &&
Expand Down
5 changes: 4 additions & 1 deletion net/core/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -5461,8 +5461,11 @@ u32 bpf_prog_run_generic_xdp(struct sk_buff *skb, struct xdp_buff *xdp,
break;
case XDP_PASS:
metalen = xdp->data - xdp->data_meta;
if (metalen)
if (metalen) {
__skb_push(skb, mac_len);
skb_metadata_set(skb, metalen);
__skb_pull(skb, mac_len);
}
break;
}

Expand Down
Loading
Loading