Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b2c4618

Browse files
joamakiborkmann
authored andcommitted
bpf, sockmap: sk_skb data_end access incorrect when src_reg = dst_reg
The current conversion of skb->data_end reads like this: ; data_end = (void*)(long)skb->data_end; 559: (79) r1 = *(u64 *)(r2 +200) ; r1 = skb->data 560: (61) r11 = *(u32 *)(r2 +112) ; r11 = skb->len 561: (0f) r1 += r11 562: (61) r11 = *(u32 *)(r2 +116) 563: (1f) r1 -= r11 But similar to the case in 84f44df ("bpf: sock_ops sk access may stomp registers when dst_reg = src_reg"), the code will read an incorrect skb->len when src == dst. In this case we end up generating this xlated code: ; data_end = (void*)(long)skb->data_end; 559: (79) r1 = *(u64 *)(r1 +200) ; r1 = skb->data 560: (61) r11 = *(u32 *)(r1 +112) ; r11 = (skb->data)->len 561: (0f) r1 += r11 562: (61) r11 = *(u32 *)(r1 +116) 563: (1f) r1 -= r11 ... where line 560 is the reading 4B of (skb->data + 112) instead of the intended skb->len Here the skb pointer in r1 gets set to skb->data and the later deref for skb->len ends up following skb->data instead of skb. This fixes the issue similarly to the patch mentioned above by creating an additional temporary variable and using to store the register when dst_reg = src_reg. We name the variable bpf_temp_reg and place it in the cb context for sk_skb. Then we restore from the temp to ensure nothing is lost. Fixes: 16137b0 ("bpf: Compute data_end dynamically with JIT code") Signed-off-by: Jussi Maki <[email protected]> Signed-off-by: John Fastabend <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]> Reviewed-by: Jakub Sitnicki <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent e0dc3b9 commit b2c4618

File tree

2 files changed

+34
-6
lines changed

2 files changed

+34
-6
lines changed

include/net/strparser.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ struct sk_skb_cb {
6666
#define SK_SKB_CB_PRIV_LEN 20
6767
unsigned char data[SK_SKB_CB_PRIV_LEN];
6868
struct _strp_msg strp;
69+
/* temp_reg is a temporary register used for bpf_convert_data_end_access
70+
* when dst_reg == src_reg.
71+
*/
72+
u64 temp_reg;
6973
};
7074

7175
static inline struct strp_msg *strp_msg(struct sk_buff *skb)

net/core/filter.c

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9756,22 +9756,46 @@ static u32 sock_ops_convert_ctx_access(enum bpf_access_type type,
97569756
static struct bpf_insn *bpf_convert_data_end_access(const struct bpf_insn *si,
97579757
struct bpf_insn *insn)
97589758
{
9759-
/* si->dst_reg = skb->data */
9759+
int reg;
9760+
int temp_reg_off = offsetof(struct sk_buff, cb) +
9761+
offsetof(struct sk_skb_cb, temp_reg);
9762+
9763+
if (si->src_reg == si->dst_reg) {
9764+
/* We need an extra register, choose and save a register. */
9765+
reg = BPF_REG_9;
9766+
if (si->src_reg == reg || si->dst_reg == reg)
9767+
reg--;
9768+
if (si->src_reg == reg || si->dst_reg == reg)
9769+
reg--;
9770+
*insn++ = BPF_STX_MEM(BPF_DW, si->src_reg, reg, temp_reg_off);
9771+
} else {
9772+
reg = si->dst_reg;
9773+
}
9774+
9775+
/* reg = skb->data */
97609776
*insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, data),
9761-
si->dst_reg, si->src_reg,
9777+
reg, si->src_reg,
97629778
offsetof(struct sk_buff, data));
97639779
/* AX = skb->len */
97649780
*insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, len),
97659781
BPF_REG_AX, si->src_reg,
97669782
offsetof(struct sk_buff, len));
9767-
/* si->dst_reg = skb->data + skb->len */
9768-
*insn++ = BPF_ALU64_REG(BPF_ADD, si->dst_reg, BPF_REG_AX);
9783+
/* reg = skb->data + skb->len */
9784+
*insn++ = BPF_ALU64_REG(BPF_ADD, reg, BPF_REG_AX);
97699785
/* AX = skb->data_len */
97709786
*insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, data_len),
97719787
BPF_REG_AX, si->src_reg,
97729788
offsetof(struct sk_buff, data_len));
9773-
/* si->dst_reg = skb->data + skb->len - skb->data_len */
9774-
*insn++ = BPF_ALU64_REG(BPF_SUB, si->dst_reg, BPF_REG_AX);
9789+
9790+
/* reg = skb->data + skb->len - skb->data_len */
9791+
*insn++ = BPF_ALU64_REG(BPF_SUB, reg, BPF_REG_AX);
9792+
9793+
if (si->src_reg == si->dst_reg) {
9794+
/* Restore the saved register */
9795+
*insn++ = BPF_MOV64_REG(BPF_REG_AX, si->src_reg);
9796+
*insn++ = BPF_MOV64_REG(si->dst_reg, reg);
9797+
*insn++ = BPF_LDX_MEM(BPF_DW, reg, BPF_REG_AX, temp_reg_off);
9798+
}
97759799

97769800
return insn;
97779801
}

0 commit comments

Comments
 (0)