Topics

Array brace-enclosed initialization


Federico Parola <fede.parola@...>
 

Hello everybody,
in my XDP eBPF program I'm trying to initialize an array with a brace-enclosed list, however my code is rejected by the verifier.
Here is a simple piece of code to replicate the problem:

#include <linux/bpf.h>

#ifndef __section
# define __section(NAME)                  \
   __attribute__((section(NAME), used))
#endif

#ifndef BPF_FUNC
# define BPF_FUNC(NAME, ...)              \
   (*NAME)(__VA_ARGS__) = (void *)BPF_FUNC_##NAME
#endif

#ifndef printk
# define printk(fmt, ...)                                      \
    ({                                                         \
        char ____fmt[] = fmt;                                  \
        trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__); \
    })
#endif

static void BPF_FUNC(trace_printk, const char *fmt, int fmt_size, ...);

__section("prog")
int xdp_prog(struct xdp_md *ctx) {
  int i;
  int array[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

#pragma nounroll
  for (i = 0; i < 10; i++) {
    printk("%d", array[i]);
  }

  return XDP_PASS;
}

char __license[] __section("license") = "GPL"
This is the error reported by the verifier:
0: (b7) r6 = 0
1: (b7) r7 = 25637
2: (b7) r8 = 0
3: (73) *(u8 *)(r10 -2) = r6
last_idx 3 first_idx 0
regs=40 stack=0 before 2: (b7) r8 = 0
regs=40 stack=0 before 1: (b7) r7 = 25637
regs=40 stack=0 before 0: (b7) r6 = 0
4: (6b) *(u16 *)(r10 -4) = r7
5: (18) r1 = 0x0
7: (0f) r1 += r8
8: (61) r3 = *(u32 *)(r1 +0)
R1 invalid mem access 'inv'
processed 8 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
I tried compiling with clang-6 and clang-9 with optimizaton set to O1 and O2, but I get this error in all cases.
If I initialize the array in another way (e.g. with a loop) the program works correctly.
The eBPF bytecode generated by clang is the following:
	.text
	.file	"test.c"
	.section	prog,"ax",@progbits
	.globl	xdp_prog                # -- Begin function xdp_prog
	.p2align	3
	.type	xdp_prog,@function
xdp_prog:                               # @xdp_prog
# %bb.0:
	r6 = 0
	r7 = 25637
	r8 = 0
LBB0_1:                                 # =>This Inner Loop Header: Depth=1
	*(u8 *)(r10 - 2) = r6
	*(u16 *)(r10 - 4) = r7
	r1 = .L__const.xdp_prog.array ll
	r1 += r8
	r3 = *(u32 *)(r1 + 0)
	r1 = r10
	r1 += -4
	r2 = 3
	call 6
	r8 += 4
	if r8 != 24 goto LBB0_1
# %bb.2:
	r0 = 2
	exit
.Lfunc_end0:
	.size	xdp_prog, .Lfunc_end0-xdp_prog
                                        # -- End function
	.type	.L__const.xdp_prog.array,@object # @__const.xdp_prog.array
	.section	.rodata,"a",@progbits
	.p2align	2
.L__const.xdp_prog.array:
	.long	0                       # 0x0
	.long	1                       # 0x1
	.long	2                       # 0x2
	.long	3                       # 0x3
	.long	4                       # 0x4
	.long	5                       # 0x5
	.long	6                       # 0x6
	.long	7                       # 0x7
	.long	8                       # 0x8
	.long	9                       # 0x9
	.size	.L__const.xdp_prog.array, 40

	.type	.L__const.xdp_prog.____fmt,@object # @__const.xdp_prog.____fmt
	.section	.rodata.str1.1,"aMS",@progbits,1
.L__const.xdp_prog.____fmt:
	.asciz	"%d"
	.size	.L__const.xdp_prog.____fmt, 3

	.type	__license,@object       # @__license
	.section	license,"aw",@progbits
	.globl	__license
__license:
	.asciz	"GPL"
	.size	__license, 4


	.addrsig
	.addrsig_sym xdp_prog
	.addrsig_sym __license
It seems like the array in the stack is not initialized in the code. With some declarations the code works, for example decalring the array in the following way:
int array[10] = {0, 1, 2, 3};
everything works, the generated bytecode is the following:
	.text
	.file	"test.c"
	.section	prog,"ax",@progbits
	.globl	xdp_prog                # -- Begin function xdp_prog
	.p2align	3
	.type	xdp_prog,@function
xdp_prog:                               # @xdp_prog
# %bb.0:
	r1 = 2
	*(u32 *)(r10 - 36) = r1
	r6 = 0
	*(u32 *)(r10 - 8) = r6
	*(u32 *)(r10 - 12) = r6
	*(u32 *)(r10 - 16) = r6
	*(u32 *)(r10 - 20) = r6
	*(u32 *)(r10 - 24) = r6
	*(u32 *)(r10 - 28) = r6
	*(u32 *)(r10 - 4) = r6
	r1 = 3
	*(u32 *)(r10 - 32) = r1
	r1 = 1
	*(u32 *)(r10 - 40) = r1
	*(u8 *)(r10 - 42) = r6
	r7 = 25637
	*(u16 *)(r10 - 44) = r7
	r1 = r10
	r1 += -44
	r2 = 3
	r3 = 1
	call 6
	r8 = 4
LBB0_1:                                 # =>This Inner Loop Header: Depth=1
	r1 = r10
	r1 += -40
	r1 += r8
	r3 = *(u32 *)(r1 + 0)
	*(u8 *)(r10 - 42) = r6
	*(u16 *)(r10 - 44) = r7
	r1 = r10
	r1 += -44
	r2 = 3
	call 6
	r8 += 4
	if r8 != 24 goto LBB0_1
# %bb.2:
	r0 = 2
	exit
.Lfunc_end0:
	.size	xdp_prog, .Lfunc_end0-xdp_prog
                                        # -- End function
	.type	.L__const.xdp_prog.____fmt,@object # @__const.xdp_prog.____fmt
	.section	.rodata.str1.1,"aMS",@progbits,1
.L__const.xdp_prog.____fmt:
	.asciz	"%d"
	.size	.L__const.xdp_prog.____fmt, 3

	.type	__license,@object       # @__license
	.section	license,"aw",@progbits
	.globl	__license
__license:
	.asciz	"GPL"
	.size	__license, 4


	.addrsig
	.addrsig_sym xdp_prog
	.addrsig_sym __license
This time the array is correctly initialized into code.
Is this a clang bug?


Yonghong Song
 

On Mon, Mar 23, 2020 at 10:05 AM Federico Parola <fede.parola@...> wrote:

Hello everybody,
in my XDP eBPF program I'm trying to initialize an array with a brace-enclosed list, however my code is rejected by the verifier.
Here is a simple piece of code to replicate the problem:

#include <linux/bpf.h>

#ifndef __section
# define __section(NAME) \
__attribute__((section(NAME), used))
#endif

#ifndef BPF_FUNC
# define BPF_FUNC(NAME, ...) \
(*NAME)(__VA_ARGS__) = (void *)BPF_FUNC_##NAME
#endif

#ifndef printk
# define printk(fmt, ...) \
({ \
char ____fmt[] = fmt; \
trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__); \
})
#endif

static void BPF_FUNC(trace_printk, const char *fmt, int fmt_size, ...);

__section("prog")
int xdp_prog(struct xdp_md *ctx) {
int i;
int array[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
The init list is too long. The compiler puts {0, 1, 2, ..., 9} in a readonly
section. That is why you got the failure below.

If you use native clang compilation and a recent kernel, libbpf
should be able to automatically create a map for you so your
code will work.


#pragma nounroll
for (i = 0; i < 10; i++) {
printk("%d", array[i]);
}

return XDP_PASS;
}

char __license[] __section("license") = "GPL"

This is the error reported by the verifier:

0: (b7) r6 = 0
1: (b7) r7 = 25637
2: (b7) r8 = 0
3: (73) *(u8 *)(r10 -2) = r6
last_idx 3 first_idx 0
regs=40 stack=0 before 2: (b7) r8 = 0
regs=40 stack=0 before 1: (b7) r7 = 25637
regs=40 stack=0 before 0: (b7) r6 = 0
4: (6b) *(u16 *)(r10 -4) = r7
5: (18) r1 = 0x0
7: (0f) r1 += r8
8: (61) r3 = *(u32 *)(r1 +0)
R1 invalid mem access 'inv'
processed 8 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0

I tried compiling with clang-6 and clang-9 with optimizaton set to O1 and O2, but I get this error in all cases.
If I initialize the array in another way (e.g. with a loop) the program works correctly.
The eBPF bytecode generated by clang is the following:

.text
.file "test.c"
.section prog,"ax",@progbits
.globl xdp_prog # -- Begin function xdp_prog
.p2align 3
.type xdp_prog,@function
xdp_prog: # @xdp_prog
# %bb.0:
r6 = 0
r7 = 25637
r8 = 0
LBB0_1: # =>This Inner Loop Header: Depth=1
*(u8 *)(r10 - 2) = r6
*(u16 *)(r10 - 4) = r7
r1 = .L__const.xdp_prog.array ll
r1 += r8
r3 = *(u32 *)(r1 + 0)
r1 = r10
r1 += -4
r2 = 3
call 6
r8 += 4
if r8 != 24 goto LBB0_1
# %bb.2:
r0 = 2
exit
.Lfunc_end0:
.size xdp_prog, .Lfunc_end0-xdp_prog
# -- End function
.type .L__const.xdp_prog.array,@object # @__const.xdp_prog.array
.section .rodata,"a",@progbits
.p2align 2
.L__const.xdp_prog.array:
.long 0 # 0x0
.long 1 # 0x1
.long 2 # 0x2
.long 3 # 0x3
.long 4 # 0x4
.long 5 # 0x5
.long 6 # 0x6
.long 7 # 0x7
.long 8 # 0x8
.long 9 # 0x9
.size .L__const.xdp_prog.array, 40

.type .L__const.xdp_prog.____fmt,@object # @__const.xdp_prog.____fmt
.section .rodata.str1.1,"aMS",@progbits,1
.L__const.xdp_prog.____fmt:
.asciz "%d"
.size .L__const.xdp_prog.____fmt, 3

.type __license,@object # @__license
.section license,"aw",@progbits
.globl __license
__license:
.asciz "GPL"
.size __license, 4


.addrsig
.addrsig_sym xdp_prog
.addrsig_sym __license

It seems like the array in the stack is not initialized in the code. With some declarations the code works, for example decalring the array in the following way:
int array[10] = {0, 1, 2, 3};
everything works, the generated bytecode is the following:

.text
.file "test.c"
.section prog,"ax",@progbits
.globl xdp_prog # -- Begin function xdp_prog
.p2align 3
.type xdp_prog,@function
xdp_prog: # @xdp_prog
# %bb.0:
r1 = 2
*(u32 *)(r10 - 36) = r1
r6 = 0
*(u32 *)(r10 - 8) = r6
*(u32 *)(r10 - 12) = r6
*(u32 *)(r10 - 16) = r6
*(u32 *)(r10 - 20) = r6
*(u32 *)(r10 - 24) = r6
*(u32 *)(r10 - 28) = r6
*(u32 *)(r10 - 4) = r6
r1 = 3
*(u32 *)(r10 - 32) = r1
r1 = 1
*(u32 *)(r10 - 40) = r1
*(u8 *)(r10 - 42) = r6
r7 = 25637
*(u16 *)(r10 - 44) = r7
r1 = r10
r1 += -44
r2 = 3
r3 = 1
call 6
r8 = 4
LBB0_1: # =>This Inner Loop Header: Depth=1
r1 = r10
r1 += -40
r1 += r8
r3 = *(u32 *)(r1 + 0)
*(u8 *)(r10 - 42) = r6
*(u16 *)(r10 - 44) = r7
r1 = r10
r1 += -44
r2 = 3
call 6
r8 += 4
if r8 != 24 goto LBB0_1
# %bb.2:
r0 = 2
exit
.Lfunc_end0:
.size xdp_prog, .Lfunc_end0-xdp_prog
# -- End function
.type .L__const.xdp_prog.____fmt,@object # @__const.xdp_prog.____fmt
.section .rodata.str1.1,"aMS",@progbits,1
.L__const.xdp_prog.____fmt:
.asciz "%d"
.size .L__const.xdp_prog.____fmt, 3

.type __license,@object # @__license
.section license,"aw",@progbits
.globl __license
__license:
.asciz "GPL"
.size __license, 4


.addrsig
.addrsig_sym xdp_prog
.addrsig_sym __license

This time the array is correctly initialized into code.
Is this a clang bug?