append_syscall_to_bpf(): Check for unlikely case of too many sock_filters

This commit is contained in:
Albert S. 2022-03-17 15:17:28 +01:00
parent dbf8e87440
commit 66def7a28f
1 changed files with 27 additions and 14 deletions

41
exile.c
View File

@ -1046,8 +1046,18 @@ static int drop_caps()
} }
static void assign_filter(struct sock_filter *left, struct sock_filter *right, struct sock_filter *endfilter)
{
if(left <= endfilter)
{
*left = *right;
return;
}
EXILE_LOG_ERROR("Too many syscall filters installed! Aborting.\n");
abort();
}
static void append_syscall_to_bpf(struct exile_syscall_policy *syscallpolicy, struct sock_filter *filter, unsigned short int *start_index) static struct sock_filter *append_syscall_to_bpf(struct exile_syscall_policy *syscallpolicy, struct sock_filter *filter, struct sock_filter *endfilter)
{ {
unsigned int action = syscallpolicy->policy; unsigned int action = syscallpolicy->policy;
if(action == EXILE_SYSCALL_ALLOW) if(action == EXILE_SYSCALL_ALLOW)
@ -1065,7 +1075,9 @@ static void append_syscall_to_bpf(struct exile_syscall_policy *syscallpolicy, st
long syscall = syscallpolicy->syscall; long syscall = syscallpolicy->syscall;
struct sock_filter syscall_load = BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct seccomp_data, nr)); struct sock_filter syscall_load = BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct seccomp_data, nr));
filter[(*start_index)++] = syscall_load; assign_filter(filter, &syscall_load, endfilter);
++filter;
if(syscall != EXILE_SYSCALL_MATCH_ALL) if(syscall != EXILE_SYSCALL_MATCH_ALL)
{ {
/* How many steps forward to jump when we don't match. This is either the last statement, /* How many steps forward to jump when we don't match. This is either the last statement,
@ -1074,11 +1086,11 @@ static void append_syscall_to_bpf(struct exile_syscall_policy *syscallpolicy, st
if(__builtin_add_overflow(next_syscall_pc, syscallpolicy->argfilterscount, &next_syscall_pc)) if(__builtin_add_overflow(next_syscall_pc, syscallpolicy->argfilterscount, &next_syscall_pc))
{ {
EXILE_LOG_ERROR("Overflow while trying to calculate jump offset\n"); EXILE_LOG_ERROR("Overflow while trying to calculate jump offset\n");
/* TODO: Return error */ abort();
return;
} }
struct sock_filter syscall_check = EXILE_BPF_CMP_EQ((unsigned int) syscall, 0, next_syscall_pc); struct sock_filter syscall_check = EXILE_BPF_CMP_EQ((unsigned int) syscall, 0, next_syscall_pc);
filter[(*start_index)++] = syscall_check; assign_filter(filter, &syscall_check, endfilter);
++filter;
--next_syscall_pc; --next_syscall_pc;
struct sock_filter return_matching = EXILE_BPF_RETURN_MATCHING; struct sock_filter return_matching = EXILE_BPF_RETURN_MATCHING;
@ -1086,8 +1098,8 @@ static void append_syscall_to_bpf(struct exile_syscall_policy *syscallpolicy, st
for(size_t i = 0; i < syscallpolicy->argfilterscount; i++) for(size_t i = 0; i < syscallpolicy->argfilterscount; i++)
{ {
filter[*start_index] = syscallpolicy->argfilters[i]; assign_filter(filter, &syscallpolicy->argfilters[i], endfilter);
struct sock_filter *current = &filter[*start_index]; struct sock_filter *current = filter;
__u8 jump_count_next_syscall = next_syscall_pc; __u8 jump_count_next_syscall = next_syscall_pc;
__u8 jump_count_return = jump_count_next_syscall - 1; __u8 jump_count_return = jump_count_next_syscall - 1;
if(current->jt == EXILE_SYSCALL_EXIT_BPF_NO_MATCH) if(current->jt == EXILE_SYSCALL_EXIT_BPF_NO_MATCH)
@ -1115,13 +1127,13 @@ static void append_syscall_to_bpf(struct exile_syscall_policy *syscallpolicy, st
current->k = jump_count_next_syscall; current->k = jump_count_next_syscall;
} }
--next_syscall_pc; --next_syscall_pc;
++*start_index; ++filter;
} }
} }
struct sock_filter syscall_action = BPF_STMT(BPF_RET+BPF_K, action); struct sock_filter syscall_action = BPF_STMT(BPF_RET+BPF_K, action);
/* TODO: we can do better than adding this below every jump */ /* TODO: we can do better than adding this below every jump */
filter[(*start_index)++] = syscall_action; assign_filter(filter, &syscall_action, endfilter);
return ++filter;
} }
static int is_valid_syscall_policy(unsigned int policy) static int is_valid_syscall_policy(unsigned int policy)
@ -1149,7 +1161,8 @@ int exile_enable_syscall_policy(struct exile_policy *policy)
BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL_PROCESS), BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL_PROCESS),
}; };
unsigned short int current_filter_index = 6; struct sock_filter *current_target = &filter[6];
struct sock_filter *end = &filter[1023];
struct exile_syscall_policy *current_policy = policy->syscall_policies; struct exile_syscall_policy *current_policy = policy->syscall_policies;
while(current_policy) while(current_policy)
@ -1159,13 +1172,13 @@ int exile_enable_syscall_policy(struct exile_policy *policy)
EXILE_LOG_ERROR("invalid syscall policy specified\n"); EXILE_LOG_ERROR("invalid syscall policy specified\n");
return -1; return -1;
} }
/* TODO: reintroduce overflow checks */ current_target = append_syscall_to_bpf(current_policy, current_target, end);
append_syscall_to_bpf(current_policy, filter, &current_filter_index);
current_policy = current_policy->next; current_policy = current_policy->next;
} }
unsigned short len = (current_target - &filter[0]);
struct sock_fprog prog = { struct sock_fprog prog = {
.len = current_filter_index , .len = len ,
.filter = filter, .filter = filter,
}; };