aboutgitcodelistschat:MatrixIRC
diff options
context:
space:
mode:
-rw-r--r--Makefile9
-rw-r--r--common/gluten.h157
-rw-r--r--common/util.h97
-rw-r--r--cooker/Makefile36
-rw-r--r--cooker/calls/net.c91
-rw-r--r--cooker/cooker.h97
-rw-r--r--cooker/emit.c94
-rw-r--r--cooker/emit.h14
-rw-r--r--cooker/gluten.c44
-rw-r--r--cooker/gluten.h28
-rw-r--r--cooker/parse.c100
-rw-r--r--eater/Makefile2
-rw-r--r--operations.c144
-rw-r--r--operations.h3
-rwxr-xr-xscripts/nr_syscalls.sh44
15 files changed, 677 insertions, 283 deletions
diff --git a/Makefile b/Makefile
index b7e2205..9edf4f2 100644
--- a/Makefile
+++ b/Makefile
@@ -3,14 +3,15 @@
# seitan - Syscall Expressive Interpreter, Transformer and Notifier
#
# Copyright 2023 Red Hat GmbH
-# Authors: Alice Frosi <afrosi@redhat.com>, Stefano Brivio <sbrivio@redhat.com>
+# Authors: Alice Frosi <afrosi@redhat.com>
+# Stefano Brivio <sbrivio@redhat.com>
DIR := $(shell pwd)
-OUTDIR ?= $(DIR)/
+OUTDIR ?= $(DIR)
export OUTDIR
COMMON_DIR := $(DIR)/common
-BIN := $(OUTDIR)seitan
+BIN := $(OUTDIR)/seitan
SRCS := seitan.c $(COMMON_DIR)/common.c $(COMMON_DIR)/util.c operations.c
HEADERS := $(COMMON_DIR)/common.h $(COMMON_DIR)/gluten.h \
$(COMMON_DIR)/numbers.h $(COMMON_DIR)/util.h operations.h
@@ -21,7 +22,7 @@ CFLAGS += -Wall -Wextra -pedantic -I$(COMMON_DIR)
all: cooker eater seitan
.PHONY: cooker
-cooker: numbers.h
+cooker:
$(MAKE) -C cooker
.PHONY: eater
diff --git a/common/gluten.h b/common/gluten.h
index eb965d9..61270d8 100644
--- a/common/gluten.h
+++ b/common/gluten.h
@@ -1,10 +1,49 @@
-#ifndef GLUTEN_H
-#define GLUTEN_H
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright 2023 Red Hat GmbH
+ * Authors: Alice Frosi <afrosi@redhat.com>
+ * Stefano Brivio <sbrivio@redhat.com>
+ */
+
+#ifndef COMMON_GLUTEN_H
+#define COMMON_GLUTEN_H
+#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
+#include <linux/seccomp.h>
+
+#include "util.h"
-#define MAX_FD_INJECTED 10
+extern struct seccomp_data anonymous_seccomp_data;
+
+#define HEADER_SIZE 4096
+#define INST_SIZE 4096
+#define RO_DATA_SIZE 4096
+#define DATA_SIZE 4096
+
+#define INST_MAX 16
+#define OFFSET_MAX MAX(MAX(MAX(DATA_SIZE, RO_DATA_SIZE), \
+ INST_MAX), \
+ ARRAY_SIZE(anonymous_seccomp_data.args))
+
+enum gluten_offset_type {
+ OFFSET_RO_DATA = 0,
+ OFFSET_DATA = 1,
+ OFFSET_SECCOMP_DATA = 2,
+ OFFSET_INSTRUCTION = 3,
+ OFFSET_TYPE_MAX = OFFSET_INSTRUCTION,
+};
+
+struct gluten_offset {
+#ifdef __GNUC__
+ enum gluten_offset_type type:BITS_PER_NUM(OFFSET_TYPE_MAX);
+#else
+ uint16_t type:BITS_PER_NUM(OFFSET_TYPE_MAX);
+#endif
+ uint16_t offset:BITS_PER_NUM(OFFSET_MAX);
+};
+
+BUILD_BUG_ON(BITS_PER_NUM(OFFSET_TYPE_MAX) + BITS_PER_NUM(OFFSET_MAX) > 16)
enum ns_spec_type {
NS_NONE,
@@ -18,7 +57,7 @@ struct ns_spec {
union {
pid_t pid;
char *path;
- };
+ } id;
};
/*
@@ -50,7 +89,7 @@ enum op_type {
OP_INJECT,
OP_INJECT_A,
OP_RETURN,
- OP_COPY_ARGS,
+ OP_LOAD,
OP_END,
OP_CMP,
OP_RESOLVEDFD,
@@ -61,12 +100,17 @@ enum value_type {
REFERENCE,
};
+struct op_nr {
+ long nr;
+ struct gluten_offset no_match;
+};
+
struct op_call {
long nr;
bool has_ret;
void *args[6];
struct op_context context;
- uint16_t ret_off;
+ struct gluten_offset ret;
};
struct op_block {
@@ -78,24 +122,12 @@ struct op_continue {
};
struct op_return {
- enum value_type type;
- union {
- int64_t value;
- uint16_t value_off;
- };
-};
-
-struct fd_type {
- enum value_type type;
- union {
- uint32_t fd;
- uint16_t fd_off;
- };
+ struct gluten_offset val;
};
struct op_inject {
- struct fd_type newfd;
- struct fd_type oldfd;
+ struct gluten_offset new_fd;
+ struct gluten_offset old_fd;
};
struct copy_arg {
@@ -104,8 +136,10 @@ struct copy_arg {
size_t size;
};
-struct op_copy_args {
- struct copy_arg args[6];
+struct op_load {
+ struct gluten_offset src;
+ struct gluten_offset dst;
+ size_t size;
};
enum op_cmp_type {
@@ -118,8 +152,8 @@ enum op_cmp_type {
};
struct op_cmp {
- uint16_t s1_off;
- uint16_t s2_off;
+ struct gluten_offset x;
+ struct gluten_offset y;
size_t size;
enum op_cmp_type cmp;
unsigned int jmp;
@@ -135,14 +169,77 @@ struct op_resolvedfd {
struct op {
enum op_type type;
union {
+ struct op_nr nr;
struct op_call call;
struct op_block block;
struct op_continue cont;
struct op_return ret;
- struct op_inject inj;
- struct op_copy_args copy;
+ struct op_inject inject;
+ struct op_load load;
struct op_cmp cmp;
struct op_resolvedfd resfd;
- };
-};
-#endif /* GLUTEN_H */
+ } op;
+};
+
+#ifdef COOKER
+# define GLUTEN_CONST
+#else
+# define GLUTEN_CONST const
+#endif
+
+struct gluten {
+ GLUTEN_CONST char header[HEADER_SIZE];
+
+ GLUTEN_CONST char inst[INST_SIZE];
+
+ GLUTEN_CONST char ro_data[RO_DATA_SIZE];
+
+ char data[DATA_SIZE];
+} __attribute__((packed));
+
+BUILD_BUG_ON(INST_SIZE < INST_MAX * sizeof(struct op))
+
+#ifdef COOKER
+static inline void *gluten_ptr(struct gluten *g, const struct gluten_offset x)
+#else
+static inline void *gluten_write_ptr(struct gluten *g,
+ const struct gluten_offset x)
+#endif
+{
+ /* TODO: Boundary checks */
+
+ switch (x.type) {
+ case OFFSET_DATA:
+ return (char *)g->data + x.offset;
+#ifdef COOKER
+ case OFFSET_RO_DATA:
+ return (char *)g->ro_data + x.offset;
+ case OFFSET_INSTRUCTION:
+ return (struct op *)(g->inst) + x.offset;
+#endif
+ default:
+ return NULL;
+ }
+}
+
+#ifndef COOKER
+static inline const void *gluten_ptr(const struct seccomp_data *s,
+ struct gluten *g,
+ const struct gluten_offset x)
+{
+ switch (x.type) {
+ case OFFSET_DATA:
+ return g->data + x.offset;
+ case OFFSET_RO_DATA:
+ return g->ro_data + x.offset;
+ case OFFSET_SECCOMP_DATA:
+ return (const uint64_t *)s->args + x.offset;
+ case OFFSET_INSTRUCTION:
+ return (const struct op *)(g->inst) + x.offset;
+ default:
+ return NULL;
+ }
+}
+#endif
+
+#endif /* COMMON_GLUTEN_H */
diff --git a/common/util.h b/common/util.h
index 84dc3db..102b55b 100644
--- a/common/util.h
+++ b/common/util.h
@@ -6,8 +6,22 @@
#ifndef UTIL_H
#define UTIL_H
+#include <string.h>
+#include <stdint.h>
+
#define BIT(n) (1UL << (n))
+#ifndef MIN
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+#endif
+#ifndef MAX
+#define MAX(x, y) (((x) > (y)) ? (x) : (y))
+#endif
+
+#define ARRAY_SIZE(a) ((int)(sizeof(a) / sizeof((a)[0])))
+
+#define BUILD_BUG_ON(x) extern int __y[1 - 2 * !!(x)];
+
void err(const char *format, ...);
void info(const char *format, ...);
void debug(const char *format, ...);
@@ -19,4 +33,87 @@ void debug(const char *format, ...);
exit(EXIT_FAILURE); \
} while (0)
+/**
+ * From the Linux kernel, include/linux/log2.h:
+ *
+ * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * const_ilog2 - log base 2 of 32-bit or a 64-bit constant unsigned value
+ * @n: parameter
+ *
+ * Use this where sparse expects a true constant expression, e.g. for array
+ * indices.
+ */
+#define const_ilog2(n) \
+( \
+ __builtin_constant_p(n) ? ( \
+ (n) < 2 ? 0 : \
+ (n) & (1ULL << 63) ? 63 : \
+ (n) & (1ULL << 62) ? 62 : \
+ (n) & (1ULL << 61) ? 61 : \
+ (n) & (1ULL << 60) ? 60 : \
+ (n) & (1ULL << 59) ? 59 : \
+ (n) & (1ULL << 58) ? 58 : \
+ (n) & (1ULL << 57) ? 57 : \
+ (n) & (1ULL << 56) ? 56 : \
+ (n) & (1ULL << 55) ? 55 : \
+ (n) & (1ULL << 54) ? 54 : \
+ (n) & (1ULL << 53) ? 53 : \
+ (n) & (1ULL << 52) ? 52 : \
+ (n) & (1ULL << 51) ? 51 : \
+ (n) & (1ULL << 50) ? 50 : \
+ (n) & (1ULL << 49) ? 49 : \
+ (n) & (1ULL << 48) ? 48 : \
+ (n) & (1ULL << 47) ? 47 : \
+ (n) & (1ULL << 46) ? 46 : \
+ (n) & (1ULL << 45) ? 45 : \
+ (n) & (1ULL << 44) ? 44 : \
+ (n) & (1ULL << 43) ? 43 : \
+ (n) & (1ULL << 42) ? 42 : \
+ (n) & (1ULL << 41) ? 41 : \
+ (n) & (1ULL << 40) ? 40 : \
+ (n) & (1ULL << 39) ? 39 : \
+ (n) & (1ULL << 38) ? 38 : \
+ (n) & (1ULL << 37) ? 37 : \
+ (n) & (1ULL << 36) ? 36 : \
+ (n) & (1ULL << 35) ? 35 : \
+ (n) & (1ULL << 34) ? 34 : \
+ (n) & (1ULL << 33) ? 33 : \
+ (n) & (1ULL << 32) ? 32 : \
+ (n) & (1ULL << 31) ? 31 : \
+ (n) & (1ULL << 30) ? 30 : \
+ (n) & (1ULL << 29) ? 29 : \
+ (n) & (1ULL << 28) ? 28 : \
+ (n) & (1ULL << 27) ? 27 : \
+ (n) & (1ULL << 26) ? 26 : \
+ (n) & (1ULL << 25) ? 25 : \
+ (n) & (1ULL << 24) ? 24 : \
+ (n) & (1ULL << 23) ? 23 : \
+ (n) & (1ULL << 22) ? 22 : \
+ (n) & (1ULL << 21) ? 21 : \
+ (n) & (1ULL << 20) ? 20 : \
+ (n) & (1ULL << 19) ? 19 : \
+ (n) & (1ULL << 18) ? 18 : \
+ (n) & (1ULL << 17) ? 17 : \
+ (n) & (1ULL << 16) ? 16 : \
+ (n) & (1ULL << 15) ? 15 : \
+ (n) & (1ULL << 14) ? 14 : \
+ (n) & (1ULL << 13) ? 13 : \
+ (n) & (1ULL << 12) ? 12 : \
+ (n) & (1ULL << 11) ? 11 : \
+ (n) & (1ULL << 10) ? 10 : \
+ (n) & (1ULL << 9) ? 9 : \
+ (n) & (1ULL << 8) ? 8 : \
+ (n) & (1ULL << 7) ? 7 : \
+ (n) & (1ULL << 6) ? 6 : \
+ (n) & (1ULL << 5) ? 5 : \
+ (n) & (1ULL << 4) ? 4 : \
+ (n) & (1ULL << 3) ? 3 : \
+ (n) & (1ULL << 2) ? 2 : \
+ 1) : \
+ -1)
+
+#define BITS_PER_NUM(n) (const_ilog2(n) + 1)
+
#endif /* UTIL_H */
diff --git a/cooker/Makefile b/cooker/Makefile
index 4f72448..be8f703 100644
--- a/cooker/Makefile
+++ b/cooker/Makefile
@@ -5,31 +5,25 @@
# cooker/Makefile - Makefile for seitan-cooker
#
# Copyright 2023 Red Hat GmbH
-# Author: Stefano Brivio <sbrivio@redhat.com>
+# Authors: Alice Frosi <afrosi@redhat.com>
+# Stefano Brivio <sbrivio@redhat.com>
-COMMON_DIR := ../common
-SRCS := calls.c emit.c filter.c gluten.c main.c parse.c parson.c \
- $(COMMON_DIR)/util.c calls/net.c
-HEADERS := calls.h cooker.h emit.h filter.h \
- gluten.h parse.h parson.h calls/net.h \
- $(COMMON_DIR)/util.h
-BIN := $(OUTDIR)seitan-cooker
+OUTDIR ?= ..
+COMMON := ../common
+BIN := $(OUTDIR)/seitan-cooker
+CFLAGS := -O0 -g -Wall -Wextra -pedantic -std=c99 -I$(COMMON)
-TARGET := $(shell $(CC) -dumpmachine)
-TARGET_ARCH := $(shell echo $(TARGET) | cut -f1 -d- | tr [A-Z] [a-z])
-TARGET_ARCH := $(shell echo $(TARGET_ARCH) | sed 's/powerpc/ppc/')
+SRCS := calls.c emit.c gluten.c main.c parse.c parson.c \
+ $(COMMON)/util.c \
+ calls/net.c
+HEADERS := calls.h cooker.h emit.h gluten.h parse.h parson.h \
+ $(COMMON)/gluten.h $(COMMON)/util.h \
+ calls/net.h
-AUDIT_ARCH := $(shell echo $(TARGET_ARCH) | tr [a-z] [A-Z] | sed 's/^ARM.*/ARM/')
-AUDIT_ARCH := $(shell echo $(AUDIT_ARCH) | sed 's/I[456]86/I386/')
-AUDIT_ARCH := $(shell echo $(AUDIT_ARCH) | sed 's/PPC64/PPC/')
-AUDIT_ARCH := $(shell echo $(AUDIT_ARCH) | sed 's/PPCLE/PPC64LE/')
-
-CFLAGS += -DSEITAN_AUDIT_ARCH=AUDIT_ARCH_$(AUDIT_ARCH)
-CFLAGS += -O0 -g -Wall -Wextra -pedantic -std=c99 -I$(COMMON_DIR)
-cooker: $(SRCS) $(HEADERS)
+$(BIN): $(SRCS) $(HEADERS)
$(CC) $(CFLAGS) -o $(BIN) $(SRCS)
-all: cooker
+all: $(BIN)
clean:
- rm -f cooker
+ rm -f $(BIN)
diff --git a/cooker/calls/net.c b/cooker/calls/net.c
index c0949cc..370a3a1 100644
--- a/cooker/calls/net.c
+++ b/cooker/calls/net.c
@@ -39,7 +39,7 @@ n = sendmmsg(fd, *msgvec, vlen, flags)
#include "../cooker.h"
#include "../calls.h"
-static struct arg_num af[] = {
+static struct num af[] = {
{ "unix", AF_UNIX },
{ "ipv4", AF_INET },
{ "ipv6", AF_INET6 },
@@ -49,7 +49,7 @@ static struct arg_num af[] = {
{ 0 },
};
-static struct arg_num socket_types[] = {
+static struct num socket_types[] = {
{ "stream", SOCK_STREAM },
{ "dgram", SOCK_DGRAM },
{ "seq", SOCK_SEQPACKET },
@@ -58,13 +58,13 @@ static struct arg_num socket_types[] = {
{ 0 },
};
-static struct arg_num socket_flags[] = {
+static struct num socket_flags[] = {
{ "nonblock", SOCK_NONBLOCK },
{ "cloexec", SOCK_CLOEXEC },
{ 0 },
};
-static struct arg_num protocols[] = {
+static struct num protocols[] = {
{ "ip", IPPROTO_IP },
{ "icmp", IPPROTO_ICMP },
{ "igmp", IPPROTO_IGMP },
@@ -83,86 +83,97 @@ static struct arg_num protocols[] = {
};
static struct arg socket_args[] = {
- { 0, "family", ARG_INT, 0, { .d_num = af } },
- { 1, "type", ARG_INTMASK, 0, { .d_num = socket_types } },
- { 1, "flags", ARG_INTFLAGS, 0, { .d_num = socket_flags } },
- { 2, "protocol", ARG_INT, 0, { .d_num = protocols } },
+ { 0, "family", INT, 0, { .d_num = af } },
+ { 1, "type", INTMASK, 0, { .d_num = socket_types } },
+ { 1, "flags", INTFLAGS, 0, { .d_num = socket_flags } },
+ { 2, "protocol", INT, 0, { .d_num = protocols } },
{ 0 },
};
-static struct arg_struct connect_addr_unix[] = {
- { "path", ARG_STRING,
+static struct field connect_addr_unix[] = {
+ {
+ "path", STRING,
offsetof(struct sockaddr_un, sun_path),
- UNIX_PATH_MAX, { 0 }
+ UNIX_PATH_MAX, { 0 }
},
{ 0 },
};
-static struct arg_struct connect_addr_ipv4[] = {
- { "port", ARG_PORT,
+static struct field connect_addr_ipv4[] = {
+ {
+ "port", PORT,
offsetof(struct sockaddr_in, sin_port),
- 0, { 0 }
+ 0, { 0 }
},
- { "addr", ARG_IPV4,
+ {
+ "addr", IPV4,
offsetof(struct sockaddr_in, sin_addr),
- 0, { 0 }
+ 0, { 0 }
},
{ 0 },
};
-static struct arg_struct connect_addr_ipv6[] = {
- { "port", ARG_PORT,
+static struct field connect_addr_ipv6[] = {
+ {
+ "port", PORT,
offsetof(struct sockaddr_in6, sin6_port),
- 0, { 0 }
+ 0, { 0 }
},
- { "addr", ARG_IPV6,
+ {
+ "addr", IPV6,
offsetof(struct sockaddr_in6, sin6_addr),
- 0, { 0 }
+ 0, { 0 }
},
{ 0 },
};
-static struct arg_struct connect_addr_nl[] = {
- { "pid", ARG_PID,
+static struct field connect_addr_nl[] = {
+ {
+ "pid", PID,
offsetof(struct sockaddr_nl, nl_pid),
- 0, { 0 }
+ 0, { 0 }
},
- { "groups", ARG_U32,
+ {
+ "groups", U32,
offsetof(struct sockaddr_in6, sin6_addr),
- 0, { 0 }
+ 0, { 0 }
},
{ 0 },
};
-static struct arg_struct connect_family = {
- "family", ARG_INT,
- offsetof(struct sockaddr, sa_family),
- 0, { .d_num = af }
+static struct field connect_family = {
+ "family", INT,
+ offsetof(struct sockaddr, sa_family),
+ 0, { .d_num = af }
};
-static struct arg_select_num connect_addr_select_family[] = {
- { AF_UNIX, ARG_STRUCT, { .d_struct = connect_addr_unix } },
- { AF_INET, ARG_STRUCT, { .d_struct = connect_addr_ipv4 } },
- { AF_INET6, ARG_STRUCT, { .d_struct = connect_addr_ipv6 } },
- { AF_NETLINK, ARG_STRUCT, { .d_struct = connect_addr_nl } },
+static struct select_num connect_addr_select_family[] = {
+ { AF_UNIX, STRUCT, { .d_struct = connect_addr_unix } },
+ { AF_INET, STRUCT, { .d_struct = connect_addr_ipv4 } },
+ { AF_INET6, STRUCT, { .d_struct = connect_addr_ipv6 } },
+ { AF_NETLINK, STRUCT, { .d_struct = connect_addr_nl } },
{ 0 },
};
-static struct arg_select connect_addr_select = {
+static struct select connect_addr_select = {
&connect_family, { .d_num = connect_addr_select_family }
};
static struct arg connect_args[] = {
- { 0, "fd", ARG_INT, 0,
+ {
+ 0, "fd", INT, 0,
{ 0 },
},
- { 0, "path", ARG_FDPATH, 0,
+ {
+ 0, "path", FDPATH, 0,
{ 0 },
},
- { 1, "addr", ARG_SELECT, sizeof(struct sockaddr_storage),
+ {
+ 1, "addr", SELECT, sizeof(struct sockaddr_storage),
{ .d_select = &connect_addr_select },
},
- { 2, "addrlen", ARG_LONG, 0,
+ {
+ 2, "addrlen", LONG, 0,
{ 0 },
},
};
diff --git a/cooker/cooker.h b/cooker/cooker.h
index 53aa0db..a1cc360 100644
--- a/cooker/cooker.h
+++ b/cooker/cooker.h
@@ -11,78 +11,95 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/types.h>
+#include <arpa/inet.h>
#define REFS_MAX 256
+#define REF_NAMEMAX 256
#define CALL_ARGS 6
-struct arg_num;
-struct arg_struct;
-struct arg_select;
+struct num;
+struct field;
+struct select;
-union arg_value {
- struct arg_num *d_num;
- struct arg_struct *d_struct;
- struct arg_select *d_select;
+union desc {
+ struct num *d_num;
+ struct field *d_struct;
+ struct select *d_select;
};
-enum arg_type {
- ARG_INT,
- ARG_INTMASK,
- ARG_INTFLAGS,
+union value {
+ int v_int;
+ uint32_t v_u32;
+ long long v_num;
+};
+
+enum type {
+ INT,
+ INTMASK,
+ INTFLAGS,
- ARG_U32,
- ARG_U32MASK,
- ARG_U32FLAGS,
+ U32,
+ U32MASK,
+ U32FLAGS,
- ARG_LONG,
- ARG_LONGMASK,
- ARG_LONGFLAGS,
+ LONG,
+ LONGMASK,
+ LONGFLAGS,
- ARG_STRING,
+ STRING,
- ARG_STRUCT,
- ARG_SELECT,
+ STRUCT,
+ SELECT,
- ARG_PID,
+ PID,
- ARG_PORT,
- ARG_IPV4,
- ARG_IPV6,
+ PORT,
+ IPV4,
+ IPV6,
- ARG_FDPATH,
+ FDPATH,
- ARG_TYPE_END,
+ TYPE_END,
};
-#define ARG_TYPE_COUNT (ARG_TYPE_END - 1)
+#define TYPE_COUNT (TYPE_END - 1)
+
+#define TYPE_IS_COMPOUND(t) ((t) == STRUCT || (t) == SELECT)
+#define TYPE_IS_NUM(t) ((t) == INT || (t) == U32 || (t) == LONG)
+
+enum jump_type {
+ NEXT_BLOCK,
+ END,
+};
-struct arg_num {
+struct num {
char *name;
long long value;
};
-struct arg_struct {
+struct field {
char *name;
- enum arg_type type;
- size_t offset;
+ enum type type;
+ off_t offset;
size_t strlen;
- union arg_value desc;
+ union desc desc;
};
-struct arg_select_num {
+struct select_num {
long long value;
- enum arg_type type;
- union arg_value desc;
+ enum type type;
+ union desc desc;
};
-struct arg_select {
- struct arg_struct *field;
+struct select {
+ struct field *field;
union {
- struct arg_select_num *d_num;
+ struct select_num *d_num;
} desc;
};
@@ -90,10 +107,10 @@ struct arg {
int pos;
char *name;
- enum arg_type type;
+ enum type type;
size_t size;
- union arg_value desc;
+ union desc desc;
};
#endif /* COOKER_H */
diff --git a/cooker/emit.c b/cooker/emit.c
index a82529c..8c35f1d 100644
--- a/cooker/emit.c
+++ b/cooker/emit.c
@@ -2,7 +2,7 @@
/* seitan - Syscall Expressive Interpreter, Transformer and Notifier
*
- * cooker/emit.c - Generate gluten (bytecode) instructions
+ * cooker/emit.c - Generate gluten (bytecode) instructions and read-only data
*
* Copyright 2023 Red Hat GmbH
* Author: Stefano Brivio <sbrivio@redhat.com>
@@ -11,17 +11,97 @@
#include "cooker.h"
#include "gluten.h"
#include "util.h"
+#include "emit.h"
-int emit_nr(struct gluten_ctx *g, long number)
+static const char *type_str[] = {
+ "INT", "INTMASK", "INTFLAGS",
+ "U32", "U32MASK", "U32FLAGS",
+ "LONG", "LONGMASK", "LONGFLAGS",
+ "STRING",
+ "STRUCT", "SELECT",
+ "PID",
+ "PORT", "IPV4", "IPV6",
+ "FDPATH",
+ NULL
+};
+
+static const char *cmp_type_str[] = { "EQ", "GT", "GE", "LT", "LE", NULL };
+
+void emit_nr(struct gluten_ctx *g, long number)
+{
+ struct op_nr *nr = (struct op_nr *)gluten_ptr(&g->g, g->ip);
+
+ nr->nr = number;
+ nr->no_match.type = OFFSET_INSTRUCTION;
+ nr->no_match.offset = NEXT_BLOCK;
+
+ debug(" %i: OP_NR %li, < >", g->ip.offset, number);
+
+ if (++g->ip.offset > INST_MAX)
+ die("Too many instructions");
+}
+
+void emit_load(struct gluten_ctx *g, struct gluten_offset dst,
+ int index, size_t len)
+{
+ struct op_load *load = (struct op_load *)gluten_ptr(&g->g, g->ip);
+
+ load->src.type = OFFSET_SECCOMP_DATA;
+ load->src.offset = index;
+
+ load->dst = dst;
+
+ debug(" %i: OP_LOAD #%i < %i (%lu)", g->ip.offset, dst.offset,
+ index, len);
+
+ if (++g->ip.offset > INST_MAX)
+ die("Too many instructions");
+}
+
+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)
{
- debug(" %i: OP_NR %li, < >", g->ip++, number);
+ struct op_cmp *op = (struct op_cmp *)gluten_ptr(&g->g, g->ip);
+
+ op->x = x;
+ op->y = y;
+ op->size = size;
+ op->cmp = cmp;
+ op->jmp = jmp;
+
+ debug(" %i: OP_CMP (#%lu) %%%lu %s %%%lu", g->ip.offset, size,
+ x.offset, cmp_type_str[cmp], y.offset);
- return 0;
+ if (++g->ip.offset > INST_MAX)
+ die("Too many instructions");
}
-int emit_load(struct gluten_ctx *g, int offset, int index, size_t len)
+void emit_cmp_field(struct gluten_ctx *g, enum op_cmp_type cmp,
+ struct field *field,
+ struct gluten_offset base, struct gluten_offset match,
+ enum jump_type jmp)
{
- debug(" %i: OP_LOAD #%i < %i (%lu)", g->ip++, offset, index, len);
+ base.offset += field->offset;
+
+ emit_cmp(g, cmp, base, match,
+ field->strlen ? field->strlen : gluten_size[field->type],
+ jmp);
+}
+
+struct gluten_offset emit_data(struct gluten_ctx *g, enum type type,
+ union value *value)
+{
+ void *p = gluten_ptr(&g->g, g->cp);
+ struct gluten_offset ret = g->cp;
+
+ if (type == INT) {
+ *(int *)p = value->v_int;
+ debug(" C#%i: (%s) %i", g->cp.offset, type_str[type],
+ value->v_int);
+ if ((g->cp.offset += sizeof(int)) > RO_DATA_SIZE)
+ die(" Read-only data section exceeded");
+ }
- return 0;
+ return ret;
}
diff --git a/cooker/emit.h b/cooker/emit.h
index 74264b1..94b2600 100644
--- a/cooker/emit.h
+++ b/cooker/emit.h
@@ -6,7 +6,17 @@
#ifndef EMIT_H
#define EMIT_H
-int emit_nr(struct gluten_ctx *g, long number);
-int emit_load(struct gluten_ctx *g, int offset, int index, size_t len);
+void emit_nr(struct gluten_ctx *g, long number);
+void emit_load(struct gluten_ctx *g, struct gluten_offset dst,
+ int index, size_t len);
+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);
+void emit_cmp_field(struct gluten_ctx *g, enum op_cmp_type cmp,
+ struct field *field,
+ struct gluten_offset base, struct gluten_offset match,
+ enum jump_type jmp);
+struct gluten_offset emit_data(struct gluten_ctx *g, enum type type,
+ union value *value);
#endif /* EMIT_H */
diff --git a/cooker/gluten.c b/cooker/gluten.c
index 1116e6b..6460798 100644
--- a/cooker/gluten.c
+++ b/cooker/gluten.c
@@ -12,33 +12,47 @@
#include "gluten.h"
#include "util.h"
-#define GLUTEN_INST_SIZE BUFSIZ
-#define GLUTEN_DATA_SIZE BUFSIZ
+size_t gluten_size[TYPE_COUNT] = {
+ [INT] = sizeof(int),
+ [INTMASK] = sizeof(int),
+ [INTFLAGS] = sizeof(int),
-static char gluten[GLUTEN_INST_SIZE + GLUTEN_DATA_SIZE];
+ [U32] = sizeof(uint32_t),
+ [U32MASK] = sizeof(uint32_t),
+ [U32FLAGS] = sizeof(uint32_t),
+
+ [LONG] = sizeof(long),
+ [LONGMASK] = sizeof(long),
+ [LONGFLAGS] = sizeof(long),
+
+ [PID] = sizeof(pid_t),
+ [PORT] = sizeof(in_port_t),
+ [IPV4] = sizeof(struct in_addr),
+ [IPV6] = sizeof(struct in6_addr),
-static size_t gluten_arg_storage[ARG_TYPE_COUNT] = {
- [ARG_INT] = sizeof(int),
- [ARG_INTMASK] = sizeof(int),
};
-int gluten_alloc(struct gluten_ctx *g, size_t size)
+struct gluten_offset gluten_alloc(struct gluten_ctx *g, size_t size)
{
- debug(" allocating %lu at offset %i", size, g->sp);
- if ((g->sp += size) >= GLUTEN_DATA_SIZE)
+ struct gluten_offset ret = g->dp;
+
+ debug(" allocating %lu at offset %i", size, g->dp.offset);
+ if ((g->dp.offset += size) >= DATA_SIZE)
die("Temporary data size exceeded");
- return g->sp - size;
+ return ret;
}
-int gluten_alloc_type(struct gluten_ctx *g, enum arg_type type)
+struct gluten_offset gluten_alloc_type(struct gluten_ctx *g, enum type type)
{
- return gluten_alloc(g, gluten_arg_storage[type]);
+ return gluten_alloc(g, gluten_size[type]);
}
-int gluten_init(struct gluten_ctx *g)
+void gluten_init(struct gluten_ctx *g)
{
- g->gluten = gluten;
+ (void)g;
- return 0;
+ g->ip.type = g->lr.type = OFFSET_INSTRUCTION;
+ g->dp.type = OFFSET_DATA;
+ g->cp.type = OFFSET_RO_DATA;
}
diff --git a/cooker/gluten.h b/cooker/gluten.h
index 440029d..a48cd6d 100644
--- a/cooker/gluten.h
+++ b/cooker/gluten.h
@@ -6,22 +6,27 @@
#ifndef GLUTEN_H
#define GLUTEN_H
+#define COOKER
+#include <gluten.h>
+
struct gluten_arg_data {
- int offset;
+ struct gluten_offset offset;
size_t len;
};
struct gluten_ref_data {
- int name;
- int offset;
+ char name[REF_NAMEMAX];
+ struct gluten_offset offset;
size_t len;
};
struct gluten_ctx {
- int ip;
- int lr;
- int sp;
- char *gluten;
+ struct gluten_offset ip;
+ struct gluten_offset lr;
+ struct gluten_offset cp;
+ struct gluten_offset dp;
+
+ struct gluten g;
struct gluten_arg_data match_dst[CALL_ARGS];
struct gluten_arg_data call_src[CALL_ARGS];
@@ -29,8 +34,11 @@ struct gluten_ctx {
struct gluten_ref_data refs[REFS_MAX];
};
-int gluten_alloc(struct gluten_ctx *g, size_t size);
-int gluten_alloc_type(struct gluten_ctx *g, enum arg_type type);
-int gluten_init(struct gluten_ctx *g);
+struct gluten_offset gluten_alloc(struct gluten_ctx *g, size_t size);
+struct gluten_offset gluten_alloc_type(struct gluten_ctx *g, enum type type);
+void gluten_init(struct gluten_ctx *g);
+void gluten_block_init(struct gluten_ctx *g);
+
+extern size_t gluten_size[TYPE_COUNT];
#endif /* GLUTEN_H */
diff --git a/cooker/parse.c b/cooker/parse.c
index 9d8a7be..0a87088 100644
--- a/cooker/parse.c
+++ b/cooker/parse.c
@@ -35,7 +35,7 @@ static int parse_match_load(struct gluten_ctx *g, struct arg *a)
return 0;
}
-static long long parse_match_expr_num(struct arg_num *desc, JSON_Value *value)
+static long long parse_match_expr_num(struct num *desc, JSON_Value *value)
{
const char *s = NULL;
long long n;
@@ -59,35 +59,109 @@ static long long parse_match_expr_num(struct arg_num *desc, JSON_Value *value)
return n;
}
-static int parse_match_key(struct gluten_ctx *g, int index, enum arg_type type,
- union arg_value desc, JSON_Value *value)
+static void parse_match_expr_value(union desc desc, enum type type,
+ JSON_Value *value, union value *out)
+{
+ if (TYPE_IS_NUM(type))
+ out->v_num = parse_match_expr_num(desc.d_num, value);
+}
+
+/**
+ * parse_match_select() - Get description and type for selected value
+ * @s: Possible selection choices
+ * @v: Selector value
+ * @type: Type of selected value, set on return
+ * @desc: Description of selected value, set on return
+ */
+static void parse_match_select(struct select *s, union value v,
+ enum type *type, union desc *desc)
+{
+ if (TYPE_IS_NUM(s->field->type)) {
+ struct select_num *d_num;
+
+ for (d_num = s->desc.d_num; d_num->type; d_num++) {
+ if (d_num->value == v.v_num) {
+ *type = d_num->type;
+ *desc = d_num->desc;
+ return;
+ }
+ }
+
+ if (!d_num->type)
+ die(" No match for numeric selector %i", v.v_num);
+ }
+
+ die(" not supported yet");
+}
+
+/*
+ * parse_match_arg()
+ * load argument
+ * parse_match_key()
+ * compound types? demux, parse_match_expr
+ * parse_match_expr
+ * in/all/not/false-true array: demux, parse_match_expr_{num,string}
+ * parse_match_expr_{num,string}
+ *
+ * at terminal values
+ * store ref *pointers*! no copies
+ * emit additional bpf statement if syscall arg is also terminal
+*/
+static int parse_match_key(struct gluten_ctx *g, int index, enum type type,
+ union desc desc, JSON_Value *value)
{
JSON_Object *tmp;
const char *ref;
- (void)index;
+ if (type == SELECT) {
+ struct gluten_offset base_offset, const_offset;
+ struct select *select = desc.d_select;
+ struct field *field = select->field;
+ JSON_Value *selector;
+ union value v;
+
+ if (!(tmp = json_value_get_object(value)))
+ die(" no object for compound value");
+
+ if (!(selector = json_object_get_value(tmp, field->name)))
+ die(" missing selector for '%s'", field->name);
+
+ parse_match_expr_value(field->desc, field->type, selector, &v);
+
+ base_offset = g->match_dst[index].offset;
+ const_offset = emit_data(g, field->type, &v);
+ emit_cmp_field(g, CMP_NE, field, base_offset, const_offset,
+ NEXT_BLOCK);
+
+ parse_match_select(select, v, &type, &desc);
+ }
if (json_value_get_type(value) == JSONObject &&
(tmp = json_value_get_object(value)) &&
(ref = json_object_get_string(tmp, "ref"))) {
+ if (TYPE_IS_COMPOUND(type))
+ die("Reference '%s' to compound value");
+
debug(" setting reference '%s'", ref);
- gluten_alloc_type(g, type);
value = json_object_get_value(tmp, "value");
+
+ emit_load(g, gluten_alloc_type(g, type), index, type);
}
+ /* Nothing to match on: just store as reference */
if (!value)
return 0;
switch (type) {
- case ARG_INTFLAGS:
- case ARG_LONGFLAGS:
- case ARG_U32FLAGS:
+ case INTFLAGS:
+ case LONGFLAGS:
+ case U32FLAGS:
/* fetch/combine expr algebra loop */
- case ARG_INTMASK:
+ case INTMASK:
/* calculate mask first */
- case ARG_INT:
- case ARG_LONG:
- case ARG_U32:
+ case INT:
+ case LONG:
+ case U32:
parse_match_expr_num(desc.d_num, value);
//emit_cmp(...);
default:
@@ -139,7 +213,6 @@ static int parse_matches(struct gluten_ctx *g, JSON_Value *value)
const char *name;
g->lr = g->ip;
- g->sp = 0;
match = json_array_get_object(matches, i);
name = json_object_get_name(match, 0);
@@ -229,6 +302,7 @@ int parse_file(struct gluten_ctx *g, const char *path)
blocks = json_value_get_array(root);
for (i = 0; i < json_array_get_count(blocks); i++) {
obj = json_array_get_object(blocks, i);
+
debug("Parsing block %i", i);
parse_block(g, obj);
}
diff --git a/eater/Makefile b/eater/Makefile
index 2e3db3f..2e08b1f 100644
--- a/eater/Makefile
+++ b/eater/Makefile
@@ -10,7 +10,7 @@
COMMON_DIR :=../common
SRCS := $(COMMON_DIR)/common.c eater.c
HEADERS := $(COMMON_DIR)/common.h
-BIN := $(OUTDIR)seitan-eater
+BIN := $(OUTDIR)/seitan-eater
CFLAGS += -Wall -Wextra -pedantic -I$(COMMON_DIR)
eater: $(SRCS) $(HEADERS)
diff --git a/operations.c b/operations.c
index 6e8d157..23d571c 100644
--- a/operations.c
+++ b/operations.c
@@ -1,6 +1,10 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later
+/* seitan - Syscall Expressive Interpreter, Transformer and Notifier
+ *
+ * operations.c - Execution of bytecode operations
+ *
* Copyright 2023 Red Hat GmbH
- * Author: Alice Frosi <afrosi@redhat.com>
+ * Authors: Alice Frosi <afrosi@redhat.com>
+ * Stefano Brivio <sbrivio@redhat.com>
*/
#define _GNU_SOURCE
@@ -111,11 +115,11 @@ static int set_namespaces(const struct op_call *a, int tpid)
ns_name);
break;
case NS_SPEC_PID:
- snprintf(path, sizeof(path), "/proc/%d/ns/%s", ns.pid,
- ns_name);
+ snprintf(path, sizeof(path), "/proc/%d/ns/%s",
+ ns.id.pid, ns_name);
break;
case NS_SPEC_PATH:
- snprintf(path, sizeof(path), "%s", ns.path);
+ snprintf(path, sizeof(path), "%s", ns.id.path);
break;
}
@@ -152,14 +156,11 @@ static int execute_syscall(void *args)
exit(0);
}
-int copy_args(struct seccomp_notif *req, struct op_copy_args *copy, void *data,
- int notifier)
+static int op_load(struct seccomp_notif *req, int notifier, struct gluten *g,
+ struct op_load *load)
{
char path[PATH_MAX];
- unsigned int i;
- ssize_t nread;
- void *dest;
- int fd;
+ int fd, ret = 0;
snprintf(path, sizeof(path), "/proc/%d/mem", req->pid);
if ((fd = open(path, O_RDONLY | O_CLOEXEC)) < 0) {
@@ -172,24 +173,17 @@ int copy_args(struct seccomp_notif *req, struct op_copy_args *copy, void *data,
*/
if (!is_cookie_valid(notifier, req->id)) {
fprintf(stderr, "the seccomp request isn't valid anymore\n");
- return -1;
- }
- for (i = 0; i < 6; i++) {
- if (copy->args[i].type == REFERENCE) {
- dest = (uint16_t *)data + copy->args[i].args_off;
- nread = pread(fd, dest, copy->args[i].size,
- req->data.args[i]);
- if (nread < 0) {
- perror("pread");
- return -1;
- }
- } else {
- memcpy((uint16_t *)data + copy->args[i].args_off,
- &req->data.args[i], copy->args[i].size);
- }
+ ret = -1;
+ goto out;
}
+
+ memcpy(gluten_write_ptr(g, load->dst),
+ gluten_ptr(&req->data, g, load->src),
+ load->size);
+
+out:
close(fd);
- return 0;
+ return ret;
}
static int resolve_fd(void *data, struct op_resolvedfd *resfd, pid_t pid)
@@ -230,57 +224,55 @@ int do_call(struct arg_clone *c)
return 0;
}
-static void set_inject_fields(uint64_t id, void *data, const struct op *a,
+static void set_inject_fields(uint64_t id, struct gluten *g,
+ const struct op_inject *a,
struct seccomp_notif_addfd *resp)
{
- const struct fd_type *new = &(a->inj).newfd;
- const struct fd_type *old = &(a->inj).oldfd;
-
resp->flags = SECCOMP_ADDFD_FLAG_SETFD;
resp->id = id;
- if (new->type == IMMEDIATE)
- resp->newfd = new->fd;
- else
- memcpy(&resp->newfd, (uint16_t *)data + new->fd_off,
- sizeof(resp->newfd));
- if (old->type == IMMEDIATE)
- resp->srcfd = old->fd;
- else
- memcpy(&resp->srcfd, (uint16_t *)data + old->fd_off,
- sizeof(resp->srcfd));
+ memcpy(&resp->newfd, gluten_ptr(NULL, g, a->new_fd),
+ sizeof(resp->newfd));
+ memcpy(&resp->srcfd, gluten_ptr(NULL, g, a->new_fd),
+ sizeof(resp->srcfd));
+
resp->newfd_flags = 0;
}
-static int op_cmp(void *data, const struct op_cmp *c)
+static int op_cmp(struct seccomp_notif *req, int notifier, struct gluten *g,
+ struct op_cmp *op)
{
- enum op_cmp_type cmp = c->cmp;
- int res = memcmp((uint16_t *)data + c->s1_off,
- (uint16_t *)data + c->s2_off, c->size);
+ int res = memcmp(gluten_ptr(&req->data, g, op->x),
+ gluten_ptr(&req->data, g, op->y), op->size);
+ enum op_cmp_type cmp = op->cmp;
+
+ (void)notifier;
+
if ((res == 0 && (cmp == CMP_EQ || cmp == CMP_LE || cmp == CMP_GE)) ||
- (res < 0 && (cmp == CMP_LT || cmp == CMP_LE)) ||
- (res > 0 && (cmp == CMP_GT || cmp == CMP_GE)))
- return c->jmp;
- else
- return -1;
+ (res < 0 && (cmp == CMP_LT || cmp == CMP_LE)) ||
+ (res > 0 && (cmp == CMP_GT || cmp == CMP_GE)))
+ return op->jmp;
+
+ return -1;
}
-int do_operations(void *data, struct op operations[], struct seccomp_notif *req,
- unsigned int n_operations, int notifyfd)
+int do_operations(struct gluten *g, struct op *ops, struct seccomp_notif *req,
+ unsigned int n_ops, int notifyfd)
{
struct seccomp_notif_addfd resp_fd;
struct seccomp_notif_resp resp;
struct arg_clone c;
unsigned int i;
+ struct op *op;
int ret;
- for (i = 0; i < n_operations; i++) {
- switch (operations[i].type) {
+ for (i = 0, op = ops; i < n_ops; i++, op++) {
+ switch (op->type) {
case OP_CALL:
resp.id = req->id;
resp.val = 0;
resp.flags = 0;
- c.args = &operations[i].call;
+ c.args = &ops[i].op.call;
c.pid = req->pid;
if (do_call(&c) == -1) {
resp.error = -1;
@@ -296,9 +288,8 @@ int do_operations(void *data, struct op operations[], struct seccomp_notif *req,
* The result of the call needs to be save as
* reference
*/
- if (operations[i].call.has_ret) {
- memcpy((uint16_t *)data +
- operations[i].call.ret_off,
+ if (ops[i].op.call.has_ret) {
+ memcpy(gluten_write_ptr(g, op->op.call.ret),
&c.ret, sizeof(c.ret));
}
break;
@@ -306,7 +297,7 @@ int do_operations(void *data, struct op operations[], struct seccomp_notif *req,
resp.id = req->id;
resp.val = 0;
resp.flags = 0;
- resp.error = operations[i].block.error;
+ resp.error = ops[i].op.block.error;
if (send_target(&resp, notifyfd) == -1)
return -1;
break;
@@ -314,13 +305,10 @@ int do_operations(void *data, struct op operations[], struct seccomp_notif *req,
resp.id = req->id;
resp.flags = 0;
resp.error = 0;
- if (operations[i].ret.type == IMMEDIATE)
- resp.val = operations[i].ret.value;
- else
- memcpy(&resp.val,
- (uint16_t *)data +
- operations[i].ret.value_off,
- sizeof(resp.val));
+
+ memcpy(&resp.val,
+ gluten_ptr(&req->data, g, op->op.ret.val),
+ sizeof(resp.val));
if (send_target(&resp, notifyfd) == -1)
return -1;
@@ -335,39 +323,41 @@ int do_operations(void *data, struct op operations[], struct seccomp_notif *req,
return -1;
break;
case OP_INJECT_A:
- set_inject_fields(req->id, data, &operations[i],
+ set_inject_fields(req->id, g, &ops[i].op.inject,
&resp_fd);
resp_fd.flags |= SECCOMP_ADDFD_FLAG_SEND;
if (send_inject_target(&resp_fd, notifyfd) == -1)
return -1;
break;
case OP_INJECT:
- set_inject_fields(req->id, data, &operations[i],
+ set_inject_fields(req->id, g, &ops[i].op.inject,
&resp_fd);
if (send_inject_target(&resp_fd, notifyfd) == -1)
return -1;
break;
- case OP_COPY_ARGS:
- if (copy_args(req, &operations[i].copy, data,
- notifyfd) < 0)
+ case OP_LOAD:
+ if (op_load(req, notifyfd, g, &op->op.load))
return -1;
+
break;
case OP_END:
return 0;
case OP_CMP:
- if ((ret = op_cmp(data, &operations[i].cmp)) != -1)
- i = ret;
+ ret = op_cmp(req, notifyfd, g, (struct op_cmp *)op);
+ if (ret == -1)
+ return -1;
+
+ i = ret;
break;
case OP_RESOLVEDFD:
- ret = resolve_fd(data, &operations[i].resfd, req->pid);
+ ret = resolve_fd(g->data, &ops[i].op.resfd, req->pid);
if (ret == -1)
return -1;
else if (ret == 1)
- i = operations[i].resfd.jmp;
+ i = ops[i].op.resfd.jmp;
break;
default:
- fprintf(stderr, "unknow operation %d \n",
- operations[i].type);
+ fprintf(stderr, "unknown operation %d \n", ops[i].type);
}
}
return 0;
diff --git a/operations.h b/operations.h
index 3a4caa2..ecb6414 100644
--- a/operations.h
+++ b/operations.h
@@ -20,6 +20,7 @@ struct arg_clone {
};
int do_call(struct arg_clone *c);
-int do_operations(void *data, struct op operations[], struct seccomp_notif *req,
+int do_operations(struct gluten *g, struct op operations[],
+ struct seccomp_notif *req,
unsigned int n_operations, int notifyfd);
#endif /* ACTIONS_H */
diff --git a/scripts/nr_syscalls.sh b/scripts/nr_syscalls.sh
index 380d6f1..5110a9b 100755
--- a/scripts/nr_syscalls.sh
+++ b/scripts/nr_syscalls.sh
@@ -27,31 +27,31 @@ FOOTER_NUMBERS="};
#endif"
-syscalls=(
- "accept"
- "bind"
- "connect"
- "getpeername"
- "getsockname"
- "getsockopt"
- "listen"
- "mount"
- "openat"
- "recvfrom"
- "recvmmsg"
- "recvmsg"
- "sendmmsg"
- "sendmsg"
- "sendto"
- "setsockopt"
- "shutdown"
- "socket"
- "socketpair"
-)
+syscalls="
+ accept
+ bind
+ connect
+ getpeername
+ getsockname
+ getsockopt
+ listen
+ mount
+ openat
+ recvfrom
+ recvmmsg
+ recvmsg
+ sendmmsg
+ sendmsg
+ sendto
+ setsockopt
+ shutdown
+ socket
+ socketpair
+"
printf '%s\n' "${HEADER_NUMBERS}" > "${OUT_NUMBERS}"
# syscall_nr - Get syscall number from compiler, also note in numbers.h
-__in="$(printf "#include <asm-generic/unistd.h>\n#include <sys/syscall.h>\n__NR_%s" ${syscalls[@]})"
+__in="$(for c in ${syscalls}; do printf "#include <asm-generic/unistd.h>\n#include <sys/syscall.h>\n__NR_%s" $c; done)"
__out="$(echo "${__in}" |cc -E -xc - -o - |sed -n '/\#.*$/!p'| sed '/^$/d')"
awk -v AS="${syscalls[*]}" -v BS="${__out[*]}" \