landlock 0.2 → 0.3
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +33 -1
- data/README.md +42 -43
- data/benchmark/landlock_overhead.rb +9 -30
- data/ext/landlock/bin/safe_exec_helper.c +432 -199
- data/ext/landlock/extconf.rb +4 -1
- data/ext/landlock/landlock.c +34 -10
- data/ext/landlock/landlock_native.h +30 -29
- data/ext/landlock/seccomp_deny_network.h +176 -0
- data/lib/landlock/env.rb +31 -0
- data/lib/landlock/errors.rb +32 -0
- data/lib/landlock/execution.rb +238 -0
- data/lib/landlock/native.rb +38 -0
- data/lib/landlock/policy.rb +161 -0
- data/lib/landlock/process_io.rb +249 -0
- data/lib/landlock/result.rb +43 -0
- data/lib/landlock/rights.rb +48 -0
- data/lib/landlock/rlimits.rb +40 -0
- data/lib/landlock/runner/fork.rb +171 -0
- data/lib/landlock/runner/native.rb +225 -0
- data/lib/landlock/runner.rb +28 -0
- data/lib/landlock/validation.rb +59 -0
- data/lib/landlock/version.rb +1 -1
- data/lib/landlock.rb +25 -246
- metadata +51 -10
- data/lib/landlock/safe_exec.rb +0 -522
data/ext/landlock/extconf.rb
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
require "mkmf"
|
|
4
4
|
|
|
5
|
+
append_cppflags("-D_GNU_SOURCE")
|
|
6
|
+
|
|
5
7
|
abort "missing ruby headers" unless have_header("ruby.h")
|
|
6
8
|
|
|
7
9
|
have_header("linux/landlock.h")
|
|
@@ -17,6 +19,7 @@ create_makefile("landlock/landlock")
|
|
|
17
19
|
if RUBY_PLATFORM.include?("linux")
|
|
18
20
|
helper = "landlock-safe-exec"
|
|
19
21
|
helper_src = "$(srcdir)/bin/safe_exec_helper.c"
|
|
22
|
+
helper_headers = "$(srcdir)/landlock_native.h $(srcdir)/seccomp_deny_network.h"
|
|
20
23
|
helper_dest = "$(RUBYARCHDIR)/#{helper}"
|
|
21
24
|
|
|
22
25
|
File.open("Makefile", "a") do |makefile|
|
|
@@ -25,7 +28,7 @@ if RUBY_PLATFORM.include?("linux")
|
|
|
25
28
|
all: #{helper}
|
|
26
29
|
|
|
27
30
|
#{helper}: #{helper_src}
|
|
28
|
-
\t$(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) #{helper_src} -o #{helper}
|
|
31
|
+
\t$(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) #{helper_src} -o #{helper}
|
|
29
32
|
|
|
30
33
|
install: install-#{helper}
|
|
31
34
|
|
data/ext/landlock/landlock.c
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#include "ruby.h"
|
|
2
2
|
#include "landlock_native.h"
|
|
3
|
+
#include "seccomp_deny_network.h"
|
|
3
4
|
|
|
4
5
|
#include <string.h>
|
|
5
6
|
|
|
@@ -9,8 +10,7 @@ static VALUE eSyscallError;
|
|
|
9
10
|
|
|
10
11
|
static void raise_syscall_error(const char *syscall_name) {
|
|
11
12
|
int saved_errno = errno;
|
|
12
|
-
VALUE err = rb_funcall(eSyscallError, rb_intern("new"), 3,
|
|
13
|
-
rb_str_new_cstr(syscall_name),
|
|
13
|
+
VALUE err = rb_funcall(eSyscallError, rb_intern("new"), 3, rb_str_new_cstr(syscall_name),
|
|
14
14
|
INT2NUM(saved_errno),
|
|
15
15
|
rb_sprintf("%s failed: %s", syscall_name, strerror(saved_errno)));
|
|
16
16
|
rb_exc_raise(err);
|
|
@@ -19,7 +19,9 @@ static void raise_syscall_error(const char *syscall_name) {
|
|
|
19
19
|
static VALUE rb_ll_abi_version(VALUE self) {
|
|
20
20
|
long abi = ll_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION);
|
|
21
21
|
if (abi < 0) {
|
|
22
|
-
if (errno == ENOSYS || errno == EOPNOTSUPP)
|
|
22
|
+
if (errno == ENOSYS || errno == EOPNOTSUPP) {
|
|
23
|
+
return INT2FIX(0);
|
|
24
|
+
}
|
|
23
25
|
raise_syscall_error("landlock_create_ruleset");
|
|
24
26
|
}
|
|
25
27
|
return LONG2NUM(abi);
|
|
@@ -45,7 +47,9 @@ static VALUE rb_ll_create_ruleset(int argc, VALUE *argv, VALUE self) {
|
|
|
45
47
|
attr.scoped = scoped;
|
|
46
48
|
|
|
47
49
|
long fd = ll_create_ruleset(&attr, attr_size, 0);
|
|
48
|
-
if (fd < 0)
|
|
50
|
+
if (fd < 0) {
|
|
51
|
+
raise_syscall_error("landlock_create_ruleset");
|
|
52
|
+
}
|
|
49
53
|
return INT2NUM(fd);
|
|
50
54
|
}
|
|
51
55
|
|
|
@@ -55,7 +59,9 @@ static VALUE rb_ll_add_path_rule(VALUE self, VALUE ruleset_fd, VALUE path, VALUE
|
|
|
55
59
|
Check_Type(path, T_STRING);
|
|
56
60
|
const char *cpath = StringValueCStr(path);
|
|
57
61
|
int parent_fd = open(cpath, O_PATH | O_CLOEXEC);
|
|
58
|
-
if (parent_fd < 0)
|
|
62
|
+
if (parent_fd < 0) {
|
|
63
|
+
raise_syscall_error("open");
|
|
64
|
+
}
|
|
59
65
|
|
|
60
66
|
struct rb_landlock_path_beneath_attr rule;
|
|
61
67
|
memset(&rule, 0, sizeof(rule));
|
|
@@ -74,7 +80,9 @@ static VALUE rb_ll_add_path_rule(VALUE self, VALUE ruleset_fd, VALUE path, VALUE
|
|
|
74
80
|
|
|
75
81
|
static VALUE rb_ll_add_net_rule(VALUE self, VALUE ruleset_fd, VALUE port, VALUE access_bits) {
|
|
76
82
|
unsigned long long p = NUM2ULL(port);
|
|
77
|
-
if (p > 65535ULL)
|
|
83
|
+
if (p > 65535ULL) {
|
|
84
|
+
rb_raise(rb_eArgError, "TCP port must be between 0 and 65535");
|
|
85
|
+
}
|
|
78
86
|
|
|
79
87
|
struct rb_landlock_net_port_attr rule;
|
|
80
88
|
memset(&rule, 0, sizeof(rule));
|
|
@@ -82,7 +90,9 @@ static VALUE rb_ll_add_net_rule(VALUE self, VALUE ruleset_fd, VALUE port, VALUE
|
|
|
82
90
|
rule.port = p;
|
|
83
91
|
|
|
84
92
|
long ret = ll_add_rule(NUM2INT(ruleset_fd), LANDLOCK_RULE_NET_PORT, &rule, 0);
|
|
85
|
-
if (ret < 0)
|
|
93
|
+
if (ret < 0) {
|
|
94
|
+
raise_syscall_error("landlock_add_rule(net_port)");
|
|
95
|
+
}
|
|
86
96
|
return Qtrue;
|
|
87
97
|
}
|
|
88
98
|
|
|
@@ -93,7 +103,9 @@ static VALUE rb_ll_restrict_self(VALUE self, VALUE ruleset_fd) {
|
|
|
93
103
|
}
|
|
94
104
|
|
|
95
105
|
long ret = ll_restrict_self(NUM2INT(ruleset_fd), 0);
|
|
96
|
-
if (ret < 0)
|
|
106
|
+
if (ret < 0) {
|
|
107
|
+
raise_syscall_error("landlock_restrict_self");
|
|
108
|
+
}
|
|
97
109
|
return Qtrue;
|
|
98
110
|
#else
|
|
99
111
|
errno = ENOSYS;
|
|
@@ -103,10 +115,20 @@ static VALUE rb_ll_restrict_self(VALUE self, VALUE ruleset_fd) {
|
|
|
103
115
|
|
|
104
116
|
static VALUE rb_ll_close_fd(VALUE self, VALUE fd_value) {
|
|
105
117
|
int fd = NUM2INT(fd_value);
|
|
106
|
-
if (fd >= 0)
|
|
118
|
+
if (fd >= 0) {
|
|
119
|
+
close(fd);
|
|
120
|
+
}
|
|
107
121
|
return Qnil;
|
|
108
122
|
}
|
|
109
123
|
|
|
124
|
+
static VALUE rb_ll_seccomp_deny_network(VALUE self) {
|
|
125
|
+
const char *error_message = "seccomp(SECCOMP_SET_MODE_FILTER)";
|
|
126
|
+
if (rb_landlock_seccomp_deny_network(&error_message) != 0) {
|
|
127
|
+
raise_syscall_error(error_message);
|
|
128
|
+
}
|
|
129
|
+
return Qtrue;
|
|
130
|
+
}
|
|
131
|
+
|
|
110
132
|
void Init_landlock(void) {
|
|
111
133
|
mLandlock = rb_define_module("Landlock");
|
|
112
134
|
|
|
@@ -128,6 +150,7 @@ void Init_landlock(void) {
|
|
|
128
150
|
rb_define_singleton_method(mLandlock, "_add_net_rule", rb_ll_add_net_rule, 3);
|
|
129
151
|
rb_define_singleton_method(mLandlock, "_restrict_self", rb_ll_restrict_self, 1);
|
|
130
152
|
rb_define_singleton_method(mLandlock, "_close_fd", rb_ll_close_fd, 1);
|
|
153
|
+
rb_define_singleton_method(mLandlock, "seccomp_deny_network!", rb_ll_seccomp_deny_network, 0);
|
|
131
154
|
|
|
132
155
|
rb_define_const(mLandlock, "ACCESS_FS_EXECUTE", ULL2NUM(LANDLOCK_ACCESS_FS_EXECUTE));
|
|
133
156
|
rb_define_const(mLandlock, "ACCESS_FS_WRITE_FILE", ULL2NUM(LANDLOCK_ACCESS_FS_WRITE_FILE));
|
|
@@ -147,6 +170,7 @@ void Init_landlock(void) {
|
|
|
147
170
|
rb_define_const(mLandlock, "ACCESS_FS_IOCTL_DEV", ULL2NUM(LANDLOCK_ACCESS_FS_IOCTL_DEV));
|
|
148
171
|
rb_define_const(mLandlock, "ACCESS_NET_BIND_TCP", ULL2NUM(LANDLOCK_ACCESS_NET_BIND_TCP));
|
|
149
172
|
rb_define_const(mLandlock, "ACCESS_NET_CONNECT_TCP", ULL2NUM(LANDLOCK_ACCESS_NET_CONNECT_TCP));
|
|
150
|
-
rb_define_const(mLandlock, "SCOPE_ABSTRACT_UNIX_SOCKET",
|
|
173
|
+
rb_define_const(mLandlock, "SCOPE_ABSTRACT_UNIX_SOCKET",
|
|
174
|
+
ULL2NUM(LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET));
|
|
151
175
|
rb_define_const(mLandlock, "SCOPE_SIGNAL", ULL2NUM(LANDLOCK_SCOPE_SIGNAL));
|
|
152
176
|
}
|
|
@@ -16,22 +16,23 @@
|
|
|
16
16
|
#endif
|
|
17
17
|
|
|
18
18
|
#ifndef SYS_landlock_create_ruleset
|
|
19
|
-
#
|
|
20
|
-
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
19
|
+
#if defined(__linux__) && defined(__NR_landlock_create_ruleset) && \
|
|
20
|
+
defined(__NR_landlock_add_rule) && defined(__NR_landlock_restrict_self)
|
|
21
|
+
#define SYS_landlock_create_ruleset __NR_landlock_create_ruleset
|
|
22
|
+
#define SYS_landlock_add_rule __NR_landlock_add_rule
|
|
23
|
+
#define SYS_landlock_restrict_self __NR_landlock_restrict_self
|
|
24
|
+
#elif defined(__linux__) && defined(__x86_64__) && defined(__ILP32__)
|
|
25
|
+
#ifndef __X32_SYSCALL_BIT
|
|
26
|
+
#define __X32_SYSCALL_BIT 0x40000000
|
|
27
|
+
#endif
|
|
28
|
+
#define SYS_landlock_create_ruleset (__X32_SYSCALL_BIT + 444)
|
|
29
|
+
#define SYS_landlock_add_rule (__X32_SYSCALL_BIT + 445)
|
|
30
|
+
#define SYS_landlock_restrict_self (__X32_SYSCALL_BIT + 446)
|
|
31
|
+
#elif defined(__linux__) && (defined(__x86_64__) || defined(__aarch64__) || defined(__i386__))
|
|
32
|
+
#define SYS_landlock_create_ruleset 444
|
|
33
|
+
#define SYS_landlock_add_rule 445
|
|
34
|
+
#define SYS_landlock_restrict_self 446
|
|
35
|
+
#endif
|
|
35
36
|
#endif
|
|
36
37
|
|
|
37
38
|
#ifndef LANDLOCK_CREATE_RULESET_VERSION
|
|
@@ -47,16 +48,16 @@
|
|
|
47
48
|
#endif
|
|
48
49
|
|
|
49
50
|
#ifndef LANDLOCK_ACCESS_FS_EXECUTE
|
|
50
|
-
#define LANDLOCK_ACCESS_FS_EXECUTE
|
|
51
|
+
#define LANDLOCK_ACCESS_FS_EXECUTE (1ULL << 0)
|
|
51
52
|
#endif
|
|
52
53
|
#ifndef LANDLOCK_ACCESS_FS_WRITE_FILE
|
|
53
54
|
#define LANDLOCK_ACCESS_FS_WRITE_FILE (1ULL << 1)
|
|
54
55
|
#endif
|
|
55
56
|
#ifndef LANDLOCK_ACCESS_FS_READ_FILE
|
|
56
|
-
#define LANDLOCK_ACCESS_FS_READ_FILE
|
|
57
|
+
#define LANDLOCK_ACCESS_FS_READ_FILE (1ULL << 2)
|
|
57
58
|
#endif
|
|
58
59
|
#ifndef LANDLOCK_ACCESS_FS_READ_DIR
|
|
59
|
-
#define LANDLOCK_ACCESS_FS_READ_DIR
|
|
60
|
+
#define LANDLOCK_ACCESS_FS_READ_DIR (1ULL << 3)
|
|
60
61
|
#endif
|
|
61
62
|
#ifndef LANDLOCK_ACCESS_FS_REMOVE_DIR
|
|
62
63
|
#define LANDLOCK_ACCESS_FS_REMOVE_DIR (1ULL << 4)
|
|
@@ -65,38 +66,38 @@
|
|
|
65
66
|
#define LANDLOCK_ACCESS_FS_REMOVE_FILE (1ULL << 5)
|
|
66
67
|
#endif
|
|
67
68
|
#ifndef LANDLOCK_ACCESS_FS_MAKE_CHAR
|
|
68
|
-
#define LANDLOCK_ACCESS_FS_MAKE_CHAR
|
|
69
|
+
#define LANDLOCK_ACCESS_FS_MAKE_CHAR (1ULL << 6)
|
|
69
70
|
#endif
|
|
70
71
|
#ifndef LANDLOCK_ACCESS_FS_MAKE_DIR
|
|
71
|
-
#define LANDLOCK_ACCESS_FS_MAKE_DIR
|
|
72
|
+
#define LANDLOCK_ACCESS_FS_MAKE_DIR (1ULL << 7)
|
|
72
73
|
#endif
|
|
73
74
|
#ifndef LANDLOCK_ACCESS_FS_MAKE_REG
|
|
74
|
-
#define LANDLOCK_ACCESS_FS_MAKE_REG
|
|
75
|
+
#define LANDLOCK_ACCESS_FS_MAKE_REG (1ULL << 8)
|
|
75
76
|
#endif
|
|
76
77
|
#ifndef LANDLOCK_ACCESS_FS_MAKE_SOCK
|
|
77
|
-
#define LANDLOCK_ACCESS_FS_MAKE_SOCK
|
|
78
|
+
#define LANDLOCK_ACCESS_FS_MAKE_SOCK (1ULL << 9)
|
|
78
79
|
#endif
|
|
79
80
|
#ifndef LANDLOCK_ACCESS_FS_MAKE_FIFO
|
|
80
|
-
#define LANDLOCK_ACCESS_FS_MAKE_FIFO
|
|
81
|
+
#define LANDLOCK_ACCESS_FS_MAKE_FIFO (1ULL << 10)
|
|
81
82
|
#endif
|
|
82
83
|
#ifndef LANDLOCK_ACCESS_FS_MAKE_BLOCK
|
|
83
84
|
#define LANDLOCK_ACCESS_FS_MAKE_BLOCK (1ULL << 11)
|
|
84
85
|
#endif
|
|
85
86
|
#ifndef LANDLOCK_ACCESS_FS_MAKE_SYM
|
|
86
|
-
#define LANDLOCK_ACCESS_FS_MAKE_SYM
|
|
87
|
+
#define LANDLOCK_ACCESS_FS_MAKE_SYM (1ULL << 12)
|
|
87
88
|
#endif
|
|
88
89
|
#ifndef LANDLOCK_ACCESS_FS_REFER
|
|
89
|
-
#define LANDLOCK_ACCESS_FS_REFER
|
|
90
|
+
#define LANDLOCK_ACCESS_FS_REFER (1ULL << 13)
|
|
90
91
|
#endif
|
|
91
92
|
#ifndef LANDLOCK_ACCESS_FS_TRUNCATE
|
|
92
|
-
#define LANDLOCK_ACCESS_FS_TRUNCATE
|
|
93
|
+
#define LANDLOCK_ACCESS_FS_TRUNCATE (1ULL << 14)
|
|
93
94
|
#endif
|
|
94
95
|
#ifndef LANDLOCK_ACCESS_FS_IOCTL_DEV
|
|
95
|
-
#define LANDLOCK_ACCESS_FS_IOCTL_DEV
|
|
96
|
+
#define LANDLOCK_ACCESS_FS_IOCTL_DEV (1ULL << 15)
|
|
96
97
|
#endif
|
|
97
98
|
|
|
98
99
|
#ifndef LANDLOCK_ACCESS_NET_BIND_TCP
|
|
99
|
-
#define LANDLOCK_ACCESS_NET_BIND_TCP
|
|
100
|
+
#define LANDLOCK_ACCESS_NET_BIND_TCP (1ULL << 0)
|
|
100
101
|
#endif
|
|
101
102
|
#ifndef LANDLOCK_ACCESS_NET_CONNECT_TCP
|
|
102
103
|
#define LANDLOCK_ACCESS_NET_CONNECT_TCP (1ULL << 1)
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
#ifndef RB_LANDLOCK_SECCOMP_DENY_NETWORK_H
|
|
2
|
+
#define RB_LANDLOCK_SECCOMP_DENY_NETWORK_H
|
|
3
|
+
|
|
4
|
+
#include <errno.h>
|
|
5
|
+
#include <stddef.h>
|
|
6
|
+
#include <stdlib.h>
|
|
7
|
+
#include <unistd.h>
|
|
8
|
+
|
|
9
|
+
#ifdef __linux__
|
|
10
|
+
#include <linux/audit.h>
|
|
11
|
+
#include <linux/filter.h>
|
|
12
|
+
#include <linux/seccomp.h>
|
|
13
|
+
#include <sys/prctl.h>
|
|
14
|
+
#include <sys/syscall.h>
|
|
15
|
+
#endif
|
|
16
|
+
|
|
17
|
+
#ifndef SECCOMP_RET_ALLOW
|
|
18
|
+
#define SECCOMP_RET_ALLOW 0x7fff0000U
|
|
19
|
+
#endif
|
|
20
|
+
#ifndef SECCOMP_RET_ERRNO
|
|
21
|
+
#define SECCOMP_RET_ERRNO 0x00050000U
|
|
22
|
+
#endif
|
|
23
|
+
#ifndef SECCOMP_RET_KILL_PROCESS
|
|
24
|
+
#define SECCOMP_RET_KILL_PROCESS 0x80000000U
|
|
25
|
+
#endif
|
|
26
|
+
#ifndef SECCOMP_SET_MODE_FILTER
|
|
27
|
+
#define SECCOMP_SET_MODE_FILTER 1
|
|
28
|
+
#endif
|
|
29
|
+
|
|
30
|
+
#ifdef __linux__
|
|
31
|
+
static int rb_landlock_deny_network_syscalls[] = {
|
|
32
|
+
#ifdef __NR_socket
|
|
33
|
+
__NR_socket,
|
|
34
|
+
#endif
|
|
35
|
+
#ifdef __NR_socketpair
|
|
36
|
+
__NR_socketpair,
|
|
37
|
+
#endif
|
|
38
|
+
#ifdef __NR_connect
|
|
39
|
+
__NR_connect,
|
|
40
|
+
#endif
|
|
41
|
+
#ifdef __NR_bind
|
|
42
|
+
__NR_bind,
|
|
43
|
+
#endif
|
|
44
|
+
#ifdef __NR_listen
|
|
45
|
+
__NR_listen,
|
|
46
|
+
#endif
|
|
47
|
+
#ifdef __NR_accept
|
|
48
|
+
__NR_accept,
|
|
49
|
+
#endif
|
|
50
|
+
#ifdef __NR_accept4
|
|
51
|
+
__NR_accept4,
|
|
52
|
+
#endif
|
|
53
|
+
#ifdef __NR_sendto
|
|
54
|
+
__NR_sendto,
|
|
55
|
+
#endif
|
|
56
|
+
#ifdef __NR_sendmsg
|
|
57
|
+
__NR_sendmsg,
|
|
58
|
+
#endif
|
|
59
|
+
#ifdef __NR_sendmmsg
|
|
60
|
+
__NR_sendmmsg,
|
|
61
|
+
#endif
|
|
62
|
+
#ifdef __NR_recvfrom
|
|
63
|
+
__NR_recvfrom,
|
|
64
|
+
#endif
|
|
65
|
+
#ifdef __NR_recvmsg
|
|
66
|
+
__NR_recvmsg,
|
|
67
|
+
#endif
|
|
68
|
+
#ifdef __NR_recvmmsg
|
|
69
|
+
__NR_recvmmsg,
|
|
70
|
+
#endif
|
|
71
|
+
#ifdef __NR_socketcall
|
|
72
|
+
__NR_socketcall,
|
|
73
|
+
#endif
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
#if defined(__x86_64__) && defined(AUDIT_ARCH_X86_64)
|
|
77
|
+
#define RB_LANDLOCK_EXPECTED_AUDIT_ARCH AUDIT_ARCH_X86_64
|
|
78
|
+
#elif defined(__aarch64__) && defined(AUDIT_ARCH_AARCH64)
|
|
79
|
+
#define RB_LANDLOCK_EXPECTED_AUDIT_ARCH AUDIT_ARCH_AARCH64
|
|
80
|
+
#elif defined(__i386__) && defined(AUDIT_ARCH_I386)
|
|
81
|
+
#define RB_LANDLOCK_EXPECTED_AUDIT_ARCH AUDIT_ARCH_I386
|
|
82
|
+
#endif
|
|
83
|
+
|
|
84
|
+
#if defined(__x86_64__) && !defined(__ILP32__)
|
|
85
|
+
#ifndef __X32_SYSCALL_BIT
|
|
86
|
+
#define __X32_SYSCALL_BIT 0x40000000
|
|
87
|
+
#endif
|
|
88
|
+
#define RB_LANDLOCK_DENY_X32_SYSCALLS 1
|
|
89
|
+
#endif
|
|
90
|
+
#endif
|
|
91
|
+
|
|
92
|
+
static int rb_landlock_seccomp_deny_network(const char **error_message) {
|
|
93
|
+
#ifdef __linux__
|
|
94
|
+
#ifndef RB_LANDLOCK_EXPECTED_AUDIT_ARCH
|
|
95
|
+
errno = ENOSYS;
|
|
96
|
+
if (error_message) {
|
|
97
|
+
*error_message = "seccomp unsupported architecture";
|
|
98
|
+
}
|
|
99
|
+
return -1;
|
|
100
|
+
#else
|
|
101
|
+
size_t count =
|
|
102
|
+
sizeof(rb_landlock_deny_network_syscalls) / sizeof(rb_landlock_deny_network_syscalls[0]);
|
|
103
|
+
if (count == 0) {
|
|
104
|
+
return 0;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
size_t len = 1 + (2 * count) + 1;
|
|
108
|
+
len += 3;
|
|
109
|
+
#ifdef RB_LANDLOCK_DENY_X32_SYSCALLS
|
|
110
|
+
len += 2;
|
|
111
|
+
#endif
|
|
112
|
+
struct sock_filter *filter = calloc(len, sizeof(struct sock_filter));
|
|
113
|
+
if (!filter) {
|
|
114
|
+
if (error_message) {
|
|
115
|
+
*error_message = "calloc";
|
|
116
|
+
}
|
|
117
|
+
return -1;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
size_t pc = 0;
|
|
121
|
+
filter[pc++] =
|
|
122
|
+
(struct sock_filter)BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, arch));
|
|
123
|
+
filter[pc++] = (struct sock_filter)BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K,
|
|
124
|
+
RB_LANDLOCK_EXPECTED_AUDIT_ARCH, 1, 0);
|
|
125
|
+
filter[pc++] = (struct sock_filter)BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS);
|
|
126
|
+
filter[pc++] =
|
|
127
|
+
(struct sock_filter)BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, nr));
|
|
128
|
+
#ifdef RB_LANDLOCK_DENY_X32_SYSCALLS
|
|
129
|
+
filter[pc++] = (struct sock_filter)BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K, __X32_SYSCALL_BIT, 0, 1);
|
|
130
|
+
filter[pc++] = (struct sock_filter)BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ERRNO | EPERM);
|
|
131
|
+
#endif
|
|
132
|
+
for (size_t i = 0; i < count; i++) {
|
|
133
|
+
filter[pc++] = (struct sock_filter)BPF_JUMP(
|
|
134
|
+
BPF_JMP | BPF_JEQ | BPF_K, (unsigned int)rb_landlock_deny_network_syscalls[i], 0, 1);
|
|
135
|
+
filter[pc++] = (struct sock_filter)BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ERRNO | EPERM);
|
|
136
|
+
}
|
|
137
|
+
filter[pc++] = (struct sock_filter)BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW);
|
|
138
|
+
|
|
139
|
+
struct sock_fprog prog;
|
|
140
|
+
prog.len = (unsigned short)pc;
|
|
141
|
+
prog.filter = filter;
|
|
142
|
+
|
|
143
|
+
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0) {
|
|
144
|
+
if (error_message) {
|
|
145
|
+
*error_message = "prctl(PR_SET_NO_NEW_PRIVS)";
|
|
146
|
+
}
|
|
147
|
+
free(filter);
|
|
148
|
+
return -1;
|
|
149
|
+
}
|
|
150
|
+
#ifdef SYS_seccomp
|
|
151
|
+
if (syscall(SYS_seccomp, SECCOMP_SET_MODE_FILTER, 0, &prog) == 0) {
|
|
152
|
+
free(filter);
|
|
153
|
+
return 0;
|
|
154
|
+
}
|
|
155
|
+
#endif
|
|
156
|
+
if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) != 0) {
|
|
157
|
+
if (error_message) {
|
|
158
|
+
*error_message = "seccomp(SECCOMP_SET_MODE_FILTER)";
|
|
159
|
+
}
|
|
160
|
+
free(filter);
|
|
161
|
+
return -1;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
free(filter);
|
|
165
|
+
return 0;
|
|
166
|
+
#endif
|
|
167
|
+
#else
|
|
168
|
+
errno = ENOSYS;
|
|
169
|
+
if (error_message) {
|
|
170
|
+
*error_message = "seccomp(SECCOMP_SET_MODE_FILTER)";
|
|
171
|
+
}
|
|
172
|
+
return -1;
|
|
173
|
+
#endif
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
#endif
|
data/lib/landlock/env.rb
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Landlock
|
|
4
|
+
module Env
|
|
5
|
+
module_function
|
|
6
|
+
|
|
7
|
+
def normalize(env)
|
|
8
|
+
return nil if env.nil?
|
|
9
|
+
|
|
10
|
+
raise ArgumentError, "env must be a Hash-compatible object" unless env.respond_to?(:each_pair)
|
|
11
|
+
|
|
12
|
+
normalized = {}
|
|
13
|
+
env.each_pair do |key, value|
|
|
14
|
+
key = key.to_s
|
|
15
|
+
raise ArgumentError, "env key must not be empty" if key.empty?
|
|
16
|
+
raise ArgumentError, "env key must not contain '='" if key.include?("=")
|
|
17
|
+
raise ArgumentError, "env key must not contain NUL" if key.include?("\0")
|
|
18
|
+
|
|
19
|
+
if value.nil?
|
|
20
|
+
normalized[key] = nil
|
|
21
|
+
else
|
|
22
|
+
value = value.to_s
|
|
23
|
+
raise ArgumentError, "env value must not contain NUL" if value.include?("\0")
|
|
24
|
+
|
|
25
|
+
normalized[key] = value
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
normalized
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Landlock
|
|
4
|
+
Error = Class.new(StandardError)
|
|
5
|
+
UnsupportedError = Class.new(Error)
|
|
6
|
+
|
|
7
|
+
class SyscallError < Error
|
|
8
|
+
attr_reader :errno, :syscall
|
|
9
|
+
|
|
10
|
+
def initialize(syscall, errno, message = nil)
|
|
11
|
+
@syscall = syscall
|
|
12
|
+
@errno = errno
|
|
13
|
+
super(message || "#{syscall} failed: #{errno}")
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
class CommandError < Error
|
|
18
|
+
attr_reader :stdout, :stderr, :status, :result
|
|
19
|
+
|
|
20
|
+
def initialize(message, stdout: "", stderr: "", status: nil, result: nil)
|
|
21
|
+
@stdout = stdout
|
|
22
|
+
@stderr = stderr
|
|
23
|
+
@status = status
|
|
24
|
+
@result = result
|
|
25
|
+
super(message)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class OutputTooLargeError < Error
|
|
30
|
+
attr_accessor :result
|
|
31
|
+
end
|
|
32
|
+
end
|