Skip to content

Commit a998d43

Browse files
kaffeemonsterdavem330
authored andcommitted
bpf jit: Let the x86 jit handle negative offsets
Now the helper function from filter.c for negative offsets is exported, it can be used it in the jit to handle negative offsets. First modify the asm load helper functions to handle: - know positive offsets - know negative offsets - any offset then the compiler can be modified to explicitly use these helper when appropriate. This fixes the case of a negative X register and allows to lift the restriction that bpf programs with negative offsets can't be jited. Signed-of-by: Jan Seiffert <[email protected]> Signed-off-by: Eric Dumazet <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent f03fb3f commit a998d43

File tree

2 files changed

+115
-48
lines changed

2 files changed

+115
-48
lines changed

arch/x86/net/bpf_jit.S

Lines changed: 91 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,17 @@
1818
* r9d : hlen = skb->len - skb->data_len
1919
*/
2020
#define SKBDATA %r8
21-
22-
sk_load_word_ind:
23-
.globl sk_load_word_ind
24-
25-
add %ebx,%esi /* offset += X */
26-
# test %esi,%esi /* if (offset < 0) goto bpf_error; */
27-
js bpf_error
21+
#define SKF_MAX_NEG_OFF $(-0x200000) /* SKF_LL_OFF from filter.h */
2822

2923
sk_load_word:
3024
.globl sk_load_word
3125

26+
test %esi,%esi
27+
js bpf_slow_path_word_neg
28+
29+
sk_load_word_positive_offset:
30+
.globl sk_load_word_positive_offset
31+
3232
mov %r9d,%eax # hlen
3333
sub %esi,%eax # hlen - offset
3434
cmp $3,%eax
@@ -37,16 +37,15 @@ sk_load_word:
3737
bswap %eax /* ntohl() */
3838
ret
3939

40-
41-
sk_load_half_ind:
42-
.globl sk_load_half_ind
43-
44-
add %ebx,%esi /* offset += X */
45-
js bpf_error
46-
4740
sk_load_half:
4841
.globl sk_load_half
4942

43+
test %esi,%esi
44+
js bpf_slow_path_half_neg
45+
46+
sk_load_half_positive_offset:
47+
.globl sk_load_half_positive_offset
48+
5049
mov %r9d,%eax
5150
sub %esi,%eax # hlen - offset
5251
cmp $1,%eax
@@ -55,14 +54,15 @@ sk_load_half:
5554
rol $8,%ax # ntohs()
5655
ret
5756

58-
sk_load_byte_ind:
59-
.globl sk_load_byte_ind
60-
add %ebx,%esi /* offset += X */
61-
js bpf_error
62-
6357
sk_load_byte:
6458
.globl sk_load_byte
6559

60+
test %esi,%esi
61+
js bpf_slow_path_byte_neg
62+
63+
sk_load_byte_positive_offset:
64+
.globl sk_load_byte_positive_offset
65+
6666
cmp %esi,%r9d /* if (offset >= hlen) goto bpf_slow_path_byte */
6767
jle bpf_slow_path_byte
6868
movzbl (SKBDATA,%rsi),%eax
@@ -73,25 +73,21 @@ sk_load_byte:
7373
*
7474
* Implements BPF_S_LDX_B_MSH : ldxb 4*([offset]&0xf)
7575
* Must preserve A accumulator (%eax)
76-
* Inputs : %esi is the offset value, already known positive
76+
* Inputs : %esi is the offset value
7777
*/
78-
ENTRY(sk_load_byte_msh)
79-
CFI_STARTPROC
78+
sk_load_byte_msh:
79+
.globl sk_load_byte_msh
80+
test %esi,%esi
81+
js bpf_slow_path_byte_msh_neg
82+
83+
sk_load_byte_msh_positive_offset:
84+
.globl sk_load_byte_msh_positive_offset
8085
cmp %esi,%r9d /* if (offset >= hlen) goto bpf_slow_path_byte_msh */
8186
jle bpf_slow_path_byte_msh
8287
movzbl (SKBDATA,%rsi),%ebx
8388
and $15,%bl
8489
shl $2,%bl
8590
ret
86-
CFI_ENDPROC
87-
ENDPROC(sk_load_byte_msh)
88-
89-
bpf_error:
90-
# force a return 0 from jit handler
91-
xor %eax,%eax
92-
mov -8(%rbp),%rbx
93-
leaveq
94-
ret
9591

9692
/* rsi contains offset and can be scratched */
9793
#define bpf_slow_path_common(LEN) \
@@ -138,3 +134,67 @@ bpf_slow_path_byte_msh:
138134
shl $2,%al
139135
xchg %eax,%ebx
140136
ret
137+
138+
#define sk_negative_common(SIZE) \
139+
push %rdi; /* save skb */ \
140+
push %r9; \
141+
push SKBDATA; \
142+
/* rsi already has offset */ \
143+
mov $SIZE,%ecx; /* size */ \
144+
call bpf_internal_load_pointer_neg_helper; \
145+
test %rax,%rax; \
146+
pop SKBDATA; \
147+
pop %r9; \
148+
pop %rdi; \
149+
jz bpf_error
150+
151+
152+
bpf_slow_path_word_neg:
153+
cmp SKF_MAX_NEG_OFF, %esi /* test range */
154+
jl bpf_error /* offset lower -> error */
155+
sk_load_word_negative_offset:
156+
.globl sk_load_word_negative_offset
157+
sk_negative_common(4)
158+
mov (%rax), %eax
159+
bswap %eax
160+
ret
161+
162+
bpf_slow_path_half_neg:
163+
cmp SKF_MAX_NEG_OFF, %esi
164+
jl bpf_error
165+
sk_load_half_negative_offset:
166+
.globl sk_load_half_negative_offset
167+
sk_negative_common(2)
168+
mov (%rax),%ax
169+
rol $8,%ax
170+
movzwl %ax,%eax
171+
ret
172+
173+
bpf_slow_path_byte_neg:
174+
cmp SKF_MAX_NEG_OFF, %esi
175+
jl bpf_error
176+
sk_load_byte_negative_offset:
177+
.globl sk_load_byte_negative_offset
178+
sk_negative_common(1)
179+
movzbl (%rax), %eax
180+
ret
181+
182+
bpf_slow_path_byte_msh_neg:
183+
cmp SKF_MAX_NEG_OFF, %esi
184+
jl bpf_error
185+
sk_load_byte_msh_negative_offset:
186+
.globl sk_load_byte_msh_negative_offset
187+
xchg %eax,%ebx /* dont lose A , X is about to be scratched */
188+
sk_negative_common(1)
189+
movzbl (%rax),%eax
190+
and $15,%al
191+
shl $2,%al
192+
xchg %eax,%ebx
193+
ret
194+
195+
bpf_error:
196+
# force a return 0 from jit handler
197+
xor %eax,%eax
198+
mov -8(%rbp),%rbx
199+
leaveq
200+
ret

arch/x86/net/bpf_jit_comp.c

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ int bpf_jit_enable __read_mostly;
3030
* assembly code in arch/x86/net/bpf_jit.S
3131
*/
3232
extern u8 sk_load_word[], sk_load_half[], sk_load_byte[], sk_load_byte_msh[];
33-
extern u8 sk_load_word_ind[], sk_load_half_ind[], sk_load_byte_ind[];
33+
extern u8 sk_load_word_positive_offset[], sk_load_half_positive_offset[];
34+
extern u8 sk_load_byte_positive_offset[], sk_load_byte_msh_positive_offset[];
35+
extern u8 sk_load_word_negative_offset[], sk_load_half_negative_offset[];
36+
extern u8 sk_load_byte_negative_offset[], sk_load_byte_msh_negative_offset[];
3437

3538
static inline u8 *emit_code(u8 *ptr, u32 bytes, unsigned int len)
3639
{
@@ -117,6 +120,8 @@ static inline void bpf_flush_icache(void *start, void *end)
117120
set_fs(old_fs);
118121
}
119122

123+
#define CHOOSE_LOAD_FUNC(K, func) \
124+
((int)K < 0 ? ((int)K >= SKF_LL_OFF ? func##_negative_offset : func) : func##_positive_offset)
120125

121126
void bpf_jit_compile(struct sk_filter *fp)
122127
{
@@ -473,44 +478,46 @@ void bpf_jit_compile(struct sk_filter *fp)
473478
#endif
474479
break;
475480
case BPF_S_LD_W_ABS:
476-
func = sk_load_word;
481+
func = CHOOSE_LOAD_FUNC(K, sk_load_word);
477482
common_load: seen |= SEEN_DATAREF;
478-
if ((int)K < 0) {
479-
/* Abort the JIT because __load_pointer() is needed. */
480-
goto out;
481-
}
482483
t_offset = func - (image + addrs[i]);
483484
EMIT1_off32(0xbe, K); /* mov imm32,%esi */
484485
EMIT1_off32(0xe8, t_offset); /* call */
485486
break;
486487
case BPF_S_LD_H_ABS:
487-
func = sk_load_half;
488+
func = CHOOSE_LOAD_FUNC(K, sk_load_half);
488489
goto common_load;
489490
case BPF_S_LD_B_ABS:
490-
func = sk_load_byte;
491+
func = CHOOSE_LOAD_FUNC(K, sk_load_byte);
491492
goto common_load;
492493
case BPF_S_LDX_B_MSH:
493-
if ((int)K < 0) {
494-
/* Abort the JIT because __load_pointer() is needed. */
495-
goto out;
496-
}
494+
func = CHOOSE_LOAD_FUNC(K, sk_load_byte_msh);
497495
seen |= SEEN_DATAREF | SEEN_XREG;
498-
t_offset = sk_load_byte_msh - (image + addrs[i]);
496+
t_offset = func - (image + addrs[i]);
499497
EMIT1_off32(0xbe, K); /* mov imm32,%esi */
500498
EMIT1_off32(0xe8, t_offset); /* call sk_load_byte_msh */
501499
break;
502500
case BPF_S_LD_W_IND:
503-
func = sk_load_word_ind;
501+
func = sk_load_word;
504502
common_load_ind: seen |= SEEN_DATAREF | SEEN_XREG;
505503
t_offset = func - (image + addrs[i]);
506-
EMIT1_off32(0xbe, K); /* mov imm32,%esi */
504+
if (K) {
505+
if (is_imm8(K)) {
506+
EMIT3(0x8d, 0x73, K); /* lea imm8(%rbx), %esi */
507+
} else {
508+
EMIT2(0x8d, 0xb3); /* lea imm32(%rbx),%esi */
509+
EMIT(K, 4);
510+
}
511+
} else {
512+
EMIT2(0x89,0xde); /* mov %ebx,%esi */
513+
}
507514
EMIT1_off32(0xe8, t_offset); /* call sk_load_xxx_ind */
508515
break;
509516
case BPF_S_LD_H_IND:
510-
func = sk_load_half_ind;
517+
func = sk_load_half;
511518
goto common_load_ind;
512519
case BPF_S_LD_B_IND:
513-
func = sk_load_byte_ind;
520+
func = sk_load_byte;
514521
goto common_load_ind;
515522
case BPF_S_JMP_JA:
516523
t_offset = addrs[i + K] - addrs[i];

0 commit comments

Comments
 (0)