aboutgitcodelistschat:MatrixIRC
diff options
context:
space:
mode:
authorStefano Brivio <sbrivio@redhat.com>2023-06-08 20:05:18 +0200
committerStefano Brivio <sbrivio@redhat.com>2023-06-08 20:05:18 +0200
commit15b54482241083d52b6e9857a66fecbf915d467d (patch)
tree2c10f8cfb05a2e534b0a8176f9c7c1cd0b486b14
parentc38fccbc867019d6c063be1c1d8137edfe52f8de (diff)
downloadseitan-15b54482241083d52b6e9857a66fecbf915d467d.tar
seitan-15b54482241083d52b6e9857a66fecbf915d467d.tar.gz
seitan-15b54482241083d52b6e9857a66fecbf915d467d.tar.bz2
seitan-15b54482241083d52b6e9857a66fecbf915d467d.tar.lz
seitan-15b54482241083d52b6e9857a66fecbf915d467d.tar.xz
seitan-15b54482241083d52b6e9857a66fecbf915d467d.tar.zst
seitan-15b54482241083d52b6e9857a66fecbf915d467d.zip
cooker: Full support for flags and masks, assorted fixes
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
-rw-r--r--common/gluten.h2
-rw-r--r--cooker/call.c29
-rw-r--r--cooker/calls/ioctl.c2
-rw-r--r--cooker/calls/net.c8
-rw-r--r--cooker/calls/process.c20
-rw-r--r--cooker/emit.c14
-rw-r--r--cooker/example.hjson24
-rw-r--r--cooker/match.c61
-rw-r--r--cooker/parse.c60
-rw-r--r--cooker/parse.h4
-rw-r--r--demo/socket.hjson11
-rw-r--r--operations.c10
12 files changed, 193 insertions, 52 deletions
diff --git a/common/gluten.h b/common/gluten.h
index 101b92e..a90cf4a 100644
--- a/common/gluten.h
+++ b/common/gluten.h
@@ -352,7 +352,7 @@ static inline const void *gluten_ptr(const struct seccomp_data *s,
static inline bool check_gluten_limits(struct gluten_offset v, size_t size)
{
struct gluten_offset off = { v.type, v.offset + size };
- if (is_offset_valid(off))
+ if (v.type == OFFSET_SECCOMP_DATA || is_offset_valid(off))
return true;
err(" offset limits are invalid");
diff --git a/cooker/call.c b/cooker/call.c
index 7ae3d48..e2a5777 100644
--- a/cooker/call.c
+++ b/cooker/call.c
@@ -149,14 +149,19 @@ static union value parse_field(struct gluten_ctx *g, struct arg *args,
case U32:
case GNU_DEV_MAJOR:
case GNU_DEV_MINOR:
- if (f->flags == SIZE) {
+ if (json_value_get_type(jvalue) == JSONArray) {
+ JSON_Array *array = json_value_get_array(jvalue);
+ unsigned i;
+
+ if (!(f->flags & FLAGS))
+ die("multiple values for non-FLAGS argument");
+
+ for (i = 0; i < json_array_get_count(array); i++) {
+ jvalue = json_array_get_value(array, i);
+ v.v_num |= value_get_num(f->desc.d_num, jvalue);
+ }
+ } else if (f->flags == SIZE) {
v.v_num = value_get_size(g, f->desc.d_size);
- } else if (f->flags == FLAGS) {
- /* fetch/combine expr algebra loop */
- v.v_num = value_get_num(f->desc.d_num, jvalue);
- } else if (f->flags == MASK) {
- /* calculate mask first */
- v.v_num = value_get_num(f->desc.d_num, jvalue);
} else {
v.v_num = value_get_num(f->desc.d_num, jvalue);
}
@@ -164,12 +169,14 @@ static union value parse_field(struct gluten_ctx *g, struct arg *args,
if (dry_run)
break;
- if (base_offset->type == OFFSET_NULL)
- *base_offset = emit_data(g, f->type, 0, &v);
- else if (add)
+ if (base_offset->type == OFFSET_NULL) {
+ *base_offset = gluten_ro_alloc_type(g, U64);
+ emit_data_at(g, *base_offset, f->type, &v);
+ } else if (add) {
emit_data_or(g, offset, f->type, &v);
- else
+ } else {
emit_data_at(g, offset, f->type, &v);
+ }
break;
case SELECT:
diff --git a/cooker/calls/ioctl.c b/cooker/calls/ioctl.c
index 1609541..336d3c3 100644
--- a/cooker/calls/ioctl.c
+++ b/cooker/calls/ioctl.c
@@ -76,7 +76,7 @@ static struct field tun_ifr[] = { /* netdevice(7) */
IFNAMSIZ, { 0 },
},
{
- "flags", INT, /* One allowed at a time? */ 0,
+ "flags", INT, FLAGS,
offsetof(struct ifreq, ifr_flags),
0, { .d_num = tun_ifr_flags },
},
diff --git a/cooker/calls/net.c b/cooker/calls/net.c
index 7a7fd33..74ea668 100644
--- a/cooker/calls/net.c
+++ b/cooker/calls/net.c
@@ -85,25 +85,25 @@ static struct num protocols[] = {
static struct arg socket_args[] = {
{ 0,
{
- "family", INT, 0, 0, 0,
+ "family", INT, 0, 0, 0,
{ .d_num = af }
}
},
{ 1,
{
- "type", INT, MASK, 0, 0,
+ "type", INT, MASK, 0, 0,
{ .d_num = socket_types }
}
},
{ 1,
{
- "flags", INT, FLAGS, 0, 0,
+ "flags", INT, MASK | FLAGS, 0, 0,
{ .d_num = socket_flags }
}
},
{ 2,
{
- "protocol", INT, 0, 0, 0,
+ "protocol", INT, 0, 0, 0,
{ .d_num = protocols }
}
},
diff --git a/cooker/calls/process.c b/cooker/calls/process.c
index b7a92f0..647f136 100644
--- a/cooker/calls/process.c
+++ b/cooker/calls/process.c
@@ -27,6 +27,7 @@ clone3
#include <asm-generic/unistd.h>
#include <sys/syscall.h>
+#define _GNU_SOURCE
#include <unistd.h>
#include <sched.h>
#include <linux/kcmp.h>
@@ -35,11 +36,26 @@ clone3
#include "../cooker.h"
#include "../calls.h"
+static struct num unshare_flags[] = {
+ { "CLONE_FILES", CLONE_FILES },
+ { "CLONE_FS", CLONE_FS },
+ { "CLONE_NEWCGROUP", CLONE_NEWCGROUP },
+ { "CLONE_NEWIPC", CLONE_NEWIPC },
+ { "CLONE_NEWNET", CLONE_NEWNET },
+ { "CLONE_NEWNS", CLONE_NEWNS },
+ { "CLONE_NEWPID", CLONE_NEWPID },
+ { "CLONE_NEWTIME", CLONE_NEWTIME },
+ { "CLONE_NEWUSER", CLONE_NEWUSER },
+ { "CLONE_NEWUTS", CLONE_NEWUTS },
+ { "CLONE_SYSVSEM", CLONE_SYSVSEM },
+ { 0 }
+};
+
static struct arg unshare_args[] = {
{ 0,
{
- "flags", UNDEF /* TODO */, FLAGS, 0, 0,
- { 0 /* TODO */ }
+ "flags", INT, FLAGS, 0, 0,
+ { .d_num = unshare_flags }
}
}
};
diff --git a/cooker/emit.c b/cooker/emit.c
index 107b2ce..d4ca97b 100644
--- a/cooker/emit.c
+++ b/cooker/emit.c
@@ -425,12 +425,14 @@ static struct gluten_offset emit_data_do(struct gluten_ctx *g,
case U32:
if (add) {
*(int *)p |= value->v_int;
- debug(" C#%i |= (%s) %i",
- ret.offset, type_str[type], value->v_int);
+ debug(" C#%i |= (%s) %i (0x%04x)",
+ ret.offset, type_str[type],
+ value->v_num, value->v_num);
} else {
*(int *)p = value->v_int;
- debug(" C#%i := (%s) %i",
- ret.offset, type_str[type], value->v_int);
+ debug(" C#%i := (%s) %i (0x%04x)",
+ ret.offset, type_str[type],
+ value->v_num, value->v_num);
}
break;
@@ -475,9 +477,7 @@ static struct gluten_offset emit_data_do(struct gluten_ctx *g,
struct gluten_offset emit_data(struct gluten_ctx *g, enum type type,
size_t str_len, union value *value)
{
- struct gluten_offset offset = { .type = OFFSET_NULL, .offset = 0 };
-
- return emit_data_do(g, offset, type, str_len, value, false);
+ return emit_data_do(g, NULL_OFFSET, type, str_len, value, false);
}
struct gluten_offset emit_data_at(struct gluten_ctx *g,
diff --git a/cooker/example.hjson b/cooker/example.hjson
index 9e08163..458961c 100644
--- a/cooker/example.hjson
+++ b/cooker/example.hjson
@@ -44,30 +44,36 @@
]
/*
- * INTFLAGS, LONGFLAGS, U32FLAGS
+ * FLAGS
*
- * "field": { "in": [ "ipc", "mount", "uts" ] }
+ * "field": { "some": [ "ipc", "mount", "uts" ] }
* flags & set
* !!(flags & (ipc | mount | ns))
+ * OP_BITWISE field AND set
+ * OP_CMP result EQ 0 -> next match
*
* "field": { "all": [ "ipc", "mount", "uts" ] }
* flags & set == set
* flags & (ipc | mount | ns) == (ipc | mount | ns)
+ * OP_BITWISE field AND set
+ * OP_CMP result NE set -> next match
*
- * "field": { "not": [ "ipc", "mount", "uts" ] }
+ * "field": { "none": [ "ipc", "mount", "uts" ] }
* !(flags & set)
+ * OP_BITWISE field AND set
+ * OP_CMP result NE 0 -> next match
*
- * "field": { "ipc": false, "mount": true, "uts": false }
- * flags & set == set
- * !(flags & ipc) && (flags & mount) && !(flags & utc)
+ * "field": { [ "ipc", "mount", "uts" ] }
+ * flags == set
+ * flags == (ipc | mount | ns)
*
- * "field": { "ipc" }
+ * "field": "ipc"
* flags == ipc
*
- * INTMASK
+ * MASK
* value = (target value & known values)
*
- * INT, LONG, U32
+ * NUMBERS
* "arg": { "in": [ 0, 1 ] }
* arg == 0 || arg == 1
*/
diff --git a/cooker/match.c b/cooker/match.c
index d32bf0a..5fd46db 100644
--- a/cooker/match.c
+++ b/cooker/match.c
@@ -78,7 +78,8 @@ 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, seccomp_offset;
+ struct gluten_offset const_offset, mask_offset, data_offset;
+ struct gluten_offset seccomp_offset;
union value v = { .v_num = 0 };
struct field *f_inner;
const char *tag_name;
@@ -125,7 +126,8 @@ xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
jvalue = json_object_get_value(tmp, "value");
}
- if (json_value_get_type(jvalue) == JSONObject &&
+ if (!(f->flags & FLAGS) && /* For FLAGS, it's a single operation */
+ json_value_get_type(jvalue) == JSONObject &&
(tmp = json_value_get_object(jvalue)) &&
(set = json_object_get_array(tmp, "in"))) {
unsigned i, count = json_array_get_count(set);
@@ -160,19 +162,54 @@ xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
case INT:
case LONG:
case U32:
- if (f->flags == FLAGS) {
- /* fetch/combine expr algebra loop */
- ;
+ data_offset = offset;
+
+ if ((f->flags & FLAGS) &&
+ json_value_get_type(jvalue) == JSONObject &&
+ (tmp = json_value_get_object(jvalue))) {
+ struct gluten_offset set_offset, cmp_offset, masked;
+ union value set, cmpterm;
+
+ value_get_flags(f->desc.d_num, tmp,
+ &set, &cmp, &cmpterm);
+
+ set_offset = emit_data(g, f->type, 0, &set);
+ masked = emit_bitwise(g, f->type, BITWISE_AND,
+ NULL_OFFSET,
+ offset, set_offset);
+
+ cmp_offset = emit_data(g, f->type, 0, &cmpterm);
+ emit_cmp(g, cmp, masked, cmp_offset,
+ gluten_size[f->type], jump);
+
+ break;
}
- if (f->flags == MASK) {
- /* calculate mask first */
- ;
+
+ if (json_value_get_type(jvalue) == JSONArray) {
+ JSON_Array *array = json_value_get_array(jvalue);
+ unsigned i;
+
+ if (!(f->flags & FLAGS))
+ die("multiple values for non-FLAGS argument");
+
+ for (i = 0; i < json_array_get_count(array); i++) {
+ jvalue = json_array_get_value(array, i);
+ v.v_num |= value_get_num(f->desc.d_num, jvalue);
+ }
+ } else if (f->flags & MASK) {
+ v.v_num = value_get_mask(f->desc.d_num);
+ mask_offset = emit_data(g, f->type, 0, &v);
+ data_offset = emit_bitwise(g, f->type, BITWISE_AND,
+ NULL_OFFSET, offset,
+ mask_offset);
+ v.v_num = value_get_num(f->desc.d_num, jvalue);
+ } else {
+ v.v_num = value_get_num(f->desc.d_num, jvalue);
}
- /* Falls through */
- v.v_num = value_get_num(f->desc.d_num, jvalue);
+
const_offset = emit_data(g, f->type, 0, &v);
- emit_cmp(g, cmp, offset, const_offset, gluten_size[f->type],
- jump);
+ emit_cmp(g, cmp, data_offset, const_offset,
+ gluten_size[f->type], jump);
break;
case GNU_DEV_MAJOR:
/*
diff --git a/cooker/parse.c b/cooker/parse.c
index 353947e..7cac43f 100644
--- a/cooker/parse.c
+++ b/cooker/parse.c
@@ -128,6 +128,66 @@ struct rule_parser {
{ NULL, NULL },
};
+static union value value_get_set(struct num *desc, JSON_Array *set)
+{
+ struct num *tmp;
+ union value n;
+ unsigned i;
+
+ for (i = 0; i < json_array_get_count(set); i++) {
+ for (tmp = desc; tmp->name; tmp++) {
+ if (!strcmp(tmp->name, json_array_get_string(set, i))) {
+ n.v_num |= desc->value;
+ break;
+ }
+ }
+
+ if (!tmp->name)
+ die("invalid flag'%s'", json_array_get_string(set, i));
+ }
+
+ return n;
+}
+
+void value_get_flags(struct num *desc, JSON_Object *obj,
+ union value *bitset, enum op_cmp_type *cmp,
+ union value *cmpterm)
+{
+ JSON_Array *set;
+
+ if ((set = json_object_get_array(obj, "some"))) {
+ *bitset = value_get_set(desc, set);
+ *cmp = CMP_EQ;
+ cmpterm->v_num = 0;
+ } else if ((set = json_object_get_array(obj, "all"))) {
+ *bitset = value_get_set(desc, set);
+ *cmp = CMP_NE;
+ *cmpterm = *bitset;
+ } else if ((set = json_object_get_array(obj, "not"))) {
+ *bitset = value_get_set(desc, set);
+ *cmp = CMP_NE;
+ cmpterm->v_num = 0;
+ } else {
+ die("unsupported flag quantifier");
+ }
+}
+
+/**
+ * value_get_mask() - Get union of all possible numeric values from description
+ * @desc: Description of possible values from model
+ *
+ * Return: numeric value
+ */
+long long value_get_mask(struct num *desc)
+{
+ long long n = 0;
+
+ while ((desc++)->name)
+ n |= desc->value;
+
+ return n;
+}
+
/**
* value_get_num() - Get numeric value from description matching JSON input
* @desc: Description of possible values from model
diff --git a/cooker/parse.h b/cooker/parse.h
index 8bb37a4..7dd3e11 100644
--- a/cooker/parse.h
+++ b/cooker/parse.h
@@ -7,6 +7,10 @@
#define PARSE_H
long long value_get_num(struct num *desc, JSON_Value *value);
+long long value_get_mask(struct num *desc);
+void value_get_flags(struct num *desc, JSON_Object *obj,
+ union value *bitset, enum op_cmp_type *cmp,
+ union value *cmpterm);
size_t value_get_size(struct gluten_ctx *g, intptr_t id);
void value_get(union desc desc, enum type type, JSON_Value *value,
union value *out);
diff --git a/demo/socket.hjson b/demo/socket.hjson
new file mode 100644
index 0000000..7a16ccc
--- /dev/null
+++ b/demo/socket.hjson
@@ -0,0 +1,11 @@
+[
+ {
+ "match": [
+ { "socket": { "family": "unix", "type": "stream", "flags": 0, "protocol": 0 } }
+ ],
+ "call": [
+ { "socket": { "family": "unix", "type": "stream", "flags": [ "cloexec", "nonblock" ], "protocol": 0 }, "ret": "new_fd" }
+ ],
+ "fd": { "src": { "tag": "new_fd" }, "close_on_exec": false, "return": true }
+ }
+]
diff --git a/operations.c b/operations.c
index 120b142..b08d837 100644
--- a/operations.c
+++ b/operations.c
@@ -141,15 +141,15 @@ static int prepare_arg_clone(const struct seccomp_notif *req, struct gluten *g,
static int set_namespaces(struct arg_clone *c)
{
- char *path;
+ char (*path)[PATH_MAX];
int fd;
- for (path = c->ns_path[0]; *path; path++) {
- if ((fd = open(path, O_CLOEXEC)) < 0)
- ret_err(-1, "open for file %s", path);
+ for (path = c->ns_path; **path; *path++) {
+ if ((fd = open(*path, O_CLOEXEC)) < 0)
+ ;//ret_err(-1, "open for file %s", *path);
if (setns(fd, 0) != 0)
- ret_err(-1, "setns");
+ ;//ret_err(-1, "setns");
}
return 0;
}