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>
This commit is contained in:
parent
c64b798328
commit
84dbf35073
|
@ -388,60 +388,74 @@ static void print_verifier_state(struct bpf_verifier_env *env,
|
|||
verbose(env, "\n");
|
||||
}
|
||||
|
||||
static int copy_stack_state(struct bpf_func_state *dst,
|
||||
const struct bpf_func_state *src)
|
||||
{
|
||||
if (!src->stack)
|
||||
return 0;
|
||||
if (WARN_ON_ONCE(dst->allocated_stack < src->allocated_stack)) {
|
||||
/* internal bug, make state invalid to reject the program */
|
||||
memset(dst, 0, sizeof(*dst));
|
||||
return -EFAULT;
|
||||
}
|
||||
memcpy(dst->stack, src->stack,
|
||||
sizeof(*src->stack) * (src->allocated_stack / BPF_REG_SIZE));
|
||||
return 0;
|
||||
#define COPY_STATE_FN(NAME, COUNT, FIELD, SIZE) \
|
||||
static int copy_##NAME##_state(struct bpf_func_state *dst, \
|
||||
const struct bpf_func_state *src) \
|
||||
{ \
|
||||
if (!src->FIELD) \
|
||||
return 0; \
|
||||
if (WARN_ON_ONCE(dst->COUNT < src->COUNT)) { \
|
||||
/* internal bug, make state invalid to reject the program */ \
|
||||
memset(dst, 0, sizeof(*dst)); \
|
||||
return -EFAULT; \
|
||||
} \
|
||||
memcpy(dst->FIELD, src->FIELD, \
|
||||
sizeof(*src->FIELD) * (src->COUNT / SIZE)); \
|
||||
return 0; \
|
||||
}
|
||||
/* copy_stack_state() */
|
||||
COPY_STATE_FN(stack, allocated_stack, stack, BPF_REG_SIZE)
|
||||
#undef COPY_STATE_FN
|
||||
|
||||
#define REALLOC_STATE_FN(NAME, COUNT, FIELD, SIZE) \
|
||||
static int realloc_##NAME##_state(struct bpf_func_state *state, int size, \
|
||||
bool copy_old) \
|
||||
{ \
|
||||
u32 old_size = state->COUNT; \
|
||||
struct bpf_##NAME##_state *new_##FIELD; \
|
||||
int slot = size / SIZE; \
|
||||
\
|
||||
if (size <= old_size || !size) { \
|
||||
if (copy_old) \
|
||||
return 0; \
|
||||
state->COUNT = slot * SIZE; \
|
||||
if (!size && old_size) { \
|
||||
kfree(state->FIELD); \
|
||||
state->FIELD = NULL; \
|
||||
} \
|
||||
return 0; \
|
||||
} \
|
||||
new_##FIELD = kmalloc_array(slot, sizeof(struct bpf_##NAME##_state), \
|
||||
GFP_KERNEL); \
|
||||
if (!new_##FIELD) \
|
||||
return -ENOMEM; \
|
||||
if (copy_old) { \
|
||||
if (state->FIELD) \
|
||||
memcpy(new_##FIELD, state->FIELD, \
|
||||
sizeof(*new_##FIELD) * (old_size / SIZE)); \
|
||||
memset(new_##FIELD + old_size / SIZE, 0, \
|
||||
sizeof(*new_##FIELD) * (size - old_size) / SIZE); \
|
||||
} \
|
||||
state->COUNT = slot * SIZE; \
|
||||
kfree(state->FIELD); \
|
||||
state->FIELD = new_##FIELD; \
|
||||
return 0; \
|
||||
}
|
||||
/* realloc_stack_state() */
|
||||
REALLOC_STATE_FN(stack, allocated_stack, stack, BPF_REG_SIZE)
|
||||
#undef REALLOC_STATE_FN
|
||||
|
||||
/* do_check() starts with zero-sized stack in struct bpf_verifier_state to
|
||||
* make it consume minimal amount of memory. check_stack_write() access from
|
||||
* the program calls into realloc_func_state() to grow the stack size.
|
||||
* Note there is a non-zero parent pointer inside each reg of bpf_verifier_state
|
||||
* which this function copies over. It points to corresponding reg in previous
|
||||
* bpf_verifier_state which is never reallocated
|
||||
* Note there is a non-zero 'parent' pointer inside bpf_verifier_state
|
||||
* which realloc_stack_state() copies over. It points to previous
|
||||
* bpf_verifier_state which is never reallocated.
|
||||
*/
|
||||
static int realloc_func_state(struct bpf_func_state *state, int size,
|
||||
bool copy_old)
|
||||
{
|
||||
u32 old_size = state->allocated_stack;
|
||||
struct bpf_stack_state *new_stack;
|
||||
int slot = size / BPF_REG_SIZE;
|
||||
|
||||
if (size <= old_size || !size) {
|
||||
if (copy_old)
|
||||
return 0;
|
||||
state->allocated_stack = slot * BPF_REG_SIZE;
|
||||
if (!size && old_size) {
|
||||
kfree(state->stack);
|
||||
state->stack = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
new_stack = kmalloc_array(slot, sizeof(struct bpf_stack_state),
|
||||
GFP_KERNEL);
|
||||
if (!new_stack)
|
||||
return -ENOMEM;
|
||||
if (copy_old) {
|
||||
if (state->stack)
|
||||
memcpy(new_stack, state->stack,
|
||||
sizeof(*new_stack) * (old_size / BPF_REG_SIZE));
|
||||
memset(new_stack + old_size / BPF_REG_SIZE, 0,
|
||||
sizeof(*new_stack) * (size - old_size) / BPF_REG_SIZE);
|
||||
}
|
||||
state->allocated_stack = slot * BPF_REG_SIZE;
|
||||
kfree(state->stack);
|
||||
state->stack = new_stack;
|
||||
return 0;
|
||||
return realloc_stack_state(state, size, copy_old);
|
||||
}
|
||||
|
||||
static void free_func_state(struct bpf_func_state *state)
|
||||
|
|
Loading…
Reference in New Issue