Skip to content

Commit 5b58e5d

Browse files
committed
Implement policy knitting
It is too hard to tweak bison / flex stuff to combine policies targeting different architectures so I decided to generate a separate policy for every target and companion architecture, and knit them altogether following these rules: * The architecture check of each target policy passes the control to the next target policy if present, or returns KILL if no more architectures left. This ensures no target architecture can slip towards filter (see google#19) * The default action of each target architecture passes the control to the next companion architecture if present. This is sufficient assuming there can be only one companion architecture for any target architecture. Signed-off-by: Vasyl Gello <[email protected]>
1 parent 872a40d commit 5b58e5d

File tree

4 files changed

+182
-9
lines changed

4 files changed

+182
-9
lines changed

src/codegen.c

+109-4
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <stddef.h>
2727
#include <stdint.h>
2828
#include <stdlib.h>
29+
#include <string.h>
2930
#include <sys/queue.h>
3031

3132
#include "common.h"
@@ -113,6 +114,14 @@ struct codegen_ctxt {
113114
size_t max_stack_ptr;
114115
};
115116

117+
void free_sock_program(struct sock_fprog* prog) {
118+
ASSERT(prog);
119+
120+
if (prog->filter) free(prog->filter);
121+
prog->filter = NULL;
122+
prog->len = 0;
123+
}
124+
116125
static struct codegen_ctxt *context_create(void) {
117126
struct codegen_ctxt *ctxt = calloc(1, sizeof(*ctxt));
118127
ctxt->buffer.capacity = CODEGEN_INITAL_BUFFER_SIZE;
@@ -288,6 +297,8 @@ static int add_jump_set(struct codegen_ctxt *ctxt, __u32 what, int tloc,
288297
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct seccomp_data, nr))
289298
#define BPF_LOAD_ARG_WORD(arg, high) \
290299
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, ARG_WORD(arg, high))
300+
#define BPF_NEXT_ARCH_MARKER \
301+
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 0x12345678)
291302

292303
static bool is_const_value(struct expr_tree *expr, int word) {
293304
return word == HIGH_WORD ? expr->high.is_const : expr->low.is_const;
@@ -615,15 +626,23 @@ int compile_policy(struct kafel_ctxt *kafel_ctxt, struct sock_fprog *prog) {
615626
normalize_rules(rules, kafel_ctxt->default_action);
616627
int begin = CURRENT_LOC;
617628
int next = generate_rules(ctxt, rules->data, rules->len);
629+
int next2 = 0;
618630
range_rules_destroy(&rules);
619631
if (next > begin) {
620632
begin = next = ADD_INSTR(BPF_LOAD_SYSCALL);
633+
if (!kafel_ctxt->use_companion_arch) {
634+
next2 = ADD_INSTR(BPF_NEXT_ARCH_MARKER);
635+
} else {
636+
next2 = next;
637+
}
621638
} else {
622-
next = -kafel_ctxt->default_action;
639+
next2 = next = -kafel_ctxt->default_action;
623640
}
624-
next = add_jump(ctxt, BPF_JEQ, kafel_ctxt->target_arch, next, -ACTION_KILL);
625-
if (next > begin) {
626-
begin = next = ADD_INSTR(BPF_LOAD_ARCH);
641+
if (!kafel_ctxt->use_companion_arch) {
642+
next = add_jump(ctxt, BPF_JEQ, kafel_ctxt->target_arch, next, next2);
643+
if (next > begin) {
644+
begin = next = ADD_INSTR(BPF_LOAD_ARCH);
645+
}
627646
}
628647
if (next < 0) {
629648
resolve_location(ctxt, next);
@@ -639,3 +658,89 @@ int compile_policy(struct kafel_ctxt *kafel_ctxt, struct sock_fprog *prog) {
639658
context_destroy(&ctxt);
640659
return rv;
641660
}
661+
662+
int knit_policy(struct kafel_ctxt* kafel_ctxt,
663+
struct sock_fprog* target_programs,
664+
struct sock_fprog* companion_programs,
665+
int default_action,
666+
struct sock_fprog* prog)
667+
{
668+
unsigned char i = 0;
669+
uint32_t j = 0;
670+
uint32_t k = 0;
671+
uint32_t cur_target_policy_start = 0;
672+
uint32_t total_count = 1;
673+
674+
for (i = 0; i < MAX_TARGET_ARCHS; i++) {
675+
if (!target_programs[i].len) continue;
676+
total_count += target_programs[i].len;
677+
if (!companion_programs[i].len) continue;
678+
total_count += companion_programs[i].len;
679+
}
680+
681+
struct sock_filter* filters = calloc(total_count, sizeof(struct sock_filter));
682+
if (!filters) {
683+
append_error(kafel_ctxt, "Cannot allocate %d bytes of memory",
684+
total_count * sizeof(struct sock_filter));
685+
686+
for (i = 0; i < MAX_TARGET_ARCHS; i++) {
687+
free_sock_program(&target_programs[i]);
688+
free_sock_program(&companion_programs[i]);
689+
}
690+
691+
return -1;
692+
}
693+
694+
for (i = 0; i < MAX_TARGET_ARCHS; i++) {
695+
if (!target_programs[i].len) continue;
696+
697+
cur_target_policy_start = k;
698+
699+
memcpy(&filters[k], target_programs[i].filter,
700+
target_programs[i].len * sizeof(struct sock_filter));
701+
k += target_programs[i].len;
702+
703+
if (companion_programs[i].len) {
704+
// In parent policy replace default action with JA
705+
// to start of companion policy
706+
707+
for (j = k - 1; j > (k - target_programs[i].len); j--) {
708+
if (filters[j].code == (BPF_RET | BPF_K) &&
709+
filters[j].jt == 0 &&
710+
filters[j].jf == 0 &&
711+
filters[j].k == ACTION_TO_BPF(default_action)) {
712+
filters[j].code = BPF_JMP | BPF_JA;
713+
filters[j].k = k - j - 1;
714+
break;
715+
}
716+
}
717+
718+
memcpy(&filters[k], companion_programs[i].filter,
719+
companion_programs[i].len * sizeof(struct sock_filter));
720+
k += companion_programs[i].len;
721+
}
722+
723+
// Replace marker JA to next parent policy
724+
725+
for (j = cur_target_policy_start; j < k; j++) {
726+
if (filters[j].code == (BPF_LD + BPF_W + BPF_ABS) &&
727+
filters[j].jt == 0 &&
728+
filters[j].jf == 0 &&
729+
filters[j].k == 0x12345678) {
730+
filters[j].code = BPF_JMP | BPF_JA;
731+
filters[j].k = k - j - 1;
732+
break;
733+
}
734+
}
735+
}
736+
737+
// Finally, add one KILL statement to complete jumps
738+
739+
filters[total_count - 1].code = BPF_RET | BPF_K;
740+
filters[total_count - 1].k = SECCOMP_RET_KILL;
741+
742+
prog->len = total_count;
743+
prog->filter = filters;
744+
745+
return 0;
746+
}

src/codegen.h

+6
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,11 @@
2626
#include "context.h"
2727

2828
int compile_policy(struct kafel_ctxt *kafel_ctxt, struct sock_fprog *prog);
29+
void free_sock_program(struct sock_fprog* prog);
30+
int knit_policy(struct kafel_ctxt* kafel_ctxt,
31+
struct sock_fprog* target_programs,
32+
struct sock_fprog* companion_programs,
33+
int default_action,
34+
struct sock_fprog* prog);
2935

3036
#endif /* KAFEL_CODEGEN_H */

src/context.h

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
#ifndef KAFEL_CONTEXT_H
2222
#define KAFEL_CONTEXT_H
2323

24+
#include <linux/audit.h>
25+
2426
#include <stdbool.h>
2527
#include <stddef.h>
2628
#include <stdint.h>

src/kafel.c

+65-5
Original file line numberDiff line numberDiff line change
@@ -163,14 +163,74 @@ KAFEL_API int kafel_compile(kafel_ctxt_t ctxt, struct sock_fprog* prog) {
163163
return -EINVAL;
164164
}
165165

166-
kafel_ctxt_reset(ctxt);
166+
struct sock_fprog target_programs[MAX_TARGET_ARCHS] = { 0 };
167+
struct sock_fprog companion_programs[MAX_TARGET_ARCHS] = { 0 };
168+
unsigned char i = 0;
169+
int default_action = 0;
170+
171+
for (i = 0; i < MAX_TARGET_ARCHS; i++) {
172+
if (!ctxt->all_architectures[i]) continue;
173+
174+
kafel_ctxt_reset(ctxt);
175+
set_target_arch(ctxt, ctxt->all_architectures[i]);
176+
set_use_companion_arch(ctxt, false);
177+
178+
int rv = parse(ctxt);
179+
if (rv) {
180+
for (i = 0; i < MAX_TARGET_ARCHS; i++) {
181+
free_sock_program(&target_programs[i]);
182+
free_sock_program(&companion_programs[i]);
183+
}
184+
185+
return rv;
186+
}
187+
188+
default_action = ctxt->default_action;
189+
190+
rv = compile_policy(ctxt, &target_programs[i]);
191+
if (rv) {
192+
for (i = 0; i < MAX_TARGET_ARCHS; i++) {
193+
free_sock_program(&target_programs[i]);
194+
free_sock_program(&companion_programs[i]);
195+
}
196+
197+
return rv;
198+
}
199+
200+
if (!rv && target_programs[0].len == 1) {
201+
*prog = target_programs[0];
202+
return rv;
203+
}
167204

168-
int rv = parse(ctxt);
169-
if (rv) {
170-
return rv;
205+
kafel_ctxt_reset(ctxt);
206+
set_target_arch(ctxt, ctxt->all_architectures[i]);
207+
set_use_companion_arch(ctxt, true);
208+
209+
rv = parse(ctxt);
210+
if (rv) {
211+
if (rv == -2) continue;
212+
213+
for (i = 0; i < MAX_TARGET_ARCHS; i++) {
214+
free_sock_program(&target_programs[i]);
215+
free_sock_program(&companion_programs[i]);
216+
}
217+
218+
return rv;
219+
}
220+
221+
rv = compile_policy(ctxt, &companion_programs[i]);
222+
if (rv) {
223+
for (i = 0; i < MAX_TARGET_ARCHS; i++) {
224+
free_sock_program(&target_programs[i]);
225+
free_sock_program(&companion_programs[i]);
226+
}
227+
228+
return rv;
229+
}
171230
}
172231

173-
return compile_policy(ctxt, prog);
232+
return knit_policy(ctxt, target_programs, companion_programs,
233+
default_action, prog);
174234
}
175235

176236
KAFEL_API int kafel_compile_file(FILE* file, struct sock_fprog* prog) {

0 commit comments

Comments
 (0)