1 // SPDX-License-Identifier: 0BSD
2
3 ///////////////////////////////////////////////////////////////////////////////
4 //
5 /// \file my_landlock.h
6 /// \brief Linux Landlock sandbox helper functions
7 //
8 // Author: Lasse Collin
9 //
10 ///////////////////////////////////////////////////////////////////////////////
11
12 #ifndef MY_LANDLOCK_H
13 #define MY_LANDLOCK_H
14
15 #include "sysdefs.h"
16
17 #include <linux/landlock.h>
18 #include <sys/syscall.h>
19 #include <sys/prctl.h>
20
21
22 /// \brief Initialize Landlock ruleset attributes to forbid everything
23 ///
24 /// The supported Landlock ABI is checked at runtime and only the supported
25 /// actions are forbidden in the attributes. Thus, if the attributes are
26 /// used with my_landlock_create_ruleset(), it shouldn't fail.
27 ///
28 /// \return On success, the Landlock ABI version is returned (a positive
29 /// integer). If Landlock isn't supported, -1 is returned.
30 static int
my_landlock_ruleset_attr_forbid_all(struct landlock_ruleset_attr * attr)31 my_landlock_ruleset_attr_forbid_all(struct landlock_ruleset_attr *attr)
32 {
33 memzero(attr, sizeof(*attr));
34
35 const int abi_version = syscall(SYS_landlock_create_ruleset,
36 (void *)NULL, 0, LANDLOCK_CREATE_RULESET_VERSION);
37 if (abi_version <= 0)
38 return -1;
39
40 // ABI 1 except the few at the end
41 attr->handled_access_fs
42 = LANDLOCK_ACCESS_FS_EXECUTE
43 | LANDLOCK_ACCESS_FS_WRITE_FILE
44 | LANDLOCK_ACCESS_FS_READ_FILE
45 | LANDLOCK_ACCESS_FS_READ_DIR
46 | LANDLOCK_ACCESS_FS_REMOVE_DIR
47 | LANDLOCK_ACCESS_FS_REMOVE_FILE
48 | LANDLOCK_ACCESS_FS_MAKE_CHAR
49 | LANDLOCK_ACCESS_FS_MAKE_DIR
50 | LANDLOCK_ACCESS_FS_MAKE_REG
51 | LANDLOCK_ACCESS_FS_MAKE_SOCK
52 | LANDLOCK_ACCESS_FS_MAKE_FIFO
53 | LANDLOCK_ACCESS_FS_MAKE_BLOCK
54 | LANDLOCK_ACCESS_FS_MAKE_SYM
55 #ifdef LANDLOCK_ACCESS_FS_REFER
56 | LANDLOCK_ACCESS_FS_REFER // ABI 2
57 #endif
58 #ifdef LANDLOCK_ACCESS_FS_TRUNCATE
59 | LANDLOCK_ACCESS_FS_TRUNCATE // ABI 3
60 #endif
61 #ifdef LANDLOCK_ACCESS_FS_IOCTL_DEV
62 | LANDLOCK_ACCESS_FS_IOCTL_DEV // ABI 5
63 #endif
64 ;
65
66 #ifdef LANDLOCK_ACCESS_NET_BIND_TCP
67 // ABI 4
68 attr->handled_access_net
69 = LANDLOCK_ACCESS_NET_BIND_TCP
70 | LANDLOCK_ACCESS_NET_CONNECT_TCP;
71 #endif
72
73 #ifdef LANDLOCK_SCOPE_SIGNAL
74 // ABI 6
75 attr->scoped
76 = LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET
77 | LANDLOCK_SCOPE_SIGNAL;
78 #endif
79
80 // Disable flags that require a new ABI version.
81 switch (abi_version) {
82 case 1:
83 #ifdef LANDLOCK_ACCESS_FS_REFER
84 attr->handled_access_fs &= ~LANDLOCK_ACCESS_FS_REFER;
85 #endif
86 FALLTHROUGH;
87
88 case 2:
89 #ifdef LANDLOCK_ACCESS_FS_TRUNCATE
90 attr->handled_access_fs &= ~LANDLOCK_ACCESS_FS_TRUNCATE;
91 #endif
92 FALLTHROUGH;
93
94 case 3:
95 #ifdef LANDLOCK_ACCESS_NET_BIND_TCP
96 attr->handled_access_net = 0;
97 #endif
98 FALLTHROUGH;
99
100 case 4:
101 #ifdef LANDLOCK_ACCESS_FS_IOCTL_DEV
102 attr->handled_access_fs &= ~LANDLOCK_ACCESS_FS_IOCTL_DEV;
103 #endif
104 FALLTHROUGH;
105
106 case 5:
107 #ifdef LANDLOCK_SCOPE_SIGNAL
108 attr->scoped = 0;
109 #endif
110 FALLTHROUGH;
111
112 default:
113 // We only know about the features of the ABIs 1-6.
114 break;
115 }
116
117 return abi_version;
118 }
119
120
121 /// \brief Wrapper for the landlock_create_ruleset(2) syscall
122 ///
123 /// Syscall wrappers provide argument type checking.
124 ///
125 /// \note Remember to call `prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)` too!
126 static inline int
my_landlock_create_ruleset(const struct landlock_ruleset_attr * attr,size_t size,uint32_t flags)127 my_landlock_create_ruleset(const struct landlock_ruleset_attr *attr,
128 size_t size, uint32_t flags)
129 {
130 return syscall(SYS_landlock_create_ruleset, attr, size, flags);
131 }
132
133
134 /// \brief Wrapper for the landlock_restrict_self(2) syscall
135 static inline int
my_landlock_restrict_self(int ruleset_fd,uint32_t flags)136 my_landlock_restrict_self(int ruleset_fd, uint32_t flags)
137 {
138 return syscall(SYS_landlock_restrict_self, ruleset_fd, flags);
139 }
140
141 #endif
142