script_core 0.2.6 → 0.2.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (191) hide show
  1. checksums.yaml +4 -4
  2. data/ext/enterprise_script_service/libseccomp/.travis.yml +21 -7
  3. data/ext/enterprise_script_service/libseccomp/CHANGELOG +22 -0
  4. data/ext/enterprise_script_service/libseccomp/CONTRIBUTING.md +37 -26
  5. data/ext/enterprise_script_service/libseccomp/CREDITS +8 -0
  6. data/ext/enterprise_script_service/libseccomp/README.md +3 -1
  7. data/ext/enterprise_script_service/libseccomp/configure.ac +13 -8
  8. data/ext/enterprise_script_service/libseccomp/doc/Makefile.am +6 -0
  9. data/ext/enterprise_script_service/libseccomp/doc/man/man3/seccomp_api_get.3 +12 -2
  10. data/ext/enterprise_script_service/libseccomp/doc/man/man3/seccomp_arch_add.3 +38 -6
  11. data/ext/enterprise_script_service/libseccomp/doc/man/man3/seccomp_attr_set.3 +53 -2
  12. data/ext/enterprise_script_service/libseccomp/doc/man/man3/seccomp_export_bpf.3 +20 -2
  13. data/ext/enterprise_script_service/libseccomp/doc/man/man3/seccomp_init.3 +9 -2
  14. data/ext/enterprise_script_service/libseccomp/doc/man/man3/seccomp_load.3 +32 -2
  15. data/ext/enterprise_script_service/libseccomp/doc/man/man3/seccomp_merge.3 +16 -2
  16. data/ext/enterprise_script_service/libseccomp/doc/man/man3/seccomp_notify_alloc.3 +113 -0
  17. data/ext/enterprise_script_service/libseccomp/doc/man/man3/seccomp_notify_fd.3 +1 -0
  18. data/ext/enterprise_script_service/libseccomp/doc/man/man3/seccomp_notify_free.3 +1 -0
  19. data/ext/enterprise_script_service/libseccomp/doc/man/man3/seccomp_notify_id_valid.3 +1 -0
  20. data/ext/enterprise_script_service/libseccomp/doc/man/man3/seccomp_notify_receive.3 +1 -0
  21. data/ext/enterprise_script_service/libseccomp/doc/man/man3/seccomp_notify_respond.3 +1 -0
  22. data/ext/enterprise_script_service/libseccomp/doc/man/man3/seccomp_rule_add.3 +64 -3
  23. data/ext/enterprise_script_service/libseccomp/doc/man/man3/seccomp_syscall_priority.3 +18 -3
  24. data/ext/enterprise_script_service/libseccomp/include/seccomp-syscalls.h +12 -0
  25. data/ext/enterprise_script_service/libseccomp/include/seccomp.h.in +116 -0
  26. data/ext/enterprise_script_service/libseccomp/src/.gitignore +2 -0
  27. data/ext/enterprise_script_service/libseccomp/src/Makefile.am +31 -17
  28. data/ext/enterprise_script_service/libseccomp/src/api.c +254 -58
  29. data/ext/enterprise_script_service/libseccomp/src/arch-aarch64.h +1 -9
  30. data/ext/enterprise_script_service/libseccomp/src/arch-arm.c +47 -2
  31. data/ext/enterprise_script_service/libseccomp/src/arch-arm.h +1 -9
  32. data/ext/enterprise_script_service/libseccomp/src/arch-gperf-generate +40 -0
  33. data/ext/enterprise_script_service/libseccomp/src/arch-mips.c +41 -4
  34. data/ext/enterprise_script_service/libseccomp/src/arch-mips.h +2 -10
  35. data/ext/enterprise_script_service/libseccomp/src/arch-mips64.c +41 -4
  36. data/ext/enterprise_script_service/libseccomp/src/arch-mips64.h +3 -11
  37. data/ext/enterprise_script_service/libseccomp/src/arch-mips64n32.c +41 -4
  38. data/ext/enterprise_script_service/libseccomp/src/arch-mips64n32.h +2 -10
  39. data/ext/enterprise_script_service/libseccomp/src/arch-parisc.h +1 -10
  40. data/ext/enterprise_script_service/libseccomp/src/arch-parisc64.c +3 -3
  41. data/ext/enterprise_script_service/libseccomp/src/arch-parisc64.h +29 -0
  42. data/ext/enterprise_script_service/libseccomp/src/arch-ppc.h +1 -9
  43. data/ext/enterprise_script_service/libseccomp/src/arch-ppc64.c +606 -8
  44. data/ext/enterprise_script_service/libseccomp/src/arch-ppc64.h +2 -10
  45. data/ext/enterprise_script_service/libseccomp/src/arch-riscv64.c +31 -0
  46. data/ext/enterprise_script_service/libseccomp/src/arch-riscv64.h +22 -0
  47. data/ext/enterprise_script_service/libseccomp/src/arch-s390.c +171 -12
  48. data/ext/enterprise_script_service/libseccomp/src/arch-s390.h +1 -17
  49. data/ext/enterprise_script_service/libseccomp/src/arch-s390x.c +166 -10
  50. data/ext/enterprise_script_service/libseccomp/src/arch-s390x.h +1 -20
  51. data/ext/enterprise_script_service/libseccomp/src/arch-syscall-dump.c +8 -1
  52. data/ext/enterprise_script_service/libseccomp/src/arch-syscall-validate +359 -143
  53. data/ext/enterprise_script_service/libseccomp/src/arch-x32.c +36 -2
  54. data/ext/enterprise_script_service/libseccomp/src/arch-x32.h +2 -10
  55. data/ext/enterprise_script_service/libseccomp/src/arch-x86.c +172 -10
  56. data/ext/enterprise_script_service/libseccomp/src/arch-x86.h +1 -14
  57. data/ext/enterprise_script_service/libseccomp/src/arch-x86_64.h +1 -9
  58. data/ext/enterprise_script_service/libseccomp/src/arch.c +11 -3
  59. data/ext/enterprise_script_service/libseccomp/src/arch.h +7 -0
  60. data/ext/enterprise_script_service/libseccomp/src/db.c +268 -57
  61. data/ext/enterprise_script_service/libseccomp/src/db.h +16 -2
  62. data/ext/enterprise_script_service/libseccomp/src/gen_bpf.c +503 -148
  63. data/ext/enterprise_script_service/libseccomp/src/gen_bpf.h +2 -1
  64. data/ext/enterprise_script_service/libseccomp/src/gen_pfc.c +165 -37
  65. data/ext/enterprise_script_service/libseccomp/src/python/libseccomp.pxd +37 -1
  66. data/ext/enterprise_script_service/libseccomp/src/python/seccomp.pyx +295 -5
  67. data/ext/enterprise_script_service/libseccomp/src/syscalls.c +56 -0
  68. data/ext/enterprise_script_service/libseccomp/src/syscalls.csv +470 -0
  69. data/ext/enterprise_script_service/libseccomp/src/syscalls.h +62 -0
  70. data/ext/enterprise_script_service/libseccomp/src/syscalls.perf.template +82 -0
  71. data/ext/enterprise_script_service/libseccomp/src/system.c +196 -16
  72. data/ext/enterprise_script_service/libseccomp/src/system.h +68 -13
  73. data/ext/enterprise_script_service/libseccomp/tests/.gitignore +9 -2
  74. data/ext/enterprise_script_service/libseccomp/tests/06-sim-actions.tests +1 -1
  75. data/ext/enterprise_script_service/libseccomp/tests/11-basic-basic_errors.c +5 -5
  76. data/ext/enterprise_script_service/libseccomp/tests/13-basic-attrs.c +35 -1
  77. data/ext/enterprise_script_service/libseccomp/tests/13-basic-attrs.py +10 -1
  78. data/ext/enterprise_script_service/libseccomp/tests/15-basic-resolver.c +1 -0
  79. data/ext/enterprise_script_service/libseccomp/tests/16-sim-arch_basic.c +12 -0
  80. data/ext/enterprise_script_service/libseccomp/tests/16-sim-arch_basic.py +1 -0
  81. data/ext/enterprise_script_service/libseccomp/tests/{18-sim-basic_whitelist.c → 18-sim-basic_allowlist.c} +0 -0
  82. data/ext/enterprise_script_service/libseccomp/tests/{18-sim-basic_whitelist.py → 18-sim-basic_allowlist.py} +0 -0
  83. data/ext/enterprise_script_service/libseccomp/tests/18-sim-basic_allowlist.tests +32 -0
  84. data/ext/enterprise_script_service/libseccomp/tests/23-sim-arch_all_le_basic.c +3 -0
  85. data/ext/enterprise_script_service/libseccomp/tests/23-sim-arch_all_le_basic.py +1 -0
  86. data/ext/enterprise_script_service/libseccomp/tests/30-sim-socket_syscalls.c +3 -0
  87. data/ext/enterprise_script_service/libseccomp/tests/30-sim-socket_syscalls.py +1 -0
  88. data/ext/enterprise_script_service/libseccomp/tests/30-sim-socket_syscalls.tests +33 -17
  89. data/ext/enterprise_script_service/libseccomp/tests/{34-sim-basic_blacklist.c → 34-sim-basic_denylist.c} +0 -0
  90. data/ext/enterprise_script_service/libseccomp/tests/{34-sim-basic_blacklist.py → 34-sim-basic_denylist.py} +0 -0
  91. data/ext/enterprise_script_service/libseccomp/tests/34-sim-basic_denylist.tests +32 -0
  92. data/ext/enterprise_script_service/libseccomp/tests/36-sim-ipc_syscalls.c +3 -0
  93. data/ext/enterprise_script_service/libseccomp/tests/36-sim-ipc_syscalls.py +1 -0
  94. data/ext/enterprise_script_service/libseccomp/tests/36-sim-ipc_syscalls.tests +25 -25
  95. data/ext/enterprise_script_service/libseccomp/tests/39-basic-api_level.c +24 -3
  96. data/ext/enterprise_script_service/libseccomp/tests/39-basic-api_level.py +16 -1
  97. data/ext/enterprise_script_service/libseccomp/tests/47-live-kill_process.c +3 -3
  98. data/ext/enterprise_script_service/libseccomp/tests/51-live-user_notification.c +112 -0
  99. data/ext/enterprise_script_service/libseccomp/tests/51-live-user_notification.py +60 -0
  100. data/ext/enterprise_script_service/libseccomp/tests/51-live-user_notification.tests +11 -0
  101. data/ext/enterprise_script_service/libseccomp/tests/53-sim-binary_tree.c +156 -0
  102. data/ext/enterprise_script_service/libseccomp/tests/53-sim-binary_tree.py +95 -0
  103. data/ext/enterprise_script_service/libseccomp/tests/53-sim-binary_tree.tests +65 -0
  104. data/ext/enterprise_script_service/libseccomp/tests/54-live-binary_tree.c +128 -0
  105. data/ext/enterprise_script_service/libseccomp/tests/54-live-binary_tree.py +95 -0
  106. data/ext/enterprise_script_service/libseccomp/tests/54-live-binary_tree.tests +11 -0
  107. data/ext/enterprise_script_service/libseccomp/tests/55-basic-pfc_binary_tree.c +134 -0
  108. data/ext/enterprise_script_service/libseccomp/tests/55-basic-pfc_binary_tree.sh +46 -0
  109. data/ext/enterprise_script_service/libseccomp/tests/55-basic-pfc_binary_tree.tests +11 -0
  110. data/ext/enterprise_script_service/libseccomp/tests/56-basic-iterate_syscalls.c +90 -0
  111. data/ext/enterprise_script_service/libseccomp/tests/56-basic-iterate_syscalls.py +65 -0
  112. data/ext/enterprise_script_service/libseccomp/tests/56-basic-iterate_syscalls.tests +11 -0
  113. data/ext/enterprise_script_service/libseccomp/tests/57-basic-rawsysrc.c +64 -0
  114. data/ext/enterprise_script_service/libseccomp/tests/57-basic-rawsysrc.py +46 -0
  115. data/ext/enterprise_script_service/libseccomp/tests/57-basic-rawsysrc.tests +11 -0
  116. data/ext/enterprise_script_service/libseccomp/tests/58-live-tsync_notify.c +116 -0
  117. data/ext/enterprise_script_service/libseccomp/tests/58-live-tsync_notify.py +61 -0
  118. data/ext/enterprise_script_service/libseccomp/tests/58-live-tsync_notify.tests +11 -0
  119. data/ext/enterprise_script_service/libseccomp/tests/Makefile.am +31 -10
  120. data/ext/enterprise_script_service/libseccomp/tests/regression +6 -3
  121. data/ext/enterprise_script_service/libseccomp/tests/util.c +3 -3
  122. data/ext/enterprise_script_service/libseccomp/tools/check-syntax +1 -1
  123. data/ext/enterprise_script_service/libseccomp/tools/scmp_arch_detect.c +3 -0
  124. data/ext/enterprise_script_service/libseccomp/tools/scmp_bpf_disasm.c +4 -2
  125. data/ext/enterprise_script_service/libseccomp/tools/scmp_bpf_sim.c +2 -0
  126. data/ext/enterprise_script_service/libseccomp/tools/util.c +14 -12
  127. data/ext/enterprise_script_service/libseccomp/tools/util.h +7 -0
  128. data/ext/enterprise_script_service/mruby/.github/workflows/codeql-analysis.yml +51 -0
  129. data/ext/enterprise_script_service/mruby/Doxyfile +1 -1
  130. data/ext/enterprise_script_service/mruby/README.md +1 -1
  131. data/ext/enterprise_script_service/mruby/doc/guides/debugger.md +1 -1
  132. data/ext/enterprise_script_service/mruby/doc/limitations.md +10 -10
  133. data/ext/enterprise_script_service/mruby/include/mruby.h +13 -0
  134. data/ext/enterprise_script_service/mruby/include/mruby/boxing_word.h +0 -1
  135. data/ext/enterprise_script_service/mruby/include/mruby/proc.h +13 -8
  136. data/ext/enterprise_script_service/mruby/include/mruby/value.h +25 -29
  137. data/ext/enterprise_script_service/mruby/include/mruby/version.h +3 -3
  138. data/ext/enterprise_script_service/mruby/mrbgems/mruby-array-ext/src/array.c +5 -8
  139. data/ext/enterprise_script_service/mruby/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c +2 -2
  140. data/ext/enterprise_script_service/mruby/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c +17 -10
  141. data/ext/enterprise_script_service/mruby/mrbgems/mruby-complex/mrblib/complex.rb +1 -1
  142. data/ext/enterprise_script_service/mruby/mrbgems/mruby-complex/src/complex.c +1 -2
  143. data/ext/enterprise_script_service/mruby/mrbgems/mruby-eval/src/eval.c +1 -1
  144. data/ext/enterprise_script_service/mruby/mrbgems/mruby-fiber/src/fiber.c +1 -2
  145. data/ext/enterprise_script_service/mruby/mrbgems/mruby-inline-struct/test/inline.c +3 -4
  146. data/ext/enterprise_script_service/mruby/mrbgems/mruby-io/src/file.c +1 -2
  147. data/ext/enterprise_script_service/mruby/mrbgems/mruby-io/src/file_test.c +9 -26
  148. data/ext/enterprise_script_service/mruby/mrbgems/mruby-io/src/io.c +1 -2
  149. data/ext/enterprise_script_service/mruby/mrbgems/mruby-kernel-ext/src/kernel.c +6 -8
  150. data/ext/enterprise_script_service/mruby/mrbgems/mruby-method/src/method.c +3 -4
  151. data/ext/enterprise_script_service/mruby/mrbgems/mruby-objectspace/src/mruby_objectspace.c +0 -1
  152. data/ext/enterprise_script_service/mruby/mrbgems/mruby-print/src/print.c +1 -2
  153. data/ext/enterprise_script_service/mruby/mrbgems/mruby-range-ext/src/range.c +1 -3
  154. data/ext/enterprise_script_service/mruby/mrbgems/mruby-rational/mrblib/rational.rb +1 -3
  155. data/ext/enterprise_script_service/mruby/mrbgems/mruby-sprintf/src/sprintf.c +3 -3
  156. data/ext/enterprise_script_service/mruby/mrbgems/mruby-string-ext/src/string.c +1 -2
  157. data/ext/enterprise_script_service/mruby/mrbgems/mruby-struct/src/struct.c +5 -11
  158. data/ext/enterprise_script_service/mruby/mrbgems/mruby-time/src/time.c +5 -10
  159. data/ext/enterprise_script_service/mruby/mrblib/00class.rb +10 -0
  160. data/ext/enterprise_script_service/mruby/src/array.c +14 -11
  161. data/ext/enterprise_script_service/mruby/src/class.c +22 -21
  162. data/ext/enterprise_script_service/mruby/src/error.c +1 -2
  163. data/ext/enterprise_script_service/mruby/src/etc.c +0 -1
  164. data/ext/enterprise_script_service/mruby/src/gc.c +5 -5
  165. data/ext/enterprise_script_service/mruby/src/hash.c +8 -15
  166. data/ext/enterprise_script_service/mruby/src/kernel.c +4 -7
  167. data/ext/enterprise_script_service/mruby/src/numeric.c +28 -60
  168. data/ext/enterprise_script_service/mruby/src/object.c +11 -1
  169. data/ext/enterprise_script_service/mruby/src/proc.c +7 -8
  170. data/ext/enterprise_script_service/mruby/src/range.c +4 -12
  171. data/ext/enterprise_script_service/mruby/src/string.c +24 -21
  172. data/ext/enterprise_script_service/mruby/src/symbol.c +1 -2
  173. data/ext/enterprise_script_service/mruby/src/vm.c +28 -24
  174. data/ext/enterprise_script_service/mruby/test/t/kernel.rb +7 -0
  175. data/lib/script_core/version.rb +1 -1
  176. metadata +45 -21
  177. data/ext/enterprise_script_service/libseccomp/src/arch-aarch64-syscalls.c +0 -559
  178. data/ext/enterprise_script_service/libseccomp/src/arch-arm-syscalls.c +0 -570
  179. data/ext/enterprise_script_service/libseccomp/src/arch-mips-syscalls.c +0 -562
  180. data/ext/enterprise_script_service/libseccomp/src/arch-mips64-syscalls.c +0 -562
  181. data/ext/enterprise_script_service/libseccomp/src/arch-mips64n32-syscalls.c +0 -562
  182. data/ext/enterprise_script_service/libseccomp/src/arch-parisc-syscalls.c +0 -542
  183. data/ext/enterprise_script_service/libseccomp/src/arch-ppc-syscalls.c +0 -559
  184. data/ext/enterprise_script_service/libseccomp/src/arch-ppc64-syscalls.c +0 -559
  185. data/ext/enterprise_script_service/libseccomp/src/arch-s390-syscalls.c +0 -642
  186. data/ext/enterprise_script_service/libseccomp/src/arch-s390x-syscalls.c +0 -642
  187. data/ext/enterprise_script_service/libseccomp/src/arch-x32-syscalls.c +0 -558
  188. data/ext/enterprise_script_service/libseccomp/src/arch-x86-syscalls.c +0 -692
  189. data/ext/enterprise_script_service/libseccomp/src/arch-x86_64-syscalls.c +0 -559
  190. data/ext/enterprise_script_service/libseccomp/tests/18-sim-basic_whitelist.tests +0 -32
  191. data/ext/enterprise_script_service/libseccomp/tests/34-sim-basic_blacklist.tests +0 -32
@@ -116,6 +116,12 @@ struct db_filter_attr {
116
116
  uint32_t api_tskip;
117
117
  /* SECCOMP_FILTER_FLAG_LOG related attributes */
118
118
  uint32_t log_enable;
119
+ /* SPEC_ALLOW related attributes */
120
+ uint32_t spec_allow;
121
+ /* SCMP_FLTATR_CTL_OPTIMIZE related attributes */
122
+ uint32_t optimize;
123
+ /* return the raw system return codes */
124
+ uint32_t api_sysrawrc;
119
125
  };
120
126
 
121
127
  struct db_filter {
@@ -124,6 +130,7 @@ struct db_filter {
124
130
 
125
131
  /* syscall filters, kept as a sorted single-linked list */
126
132
  struct db_sys_list *syscalls;
133
+ unsigned int syscall_cnt;
127
134
 
128
135
  /* list of rules used to build the filters, kept in order */
129
136
  struct db_api_rule_list *rules;
@@ -133,6 +140,7 @@ struct db_filter_snap {
133
140
  /* individual filters */
134
141
  struct db_filter **filters;
135
142
  unsigned int filter_cnt;
143
+ bool shadow;
136
144
 
137
145
  struct db_filter_snap *next;
138
146
  };
@@ -151,6 +159,10 @@ struct db_filter_col {
151
159
 
152
160
  /* transaction snapshots */
153
161
  struct db_filter_snap *snapshots;
162
+
163
+ /* notification fd that was returned from seccomp() */
164
+ int notify_fd;
165
+ bool notify_used;
154
166
  };
155
167
 
156
168
  /**
@@ -165,8 +177,6 @@ struct db_filter_col {
165
177
  #define db_list_foreach(iter,list) \
166
178
  for (iter = (list); iter != NULL; iter = iter->next)
167
179
 
168
- int db_action_valid(uint32_t action);
169
-
170
180
  struct db_api_rule_list *db_rule_dup(const struct db_api_rule_list *src);
171
181
 
172
182
  struct db_filter_col *db_col_init(uint32_t def_action);
@@ -175,12 +185,16 @@ void db_col_release(struct db_filter_col *col);
175
185
 
176
186
  int db_col_valid(struct db_filter_col *col);
177
187
 
188
+ int db_col_action_valid(const struct db_filter_col *col, uint32_t action);
189
+
178
190
  int db_col_merge(struct db_filter_col *col_dst, struct db_filter_col *col_src);
179
191
 
180
192
  int db_col_arch_exist(struct db_filter_col *col, uint32_t arch_token);
181
193
 
182
194
  int db_col_attr_get(const struct db_filter_col *col,
183
195
  enum scmp_filter_attr attr, uint32_t *value);
196
+ uint32_t db_col_attr_read(const struct db_filter_col *col,
197
+ enum scmp_filter_attr attr);
184
198
  int db_col_attr_set(struct db_filter_col *col,
185
199
  enum scmp_filter_attr attr, uint32_t value);
186
200
 
@@ -21,6 +21,7 @@
21
21
 
22
22
  #include <errno.h>
23
23
  #include <inttypes.h>
24
+ #include <limits.h>
24
25
  #include <stdlib.h>
25
26
  #include <stdio.h>
26
27
  #include <string.h>
@@ -45,6 +46,11 @@
45
46
  #define AINC_BLK 2
46
47
  #define AINC_PROG 64
47
48
 
49
+ /* binary tree definitions */
50
+ #define SYSCALLS_PER_NODE (4)
51
+ #define BTREE_HSH_INVALID (UINT64_MAX)
52
+ #define BTREE_SYSCALL_INVALID (UINT_MAX)
53
+
48
54
  struct acc_state {
49
55
  int32_t offset;
50
56
  uint32_t mask;
@@ -159,11 +165,14 @@ struct bpf_state {
159
165
  /* default action */
160
166
  uint64_t def_hsh;
161
167
 
162
- /* target arch - NOTE: be careful, temporary use only! */
163
- const struct arch_def *arch;
164
-
165
168
  /* bpf program */
166
169
  struct bpf_program *bpf;
170
+
171
+ /* WARNING - the following variables are temporary use only */
172
+ const struct arch_def *arch;
173
+ struct bpf_blk *b_head;
174
+ struct bpf_blk *b_tail;
175
+ struct bpf_blk *b_new;
167
176
  };
168
177
 
169
178
  /**
@@ -1143,6 +1152,318 @@ chain_failure:
1143
1152
  return NULL;
1144
1153
  }
1145
1154
 
1155
+ /**
1156
+ * Sort the syscalls by syscall number
1157
+ * @param syscalls the linked list of syscalls to be sorted
1158
+ * @param s_head the head of the linked list to be returned to the caller
1159
+ * @param s_tail the tail of the linked list to be returned to the caller
1160
+ */
1161
+ static void _sys_num_sort(struct db_sys_list *syscalls,
1162
+ struct db_sys_list **s_head,
1163
+ struct db_sys_list **s_tail)
1164
+ {
1165
+ struct db_sys_list *s_iter, *s_iter_b;
1166
+
1167
+ db_list_foreach(s_iter, syscalls) {
1168
+ if (*s_head != NULL) {
1169
+ s_iter_b = *s_head;
1170
+ while ((s_iter_b->pri_nxt != NULL) &&
1171
+ (s_iter->num <= s_iter_b->num))
1172
+ s_iter_b = s_iter_b->pri_nxt;
1173
+
1174
+ if (s_iter->num > s_iter_b->num) {
1175
+ s_iter->pri_prv = s_iter_b->pri_prv;
1176
+ s_iter->pri_nxt = s_iter_b;
1177
+ if (s_iter_b == *s_head) {
1178
+ (*s_head)->pri_prv = s_iter;
1179
+ *s_head = s_iter;
1180
+ } else {
1181
+ s_iter->pri_prv->pri_nxt = s_iter;
1182
+ s_iter->pri_nxt->pri_prv = s_iter;
1183
+ }
1184
+ } else {
1185
+ s_iter->pri_prv = *s_tail;
1186
+ s_iter->pri_nxt = NULL;
1187
+ s_iter->pri_prv->pri_nxt = s_iter;
1188
+ *s_tail = s_iter;
1189
+ }
1190
+ } else {
1191
+ *s_head = s_iter;
1192
+ *s_tail = s_iter;
1193
+ (*s_head)->pri_prv = NULL;
1194
+ (*s_head)->pri_nxt = NULL;
1195
+ }
1196
+ }
1197
+ }
1198
+
1199
+ /**
1200
+ * Sort the syscalls by priority
1201
+ * @param syscalls the linked list of syscalls to be sorted
1202
+ * @param s_head the head of the linked list to be returned to the caller
1203
+ * @param s_tail the tail of the linked list to be returned to the caller
1204
+ */
1205
+ static void _sys_priority_sort(struct db_sys_list *syscalls,
1206
+ struct db_sys_list **s_head,
1207
+ struct db_sys_list **s_tail)
1208
+ {
1209
+ struct db_sys_list *s_iter, *s_iter_b;
1210
+
1211
+ db_list_foreach(s_iter, syscalls) {
1212
+ if (*s_head != NULL) {
1213
+ s_iter_b = *s_head;
1214
+ while ((s_iter_b->pri_nxt != NULL) &&
1215
+ (s_iter->priority <= s_iter_b->priority))
1216
+ s_iter_b = s_iter_b->pri_nxt;
1217
+
1218
+ if (s_iter->priority > s_iter_b->priority) {
1219
+ s_iter->pri_prv = s_iter_b->pri_prv;
1220
+ s_iter->pri_nxt = s_iter_b;
1221
+ if (s_iter_b == *s_head) {
1222
+ (*s_head)->pri_prv = s_iter;
1223
+ *s_head = s_iter;
1224
+ } else {
1225
+ s_iter->pri_prv->pri_nxt = s_iter;
1226
+ s_iter->pri_nxt->pri_prv = s_iter;
1227
+ }
1228
+ } else {
1229
+ s_iter->pri_prv = *s_tail;
1230
+ s_iter->pri_nxt = NULL;
1231
+ s_iter->pri_prv->pri_nxt = s_iter;
1232
+ *s_tail = s_iter;
1233
+ }
1234
+ } else {
1235
+ *s_head = s_iter;
1236
+ *s_tail = s_iter;
1237
+ (*s_head)->pri_prv = NULL;
1238
+ (*s_head)->pri_nxt = NULL;
1239
+ }
1240
+ }
1241
+ }
1242
+
1243
+ /**
1244
+ * Sort the syscalls
1245
+ * @param syscalls the linked list of syscalls to be sorted
1246
+ * @param s_head the head of the linked list to be returned to the caller
1247
+ * @param s_tail the tail of the linked list to be returned to the caller
1248
+ *
1249
+ * Wrapper function for sorting syscalls
1250
+ *
1251
+ */
1252
+ static void _sys_sort(struct db_sys_list *syscalls,
1253
+ struct db_sys_list **s_head,
1254
+ struct db_sys_list **s_tail,
1255
+ uint32_t optimize)
1256
+ {
1257
+ if (optimize != 2)
1258
+ _sys_priority_sort(syscalls, s_head, s_tail);
1259
+ else
1260
+ /* sort by number for the binary tree */
1261
+ _sys_num_sort(syscalls, s_head, s_tail);
1262
+ }
1263
+
1264
+ /**
1265
+ * Insert an instruction into the BPF state and connect the linked list
1266
+ * @param state the BPF state
1267
+ * @param instr the instruction to insert
1268
+ * @param insert the BPF blk that represents the instruction
1269
+ * @param next the next BPF instruction in the linked list
1270
+ * @param existing_blk insert will be added to the end of this blk if non-NULL
1271
+ *
1272
+ * Insert a set of instructions into the BPF state and associate those
1273
+ * instructions with the bpf_blk called insert. The "next" field in the
1274
+ * newly inserted block will be linked with the "next" bpf_blk parameter.
1275
+ */
1276
+ static int _gen_bpf_insert(struct bpf_state *state, struct bpf_instr *instr,
1277
+ struct bpf_blk **insert, struct bpf_blk **next,
1278
+ struct bpf_blk *existing_blk)
1279
+ {
1280
+ int rc;
1281
+
1282
+ *insert = _blk_append(state, existing_blk, instr);
1283
+ if (*insert == NULL)
1284
+ return -ENOMEM;
1285
+ (*insert)->next = (*next);
1286
+ if (*next != NULL)
1287
+ (*next)->prev = (*insert);
1288
+ *next = *insert;
1289
+
1290
+ rc = _hsh_add(state, insert, 1);
1291
+ return rc;
1292
+ }
1293
+
1294
+ /**
1295
+ * Decide if we need to omit the syscall from the BPF filter
1296
+ * @param state the BPF state
1297
+ * @param syscall syscall being tested
1298
+ * @return true if syscall is to be skipped, false otherwise
1299
+ */
1300
+ static inline bool _skip_syscall(struct bpf_state *state,
1301
+ struct db_sys_list *syscall)
1302
+ {
1303
+ if (!syscall->valid)
1304
+ return true;
1305
+
1306
+ /* psuedo-syscalls should not be added to the filter unless explicity
1307
+ * requested via SCMP_FLTATR_API_TSKIP
1308
+ */
1309
+ if (((int)syscall->num < 0) &&
1310
+ (state->attr->api_tskip == 0 || syscall->num != -1))
1311
+ return true;
1312
+
1313
+ return false;
1314
+ }
1315
+
1316
+ /**
1317
+ * Calculate the number of syscalls that will be in the BPF filter
1318
+ * @param state the BPF state
1319
+ * @param s_tail the last syscall in the syscall linked list
1320
+ */
1321
+ static unsigned int _get_syscall_cnt(struct bpf_state *state,
1322
+ struct db_sys_list *s_tail)
1323
+ {
1324
+ struct db_sys_list *s_iter;
1325
+ unsigned int syscall_cnt = 0;
1326
+
1327
+ for (s_iter = s_tail; s_iter != NULL; s_iter = s_iter->pri_prv) {
1328
+ if (_skip_syscall(state, s_iter))
1329
+ continue;
1330
+
1331
+ syscall_cnt++;
1332
+ }
1333
+
1334
+ return syscall_cnt;
1335
+ }
1336
+
1337
+ /**
1338
+ * Calculate the number of levels in the binary tree
1339
+ * @param syscall_cnt the number of syscalls in this seccomp filter
1340
+ */
1341
+ static int _get_bintree_levels(unsigned int syscall_cnt)
1342
+ {
1343
+ unsigned int i = 2, max_level = SYSCALLS_PER_NODE * 2;
1344
+
1345
+ while (max_level < syscall_cnt) {
1346
+ max_level <<= 1;
1347
+ i++;
1348
+ }
1349
+
1350
+ return i;
1351
+ }
1352
+
1353
+ /**
1354
+ * Initialize the binary tree
1355
+ * @param bintree_hashes Array of hashes that store binary tree jump dests
1356
+ * @param bintree_syscalls Array of syscalls for the binary tree "if > " logic
1357
+ * @param bintree_levels Number of levels in the binary tree
1358
+ * @param syscall_cnt Number of syscalls in this filter
1359
+ * @param empty_cnt Number of empty slots needed to balance the tree
1360
+ *
1361
+ */
1362
+ static int _gen_bpf_init_bintree(uint64_t **bintree_hashes,
1363
+ unsigned int **bintree_syscalls,
1364
+ unsigned int *bintree_levels,
1365
+ unsigned int syscall_cnt,
1366
+ unsigned int *empty_cnt)
1367
+ {
1368
+ int i;
1369
+
1370
+ *bintree_levels = _get_bintree_levels(syscall_cnt);
1371
+
1372
+ if (*bintree_levels > 0) {
1373
+ *empty_cnt = ((unsigned int)(SYSCALLS_PER_NODE * 2) <<
1374
+ ((*bintree_levels) - 1)) - syscall_cnt;
1375
+ *bintree_hashes = zmalloc(sizeof(uint64_t) *
1376
+ (*bintree_levels));
1377
+ if (*bintree_hashes == NULL)
1378
+ return -ENOMEM;
1379
+
1380
+ *bintree_syscalls = zmalloc(sizeof(unsigned int) *
1381
+ (*bintree_levels));
1382
+ if (*bintree_syscalls == NULL)
1383
+ return -ENOMEM;
1384
+
1385
+ for (i = 0; i < *bintree_levels; i++) {
1386
+ (*bintree_syscalls)[i] = BTREE_SYSCALL_INVALID;
1387
+ (*bintree_hashes)[i] = BTREE_HSH_INVALID;
1388
+ }
1389
+ }
1390
+
1391
+ return 0;
1392
+ }
1393
+
1394
+ /**
1395
+ * Generate the binary tree
1396
+ * @param state the BPF state
1397
+ * @param bintree_hashes Array of hashes that store binary tree jump dests
1398
+ * @param bintree_syscalls Array of syscalls for the binary tree "if > " logic
1399
+ * @param bintree_levels Number of levels in the binary tree
1400
+ * @param total_cnt Total number of syscalls and empty slots in the bintree
1401
+ * @param cur_syscall Current syscall being processed
1402
+ * @param blks_added Number of BPF blocks added by this function
1403
+ *
1404
+ * Generate the BPF instruction blocks for the binary tree for cur_syscall.
1405
+ * If this syscall is at the end of the node, then this function will
1406
+ * create the requisite ifs and elses for the tree.
1407
+ */
1408
+ static int _gen_bpf_bintree(struct bpf_state *state, uint64_t *bintree_hashes,
1409
+ unsigned int *bintree_syscalls,
1410
+ unsigned int bintree_levels,
1411
+ unsigned int total_cnt, unsigned int cur_syscall,
1412
+ unsigned int *blks_added)
1413
+ {
1414
+ struct bpf_blk *b_bintree = NULL;
1415
+ struct bpf_instr instr;
1416
+ unsigned int level;
1417
+ int rc = 0, i, j;
1418
+
1419
+ for (i = bintree_levels - 1; i >= 0; i--) {
1420
+ level = SYSCALLS_PER_NODE << i;
1421
+
1422
+ if ((total_cnt % level) == 0) {
1423
+ /* save the "if greater than" syscall num */
1424
+ bintree_syscalls[i] = cur_syscall;
1425
+ /* save the hash for the jf case */
1426
+ bintree_hashes[i] = state->b_new->hash;
1427
+
1428
+ for (j = 0; j < i; j++) {
1429
+ if (bintree_syscalls[j] == BTREE_SYSCALL_INVALID ||
1430
+ bintree_hashes[j] == BTREE_HSH_INVALID)
1431
+ /* we are near the end of the binary
1432
+ * tree and the jump-to location is
1433
+ * not valid. skip this if-else
1434
+ */
1435
+ continue;
1436
+
1437
+ _BPF_INSTR(instr,
1438
+ _BPF_OP(state->arch, BPF_JMP + BPF_JGT),
1439
+ _BPF_JMP_NO,
1440
+ _BPF_JMP_NO,
1441
+ _BPF_K(state->arch, bintree_syscalls[j]));
1442
+ instr.jt = _BPF_JMP_HSH(b_bintree == NULL ?
1443
+ state->b_new->hash : b_bintree->hash);
1444
+ instr.jf = _BPF_JMP_HSH(bintree_hashes[j]);
1445
+ (*blks_added)++;
1446
+
1447
+ rc = _gen_bpf_insert(state, &instr,
1448
+ &b_bintree, &state->b_head, NULL);
1449
+ if (rc < 0)
1450
+ goto out;
1451
+ }
1452
+
1453
+ if (b_bintree != NULL)
1454
+ /* this is the last if in this "block".
1455
+ * save it off so the next binary tree
1456
+ * if can "else" to it.
1457
+ */
1458
+ bintree_hashes[j] = b_bintree->hash;
1459
+ break;
1460
+ }
1461
+ }
1462
+
1463
+ out:
1464
+ return rc;
1465
+ }
1466
+
1146
1467
  /**
1147
1468
  * Generate the BPF instruction blocks for a given syscall
1148
1469
  * @param state the BPF state
@@ -1222,94 +1543,44 @@ static struct bpf_blk *_gen_bpf_syscall(struct bpf_state *state,
1222
1543
  }
1223
1544
 
1224
1545
  /**
1225
- * Generate the BPF instruction blocks for a given filter/architecture
1546
+ * Loop through the syscalls in the db_filter and generate their bpf
1226
1547
  * @param state the BPF state
1227
1548
  * @param db the filter DB
1228
1549
  * @param db_secondary the secondary DB
1229
- *
1230
- * Generate the BPF instruction block for the given filter DB(s)/architecture(s)
1231
- * and return a pointer to the block on succes, NULL on failure. The resulting
1232
- * block assumes that the architecture token has already been loaded into the
1233
- * BPF accumulator.
1234
- *
1550
+ * @param Number of blocks added by this function
1235
1551
  */
1236
- static struct bpf_blk *_gen_bpf_arch(struct bpf_state *state,
1237
- const struct db_filter *db,
1238
- const struct db_filter *db_secondary)
1552
+ static int _gen_bpf_syscalls(struct bpf_state *state,
1553
+ const struct db_filter *db,
1554
+ const struct db_filter *db_secondary,
1555
+ unsigned int *blks_added, uint32_t optimize,
1556
+ unsigned int *bintree_levels)
1239
1557
  {
1240
- int rc;
1241
- unsigned int blk_cnt = 0;
1558
+ struct db_sys_list *s_head = NULL, *s_tail = NULL, *s_iter;
1559
+ unsigned int syscall_cnt, empty_cnt = 0;
1560
+ uint64_t *bintree_hashes = NULL, nxt_hsh;
1561
+ unsigned int *bintree_syscalls = NULL;
1242
1562
  bool acc_reset;
1243
- struct bpf_instr instr;
1244
- struct db_sys_list *s_head = NULL, *s_tail = NULL, *s_iter, *s_iter_b;
1245
- struct bpf_blk *b_head = NULL, *b_tail = NULL, *b_iter, *b_new;
1563
+ int rc = 0;
1246
1564
 
1247
1565
  state->arch = db->arch;
1566
+ state->b_head = NULL;
1567
+ state->b_tail = NULL;
1568
+ state->b_new = NULL;
1248
1569
 
1249
- /* sort the syscall list */
1250
- db_list_foreach(s_iter, db->syscalls) {
1251
- if (s_head != NULL) {
1252
- s_iter_b = s_head;
1253
- while ((s_iter_b->pri_nxt != NULL) &&
1254
- (s_iter->priority <= s_iter_b->priority))
1255
- s_iter_b = s_iter_b->pri_nxt;
1570
+ *blks_added = 0;
1256
1571
 
1257
- if (s_iter->priority > s_iter_b->priority) {
1258
- s_iter->pri_prv = s_iter_b->pri_prv;
1259
- s_iter->pri_nxt = s_iter_b;
1260
- if (s_iter_b == s_head) {
1261
- s_head->pri_prv = s_iter;
1262
- s_head = s_iter;
1263
- } else {
1264
- s_iter->pri_prv->pri_nxt = s_iter;
1265
- s_iter->pri_nxt->pri_prv = s_iter;
1266
- }
1267
- } else {
1268
- s_iter->pri_prv = s_tail;
1269
- s_iter->pri_nxt = NULL;
1270
- s_iter->pri_prv->pri_nxt = s_iter;
1271
- s_tail = s_iter;
1272
- }
1273
- } else {
1274
- s_head = s_iter;
1275
- s_tail = s_iter;
1276
- s_head->pri_prv = NULL;
1277
- s_head->pri_nxt = NULL;
1278
- }
1279
- }
1280
- if (db_secondary != NULL) {
1281
- db_list_foreach(s_iter, db_secondary->syscalls) {
1282
- if (s_head != NULL) {
1283
- s_iter_b = s_head;
1284
- while ((s_iter_b->pri_nxt != NULL) &&
1285
- (s_iter->priority <= s_iter_b->priority))
1286
- s_iter_b = s_iter_b->pri_nxt;
1287
-
1288
- if (s_iter->priority > s_iter_b->priority) {
1289
- s_iter->pri_prv = s_iter_b->pri_prv;
1290
- s_iter->pri_nxt = s_iter_b;
1291
- if (s_iter_b == s_head) {
1292
- s_head->pri_prv = s_iter;
1293
- s_head = s_iter;
1294
- } else {
1295
- s_iter->pri_prv->pri_nxt =
1296
- s_iter;
1297
- s_iter->pri_nxt->pri_prv =
1298
- s_iter;
1299
- }
1300
- } else {
1301
- s_iter->pri_prv = s_tail;
1302
- s_iter->pri_nxt = NULL;
1303
- s_iter->pri_prv->pri_nxt = s_iter;
1304
- s_tail = s_iter;
1305
- }
1306
- } else {
1307
- s_head = s_iter;
1308
- s_tail = s_iter;
1309
- s_head->pri_prv = NULL;
1310
- s_head->pri_nxt = NULL;
1311
- }
1312
- }
1572
+ /* sort the syscall list */
1573
+ _sys_sort(db->syscalls, &s_head, &s_tail, optimize);
1574
+ if (db_secondary != NULL)
1575
+ _sys_sort(db_secondary->syscalls, &s_head, &s_tail, optimize);
1576
+
1577
+ if (optimize == 2) {
1578
+ syscall_cnt = _get_syscall_cnt(state, s_tail);
1579
+ rc = _gen_bpf_init_bintree(&bintree_hashes, &bintree_syscalls,
1580
+ bintree_levels, syscall_cnt,
1581
+ &empty_cnt);
1582
+ if (rc < 0)
1583
+ goto out;
1313
1584
  }
1314
1585
 
1315
1586
  if ((state->arch->token == SCMP_ARCH_X86_64 ||
@@ -1318,34 +1589,115 @@ static struct bpf_blk *_gen_bpf_arch(struct bpf_state *state,
1318
1589
  else
1319
1590
  acc_reset = true;
1320
1591
 
1592
+ if (*bintree_levels > 0)
1593
+ /* The accumulator is reset when the first bintree "if" is
1594
+ * generated.
1595
+ */
1596
+ acc_reset = false;
1597
+
1598
+ syscall_cnt = 0;
1599
+
1321
1600
  /* create the syscall filters and add them to block list group */
1322
1601
  for (s_iter = s_tail; s_iter != NULL; s_iter = s_iter->pri_prv) {
1323
- if (!s_iter->valid)
1602
+ if (_skip_syscall(state, s_iter))
1324
1603
  continue;
1325
1604
 
1605
+ if (*bintree_levels > 0 &&
1606
+ ((syscall_cnt + empty_cnt) % SYSCALLS_PER_NODE) == 0)
1607
+ /* This is the last syscall in the node. go to the
1608
+ * default hash */
1609
+ nxt_hsh = state->def_hsh;
1610
+ else
1611
+ nxt_hsh = state->b_head == NULL ?
1612
+ state->def_hsh : state->b_head->hash;
1613
+
1326
1614
  /* build the syscall filter */
1327
- b_new = _gen_bpf_syscall(state, s_iter,
1328
- (b_head == NULL ?
1329
- state->def_hsh : b_head->hash),
1330
- (s_iter == s_head ?
1331
- acc_reset : false));
1332
- if (b_new == NULL)
1333
- goto arch_failure;
1615
+ state->b_new = _gen_bpf_syscall(state, s_iter, nxt_hsh,
1616
+ (s_iter == s_head ?
1617
+ acc_reset : false));
1618
+ if (state->b_new == NULL)
1619
+ goto out;
1334
1620
 
1335
1621
  /* add the filter to the list head */
1336
- b_new->prev = NULL;
1337
- b_new->next = b_head;
1338
- if (b_tail != NULL) {
1339
- b_head->prev = b_new;
1340
- b_head = b_new;
1622
+ state->b_new->prev = NULL;
1623
+ state->b_new->next = state->b_head;
1624
+ if (state->b_tail != NULL) {
1625
+ state->b_head->prev = state->b_new;
1626
+ state->b_head = state->b_new;
1341
1627
  } else {
1342
- b_head = b_new;
1343
- b_tail = b_head;
1628
+ state->b_head = state->b_new;
1629
+ state->b_tail = state->b_head;
1344
1630
  }
1345
1631
 
1346
- if (b_tail->next != NULL)
1347
- b_tail = b_tail->next;
1632
+ if (state->b_tail->next != NULL)
1633
+ state->b_tail = state->b_tail->next;
1634
+ (*blks_added)++;
1635
+ syscall_cnt++;
1636
+
1637
+ /* build the binary tree if and else logic */
1638
+ if (*bintree_levels > 0) {
1639
+ rc = _gen_bpf_bintree(state, bintree_hashes,
1640
+ bintree_syscalls,
1641
+ *bintree_levels,
1642
+ syscall_cnt + empty_cnt,
1643
+ s_iter->num, blks_added);
1644
+ if (rc < 0)
1645
+ goto out;
1646
+ }
1647
+ }
1648
+
1649
+ out:
1650
+ if (bintree_hashes != NULL)
1651
+ free(bintree_hashes);
1652
+ if (bintree_syscalls != NULL)
1653
+ free(bintree_syscalls);
1654
+
1655
+ return rc;
1656
+ }
1657
+
1658
+ /**
1659
+ * Generate the BPF instruction blocks for a given filter/architecture
1660
+ * @param state the BPF state
1661
+ * @param db the filter DB
1662
+ * @param db_secondary the secondary DB
1663
+ *
1664
+ * Generate the BPF instruction block for the given filter DB(s)/architecture(s)
1665
+ * and return a pointer to the block on succes, NULL on failure. The resulting
1666
+ * block assumes that the architecture token has already been loaded into the
1667
+ * BPF accumulator.
1668
+ *
1669
+ */
1670
+ static struct bpf_blk *_gen_bpf_arch(struct bpf_state *state,
1671
+ const struct db_filter *db,
1672
+ const struct db_filter *db_secondary,
1673
+ uint32_t optimize)
1674
+ {
1675
+ int rc;
1676
+ unsigned int blk_cnt = 0, blks_added = 0, bintree_levels = 0;
1677
+ struct bpf_instr instr;
1678
+ struct bpf_blk *b_iter, *b_bintree;
1679
+
1680
+ state->arch = db->arch;
1681
+
1682
+ /* create the syscall filters and add them to block list group */
1683
+ rc = _gen_bpf_syscalls(state, db, db_secondary, &blks_added, optimize,
1684
+ &bintree_levels);
1685
+ if (rc < 0)
1686
+ goto arch_failure;
1687
+ blk_cnt += blks_added;
1688
+
1689
+ if (bintree_levels > 0) {
1690
+ _BPF_INSTR(instr, _BPF_OP(state->arch, BPF_LD + BPF_ABS),
1691
+ _BPF_JMP_NO, _BPF_JMP_NO,
1692
+ _BPF_SYSCALL(state->arch));
1348
1693
  blk_cnt++;
1694
+
1695
+ rc = _gen_bpf_insert(state, &instr, &b_bintree,
1696
+ &state->b_head, NULL);
1697
+ if (rc < 0)
1698
+ goto arch_failure;
1699
+ b_bintree->acc_start = _ACC_STATE_UNDEF;
1700
+ b_bintree->acc_end = _ACC_STATE_OFFSET(_BPF_OFFSET_SYSCALL);
1349
1701
  }
1350
1702
 
1351
1703
  /* additional ABI filtering */
@@ -1353,10 +1705,10 @@ static struct bpf_blk *_gen_bpf_arch(struct bpf_state *state,
1353
1705
  state->arch->token == SCMP_ARCH_X32) && (db_secondary == NULL)) {
1354
1706
  _BPF_INSTR(instr, _BPF_OP(state->arch, BPF_LD + BPF_ABS),
1355
1707
  _BPF_JMP_NO, _BPF_JMP_NO, _BPF_SYSCALL(state->arch));
1356
- b_new = _blk_append(state, NULL, &instr);
1357
- if (b_new == NULL)
1708
+ state->b_new = _blk_append(state, NULL, &instr);
1709
+ if (state->b_new == NULL)
1358
1710
  goto arch_failure;
1359
- b_new->acc_end = _ACC_STATE_OFFSET(_BPF_OFFSET_SYSCALL);
1711
+ state->b_new->acc_end = _ACC_STATE_OFFSET(_BPF_OFFSET_SYSCALL);
1360
1712
  if (state->arch->token == SCMP_ARCH_X86_64) {
1361
1713
  /* filter out x32 */
1362
1714
  _BPF_INSTR(instr,
@@ -1364,12 +1716,12 @@ static struct bpf_blk *_gen_bpf_arch(struct bpf_state *state,
1364
1716
  _BPF_JMP_NO,
1365
1717
  _BPF_JMP_NO,
1366
1718
  _BPF_K(state->arch, X32_SYSCALL_BIT));
1367
- if (b_head != NULL)
1368
- instr.jf = _BPF_JMP_HSH(b_head->hash);
1719
+ if (state->b_head != NULL)
1720
+ instr.jf = _BPF_JMP_HSH(state->b_head->hash);
1369
1721
  else
1370
1722
  instr.jf = _BPF_JMP_HSH(state->def_hsh);
1371
- b_new = _blk_append(state, b_new, &instr);
1372
- if (b_new == NULL)
1723
+ state->b_new = _blk_append(state, state->b_new, &instr);
1724
+ if (state->b_new == NULL)
1373
1725
  goto arch_failure;
1374
1726
  /* NOTE: starting with Linux v4.8 the seccomp filters
1375
1727
  * are processed both when the syscall is
@@ -1383,8 +1735,8 @@ static struct bpf_blk *_gen_bpf_arch(struct bpf_state *state,
1383
1735
  _BPF_JMP_NO,
1384
1736
  _BPF_JMP_HSH(state->bad_arch_hsh),
1385
1737
  _BPF_K(state->arch, -1));
1386
- if (b_head != NULL)
1387
- instr.jt = _BPF_JMP_HSH(b_head->hash);
1738
+ if (state->b_head != NULL)
1739
+ instr.jt = _BPF_JMP_HSH(state->b_head->hash);
1388
1740
  else
1389
1741
  instr.jt = _BPF_JMP_HSH(state->def_hsh);
1390
1742
  blk_cnt++;
@@ -1395,22 +1747,17 @@ static struct bpf_blk *_gen_bpf_arch(struct bpf_state *state,
1395
1747
  _BPF_JMP_NO,
1396
1748
  _BPF_JMP_HSH(state->bad_arch_hsh),
1397
1749
  _BPF_K(state->arch, X32_SYSCALL_BIT));
1398
- if (b_head != NULL)
1399
- instr.jt = _BPF_JMP_HSH(b_head->hash);
1750
+ if (state->b_head != NULL)
1751
+ instr.jt = _BPF_JMP_HSH(state->b_head->hash);
1400
1752
  else
1401
1753
  instr.jt = _BPF_JMP_HSH(state->def_hsh);
1402
1754
  blk_cnt++;
1403
1755
  } else
1404
1756
  /* we should never get here */
1405
1757
  goto arch_failure;
1406
- b_new = _blk_append(state, b_new, &instr);
1407
- if (b_new == NULL)
1408
- goto arch_failure;
1409
- b_new->next = b_head;
1410
- if (b_head != NULL)
1411
- b_head->prev = b_new;
1412
- b_head = b_new;
1413
- rc = _hsh_add(state, &b_head, 1);
1758
+
1759
+ rc = _gen_bpf_insert(state, &instr, &state->b_new,
1760
+ &state->b_head, state->b_new);
1414
1761
  if (rc < 0)
1415
1762
  goto arch_failure;
1416
1763
  }
@@ -1419,34 +1766,29 @@ static struct bpf_blk *_gen_bpf_arch(struct bpf_state *state,
1419
1766
  _BPF_INSTR(instr, _BPF_OP(state->arch, BPF_JMP + BPF_JEQ),
1420
1767
  _BPF_JMP_NO, _BPF_JMP_NXT(blk_cnt++),
1421
1768
  _BPF_K(state->arch, state->arch->token_bpf));
1422
- if (b_head != NULL)
1423
- instr.jt = _BPF_JMP_HSH(b_head->hash);
1769
+ if (state->b_head != NULL)
1770
+ instr.jt = _BPF_JMP_HSH(state->b_head->hash);
1424
1771
  else
1425
1772
  instr.jt = _BPF_JMP_HSH(state->def_hsh);
1426
- b_new = _blk_append(state, NULL, &instr);
1427
- if (b_new == NULL)
1428
- goto arch_failure;
1429
- b_new->next = b_head;
1430
- if (b_head != NULL)
1431
- b_head->prev = b_new;
1432
- b_head = b_new;
1433
- rc = _hsh_add(state, &b_head, 1);
1773
+
1774
+ rc = _gen_bpf_insert(state, &instr, &state->b_new, &state->b_head,
1775
+ NULL);
1434
1776
  if (rc < 0)
1435
1777
  goto arch_failure;
1436
1778
 
1437
1779
  state->arch = NULL;
1438
- return b_head;
1780
+ return state->b_head;
1439
1781
 
1440
1782
  arch_failure:
1441
1783
  /* NOTE: we do the cleanup here and not just return an error as all of
1442
1784
  * the instruction blocks may not be added to the hash table when we
1443
1785
  * hit an error */
1444
1786
  state->arch = NULL;
1445
- b_iter = b_head;
1787
+ b_iter = state->b_head;
1446
1788
  while (b_iter != NULL) {
1447
- b_new = b_iter->next;
1789
+ state->b_new = b_iter->next;
1448
1790
  _blk_free(state, b_iter);
1449
- b_iter = b_new;
1791
+ b_iter = state->b_new;
1450
1792
  }
1451
1793
  return NULL;
1452
1794
  }
@@ -1653,9 +1995,6 @@ static int _gen_bpf_build_bpf(struct bpf_state *state,
1653
1995
  struct db_filter *db_secondary = NULL;
1654
1996
  struct arch_def pseudo_arch;
1655
1997
 
1656
- if (col->filter_cnt == 0)
1657
- return -EINVAL;
1658
-
1659
1998
  /* create a fake architecture definition for use in the early stages */
1660
1999
  memset(&pseudo_arch, 0, sizeof(pseudo_arch));
1661
2000
  pseudo_arch.endian = col->endian;
@@ -1714,7 +2053,8 @@ static int _gen_bpf_build_bpf(struct bpf_state *state,
1714
2053
  db_secondary = NULL;
1715
2054
 
1716
2055
  /* create the filter for the architecture(s) */
1717
- b_new = _gen_bpf_arch(state, col->filters[iter], db_secondary);
2056
+ b_new = _gen_bpf_arch(state, col->filters[iter], db_secondary,
2057
+ col->attr.optimize);
1718
2058
  if (b_new == NULL)
1719
2059
  return -ENOMEM;
1720
2060
  b_new->prev = b_tail;
@@ -1850,6 +2190,7 @@ static int _gen_bpf_build_bpf(struct bpf_state *state,
1850
2190
  break;
1851
2191
  default:
1852
2192
  /* fatal error */
2193
+ rc = -EFAULT;
1853
2194
  goto build_bpf_free_blks;
1854
2195
  }
1855
2196
  switch (i_iter->jf.type) {
@@ -1867,6 +2208,7 @@ static int _gen_bpf_build_bpf(struct bpf_state *state,
1867
2208
  break;
1868
2209
  default:
1869
2210
  /* fatal error */
2211
+ rc = -EFAULT;
1870
2212
  goto build_bpf_free_blks;
1871
2213
  }
1872
2214
  }
@@ -1888,8 +2230,10 @@ static int _gen_bpf_build_bpf(struct bpf_state *state,
1888
2230
  jmp_len += b_jmp->blk_cnt;
1889
2231
  b_jmp = b_jmp->next;
1890
2232
  }
1891
- if (b_jmp == NULL || jmp_len > _BPF_JMP_MAX)
2233
+ if (b_jmp == NULL || jmp_len > _BPF_JMP_MAX) {
2234
+ rc = -EFAULT;
1892
2235
  goto build_bpf_free_blks;
2236
+ }
1893
2237
  i_iter->jt = _BPF_JMP_IMM(jmp_len);
1894
2238
  }
1895
2239
  if (i_iter->jf.type == TGT_PTR_HSH) {
@@ -1900,8 +2244,10 @@ static int _gen_bpf_build_bpf(struct bpf_state *state,
1900
2244
  jmp_len += b_jmp->blk_cnt;
1901
2245
  b_jmp = b_jmp->next;
1902
2246
  }
1903
- if (b_jmp == NULL || jmp_len > _BPF_JMP_MAX)
2247
+ if (b_jmp == NULL || jmp_len > _BPF_JMP_MAX) {
2248
+ rc = -EFAULT;
1904
2249
  goto build_bpf_free_blks;
2250
+ }
1905
2251
  i_iter->jf = _BPF_JMP_IMM(jmp_len);
1906
2252
  }
1907
2253
  if (i_iter->k.type == TGT_PTR_HSH) {
@@ -1915,14 +2261,17 @@ static int _gen_bpf_build_bpf(struct bpf_state *state,
1915
2261
  jmp_len += b_jmp->blk_cnt;
1916
2262
  b_jmp = b_jmp->prev;
1917
2263
  }
1918
- if (b_jmp == NULL)
2264
+ if (b_jmp == NULL) {
2265
+ rc = -EFAULT;
1919
2266
  goto build_bpf_free_blks;
2267
+ }
1920
2268
  i_iter->k = _BPF_K(state->arch, jmp_len);
1921
2269
  }
1922
2270
  }
1923
2271
 
1924
2272
  /* build the bpf program */
1925
- if (_bpf_append_blk(state->bpf, b_iter) < 0)
2273
+ rc = _bpf_append_blk(state->bpf, b_iter);
2274
+ if (rc < 0)
1926
2275
  goto build_bpf_free_blks;
1927
2276
 
1928
2277
  /* we're done with the block, free it */
@@ -1940,37 +2289,43 @@ build_bpf_free_blks:
1940
2289
  __blk_free(state, b_iter);
1941
2290
  b_iter = b_jmp;
1942
2291
  }
1943
- return -EFAULT;
2292
+ return rc;
1944
2293
  }
1945
2294
 
1946
2295
  /**
1947
2296
  * Generate a BPF representation of the filter DB
1948
2297
  * @param col the seccomp filter collection
2298
+ * @param prgm_ptr the bpf program pointer
1949
2299
  *
1950
2300
  * This function generates a BPF representation of the given filter collection.
1951
- * Returns a pointer to a valid bpf_program on success, NULL on failure.
2301
+ * Returns zero on success, negative values on failure.
1952
2302
  *
1953
2303
  */
1954
- struct bpf_program *gen_bpf_generate(const struct db_filter_col *col)
2304
+ int gen_bpf_generate(const struct db_filter_col *col,
2305
+ struct bpf_program **prgm_ptr)
1955
2306
  {
1956
2307
  int rc;
1957
2308
  struct bpf_state state;
1958
2309
  struct bpf_program *prgm;
1959
2310
 
2311
+ if (col->filter_cnt == 0)
2312
+ return -EINVAL;
2313
+
1960
2314
  memset(&state, 0, sizeof(state));
1961
2315
  state.attr = &col->attr;
1962
2316
 
1963
- prgm = zmalloc(sizeof(*(prgm)));
1964
- if (prgm == NULL)
1965
- return NULL;
1966
- state.bpf = prgm;
2317
+ state.bpf = zmalloc(sizeof(*(prgm)));
2318
+ if (state.bpf == NULL)
2319
+ return -ENOMEM;
1967
2320
 
1968
2321
  rc = _gen_bpf_build_bpf(&state, col);
1969
- if (rc == 0)
2322
+ if (rc == 0) {
2323
+ *prgm_ptr = state.bpf;
1970
2324
  state.bpf = NULL;
2325
+ }
1971
2326
  _state_release(&state);
1972
2327
 
1973
- return prgm;
2328
+ return rc;
1974
2329
  }
1975
2330
 
1976
2331
  /**