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:
@@ -370,21 +370,63 @@ static void print_verifier_state(struct bpf_verifier_env *env,
|
|||||||
verbose(env, "\n");
|
verbose(env, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int copy_stack_state(struct bpf_func_state *dst,
|
#define COPY_STATE_FN(NAME, COUNT, FIELD, SIZE) \
|
||||||
const struct bpf_func_state *src)
|
static int copy_##NAME##_state(struct bpf_func_state *dst, \
|
||||||
{
|
const struct bpf_func_state *src) \
|
||||||
if (!src->stack)
|
{ \
|
||||||
return 0;
|
if (!src->FIELD) \
|
||||||
if (WARN_ON_ONCE(dst->allocated_stack < src->allocated_stack)) {
|
return 0; \
|
||||||
/* internal bug, make state invalid to reject the program */
|
if (WARN_ON_ONCE(dst->COUNT < src->COUNT)) { \
|
||||||
memset(dst, 0, sizeof(*dst));
|
/* internal bug, make state invalid to reject the program */ \
|
||||||
return -EFAULT;
|
memset(dst, 0, sizeof(*dst)); \
|
||||||
}
|
return -EFAULT; \
|
||||||
memcpy(dst->stack, src->stack,
|
} \
|
||||||
sizeof(*src->stack) * (src->allocated_stack / BPF_REG_SIZE));
|
memcpy(dst->FIELD, src->FIELD, \
|
||||||
return 0;
|
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
|
/* 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
|
* make it consume minimal amount of memory. check_stack_write() access from
|
||||||
* the program calls into realloc_func_state() to grow the stack size.
|
* the program calls into realloc_func_state() to grow the stack size.
|
||||||
@@ -395,35 +437,7 @@ static int copy_stack_state(struct bpf_func_state *dst,
|
|||||||
static int realloc_func_state(struct bpf_func_state *state, int size,
|
static int realloc_func_state(struct bpf_func_state *state, int size,
|
||||||
bool copy_old)
|
bool copy_old)
|
||||||
{
|
{
|
||||||
u32 old_size = state->allocated_stack;
|
return realloc_stack_state(state, size, copy_old);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_func_state(struct bpf_func_state *state)
|
static void free_func_state(struct bpf_func_state *state)
|
||||||
|
|||||||
Reference in New Issue
Block a user