aboutgitcodelistschat:MatrixIRC
diff options
context:
space:
mode:
-rw-r--r--common/gluten.h26
-rw-r--r--common/util.c2
-rw-r--r--cooker/call.c41
-rw-r--r--cooker/calls/fs.c63
-rw-r--r--cooker/cooker.h1
-rw-r--r--cooker/emit.c56
-rw-r--r--cooker/emit.h9
-rw-r--r--cooker/match.c44
-rw-r--r--demo/mknod.hjson33
-rw-r--r--operations.c35
-rw-r--r--operations.h2
11 files changed, 225 insertions, 87 deletions
diff --git a/common/gluten.h b/common/gluten.h
index 2f82509..101b92e 100644
--- a/common/gluten.h
+++ b/common/gluten.h
@@ -45,6 +45,8 @@ enum gluten_offset_type {
OFFSET_TYPE_MAX = OFFSET_INSTRUCTION,
};
+#define NULL_OFFSET ((struct gluten_offset){ .type = OFFSET_NULL })
+
extern const char *gluten_offset_name[OFFSET_TYPE_MAX + 1];
struct gluten_offset {
@@ -66,7 +68,7 @@ enum op_type {
OP_FD,
OP_RETURN,
OP_LOAD,
- OP_MASK,
+ OP_BITWISE,
OP_CMP,
OP_RESOLVEDFD,
};
@@ -210,15 +212,24 @@ struct op_cmp {
struct gluten_offset desc; /* struct cmp_desc */
};
-struct mask_desc {
+enum bitwise_type {
+ BITWISE_AND,
+ BITWISE_OR,
+ BITWISE_MAX = BITWISE_OR,
+};
+
+extern const char *bitwise_type_str[BITWISE_MAX + 1];
+
+struct bitwise_desc {
size_t size;
+ enum bitwise_type type;
struct gluten_offset dst;
- struct gluten_offset src;
- struct gluten_offset mask;
+ struct gluten_offset x;
+ struct gluten_offset y;
};
-struct op_mask {
- struct gluten_offset desc; /* struct mask_desc */
+struct op_bitwise {
+ struct gluten_offset desc; /* struct bitwise_desc */
};
struct resolvefd_desc {
@@ -246,7 +257,7 @@ struct op {
struct op_return ret;
struct op_fd fd;
struct op_load load;
- struct op_mask mask;
+ struct op_bitwise bitwise;
struct op_cmp cmp;
struct op_resolvefd resfd;
struct op_copy copy;
@@ -352,6 +363,7 @@ static inline int gluten_write(struct gluten *g, struct gluten_offset dst,
const void *src, size_t size)
{
void *p = gluten_write_ptr(g, dst);
+
if (p == NULL || !check_gluten_limits(dst, size))
return -1;
memcpy(p, src, size);
diff --git a/common/util.c b/common/util.c
index 4cb7b7a..a03b73e 100644
--- a/common/util.c
+++ b/common/util.c
@@ -37,3 +37,5 @@ const char *gluten_offset_name[OFFSET_TYPE_MAX + 1] = {
const char *ns_type_name[NS_TYPE_MAX + 1] = {
"mnt", "cgroup", "uts", "ipc", "user", "pid", "net", "time",
};
+
+const char *bitwise_type_str[BITWISE_MAX + 1] = { "&", "|" };
diff --git a/cooker/call.c b/cooker/call.c
index 7aef157..7ae3d48 100644
--- a/cooker/call.c
+++ b/cooker/call.c
@@ -113,10 +113,14 @@ static union value parse_field(struct gluten_ctx *g, struct arg *args,
if (tag_offset.type == OFFSET_NULL)
die(" tag not found");
- if (base_offset->type == OFFSET_NULL)
+ if (base_offset->type == OFFSET_NULL) {
*base_offset = tag_offset;
- else
+ } else if (f->flags & MASK || add) {
+ emit_bitwise(g, f->type, BITWISE_OR, offset,
+ offset, tag_offset);
+ } else {
emit_copy_field(g, f, offset, tag_offset);
+ }
}
if (json_object_get_count(tmp2) > count)
@@ -252,9 +256,10 @@ bool arg_needs_temp(struct field *f, int pos, JSON_Value *jvalue,
case INT:
case LONG:
case U32:
+ return false;
case GNU_DEV_MAJOR:
case GNU_DEV_MINOR:
- return false;
+ return true;
case SELECT:
f_inner = f->desc.d_select->field;
if (arg_needs_temp(f_inner, pos, jvalue, top_level_tag, level))
@@ -300,7 +305,7 @@ bool arg_needs_temp(struct field *f, int pos, JSON_Value *jvalue,
}
static struct gluten_offset parse_arg(struct gluten_ctx *g, struct arg *args,
- struct arg *a,
+ struct arg *a, bool multi_field,
struct gluten_offset offset,
JSON_Value *jvalue)
{
@@ -314,10 +319,15 @@ static struct gluten_offset parse_arg(struct gluten_ctx *g, struct arg *args,
return offset;
}
- if (arg_needs_temp(&a->f, a->pos, jvalue, &top_level_tag, 0))
- offset = gluten_rw_alloc(g, a->f.size);
- else if (a->f.size && !top_level_tag)
+ if (arg_needs_temp(&a->f, a->pos, jvalue, &top_level_tag, 0) ||
+ multi_field) {
+ if (a->f.size)
+ offset = gluten_rw_alloc(g, a->f.size);
+ else
+ offset = gluten_rw_alloc_type(g, a->f.type);
+ } else if ((a->f.size && !top_level_tag)) {
offset = gluten_ro_alloc(g, a->f.size);
+ }
parse_field(g, args, &offset, a->pos, &a->f, jvalue, false, false);
return offset;
@@ -336,6 +346,8 @@ static void parse_call(struct gluten_ctx *g, struct ns_spec *ns, long nr,
struct {
bool needs_fd;
bool has_fd;
+ bool found;
+ bool multi_field;
} arg_check[6] = { 0 };
int arg_max_pos = -1;
unsigned count = 0;
@@ -349,6 +361,10 @@ static void parse_call(struct gluten_ctx *g, struct ns_spec *ns, long nr,
a = g->selected_arg[a->pos];
}
+ if (arg_check[a->pos].found)
+ arg_check[a->pos].multi_field = true;
+ arg_check[a->pos].found = true;
+
if (a->f.type == FDPATH)
arg_check[a->pos].needs_fd = true;
@@ -362,10 +378,13 @@ static void parse_call(struct gluten_ctx *g, struct ns_spec *ns, long nr,
/* TODO: Factor this out into a function in... parse.c? */
for (a = args; a->f.name; a++) {
JSON_Value *jvalue;
+ bool multi_field;
if (a->f.type == SELECTED)
a = g->selected_arg[a->pos];
+ multi_field = arg_check[a->pos].multi_field;
+
/* Not common with parse_match(), though */
if ((jvalue = json_object_get_value(obj, a->f.name))) {
if (arg_check[a->pos].has_fd)
@@ -373,15 +392,15 @@ static void parse_call(struct gluten_ctx *g, struct ns_spec *ns, long nr,
else if (arg_check[a->pos].needs_fd)
arg_check[a->pos].has_fd = true;
- offset[a->pos] = parse_arg(g, args, a, offset[a->pos],
- jvalue);
+ offset[a->pos] = parse_arg(g, args, a, multi_field,
+ offset[a->pos], jvalue);
count++;
} else if (arg_check[a->pos].needs_fd &&
arg_check[a->pos].has_fd) {
;
} else if (a->f.flags & SIZE) {
- offset[a->pos] = parse_arg(g, args, a, offset[a->pos],
- jvalue);
+ offset[a->pos] = parse_arg(g, args, a, multi_field,
+ offset[a->pos], jvalue);
} else {
die(" No specification for argument %s", a->f.name);
}
diff --git a/cooker/calls/fs.c b/cooker/calls/fs.c
index cfc0091..469dd88 100644
--- a/cooker/calls/fs.c
+++ b/cooker/calls/fs.c
@@ -58,13 +58,44 @@ swapoff
#include <asm-generic/unistd.h>
#include <sys/syscall.h>
-#include <fcntl.h>
+#define _GNU_SOURCE
#include <sys/stat.h>
+#include <fcntl.h>
#include <linux/limits.h>
#include "../cooker.h"
#include "../calls.h"
+static struct num modes[] = {
+ { "S_ISUID", S_ISUID },
+ { "S_ISGID", S_ISGID },
+ { "S_IRWXU", S_IRWXU },
+ { "S_IRUSR", S_IRUSR },
+ { "S_IWUSR", S_IWUSR },
+ { "S_IXUSR", S_IXUSR },
+ { "S_IRWXG", S_IRWXG },
+ { "S_IRGRP", S_IRGRP },
+ { "S_IWGRP", S_IWGRP },
+ { "S_IXGRP", S_IXGRP },
+ { "S_IRWXO", S_IRWXO },
+ { "S_IROTH", S_IROTH },
+ { "S_IWOTH", S_IWOTH },
+ { "S_IXOTH", S_IXOTH },
+ { "S_ISVTX", S_ISVTX },
+ { 0 },
+};
+
+static struct num types[] = {
+ { "S_IFSOCK", S_IFSOCK },
+ { "S_IFLNK", S_IFLNK },
+ { "S_IFREG", S_IFREG },
+ { "S_IFBLK", S_IFBLK },
+ { "S_IFDIR", S_IFDIR },
+ { "S_IFCHR", S_IFCHR },
+ { "S_IFIFO", S_IFIFO },
+ { 0 },
+};
+
static struct arg mknod_args[] = {
{ 0,
{
@@ -75,9 +106,16 @@ static struct arg mknod_args[] = {
},
{ 1,
{
- "mode", U32 /* TODO */, 0,
+ "mode", INT, FLAGS | MASK,
0, 0,
- { 0 /* TODO */ },
+ { .d_num = modes },
+ }
+ },
+ { 1,
+ {
+ "type", INT, FLAGS | MASK,
+ 0, 0,
+ { .d_num = types },
}
},
{ 2,
@@ -98,13 +136,7 @@ static struct arg mknod_args[] = {
};
static struct arg mknodat_args[] = {
- { 0,
- {
- "dirfd", UNDEF, 0,
- 0, 1 /* TODO: PATH_MAX */,
- { 0 }
- }
- },
+ /* No dirfd: we only support absolute paths at the moment */
{ 1,
{
"path", STRING, 0,
@@ -114,9 +146,16 @@ static struct arg mknodat_args[] = {
},
{ 2,
{
- "mode", UNDEF /* TODO */, FLAGS,
+ "mode", INT, FLAGS | MASK,
+ 0, 0,
+ { .d_num = modes },
+ }
+ },
+ { 2,
+ {
+ "type", INT, FLAGS | MASK,
0, 0,
- { 0 /* TODO */ },
+ { .d_num = types },
}
},
{ 3,
diff --git a/cooker/cooker.h b/cooker/cooker.h
index b26ea2d..24d8f7f 100644
--- a/cooker/cooker.h
+++ b/cooker/cooker.h
@@ -18,6 +18,7 @@
#include <sys/types.h>
#include <arpa/inet.h>
+#include <common.h>
#include <util.h>
#define TAGS_MAX 256
diff --git a/cooker/emit.c b/cooker/emit.c
index 506a561..107b2ce 100644
--- a/cooker/emit.c
+++ b/cooker/emit.c
@@ -198,40 +198,49 @@ void emit_resolvefd(struct gluten_ctx *g, struct gluten_offset fd,
}
/**
- * emit_mask(): Emit OP_MASK instruction: mask and store
+ * emit_bitwise(): Emit OP_BITWISE instruction: bitwise operation and store
* @g: gluten context
* @type: Type of operands
- * @src: gluten pointer to source operand
- * @mask: gluten pointer to mask
+ * @op_type: Type of bitwise operation
+ * @dst: gluten pointer to destination operand, can be OFFSET_NULL
+ * @x: gluten pointer to first source operand
+ * @y: gluten pointer to second source operand
*
- * Return: offset to destination operand, allocated here
+ * Return: offset to destination operand, allocated here if not given
*/
-struct gluten_offset emit_mask(struct gluten_ctx *g, enum type type,
- struct gluten_offset src,
- struct gluten_offset mask)
+struct gluten_offset emit_bitwise(struct gluten_ctx *g, enum type type,
+ enum bitwise_type op_type,
+ struct gluten_offset dst,
+ struct gluten_offset x,
+ struct gluten_offset y)
{
struct op *op = (struct op *)gluten_ptr(&g->g, g->ip);
- struct op_mask *op_mask = &op->op.mask;
+ struct op_bitwise *op_bitwise = &op->op.bitwise;
struct gluten_offset o;
- struct mask_desc *desc;
+ struct bitwise_desc *desc;
- op->type = OP_MASK;
+ op->type = OP_BITWISE;
- o = gluten_ro_alloc(g, sizeof(struct mask_desc));
- desc = (struct mask_desc *)gluten_ptr(&g->g, o);
+ o = gluten_ro_alloc(g, sizeof(struct bitwise_desc));
+ desc = (struct bitwise_desc *)gluten_ptr(&g->g, o);
desc->size = gluten_size[type];
- desc->dst = gluten_rw_alloc(g, desc->size);
- desc->src = src;
- desc->mask = mask;
+ desc->type = op_type;
+ if (dst.type == OFFSET_NULL)
+ desc->dst = gluten_rw_alloc(g, desc->size);
+ else
+ desc->dst = dst;
+ desc->x = x;
+ desc->y = y;
- op_mask->desc = o;
+ op_bitwise->desc = o;
- debug(" %i: OP_MASK: %s: #%lu (size: %lu) := %s: #%lu & %s: #%lu",
+ debug(" %i: OP_BITWISE: %s: #%lu (size: %lu) := %s: #%lu %s %s: #%lu",
g->ip.offset,
- gluten_offset_name[desc->dst.type], desc->dst.offset, desc->size,
- gluten_offset_name[desc->src.type], desc->src.offset,
- gluten_offset_name[desc->mask.type], desc->mask.offset);
+ gluten_offset_name[desc->dst.type], desc->dst.offset, desc->size,
+ gluten_offset_name[desc->x.type], desc->x.offset,
+ bitwise_type_str[op_type],
+ gluten_offset_name[desc->y.type], desc->y.offset);
if (++g->ip.offset > INST_MAX)
die("Too many instructions");
@@ -537,5 +546,10 @@ void link_match(struct gluten_ctx *g)
{
debug(" Linking match...");
gluten_link(g, JUMP_NEXT_MATCH, (struct op *)gluten_ptr(&g->g, g->mr));
- gluten_link(g, JUMP_NEXT_ACTION, (struct op *)gluten_ptr(&g->g, g->mr));
+}
+
+void link_matches(struct gluten_ctx *g)
+{
+ debug(" Linking matches...");
+ gluten_link(g, JUMP_NEXT_ACTION, (struct op *)gluten_ptr(&g->g, g->lr));
}
diff --git a/cooker/emit.h b/cooker/emit.h
index 81f947e..978c9e0 100644
--- a/cooker/emit.h
+++ b/cooker/emit.h
@@ -13,10 +13,12 @@ void emit_call(struct gluten_ctx *g, struct ns_spec *ns, long nr,
struct gluten_offset offset[6], struct gluten_offset ret_offset);
void emit_load(struct gluten_ctx *g, struct gluten_offset dst,
int index, size_t len);
-struct gluten_offset emit_mask(struct gluten_ctx *g, enum type type,
- struct gluten_offset src,
- struct gluten_offset mask);
struct gluten_offset emit_seccomp_data(int index);
+struct gluten_offset emit_bitwise(struct gluten_ctx *g, enum type type,
+ enum bitwise_type op_type,
+ struct gluten_offset dst,
+ struct gluten_offset x,
+ struct gluten_offset y);
void emit_cmp(struct gluten_ctx *g, enum op_cmp_type cmp,
struct gluten_offset x, struct gluten_offset y, size_t size,
enum jump_type jmp);
@@ -43,5 +45,6 @@ struct gluten_offset emit_data_or(struct gluten_ctx *g,
enum type type, union value *value);
void link_block(struct gluten_ctx *g);
void link_match(struct gluten_ctx *g);
+void link_matches(struct gluten_ctx *g);
#endif /* EMIT_H */
diff --git a/cooker/match.c b/cooker/match.c
index 3c7650c..d32bf0a 100644
--- a/cooker/match.c
+++ b/cooker/match.c
@@ -78,7 +78,7 @@ static union value parse_field(struct gluten_ctx *g,
enum op_cmp_type cmp, enum jump_type jump,
int index, struct field *f, JSON_Value *jvalue)
{
- struct gluten_offset const_offset, mask_offset, data_offset, seccomp_offset;
+ struct gluten_offset const_offset, mask_offset, seccomp_offset;
union value v = { .v_num = 0 };
struct field *f_inner;
const char *tag_name;
@@ -90,6 +90,32 @@ static union value parse_field(struct gluten_ctx *g,
if (f->name)
debug(" parsing field name %s", f->name);
+ /* Some types need pre-tagging preparation */
+ switch (f->type) {
+ case GNU_DEV_MAJOR:
+ /*
+xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
+______________________ _____________
+ */
+ v.v_num = ((long long)0xfff << 44) | (0xfff << 8);
+ mask_offset = emit_data(g, U64, 0, &v);
+ offset = emit_bitwise(g, U64, BITWISE_AND, NULL_OFFSET,
+ offset, mask_offset);
+ break;
+ case GNU_DEV_MINOR:
+ /*
+xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
+ ____________________________ ________
+ */
+ v.v_num = 0xff | ((long long)0xffffff << 12);
+ mask_offset = emit_data(g, U64, 0, &v);
+ offset = emit_bitwise(g, U64, BITWISE_AND, NULL_OFFSET,
+ offset, mask_offset);
+ break;
+ default:
+ break;
+ }
+
if (json_value_get_type(jvalue) == JSONObject &&
(tmp = json_value_get_object(jvalue)) &&
(tag_name = json_object_get_string(tmp, "tag"))) {
@@ -153,30 +179,20 @@ static union value parse_field(struct gluten_ctx *g,
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
______________________ _____________
*/
- v.v_num = ((long long)0xfff << 44) | (0xfff << 8);
- mask_offset = emit_data(g, U64, 0, &v);
-
v.v_num = value_get_num(f->desc.d_num, jvalue);
v.v_num = (v.v_num & 0xfff) << 8 | (v.v_num & ~0xfff) << 32;
const_offset = emit_data(g, U64, 0, &v);
-
- data_offset = emit_mask(g, U64, offset, mask_offset);
- emit_cmp_field(g, cmp, f, data_offset, const_offset, jump);
+ emit_cmp_field(g, cmp, f, offset, const_offset, jump);
break;
case GNU_DEV_MINOR:
/*
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
____________________________ ________
*/
- v.v_num = 0xff | ((long long)0xffffff << 12);
- mask_offset = emit_data(g, U64, 0, &v);
-
v.v_num = value_get_num(f->desc.d_num, jvalue);
v.v_num = (v.v_num & 0xff) | (v.v_num & ~0xfff) << 12;
const_offset = emit_data(g, U64, 0, &v);
-
- data_offset = emit_mask(g, U64, offset, mask_offset);
- emit_cmp_field(g, cmp, f, data_offset, const_offset, jump);
+ emit_cmp_field(g, cmp, f, offset, const_offset, jump);
break;
case SELECT:
f_inner = f->desc.d_select->field;
@@ -329,4 +345,6 @@ void handle_matches(struct gluten_ctx *g, JSON_Value *value)
link_match(g);
}
+
+ link_matches(g);
}
diff --git a/demo/mknod.hjson b/demo/mknod.hjson
index b61fb7a..9660e0d 100644
--- a/demo/mknod.hjson
+++ b/demo/mknod.hjson
@@ -1,13 +1,34 @@
[
{
"match": [ /* Giuseppe's example */
- { "mknodat": { "path": { "tag": "path" }, "mode": 8630, "major": 1, "minor": { "value": { "in": [ 3, 5, 7, 8, 9 ] }, "tag": "minor" } } }
+ { "mknodat":
+ { "path": { "tag": "path" },
+ "mode": { "tag": "mode" },
+ "type": { "tag": "type" },
+ "major": 1,
+ "minor": { "value": { "in": [ 3, 5, 7, 8, 9 ] }, "tag": "minor" }
+ }
+ },
+ { "mknod":
+ { "path": { "tag": "path" },
+ "mode": { "tag": "mode" },
+ "type": { "tag": "type" },
+ "major": 1,
+ "minor": { "value": { "in": [ 3, 5, 7, 8, 9 ] }, "tag": "minor" }
+ }
+ }
],
- "call": {
- "mknod": { "path": { "tag": { "get": "path" } }, "mode": 8630, "major": 1, "minor": 7 /* { "tag": { "get": "minor" } }*/ },
- "ret": "x"/*,
- "context": { "user": "init", "mnt": "caller" }*/
- },
+ "call":
+ { "mknod":
+ { "path": { "tag": { "get": "path" } },
+ "mode": { "tag": { "get": "mode" } },
+ "type": { "tag": { "get": "type" } },
+ "major": 1,
+ "minor": { "tag": { "get": "minor" } }
+ },
+ "ret": "x"/*,
+ "context": { "user": "init", "mnt": "caller" }*/
+ },
"return": { "tag": "x" }
}
]
diff --git a/operations.c b/operations.c
index eefc746..120b142 100644
--- a/operations.c
+++ b/operations.c
@@ -322,11 +322,11 @@ int op_fd(const struct seccomp_notif *req, int notifier,
return 0;
}
-int op_mask(const struct seccomp_notif *req, int notifier, struct gluten *g,
- struct op_mask *op)
+int op_bitwise(const struct seccomp_notif *req, int notifier, struct gluten *g,
+ struct op_bitwise *op)
{
- const struct mask_desc *desc = gluten_ptr(&req->data, g, op->desc);
- const unsigned char *src, *mask;
+ const struct bitwise_desc *desc = gluten_ptr(&req->data, g, op->desc);
+ const unsigned char *x, *y;
unsigned char *dst;
unsigned i;
@@ -335,9 +335,9 @@ int op_mask(const struct seccomp_notif *req, int notifier, struct gluten *g,
if (!desc)
return -1;
- dst = gluten_write_ptr( g, desc->dst);
- src = gluten_ptr(&req->data, g, desc->src);
- mask = gluten_ptr(&req->data, g, desc->mask);
+ dst = gluten_write_ptr( g, desc->dst);
+ x = gluten_ptr(&req->data, g, desc->x);
+ y = gluten_ptr(&req->data, g, desc->y);
/*
if (!dst || !src || !mask ||
@@ -346,14 +346,21 @@ int op_mask(const struct seccomp_notif *req, int notifier, struct gluten *g,
!check_gluten_limits(desc->mask, desc->size))
return -1;
*/
- debug(" op_mask: dst=(%s %d) src=(%s %d) mask=(%s %d) size=%d",
- gluten_offset_name[desc->dst.type], desc->dst.offset,
- gluten_offset_name[desc->src.type], desc->src.offset,
- gluten_offset_name[desc->mask.type], desc->mask.offset,
+ debug(" op_bitwise: dst=(%s %d) := x=(%s %d) %s y=(%s %d) size=%d",
+ gluten_offset_name[desc->dst.type], desc->dst.offset,
+ gluten_offset_name[desc->x.type], desc->x.offset,
+ bitwise_type_str[desc->type],
+ gluten_offset_name[desc->y.type], desc->y.offset,
desc->size);
- for (i = 0; i < desc->size; i++)
- dst[i] = src[i] & mask[i];
+ for (i = 0; i < desc->size; i++) {
+ if (desc->type == BITWISE_AND)
+ dst[i] = x[i] & y[i];
+ else if (desc->type == BITWISE_OR)
+ dst[i] = x[i] | y[i];
+ else
+ return -1;
+ }
return 0;
}
@@ -465,7 +472,7 @@ int eval(struct gluten *g, const struct seccomp_notif *req,
HANDLE_OP(OP_RETURN, op_return, ret, g);
HANDLE_OP(OP_FD, op_fd, fd, g);
HANDLE_OP(OP_LOAD, op_load, load, g);
- HANDLE_OP(OP_MASK, op_mask, mask, g);
+ HANDLE_OP(OP_BITWISE, op_bitwise, bitwise, g);
HANDLE_OP(OP_CMP, op_cmp, cmp, g);
HANDLE_OP(OP_RESOLVEDFD, op_resolve_fd, resfd, g);
HANDLE_OP(OP_NR, op_nr, nr, g);
diff --git a/operations.h b/operations.h
index f07b86f..ec06a15 100644
--- a/operations.h
+++ b/operations.h
@@ -46,6 +46,8 @@ int op_call(const struct seccomp_notif *req, int notifier, struct gluten *g,
struct op_call *op);
int op_return(const struct seccomp_notif *req, int notifier, struct gluten *g,
struct op_return *op);
+int op_bitwise(const struct seccomp_notif *req, int notifier, struct gluten *g,
+ struct op_bitwise *op);
int op_cmp(const struct seccomp_notif *req, int notifier, struct gluten *g,
struct op_cmp *op);
int op_resolve_fd(const struct seccomp_notif *req, int notifier,