aboutsummaryrefslogtreecommitdiffstats
path: root/src/fsec-optimize/optimizer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fsec-optimize/optimizer.c')
-rw-r--r--src/fsec-optimize/optimizer.c136
1 files changed, 136 insertions, 0 deletions
diff --git a/src/fsec-optimize/optimizer.c b/src/fsec-optimize/optimizer.c
new file mode 100644
index 000000000..8e61935d3
--- /dev/null
+++ b/src/fsec-optimize/optimizer.c
@@ -0,0 +1,136 @@
1/*
2 * Copyright (C) 2014-2017 Firejail Authors
3 *
4 * This file is part of firejail project
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19*/
20#include "fsec_optimize.h"
21
22// From /usr/include/linux/filter.h
23//struct sock_filter { /* Filter block */
24// __u16 code; /* Actual filter code */
25// __u8 jt; /* Jump true */
26// __u8 jf; /* Jump false */
27// __u32 k; /* Generic multiuse field */
28//};
29
30
31#define LIMIT_BLACKLISTS 4 // we optimize blacklists only if we have more than
32
33static inline int is_blacklist(struct sock_filter *bpf) {
34 if (bpf->code == BPF_JMP + BPF_JEQ + BPF_K &&
35 (bpf + 1)->code == BPF_RET + BPF_K &&
36 (bpf + 1)->k == SECCOMP_RET_KILL )
37 return 1;
38 return 0;
39}
40
41static int count_blacklists(struct sock_filter *filter, int entries) {
42 int cnt = 0;
43 int i;
44
45 for (i = 0; i < (entries - 1); i++, filter++) { // is_blacklist works on two consecutive lines; using entries - 1
46 if (is_blacklist(filter))
47 cnt++;
48 }
49
50 return cnt;
51}
52
53typedef struct {
54 int to_remove;
55 int to_fix_jumps;
56} Action;
57
58static int optimize_blacklists(struct sock_filter *filter, int entries) {
59 assert(entries);
60 assert(filter);
61 int i;
62 int j;
63
64 // step1: extract information
65 Action action[entries];
66 memset(&action[0], 0, sizeof(Action) * entries);
67 int remove_cnt = 0;
68 for (i = 0; i < (entries - 1); i++) { // is_blacklist works on two consecutive lines; using entries - 1
69 if (is_blacklist(filter + i)) {
70 action[i]. to_fix_jumps = 1;
71 i++;
72 action[i].to_remove = 1;
73 remove_cnt++;
74 }
75 }
76
77 // step2: remove lines
78 struct sock_filter *filter_step2 = duplicate(filter, entries);
79 Action action_step2[entries];
80 memset(&action_step2[0], 0, sizeof(Action) * entries);
81 for (i = 0, j = 0; i < entries; i++) {
82 if (!action[i].to_remove) {
83 memcpy(&filter_step2[j], &filter[i], sizeof(struct sock_filter));
84 memcpy(&action_step2[j], &action[i], sizeof(Action));
85 j++;
86 }
87 else {
88 // do nothing, we are removing this line
89 }
90 }
91
92 // step 3: add the new ret KILL, and recalculate entries
93 filter_step2[j].code = BPF_RET + BPF_K;
94 filter_step2[j].k == SECCOMP_RET_KILL;
95 entries = j + 1;
96
97 // step 4: recalculate jumps
98 for (i = 0; i < entries; i++) {
99 if (action_step2[i].to_fix_jumps) {
100 filter_step2[i].jt = entries - i - 2;
101 filter_step2[i].jf = 0;
102 }
103 }
104
105 // update
106 memcpy(filter, filter_step2, entries * sizeof(struct sock_filter));
107 free(filter_step2);
108 return entries;
109}
110
111int optimize(struct sock_filter *filter, int entries) {
112 assert(filter);
113 assert(entries);
114
115 //**********************************
116 // optimize blacklist statements
117 //**********************************
118 // count "ret KILL"
119 int cnt = count_blacklists(filter, entries);
120 if (cnt > LIMIT_BLACKLISTS)
121 entries = optimize_blacklists(filter, entries);
122 return entries;
123}
124
125struct sock_filter *duplicate(struct sock_filter *filter, int entries) {
126 int len = sizeof(struct sock_filter) * entries;
127 struct sock_filter *rv = malloc(len);
128 if (!rv) {
129 errExit("malloc");
130 exit(1);
131 }
132
133 memcpy(rv, filter, len);
134 return rv;
135}
136