landlock 0.1.1 → 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.
@@ -1,179 +1,16 @@
1
1
  #include "ruby.h"
2
+ #include "landlock_native.h"
3
+ #include "seccomp_deny_network.h"
2
4
 
3
- #include <errno.h>
4
- #include <fcntl.h>
5
- #include <stdint.h>
6
- #include <stddef.h>
7
5
  #include <string.h>
8
- #include <unistd.h>
9
- #include <sys/prctl.h>
10
- #include <sys/syscall.h>
11
-
12
- #ifdef HAVE_LINUX_LANDLOCK_H
13
- #include <linux/landlock.h>
14
- #endif
15
-
16
- #ifndef SYS_landlock_create_ruleset
17
- # if defined(__NR_landlock_create_ruleset) && defined(__NR_landlock_add_rule) && defined(__NR_landlock_restrict_self)
18
- # define SYS_landlock_create_ruleset __NR_landlock_create_ruleset
19
- # define SYS_landlock_add_rule __NR_landlock_add_rule
20
- # define SYS_landlock_restrict_self __NR_landlock_restrict_self
21
- # elif defined(__x86_64__) && defined(__ILP32__)
22
- # ifndef __X32_SYSCALL_BIT
23
- # define __X32_SYSCALL_BIT 0x40000000
24
- # endif
25
- # define SYS_landlock_create_ruleset (__X32_SYSCALL_BIT + 444)
26
- # define SYS_landlock_add_rule (__X32_SYSCALL_BIT + 445)
27
- # define SYS_landlock_restrict_self (__X32_SYSCALL_BIT + 446)
28
- # elif defined(__x86_64__)
29
- # define SYS_landlock_create_ruleset 444
30
- # define SYS_landlock_add_rule 445
31
- # define SYS_landlock_restrict_self 446
32
- # elif defined(__aarch64__)
33
- # define SYS_landlock_create_ruleset 444
34
- # define SYS_landlock_add_rule 445
35
- # define SYS_landlock_restrict_self 446
36
- # elif defined(__i386__)
37
- # define SYS_landlock_create_ruleset 444
38
- # define SYS_landlock_add_rule 445
39
- # define SYS_landlock_restrict_self 446
40
- # endif
41
- #endif
42
-
43
- #ifndef LANDLOCK_CREATE_RULESET_VERSION
44
- #define LANDLOCK_CREATE_RULESET_VERSION (1U << 0)
45
- #endif
46
-
47
- #ifndef LANDLOCK_RULE_PATH_BENEATH
48
- #define LANDLOCK_RULE_PATH_BENEATH 1
49
- #endif
50
-
51
- #ifndef LANDLOCK_RULE_NET_PORT
52
- #define LANDLOCK_RULE_NET_PORT 2
53
- #endif
54
-
55
- #ifndef LANDLOCK_ACCESS_FS_EXECUTE
56
- #define LANDLOCK_ACCESS_FS_EXECUTE (1ULL << 0)
57
- #endif
58
- #ifndef LANDLOCK_ACCESS_FS_WRITE_FILE
59
- #define LANDLOCK_ACCESS_FS_WRITE_FILE (1ULL << 1)
60
- #endif
61
- #ifndef LANDLOCK_ACCESS_FS_READ_FILE
62
- #define LANDLOCK_ACCESS_FS_READ_FILE (1ULL << 2)
63
- #endif
64
- #ifndef LANDLOCK_ACCESS_FS_READ_DIR
65
- #define LANDLOCK_ACCESS_FS_READ_DIR (1ULL << 3)
66
- #endif
67
- #ifndef LANDLOCK_ACCESS_FS_REMOVE_DIR
68
- #define LANDLOCK_ACCESS_FS_REMOVE_DIR (1ULL << 4)
69
- #endif
70
- #ifndef LANDLOCK_ACCESS_FS_REMOVE_FILE
71
- #define LANDLOCK_ACCESS_FS_REMOVE_FILE (1ULL << 5)
72
- #endif
73
- #ifndef LANDLOCK_ACCESS_FS_MAKE_CHAR
74
- #define LANDLOCK_ACCESS_FS_MAKE_CHAR (1ULL << 6)
75
- #endif
76
- #ifndef LANDLOCK_ACCESS_FS_MAKE_DIR
77
- #define LANDLOCK_ACCESS_FS_MAKE_DIR (1ULL << 7)
78
- #endif
79
- #ifndef LANDLOCK_ACCESS_FS_MAKE_REG
80
- #define LANDLOCK_ACCESS_FS_MAKE_REG (1ULL << 8)
81
- #endif
82
- #ifndef LANDLOCK_ACCESS_FS_MAKE_SOCK
83
- #define LANDLOCK_ACCESS_FS_MAKE_SOCK (1ULL << 9)
84
- #endif
85
- #ifndef LANDLOCK_ACCESS_FS_MAKE_FIFO
86
- #define LANDLOCK_ACCESS_FS_MAKE_FIFO (1ULL << 10)
87
- #endif
88
- #ifndef LANDLOCK_ACCESS_FS_MAKE_BLOCK
89
- #define LANDLOCK_ACCESS_FS_MAKE_BLOCK (1ULL << 11)
90
- #endif
91
- #ifndef LANDLOCK_ACCESS_FS_MAKE_SYM
92
- #define LANDLOCK_ACCESS_FS_MAKE_SYM (1ULL << 12)
93
- #endif
94
- #ifndef LANDLOCK_ACCESS_FS_REFER
95
- #define LANDLOCK_ACCESS_FS_REFER (1ULL << 13)
96
- #endif
97
- #ifndef LANDLOCK_ACCESS_FS_TRUNCATE
98
- #define LANDLOCK_ACCESS_FS_TRUNCATE (1ULL << 14)
99
- #endif
100
- #ifndef LANDLOCK_ACCESS_FS_IOCTL_DEV
101
- #define LANDLOCK_ACCESS_FS_IOCTL_DEV (1ULL << 15)
102
- #endif
103
-
104
- #ifndef LANDLOCK_ACCESS_NET_BIND_TCP
105
- #define LANDLOCK_ACCESS_NET_BIND_TCP (1ULL << 0)
106
- #endif
107
- #ifndef LANDLOCK_ACCESS_NET_CONNECT_TCP
108
- #define LANDLOCK_ACCESS_NET_CONNECT_TCP (1ULL << 1)
109
- #endif
110
-
111
- #ifndef LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET
112
- #define LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET (1ULL << 0)
113
- #endif
114
- #ifndef LANDLOCK_SCOPE_SIGNAL
115
- #define LANDLOCK_SCOPE_SIGNAL (1ULL << 1)
116
- #endif
117
-
118
- #ifndef O_PATH
119
- #define O_PATH 010000000
120
- #endif
121
-
122
- #ifndef O_CLOEXEC
123
- #define O_CLOEXEC 02000000
124
- #endif
125
-
126
- struct rb_landlock_ruleset_attr {
127
- uint64_t handled_access_fs;
128
- uint64_t handled_access_net;
129
- uint64_t scoped;
130
- };
131
-
132
- struct rb_landlock_path_beneath_attr {
133
- uint64_t allowed_access;
134
- int32_t parent_fd;
135
- } __attribute__((packed));
136
-
137
- struct rb_landlock_net_port_attr {
138
- uint64_t allowed_access;
139
- uint64_t port;
140
- };
141
6
 
142
7
  static VALUE mLandlock;
143
8
  static VALUE eLandlockError;
144
9
  static VALUE eSyscallError;
145
10
 
146
- static long ll_create_ruleset(const void *attr, size_t size, uint32_t flags) {
147
- #ifdef SYS_landlock_create_ruleset
148
- return syscall(SYS_landlock_create_ruleset, attr, size, flags);
149
- #else
150
- errno = ENOSYS;
151
- return -1;
152
- #endif
153
- }
154
-
155
- static long ll_add_rule(int ruleset_fd, int rule_type, const void *rule_attr, uint32_t flags) {
156
- #ifdef SYS_landlock_add_rule
157
- return syscall(SYS_landlock_add_rule, ruleset_fd, rule_type, rule_attr, flags);
158
- #else
159
- errno = ENOSYS;
160
- return -1;
161
- #endif
162
- }
163
-
164
- static long ll_restrict_self(int ruleset_fd, uint32_t flags) {
165
- #ifdef SYS_landlock_restrict_self
166
- return syscall(SYS_landlock_restrict_self, ruleset_fd, flags);
167
- #else
168
- errno = ENOSYS;
169
- return -1;
170
- #endif
171
- }
172
-
173
11
  static void raise_syscall_error(const char *syscall_name) {
174
12
  int saved_errno = errno;
175
- VALUE err = rb_funcall(eSyscallError, rb_intern("new"), 3,
176
- rb_str_new_cstr(syscall_name),
13
+ VALUE err = rb_funcall(eSyscallError, rb_intern("new"), 3, rb_str_new_cstr(syscall_name),
177
14
  INT2NUM(saved_errno),
178
15
  rb_sprintf("%s failed: %s", syscall_name, strerror(saved_errno)));
179
16
  rb_exc_raise(err);
@@ -182,7 +19,9 @@ static void raise_syscall_error(const char *syscall_name) {
182
19
  static VALUE rb_ll_abi_version(VALUE self) {
183
20
  long abi = ll_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION);
184
21
  if (abi < 0) {
185
- if (errno == ENOSYS || errno == EOPNOTSUPP) return INT2FIX(0);
22
+ if (errno == ENOSYS || errno == EOPNOTSUPP) {
23
+ return INT2FIX(0);
24
+ }
186
25
  raise_syscall_error("landlock_create_ruleset");
187
26
  }
188
27
  return LONG2NUM(abi);
@@ -208,7 +47,9 @@ static VALUE rb_ll_create_ruleset(int argc, VALUE *argv, VALUE self) {
208
47
  attr.scoped = scoped;
209
48
 
210
49
  long fd = ll_create_ruleset(&attr, attr_size, 0);
211
- if (fd < 0) raise_syscall_error("landlock_create_ruleset");
50
+ if (fd < 0) {
51
+ raise_syscall_error("landlock_create_ruleset");
52
+ }
212
53
  return INT2NUM(fd);
213
54
  }
214
55
 
@@ -218,7 +59,9 @@ static VALUE rb_ll_add_path_rule(VALUE self, VALUE ruleset_fd, VALUE path, VALUE
218
59
  Check_Type(path, T_STRING);
219
60
  const char *cpath = StringValueCStr(path);
220
61
  int parent_fd = open(cpath, O_PATH | O_CLOEXEC);
221
- if (parent_fd < 0) raise_syscall_error("open");
62
+ if (parent_fd < 0) {
63
+ raise_syscall_error("open");
64
+ }
222
65
 
223
66
  struct rb_landlock_path_beneath_attr rule;
224
67
  memset(&rule, 0, sizeof(rule));
@@ -237,7 +80,9 @@ static VALUE rb_ll_add_path_rule(VALUE self, VALUE ruleset_fd, VALUE path, VALUE
237
80
 
238
81
  static VALUE rb_ll_add_net_rule(VALUE self, VALUE ruleset_fd, VALUE port, VALUE access_bits) {
239
82
  unsigned long long p = NUM2ULL(port);
240
- if (p > 65535ULL) rb_raise(rb_eArgError, "TCP port must be between 0 and 65535");
83
+ if (p > 65535ULL) {
84
+ rb_raise(rb_eArgError, "TCP port must be between 0 and 65535");
85
+ }
241
86
 
242
87
  struct rb_landlock_net_port_attr rule;
243
88
  memset(&rule, 0, sizeof(rule));
@@ -245,26 +90,45 @@ static VALUE rb_ll_add_net_rule(VALUE self, VALUE ruleset_fd, VALUE port, VALUE
245
90
  rule.port = p;
246
91
 
247
92
  long ret = ll_add_rule(NUM2INT(ruleset_fd), LANDLOCK_RULE_NET_PORT, &rule, 0);
248
- if (ret < 0) raise_syscall_error("landlock_add_rule(net_port)");
93
+ if (ret < 0) {
94
+ raise_syscall_error("landlock_add_rule(net_port)");
95
+ }
249
96
  return Qtrue;
250
97
  }
251
98
 
252
99
  static VALUE rb_ll_restrict_self(VALUE self, VALUE ruleset_fd) {
100
+ #ifdef __linux__
253
101
  if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0) {
254
102
  raise_syscall_error("prctl(PR_SET_NO_NEW_PRIVS)");
255
103
  }
256
104
 
257
105
  long ret = ll_restrict_self(NUM2INT(ruleset_fd), 0);
258
- if (ret < 0) raise_syscall_error("landlock_restrict_self");
106
+ if (ret < 0) {
107
+ raise_syscall_error("landlock_restrict_self");
108
+ }
259
109
  return Qtrue;
110
+ #else
111
+ errno = ENOSYS;
112
+ raise_syscall_error("landlock_restrict_self");
113
+ #endif
260
114
  }
261
115
 
262
116
  static VALUE rb_ll_close_fd(VALUE self, VALUE fd_value) {
263
117
  int fd = NUM2INT(fd_value);
264
- if (fd >= 0) close(fd);
118
+ if (fd >= 0) {
119
+ close(fd);
120
+ }
265
121
  return Qnil;
266
122
  }
267
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
+
268
132
  void Init_landlock(void) {
269
133
  mLandlock = rb_define_module("Landlock");
270
134
 
@@ -286,6 +150,7 @@ void Init_landlock(void) {
286
150
  rb_define_singleton_method(mLandlock, "_add_net_rule", rb_ll_add_net_rule, 3);
287
151
  rb_define_singleton_method(mLandlock, "_restrict_self", rb_ll_restrict_self, 1);
288
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);
289
154
 
290
155
  rb_define_const(mLandlock, "ACCESS_FS_EXECUTE", ULL2NUM(LANDLOCK_ACCESS_FS_EXECUTE));
291
156
  rb_define_const(mLandlock, "ACCESS_FS_WRITE_FILE", ULL2NUM(LANDLOCK_ACCESS_FS_WRITE_FILE));
@@ -305,6 +170,7 @@ void Init_landlock(void) {
305
170
  rb_define_const(mLandlock, "ACCESS_FS_IOCTL_DEV", ULL2NUM(LANDLOCK_ACCESS_FS_IOCTL_DEV));
306
171
  rb_define_const(mLandlock, "ACCESS_NET_BIND_TCP", ULL2NUM(LANDLOCK_ACCESS_NET_BIND_TCP));
307
172
  rb_define_const(mLandlock, "ACCESS_NET_CONNECT_TCP", ULL2NUM(LANDLOCK_ACCESS_NET_CONNECT_TCP));
308
- rb_define_const(mLandlock, "SCOPE_ABSTRACT_UNIX_SOCKET", ULL2NUM(LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET));
173
+ rb_define_const(mLandlock, "SCOPE_ABSTRACT_UNIX_SOCKET",
174
+ ULL2NUM(LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET));
309
175
  rb_define_const(mLandlock, "SCOPE_SIGNAL", ULL2NUM(LANDLOCK_SCOPE_SIGNAL));
310
176
  }
@@ -0,0 +1,168 @@
1
+ #ifndef RB_LANDLOCK_NATIVE_H
2
+ #define RB_LANDLOCK_NATIVE_H
3
+
4
+ #include <errno.h>
5
+ #include <fcntl.h>
6
+ #include <stddef.h>
7
+ #include <stdint.h>
8
+ #include <unistd.h>
9
+
10
+ #ifdef __linux__
11
+ #include <sys/prctl.h>
12
+ #include <sys/syscall.h>
13
+ #ifdef HAVE_LINUX_LANDLOCK_H
14
+ #include <linux/landlock.h>
15
+ #endif
16
+ #endif
17
+
18
+ #ifndef SYS_landlock_create_ruleset
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
36
+ #endif
37
+
38
+ #ifndef LANDLOCK_CREATE_RULESET_VERSION
39
+ #define LANDLOCK_CREATE_RULESET_VERSION (1U << 0)
40
+ #endif
41
+
42
+ #ifndef LANDLOCK_RULE_PATH_BENEATH
43
+ #define LANDLOCK_RULE_PATH_BENEATH 1
44
+ #endif
45
+
46
+ #ifndef LANDLOCK_RULE_NET_PORT
47
+ #define LANDLOCK_RULE_NET_PORT 2
48
+ #endif
49
+
50
+ #ifndef LANDLOCK_ACCESS_FS_EXECUTE
51
+ #define LANDLOCK_ACCESS_FS_EXECUTE (1ULL << 0)
52
+ #endif
53
+ #ifndef LANDLOCK_ACCESS_FS_WRITE_FILE
54
+ #define LANDLOCK_ACCESS_FS_WRITE_FILE (1ULL << 1)
55
+ #endif
56
+ #ifndef LANDLOCK_ACCESS_FS_READ_FILE
57
+ #define LANDLOCK_ACCESS_FS_READ_FILE (1ULL << 2)
58
+ #endif
59
+ #ifndef LANDLOCK_ACCESS_FS_READ_DIR
60
+ #define LANDLOCK_ACCESS_FS_READ_DIR (1ULL << 3)
61
+ #endif
62
+ #ifndef LANDLOCK_ACCESS_FS_REMOVE_DIR
63
+ #define LANDLOCK_ACCESS_FS_REMOVE_DIR (1ULL << 4)
64
+ #endif
65
+ #ifndef LANDLOCK_ACCESS_FS_REMOVE_FILE
66
+ #define LANDLOCK_ACCESS_FS_REMOVE_FILE (1ULL << 5)
67
+ #endif
68
+ #ifndef LANDLOCK_ACCESS_FS_MAKE_CHAR
69
+ #define LANDLOCK_ACCESS_FS_MAKE_CHAR (1ULL << 6)
70
+ #endif
71
+ #ifndef LANDLOCK_ACCESS_FS_MAKE_DIR
72
+ #define LANDLOCK_ACCESS_FS_MAKE_DIR (1ULL << 7)
73
+ #endif
74
+ #ifndef LANDLOCK_ACCESS_FS_MAKE_REG
75
+ #define LANDLOCK_ACCESS_FS_MAKE_REG (1ULL << 8)
76
+ #endif
77
+ #ifndef LANDLOCK_ACCESS_FS_MAKE_SOCK
78
+ #define LANDLOCK_ACCESS_FS_MAKE_SOCK (1ULL << 9)
79
+ #endif
80
+ #ifndef LANDLOCK_ACCESS_FS_MAKE_FIFO
81
+ #define LANDLOCK_ACCESS_FS_MAKE_FIFO (1ULL << 10)
82
+ #endif
83
+ #ifndef LANDLOCK_ACCESS_FS_MAKE_BLOCK
84
+ #define LANDLOCK_ACCESS_FS_MAKE_BLOCK (1ULL << 11)
85
+ #endif
86
+ #ifndef LANDLOCK_ACCESS_FS_MAKE_SYM
87
+ #define LANDLOCK_ACCESS_FS_MAKE_SYM (1ULL << 12)
88
+ #endif
89
+ #ifndef LANDLOCK_ACCESS_FS_REFER
90
+ #define LANDLOCK_ACCESS_FS_REFER (1ULL << 13)
91
+ #endif
92
+ #ifndef LANDLOCK_ACCESS_FS_TRUNCATE
93
+ #define LANDLOCK_ACCESS_FS_TRUNCATE (1ULL << 14)
94
+ #endif
95
+ #ifndef LANDLOCK_ACCESS_FS_IOCTL_DEV
96
+ #define LANDLOCK_ACCESS_FS_IOCTL_DEV (1ULL << 15)
97
+ #endif
98
+
99
+ #ifndef LANDLOCK_ACCESS_NET_BIND_TCP
100
+ #define LANDLOCK_ACCESS_NET_BIND_TCP (1ULL << 0)
101
+ #endif
102
+ #ifndef LANDLOCK_ACCESS_NET_CONNECT_TCP
103
+ #define LANDLOCK_ACCESS_NET_CONNECT_TCP (1ULL << 1)
104
+ #endif
105
+
106
+ #ifndef LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET
107
+ #define LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET (1ULL << 0)
108
+ #endif
109
+ #ifndef LANDLOCK_SCOPE_SIGNAL
110
+ #define LANDLOCK_SCOPE_SIGNAL (1ULL << 1)
111
+ #endif
112
+
113
+ #ifndef O_PATH
114
+ #define O_PATH 010000000
115
+ #endif
116
+
117
+ #ifndef O_CLOEXEC
118
+ #define O_CLOEXEC 02000000
119
+ #endif
120
+
121
+ #ifndef PR_SET_NO_NEW_PRIVS
122
+ #define PR_SET_NO_NEW_PRIVS 38
123
+ #endif
124
+
125
+ struct rb_landlock_ruleset_attr {
126
+ uint64_t handled_access_fs;
127
+ uint64_t handled_access_net;
128
+ uint64_t scoped;
129
+ };
130
+
131
+ struct rb_landlock_path_beneath_attr {
132
+ uint64_t allowed_access;
133
+ int32_t parent_fd;
134
+ } __attribute__((packed));
135
+
136
+ struct rb_landlock_net_port_attr {
137
+ uint64_t allowed_access;
138
+ uint64_t port;
139
+ };
140
+
141
+ static long ll_create_ruleset(const void *attr, size_t size, uint32_t flags) {
142
+ #ifdef SYS_landlock_create_ruleset
143
+ return syscall(SYS_landlock_create_ruleset, attr, size, flags);
144
+ #else
145
+ errno = ENOSYS;
146
+ return -1;
147
+ #endif
148
+ }
149
+
150
+ static long ll_add_rule(int ruleset_fd, int rule_type, const void *rule_attr, uint32_t flags) {
151
+ #ifdef SYS_landlock_add_rule
152
+ return syscall(SYS_landlock_add_rule, ruleset_fd, rule_type, rule_attr, flags);
153
+ #else
154
+ errno = ENOSYS;
155
+ return -1;
156
+ #endif
157
+ }
158
+
159
+ static long ll_restrict_self(int ruleset_fd, uint32_t flags) {
160
+ #ifdef SYS_landlock_restrict_self
161
+ return syscall(SYS_landlock_restrict_self, ruleset_fd, flags);
162
+ #else
163
+ errno = ENOSYS;
164
+ return -1;
165
+ #endif
166
+ }
167
+
168
+ #endif
@@ -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
@@ -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