seccomp-ruby 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,685 @@
1
+ #include "seccomp_ext.h"
2
+ #include <errno.h>
3
+ #include <fcntl.h>
4
+ #include <ruby/thread.h>
5
+ #include <unistd.h>
6
+
7
+ struct seccomp_export_args {
8
+ scmp_filter_ctx ctx;
9
+ int fd;
10
+ int rc;
11
+ };
12
+
13
+ struct seccomp_bpf_mem_args {
14
+ scmp_filter_ctx ctx;
15
+ void *buffer;
16
+ size_t length;
17
+ size_t capacity;
18
+ int rc;
19
+ };
20
+
21
+ struct seccomp_precompute_args {
22
+ scmp_filter_ctx ctx;
23
+ int rc;
24
+ };
25
+
26
+ struct seccomp_load_args {
27
+ scmp_filter_ctx ctx;
28
+ int rc;
29
+ };
30
+
31
+ static int seccomp_ext_any_filter_loaded;
32
+
33
+ static void *
34
+ seccomp_ext_load_without_gvl(void *pointer)
35
+ {
36
+ struct seccomp_load_args *args = pointer;
37
+
38
+ args->rc = seccomp_load(args->ctx);
39
+ return NULL;
40
+ }
41
+
42
+ static void *
43
+ seccomp_ext_export_pfc_without_gvl(void *pointer)
44
+ {
45
+ struct seccomp_export_args *args = pointer;
46
+
47
+ args->rc = seccomp_export_pfc(args->ctx, args->fd);
48
+ return NULL;
49
+ }
50
+
51
+ static void *
52
+ seccomp_ext_export_bpf_without_gvl(void *pointer)
53
+ {
54
+ struct seccomp_export_args *args = pointer;
55
+
56
+ args->rc = seccomp_export_bpf(args->ctx, args->fd);
57
+ return NULL;
58
+ }
59
+
60
+ #ifdef HAVE_SECCOMP_EXPORT_BPF_MEM
61
+ static void *
62
+ seccomp_ext_export_bpf_mem_without_gvl(void *pointer)
63
+ {
64
+ struct seccomp_bpf_mem_args *args = pointer;
65
+
66
+ args->rc = seccomp_export_bpf_mem(args->ctx, args->buffer, &args->length);
67
+ return NULL;
68
+ }
69
+
70
+ static VALUE
71
+ seccomp_ext_export_bpf_mem_free(VALUE pointer)
72
+ {
73
+ struct seccomp_bpf_mem_args *args = (struct seccomp_bpf_mem_args *)pointer;
74
+
75
+ xfree(args->buffer);
76
+ args->buffer = NULL;
77
+ return Qnil;
78
+ }
79
+
80
+ static VALUE
81
+ seccomp_ext_export_bpf_mem_call(VALUE pointer)
82
+ {
83
+ struct seccomp_bpf_mem_args *args = (struct seccomp_bpf_mem_args *)pointer;
84
+ VALUE result;
85
+
86
+ rb_thread_call_without_gvl(seccomp_ext_export_bpf_mem_without_gvl,
87
+ args, RUBY_UBF_IO, NULL);
88
+ if (args->rc < 0)
89
+ return rb_ary_new_from_args(2, INT2NUM(args->rc), Qnil);
90
+ if (args->length > args->capacity)
91
+ return rb_ary_new_from_args(2, INT2NUM(-ERANGE), Qnil);
92
+ result = rb_str_new(args->buffer, args->length);
93
+ return rb_ary_new_from_args(2, INT2NUM(0), result);
94
+ }
95
+ #endif
96
+
97
+ #ifdef HAVE_SECCOMP_PRECOMPUTE
98
+ static void *
99
+ seccomp_ext_precompute_without_gvl(void *pointer)
100
+ {
101
+ struct seccomp_precompute_args *args = pointer;
102
+
103
+ args->rc = seccomp_precompute(args->ctx);
104
+ return NULL;
105
+ }
106
+ #endif
107
+
108
+ static void
109
+ seccomp_ext_filter_close_notify_fd(seccomp_filter_t *filter)
110
+ {
111
+ scmp_filter_ctx probe;
112
+ unsigned int api_level;
113
+
114
+ if (filter->notify_fd < 0)
115
+ return;
116
+
117
+ /* A global reset clears feature flags and the syscall number, but not the API cache. */
118
+ api_level = seccomp_api_get();
119
+ seccomp_reset(NULL, SCMP_ACT_ALLOW);
120
+ /* Reprobe the syscall number before restoring the cached feature flags. */
121
+ probe = seccomp_init(SCMP_ACT_NOTIFY);
122
+ if (probe != NULL) {
123
+ seccomp_release(probe);
124
+ seccomp_api_set(api_level);
125
+ }
126
+ filter->notify_fd = -1;
127
+ }
128
+
129
+ static void
130
+ seccomp_filter_free(void *pointer)
131
+ {
132
+ seccomp_filter_t *filter = pointer;
133
+
134
+ seccomp_ext_filter_close_notify_fd(filter);
135
+ if (filter->ctx != NULL) {
136
+ seccomp_release(filter->ctx);
137
+ filter->ctx = NULL;
138
+ }
139
+ xfree(filter);
140
+ }
141
+
142
+ static size_t
143
+ seccomp_filter_memsize(const void *pointer)
144
+ {
145
+ return pointer == NULL ? 0 : sizeof(seccomp_filter_t);
146
+ }
147
+
148
+ const rb_data_type_t seccomp_filter_type = {
149
+ .wrap_struct_name = "Seccomp::LowLevel::Context",
150
+ .function = {
151
+ .dmark = NULL,
152
+ .dfree = seccomp_filter_free,
153
+ .dsize = seccomp_filter_memsize,
154
+ },
155
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
156
+ };
157
+
158
+ seccomp_filter_t *
159
+ seccomp_ext_filter_check(VALUE object)
160
+ {
161
+ seccomp_filter_t *filter;
162
+
163
+ TypedData_Get_Struct(object, seccomp_filter_t, &seccomp_filter_type, filter);
164
+ if (filter->ctx == NULL)
165
+ rb_raise(eSeccompClosedFilterError, "filter is closed");
166
+ return filter;
167
+ }
168
+
169
+ static VALUE
170
+ seccomp_ext_filter_init(VALUE self, VALUE action)
171
+ {
172
+ seccomp_filter_t *filter;
173
+ uint32_t action_value = seccomp_ext_num_to_uint32(action, "action");
174
+ VALUE object;
175
+
176
+ (void)self;
177
+ object = TypedData_Make_Struct(cSeccompContext, seccomp_filter_t,
178
+ &seccomp_filter_type, filter);
179
+ filter->ctx = seccomp_init(action_value);
180
+ filter->loaded = 0;
181
+ filter->notify_fd = -1;
182
+ filter->in_transaction = 0;
183
+ filter->has_notification = action_value == SCMP_ACT_NOTIFY;
184
+ filter->notification_used = filter->has_notification;
185
+ filter->transaction_has_notification = 0;
186
+ if (filter->ctx == NULL)
187
+ rb_raise(rb_path2class("Seccomp::OutOfMemoryError"), "seccomp_init failed");
188
+ return object;
189
+ }
190
+
191
+ static VALUE
192
+ seccomp_ext_filter_release(VALUE self, VALUE object)
193
+ {
194
+ seccomp_filter_t *filter;
195
+
196
+ (void)self;
197
+ TypedData_Get_Struct(object, seccomp_filter_t, &seccomp_filter_type, filter);
198
+ seccomp_ext_filter_close_notify_fd(filter);
199
+ if (filter->ctx != NULL) {
200
+ seccomp_release(filter->ctx);
201
+ filter->ctx = NULL;
202
+ }
203
+ return Qnil;
204
+ }
205
+
206
+ static VALUE
207
+ seccomp_ext_filter_closed(VALUE self, VALUE object)
208
+ {
209
+ seccomp_filter_t *filter;
210
+
211
+ (void)self;
212
+ TypedData_Get_Struct(object, seccomp_filter_t, &seccomp_filter_type, filter);
213
+ return filter->ctx == NULL ? Qtrue : Qfalse;
214
+ }
215
+
216
+ static VALUE
217
+ seccomp_ext_filter_reset(VALUE self, VALUE object, VALUE action)
218
+ {
219
+ seccomp_filter_t *filter = seccomp_ext_filter_check(object);
220
+ uint32_t action_value = seccomp_ext_num_to_uint32(action, "action");
221
+ int rc;
222
+
223
+ (void)self;
224
+ rc = seccomp_reset(filter->ctx, action_value);
225
+ if (rc == 0) {
226
+ filter->in_transaction = 0;
227
+ filter->has_notification = action_value == SCMP_ACT_NOTIFY;
228
+ filter->notification_used = filter->has_notification;
229
+ }
230
+ return INT2NUM(rc);
231
+ }
232
+
233
+ static int
234
+ seccomp_ext_filter_merge_reverse(scmp_filter_ctx destination, scmp_filter_ctx source)
235
+ {
236
+ /* Preserve destination-only attributes while working around lost NOTIFY state in 2.5/2.6. */
237
+ static const enum scmp_filter_attr attributes[] = {
238
+ SCMP_FLTATR_ACT_BADARCH,
239
+ SCMP_FLTATR_API_TSKIP,
240
+ SCMP_FLTATR_CTL_LOG,
241
+ SCMP_FLTATR_CTL_SSB,
242
+ #ifdef HAVE_CONST_SCMP_FLTATR_CTL_OPTIMIZE
243
+ SCMP_FLTATR_CTL_OPTIMIZE,
244
+ #endif
245
+ #ifdef HAVE_CONST_SCMP_FLTATR_API_SYSRAWRC
246
+ SCMP_FLTATR_API_SYSRAWRC,
247
+ #endif
248
+ #ifdef HAVE_CONST_SCMP_FLTATR_CTL_WAITKILL
249
+ SCMP_FLTATR_CTL_WAITKILL,
250
+ #endif
251
+ };
252
+ uint32_t destination_values[sizeof(attributes) / sizeof(attributes[0])];
253
+ uint32_t source_values[sizeof(attributes) / sizeof(attributes[0])];
254
+ size_t index;
255
+ int merge_rc;
256
+ int rc;
257
+
258
+ for (index = 0; index < sizeof(attributes) / sizeof(attributes[0]); index++) {
259
+ rc = seccomp_attr_get(destination, attributes[index], &destination_values[index]);
260
+ if (rc < 0)
261
+ return rc;
262
+ rc = seccomp_attr_get(source, attributes[index], &source_values[index]);
263
+ if (rc < 0)
264
+ return rc;
265
+ }
266
+
267
+ for (index = 0; index < sizeof(attributes) / sizeof(attributes[0]); index++) {
268
+ if (destination_values[index] == source_values[index])
269
+ continue;
270
+ rc = seccomp_attr_set(source, attributes[index], destination_values[index]);
271
+ if (rc < 0)
272
+ goto restore;
273
+ }
274
+
275
+ merge_rc = seccomp_merge(source, destination);
276
+ if (merge_rc == 0)
277
+ return 0;
278
+ rc = merge_rc;
279
+
280
+ restore:
281
+ while (index > 0) {
282
+ index--;
283
+ if (destination_values[index] != source_values[index])
284
+ (void)seccomp_attr_set(source, attributes[index], source_values[index]);
285
+ }
286
+ return rc;
287
+ }
288
+
289
+ static VALUE
290
+ seccomp_ext_filter_merge(VALUE self, VALUE destination, VALUE source)
291
+ {
292
+ seccomp_filter_t *dst = seccomp_ext_filter_check(destination);
293
+ seccomp_filter_t *src = seccomp_ext_filter_check(source);
294
+ int reverse;
295
+ int rc;
296
+
297
+ (void)self;
298
+ if (dst == src)
299
+ return INT2NUM(-EINVAL);
300
+ if (dst->in_transaction || src->in_transaction)
301
+ return INT2NUM(-EINVAL);
302
+ reverse = !dst->notification_used && src->notification_used;
303
+ rc = reverse ? seccomp_ext_filter_merge_reverse(dst->ctx, src->ctx)
304
+ : seccomp_merge(dst->ctx, src->ctx);
305
+ if (rc == 0) {
306
+ if (reverse)
307
+ dst->ctx = src->ctx;
308
+ dst->loaded = dst->loaded || src->loaded;
309
+ dst->has_notification = dst->has_notification || src->has_notification;
310
+ dst->notification_used = dst->notification_used || src->notification_used;
311
+ if (src->notify_fd >= 0) {
312
+ if (dst->notify_fd < 0)
313
+ dst->notify_fd = src->notify_fd;
314
+ src->notify_fd = -1;
315
+ }
316
+ src->loaded = 0;
317
+ src->in_transaction = 0;
318
+ src->has_notification = 0;
319
+ src->notification_used = 0;
320
+ src->ctx = NULL;
321
+ }
322
+ return INT2NUM(rc);
323
+ }
324
+
325
+ static VALUE
326
+ seccomp_ext_filter_attr_get(VALUE self, VALUE object, VALUE attribute)
327
+ {
328
+ seccomp_filter_t *filter = seccomp_ext_filter_check(object);
329
+ uint32_t value = 0;
330
+ int rc;
331
+
332
+ (void)self;
333
+ rc = seccomp_attr_get(filter->ctx,
334
+ (enum scmp_filter_attr)seccomp_ext_num_to_uint32(attribute, "attribute"),
335
+ &value);
336
+ return rb_ary_new_from_args(2, INT2NUM(rc), seccomp_ext_uint32(value));
337
+ }
338
+
339
+ static VALUE
340
+ seccomp_ext_filter_attr_set(VALUE self, VALUE object, VALUE attribute, VALUE value)
341
+ {
342
+ seccomp_filter_t *filter = seccomp_ext_filter_check(object);
343
+ int rc;
344
+
345
+ (void)self;
346
+ rc = seccomp_attr_set(filter->ctx,
347
+ (enum scmp_filter_attr)seccomp_ext_num_to_uint32(attribute, "attribute"),
348
+ seccomp_ext_num_to_uint32(value, "value"));
349
+ return INT2NUM(rc);
350
+ }
351
+
352
+ static VALUE
353
+ seccomp_ext_filter_arch_add(VALUE self, VALUE object, VALUE arch)
354
+ {
355
+ seccomp_filter_t *filter = seccomp_ext_filter_check(object);
356
+
357
+ (void)self;
358
+ return INT2NUM(seccomp_arch_add(filter->ctx, seccomp_ext_num_to_uint32(arch, "arch")));
359
+ }
360
+
361
+ static VALUE
362
+ seccomp_ext_filter_arch_remove(VALUE self, VALUE object, VALUE arch)
363
+ {
364
+ seccomp_filter_t *filter = seccomp_ext_filter_check(object);
365
+
366
+ (void)self;
367
+ return INT2NUM(seccomp_arch_remove(filter->ctx, seccomp_ext_num_to_uint32(arch, "arch")));
368
+ }
369
+
370
+ static VALUE
371
+ seccomp_ext_filter_arch_exist(VALUE self, VALUE object, VALUE arch)
372
+ {
373
+ seccomp_filter_t *filter = seccomp_ext_filter_check(object);
374
+
375
+ (void)self;
376
+ return INT2NUM(seccomp_arch_exist(filter->ctx, seccomp_ext_num_to_uint32(arch, "arch")));
377
+ }
378
+
379
+ static void
380
+ seccomp_ext_filter_comparisons(VALUE comparisons, struct scmp_arg_cmp *result,
381
+ unsigned int *count)
382
+ {
383
+ long length;
384
+ long index;
385
+
386
+ Check_Type(comparisons, T_ARRAY);
387
+ length = RARRAY_LEN(comparisons);
388
+ if (length > 6)
389
+ rb_raise(rb_eArgError, "at most 6 argument comparisons are allowed");
390
+ *count = (unsigned int)length;
391
+ for (index = 0; index < length; index++) {
392
+ VALUE item = rb_ary_entry(comparisons, index);
393
+ uint32_t arg;
394
+ uint32_t op;
395
+
396
+ Check_Type(item, T_ARRAY);
397
+ if (RARRAY_LEN(item) != 4)
398
+ rb_raise(rb_eArgError, "comparison must contain arg, op, datum_a, datum_b");
399
+ arg = seccomp_ext_num_to_uint32(rb_ary_entry(item, 0), "comparison arg");
400
+ op = seccomp_ext_num_to_uint32(rb_ary_entry(item, 1), "comparison op");
401
+ if (arg > 5 || op < SCMP_CMP_NE || op > SCMP_CMP_MASKED_EQ)
402
+ rb_raise(rb_eArgError, "invalid argument comparison");
403
+ result[index].arg = arg;
404
+ result[index].op = (enum scmp_compare)op;
405
+ result[index].datum_a = seccomp_ext_num_to_uint64(rb_ary_entry(item, 2), "datum_a");
406
+ result[index].datum_b = seccomp_ext_num_to_uint64(rb_ary_entry(item, 3), "datum_b");
407
+ }
408
+ }
409
+
410
+ static VALUE
411
+ seccomp_ext_filter_rule_add_common(VALUE object, VALUE action, VALUE syscall,
412
+ VALUE comparisons, int exact)
413
+ {
414
+ seccomp_filter_t *filter = seccomp_ext_filter_check(object);
415
+ struct scmp_arg_cmp args[6];
416
+ unsigned int count;
417
+ uint32_t action_value = seccomp_ext_num_to_uint32(action, "action");
418
+ int rc;
419
+
420
+ seccomp_ext_filter_comparisons(comparisons, args, &count);
421
+ if (exact) {
422
+ rc = seccomp_rule_add_exact_array(filter->ctx,
423
+ action_value,
424
+ seccomp_ext_num_to_int(syscall, "syscall"), count, args);
425
+ } else {
426
+ rc = seccomp_rule_add_array(filter->ctx,
427
+ action_value,
428
+ seccomp_ext_num_to_int(syscall, "syscall"), count, args);
429
+ }
430
+ if (rc == 0 && action_value == SCMP_ACT_NOTIFY) {
431
+ filter->has_notification = 1;
432
+ filter->notification_used = 1;
433
+ }
434
+ return INT2NUM(rc);
435
+ }
436
+
437
+ static VALUE
438
+ seccomp_ext_filter_rule_add_array(VALUE self, VALUE object, VALUE action,
439
+ VALUE syscall, VALUE comparisons)
440
+ {
441
+ (void)self;
442
+ return seccomp_ext_filter_rule_add_common(object, action, syscall, comparisons, 0);
443
+ }
444
+
445
+ static VALUE
446
+ seccomp_ext_filter_rule_add_exact_array(VALUE self, VALUE object, VALUE action,
447
+ VALUE syscall, VALUE comparisons)
448
+ {
449
+ (void)self;
450
+ return seccomp_ext_filter_rule_add_common(object, action, syscall, comparisons, 1);
451
+ }
452
+
453
+ static VALUE
454
+ seccomp_ext_filter_priority(VALUE self, VALUE object, VALUE syscall, VALUE priority)
455
+ {
456
+ seccomp_filter_t *filter = seccomp_ext_filter_check(object);
457
+ uint32_t value = seccomp_ext_num_to_uint32(priority, "priority");
458
+
459
+ (void)self;
460
+ if (value > UINT8_MAX)
461
+ rb_raise(rb_eRangeError, "priority must be between 0 and 255");
462
+ return INT2NUM(seccomp_syscall_priority(filter->ctx,
463
+ seccomp_ext_num_to_int(syscall, "syscall"),
464
+ (uint8_t)value));
465
+ }
466
+
467
+ static VALUE
468
+ seccomp_ext_filter_export_pfc(VALUE self, VALUE object, VALUE fd)
469
+ {
470
+ seccomp_filter_t *filter = seccomp_ext_filter_check(object);
471
+ struct seccomp_export_args args = {
472
+ .ctx = filter->ctx,
473
+ .fd = seccomp_ext_num_to_int(fd, "fd"),
474
+ .rc = 0,
475
+ };
476
+
477
+ (void)self;
478
+ rb_thread_call_without_gvl(seccomp_ext_export_pfc_without_gvl, &args, RUBY_UBF_IO, NULL);
479
+ return INT2NUM(args.rc);
480
+ }
481
+
482
+ static VALUE
483
+ seccomp_ext_filter_export_bpf(VALUE self, VALUE object, VALUE fd)
484
+ {
485
+ seccomp_filter_t *filter = seccomp_ext_filter_check(object);
486
+ struct seccomp_export_args args = {
487
+ .ctx = filter->ctx,
488
+ .fd = seccomp_ext_num_to_int(fd, "fd"),
489
+ .rc = 0,
490
+ };
491
+
492
+ (void)self;
493
+ rb_thread_call_without_gvl(seccomp_ext_export_bpf_without_gvl, &args, RUBY_UBF_IO, NULL);
494
+ return INT2NUM(args.rc);
495
+ }
496
+
497
+ static VALUE
498
+ seccomp_ext_filter_export_bpf_mem(VALUE self, VALUE object)
499
+ {
500
+ seccomp_filter_t *filter = seccomp_ext_filter_check(object);
501
+
502
+ #ifdef HAVE_SECCOMP_EXPORT_BPF_MEM
503
+ struct seccomp_bpf_mem_args args = {
504
+ .ctx = filter->ctx,
505
+ .buffer = NULL,
506
+ .length = 0,
507
+ .capacity = 0,
508
+ .rc = 0,
509
+ };
510
+
511
+ (void)self;
512
+ rb_thread_call_without_gvl(seccomp_ext_export_bpf_mem_without_gvl, &args, RUBY_UBF_IO, NULL);
513
+ if (args.rc < 0)
514
+ return rb_ary_new_from_args(2, INT2NUM(args.rc), Qnil);
515
+ args.capacity = args.length;
516
+ args.buffer = xmalloc(args.capacity);
517
+ return rb_ensure(seccomp_ext_export_bpf_mem_call, (VALUE)&args,
518
+ seccomp_ext_export_bpf_mem_free, (VALUE)&args);
519
+ #else
520
+ (void)self;
521
+ (void)filter;
522
+ rb_raise(rb_path2class("Seccomp::NotSupportedError"),
523
+ "seccomp_export_bpf_mem is not available in this libseccomp build");
524
+ #endif
525
+ }
526
+
527
+ static VALUE
528
+ seccomp_ext_filter_precompute(VALUE self, VALUE object)
529
+ {
530
+ seccomp_filter_t *filter = seccomp_ext_filter_check(object);
531
+
532
+ #ifdef HAVE_SECCOMP_PRECOMPUTE
533
+ struct seccomp_precompute_args args = {.ctx = filter->ctx, .rc = 0};
534
+
535
+ (void)self;
536
+ rb_thread_call_without_gvl(seccomp_ext_precompute_without_gvl, &args, RUBY_UBF_IO, NULL);
537
+ return INT2NUM(args.rc);
538
+ #else
539
+ (void)self;
540
+ (void)filter;
541
+ rb_raise(rb_path2class("Seccomp::NotSupportedError"),
542
+ "seccomp_precompute is not available in this libseccomp build");
543
+ #endif
544
+ }
545
+
546
+ static VALUE
547
+ seccomp_ext_filter_load(VALUE self, VALUE object)
548
+ {
549
+ seccomp_filter_t *filter = seccomp_ext_filter_check(object);
550
+ struct seccomp_load_args args = {.ctx = filter->ctx, .rc = 0};
551
+ int notify_fd_before;
552
+ int notify_fd_after;
553
+ int reserved_fd = -1;
554
+
555
+ (void)self;
556
+ /* libseccomp retains notification state after rejecting a transaction. */
557
+ if (filter->notification_used && !filter->has_notification)
558
+ return INT2NUM(-EOPNOTSUPP);
559
+ if (filter->notification_used && fcntl(STDIN_FILENO, F_GETFD) < 0 && errno == EBADF)
560
+ reserved_fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
561
+ notify_fd_before = seccomp_notify_fd(filter->ctx);
562
+ rb_thread_call_without_gvl(seccomp_ext_load_without_gvl, &args, RUBY_UBF_IO, NULL);
563
+ if (args.rc == 0) {
564
+ filter->loaded = 1;
565
+ seccomp_ext_any_filter_loaded = 1;
566
+ notify_fd_after = seccomp_notify_fd(filter->ctx);
567
+ if (notify_fd_after >= 0 && notify_fd_after != notify_fd_before) {
568
+ filter->notify_fd = notify_fd_after;
569
+ }
570
+ }
571
+ /* After any successful load, close(2) may already be filtered. */
572
+ if (reserved_fd >= 0 && args.rc < 0 && !seccomp_ext_any_filter_loaded)
573
+ close(reserved_fd);
574
+ return INT2NUM(args.rc);
575
+ }
576
+
577
+ static VALUE
578
+ seccomp_ext_filter_loaded(VALUE self, VALUE object)
579
+ {
580
+ seccomp_filter_t *filter = seccomp_ext_filter_check(object);
581
+
582
+ (void)self;
583
+ return filter->loaded ? Qtrue : Qfalse;
584
+ }
585
+
586
+ static VALUE
587
+ seccomp_ext_filter_transaction_start(VALUE self, VALUE object)
588
+ {
589
+ seccomp_filter_t *filter = seccomp_ext_filter_check(object);
590
+
591
+ #ifdef HAVE_SECCOMP_TRANSACTION_START
592
+ int rc;
593
+
594
+ (void)self;
595
+ rc = seccomp_transaction_start(filter->ctx);
596
+ if (rc == 0) {
597
+ filter->in_transaction = 1;
598
+ filter->transaction_has_notification = filter->has_notification;
599
+ }
600
+ return INT2NUM(rc);
601
+ #else
602
+ (void)self;
603
+ (void)filter;
604
+ rb_raise(rb_path2class("Seccomp::NotSupportedError"), "transactions unavailable");
605
+ #endif
606
+ }
607
+
608
+ static VALUE
609
+ seccomp_ext_filter_transaction_commit(VALUE self, VALUE object)
610
+ {
611
+ seccomp_filter_t *filter = seccomp_ext_filter_check(object);
612
+
613
+ #ifdef HAVE_SECCOMP_TRANSACTION_COMMIT
614
+ int rc;
615
+
616
+ (void)self;
617
+ rc = seccomp_transaction_commit(filter->ctx);
618
+ if (rc == 0)
619
+ filter->in_transaction = 0;
620
+ return INT2NUM(rc);
621
+ #else
622
+ (void)self;
623
+ (void)filter;
624
+ rb_raise(rb_path2class("Seccomp::NotSupportedError"), "transactions unavailable");
625
+ #endif
626
+ }
627
+
628
+ static VALUE
629
+ seccomp_ext_filter_transaction_reject(VALUE self, VALUE object)
630
+ {
631
+ seccomp_filter_t *filter = seccomp_ext_filter_check(object);
632
+
633
+ #ifdef HAVE_SECCOMP_TRANSACTION_REJECT
634
+ (void)self;
635
+ seccomp_transaction_reject(filter->ctx);
636
+ if (filter->in_transaction)
637
+ filter->has_notification = filter->transaction_has_notification;
638
+ filter->in_transaction = 0;
639
+ return INT2NUM(0);
640
+ #else
641
+ (void)self;
642
+ (void)filter;
643
+ rb_raise(rb_path2class("Seccomp::NotSupportedError"), "transactions unavailable");
644
+ #endif
645
+ }
646
+
647
+ void
648
+ seccomp_ext_init_filter(void)
649
+ {
650
+ cSeccompContext = rb_define_class_under(mSeccompLowLevel, "Context", rb_cObject);
651
+ rb_undef_alloc_func(cSeccompContext);
652
+
653
+ rb_define_singleton_method(mSeccompLowLevel, "init", seccomp_ext_filter_init, 1);
654
+ rb_define_singleton_method(mSeccompLowLevel, "release", seccomp_ext_filter_release, 1);
655
+ rb_define_singleton_method(mSeccompLowLevel, "closed?", seccomp_ext_filter_closed, 1);
656
+ rb_define_singleton_method(mSeccompLowLevel, "reset", seccomp_ext_filter_reset, 2);
657
+ rb_define_singleton_method(mSeccompLowLevel, "merge", seccomp_ext_filter_merge, 2);
658
+ rb_define_singleton_method(mSeccompLowLevel, "attr_get", seccomp_ext_filter_attr_get, 2);
659
+ rb_define_singleton_method(mSeccompLowLevel, "attr_set", seccomp_ext_filter_attr_set, 3);
660
+ rb_define_singleton_method(mSeccompLowLevel, "arch_add", seccomp_ext_filter_arch_add, 2);
661
+ rb_define_singleton_method(mSeccompLowLevel, "arch_remove", seccomp_ext_filter_arch_remove, 2);
662
+ rb_define_singleton_method(mSeccompLowLevel, "arch_exist", seccomp_ext_filter_arch_exist, 2);
663
+ rb_define_singleton_method(mSeccompLowLevel, "rule_add_array",
664
+ seccomp_ext_filter_rule_add_array, 4);
665
+ rb_define_singleton_method(mSeccompLowLevel, "rule_add_exact_array",
666
+ seccomp_ext_filter_rule_add_exact_array, 4);
667
+ rb_define_singleton_method(mSeccompLowLevel, "syscall_priority",
668
+ seccomp_ext_filter_priority, 3);
669
+ rb_define_singleton_method(mSeccompLowLevel, "export_pfc",
670
+ seccomp_ext_filter_export_pfc, 2);
671
+ rb_define_singleton_method(mSeccompLowLevel, "export_bpf",
672
+ seccomp_ext_filter_export_bpf, 2);
673
+ rb_define_singleton_method(mSeccompLowLevel, "export_bpf_mem",
674
+ seccomp_ext_filter_export_bpf_mem, 1);
675
+ rb_define_singleton_method(mSeccompLowLevel, "precompute",
676
+ seccomp_ext_filter_precompute, 1);
677
+ rb_define_singleton_method(mSeccompLowLevel, "load", seccomp_ext_filter_load, 1);
678
+ rb_define_singleton_method(mSeccompLowLevel, "loaded?", seccomp_ext_filter_loaded, 1);
679
+ rb_define_singleton_method(mSeccompLowLevel, "transaction_start",
680
+ seccomp_ext_filter_transaction_start, 1);
681
+ rb_define_singleton_method(mSeccompLowLevel, "transaction_commit",
682
+ seccomp_ext_filter_transaction_commit, 1);
683
+ rb_define_singleton_method(mSeccompLowLevel, "transaction_reject",
684
+ seccomp_ext_filter_transaction_reject, 1);
685
+ }