Skip to content

Commit 84dbf35

Browse files
joestringerborkmann
authored andcommitted
bpf: Macrofy stack state copy
An upcoming commit will need very similar copy/realloc boilerplate, so refactor the existing stack copy/realloc functions into macros to simplify it. Signed-off-by: Joe Stringer <joe@wand.net.nz> Acked-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
1 parent c64b798 commit 84dbf35

File tree

1 file changed

+60
-46
lines changed

1 file changed

+60
-46
lines changed

kernel/bpf/verifier.c

Lines changed: 60 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -388,60 +388,74 @@ static void print_verifier_state(struct bpf_verifier_env *env,
388388
verbose(env, "\n");
389389
}
390390

391-
static int copy_stack_state(struct bpf_func_state *dst,
392-
const struct bpf_func_state *src)
393-
{
394-
if (!src->stack)
395-
return 0;
396-
if (WARN_ON_ONCE(dst->allocated_stack < src->allocated_stack)) {
397-
/* internal bug, make state invalid to reject the program */
398-
memset(dst, 0, sizeof(*dst));
399-
return -EFAULT;
400-
}
401-
memcpy(dst->stack, src->stack,
402-
sizeof(*src->stack) * (src->allocated_stack / BPF_REG_SIZE));
403-
return 0;
404-
}
391+
#define COPY_STATE_FN(NAME, COUNT, FIELD, SIZE) \
392+
static int copy_##NAME##_state(struct bpf_func_state *dst, \
393+
const struct bpf_func_state *src) \
394+
{ \
395+
if (!src->FIELD) \
396+
return 0; \
397+
if (WARN_ON_ONCE(dst->COUNT < src->COUNT)) { \
398+
/* internal bug, make state invalid to reject the program */ \
399+
memset(dst, 0, sizeof(*dst)); \
400+
return -EFAULT; \
401+
} \
402+
memcpy(dst->FIELD, src->FIELD, \
403+
sizeof(*src->FIELD) * (src->COUNT / SIZE)); \
404+
return 0; \
405+
}
406+
/* copy_stack_state() */
407+
COPY_STATE_FN(stack, allocated_stack, stack, BPF_REG_SIZE)
408+
#undef COPY_STATE_FN
409+
410+
#define REALLOC_STATE_FN(NAME, COUNT, FIELD, SIZE) \
411+
static int realloc_##NAME##_state(struct bpf_func_state *state, int size, \
412+
bool copy_old) \
413+
{ \
414+
u32 old_size = state->COUNT; \
415+
struct bpf_##NAME##_state *new_##FIELD; \
416+
int slot = size / SIZE; \
417+
\
418+
if (size <= old_size || !size) { \
419+
if (copy_old) \
420+
return 0; \
421+
state->COUNT = slot * SIZE; \
422+
if (!size && old_size) { \
423+
kfree(state->FIELD); \
424+
state->FIELD = NULL; \
425+
} \
426+
return 0; \
427+
} \
428+
new_##FIELD = kmalloc_array(slot, sizeof(struct bpf_##NAME##_state), \
429+
GFP_KERNEL); \
430+
if (!new_##FIELD) \
431+
return -ENOMEM; \
432+
if (copy_old) { \
433+
if (state->FIELD) \
434+
memcpy(new_##FIELD, state->FIELD, \
435+
sizeof(*new_##FIELD) * (old_size / SIZE)); \
436+
memset(new_##FIELD + old_size / SIZE, 0, \
437+
sizeof(*new_##FIELD) * (size - old_size) / SIZE); \
438+
} \
439+
state->COUNT = slot * SIZE; \
440+
kfree(state->FIELD); \
441+
state->FIELD = new_##FIELD; \
442+
return 0; \
443+
}
444+
/* realloc_stack_state() */
445+
REALLOC_STATE_FN(stack, allocated_stack, stack, BPF_REG_SIZE)
446+
#undef REALLOC_STATE_FN
405447

406448
/* do_check() starts with zero-sized stack in struct bpf_verifier_state to
407449
* make it consume minimal amount of memory. check_stack_write() access from
408450
* the program calls into realloc_func_state() to grow the stack size.
409-
* Note there is a non-zero parent pointer inside each reg of bpf_verifier_state
410-
* which this function copies over. It points to corresponding reg in previous
411-
* bpf_verifier_state which is never reallocated
451+
* Note there is a non-zero 'parent' pointer inside bpf_verifier_state
452+
* which realloc_stack_state() copies over. It points to previous
453+
* bpf_verifier_state which is never reallocated.
412454
*/
413455
static int realloc_func_state(struct bpf_func_state *state, int size,
414456
bool copy_old)
415457
{
416-
u32 old_size = state->allocated_stack;
417-
struct bpf_stack_state *new_stack;
418-
int slot = size / BPF_REG_SIZE;
419-
420-
if (size <= old_size || !size) {
421-
if (copy_old)
422-
return 0;
423-
state->allocated_stack = slot * BPF_REG_SIZE;
424-
if (!size && old_size) {
425-
kfree(state->stack);
426-
state->stack = NULL;
427-
}
428-
return 0;
429-
}
430-
new_stack = kmalloc_array(slot, sizeof(struct bpf_stack_state),
431-
GFP_KERNEL);
432-
if (!new_stack)
433-
return -ENOMEM;
434-
if (copy_old) {
435-
if (state->stack)
436-
memcpy(new_stack, state->stack,
437-
sizeof(*new_stack) * (old_size / BPF_REG_SIZE));
438-
memset(new_stack + old_size / BPF_REG_SIZE, 0,
439-
sizeof(*new_stack) * (size - old_size) / BPF_REG_SIZE);
440-
}
441-
state->allocated_stack = slot * BPF_REG_SIZE;
442-
kfree(state->stack);
443-
state->stack = new_stack;
444-
return 0;
458+
return realloc_stack_state(state, size, copy_old);
445459
}
446460

447461
static void free_func_state(struct bpf_func_state *state)

0 commit comments

Comments
 (0)