Skip to content

Commit eef9081

Browse files
stgrabermihalicyn
authored andcommitted
start: Add Landlock restrictions to monitor
Signed-off-by: Stéphane Graber <stgraber@stgraber.org> (cherry picked from commit 4787190)
1 parent 2c51ed1 commit eef9081

File tree

1 file changed

+167
-1
lines changed

1 file changed

+167
-1
lines changed

src/lxc/start.c

Lines changed: 167 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <errno.h>
77
#include <fcntl.h>
88
#include <grp.h>
9+
#include <linux/landlock.h>
910
#include <poll.h>
1011
#include <pthread.h>
1112
#include <signal.h>
@@ -67,6 +68,34 @@
6768
#include "strlcpy.h"
6869
#endif
6970

71+
#ifndef landlock_create_ruleset
72+
static inline int
73+
landlock_create_ruleset(const struct landlock_ruleset_attr *const attr,
74+
const size_t size, const __u32 flags)
75+
{
76+
return syscall(__NR_landlock_create_ruleset, attr, size, flags);
77+
}
78+
#endif
79+
80+
#ifndef landlock_restrict_self
81+
static inline int landlock_restrict_self(const int ruleset_fd,
82+
const __u32 flags)
83+
{
84+
return syscall(__NR_landlock_restrict_self, ruleset_fd, flags);
85+
}
86+
#endif
87+
88+
#ifndef landlock_add_rule
89+
static inline int landlock_add_rule(const int ruleset_fd,
90+
const enum landlock_rule_type rule_type,
91+
const void *const rule_attr,
92+
const __u32 flags)
93+
{
94+
return syscall(__NR_landlock_add_rule, ruleset_fd, rule_type, rule_attr,
95+
flags);
96+
}
97+
#endif
98+
7099
lxc_log_define(start, lxc);
71100

72101
extern void mod_all_rdeps(struct lxc_container *c, bool inc);
@@ -75,6 +104,125 @@ static int lxc_rmdir_onedev_wrapper(void *data);
75104
static void lxc_destroy_container_on_signal(struct lxc_handler *handler,
76105
const char *name);
77106

107+
static int lxc_mainloop_protect(void)
108+
{
109+
int err;
110+
111+
// Detect the supported Landlock ABI.
112+
int abi;
113+
abi = landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION);
114+
if (abi < 0) {
115+
// Landlock not supported.
116+
SYSERROR("Landlock not supported on system");
117+
return -1;
118+
}
119+
120+
struct landlock_ruleset_attr ruleset_attr = {
121+
.handled_access_fs =
122+
LANDLOCK_ACCESS_FS_WRITE_FILE |
123+
LANDLOCK_ACCESS_FS_READ_FILE |
124+
LANDLOCK_ACCESS_FS_TRUNCATE,
125+
};
126+
127+
// Define a new ruleset.
128+
int ruleset_fd;
129+
130+
ruleset_fd = landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
131+
if (ruleset_fd < 0) {
132+
// Failed to create ruleset.
133+
SYSERROR("Failed to create landlock ruleset");
134+
return -1;
135+
}
136+
137+
// Allow /sys/fs/cgroup write access.
138+
struct landlock_path_beneath_attr path_beneath = {
139+
.allowed_access =
140+
LANDLOCK_ACCESS_FS_READ_FILE |
141+
LANDLOCK_ACCESS_FS_WRITE_FILE,
142+
};
143+
144+
path_beneath.parent_fd = open("/sys/fs/cgroup", O_PATH | O_CLOEXEC);
145+
if (path_beneath.parent_fd < 0) {
146+
SYSERROR("Failed to open /sys/fs/cgroup");
147+
close(ruleset_fd);
148+
return -1;
149+
}
150+
151+
err = landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, &path_beneath, 0);
152+
close(path_beneath.parent_fd);
153+
if (err) {
154+
SYSERROR("Failed to update ruleset");
155+
close(ruleset_fd);
156+
return -1;
157+
}
158+
159+
// Allow /proc write access.
160+
path_beneath.parent_fd = open("/proc", O_PATH | O_CLOEXEC);
161+
if (path_beneath.parent_fd < 0) {
162+
SYSERROR("Failed to open /proc");
163+
close(ruleset_fd);
164+
return -1;
165+
}
166+
167+
err = landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, &path_beneath, 0);
168+
close(path_beneath.parent_fd);
169+
if (err) {
170+
SYSERROR("Failed to update ruleset");
171+
close(ruleset_fd);
172+
return -1;
173+
}
174+
175+
// Allow /dev/ptmx write access.
176+
path_beneath.parent_fd = open("/dev/ptmx", O_PATH | O_CLOEXEC);
177+
if (path_beneath.parent_fd < 0) {
178+
SYSERROR("Failed to open /dev/ptmx");
179+
close(ruleset_fd);
180+
return -1;
181+
}
182+
183+
err = landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, &path_beneath, 0);
184+
close(path_beneath.parent_fd);
185+
if (err) {
186+
SYSERROR("Failed to update ruleset");
187+
close(ruleset_fd);
188+
return -1;
189+
}
190+
191+
// Allow /dev/pts write access.
192+
path_beneath.parent_fd = open("/dev/pts", O_PATH | O_CLOEXEC);
193+
if (path_beneath.parent_fd < 0) {
194+
SYSERROR("Failed to open /dev/pts");
195+
close(ruleset_fd);
196+
return -1;
197+
}
198+
199+
err = landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, &path_beneath, 0);
200+
close(path_beneath.parent_fd);
201+
if (err) {
202+
SYSERROR("Failed to update ruleset");
203+
close(ruleset_fd);
204+
return -1;
205+
}
206+
207+
// Prevent getting more privileges.
208+
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
209+
SYSERROR("Failed to restrict monitor privileges");
210+
close(ruleset_fd);
211+
return -1;
212+
}
213+
214+
// Apply the Landlock restrictions.
215+
if (landlock_restrict_self(ruleset_fd, 0)) {
216+
SYSERROR("Failed to enforce Landlock ruleset");
217+
close(ruleset_fd);
218+
return -1;
219+
}
220+
221+
close(ruleset_fd);
222+
223+
return 0;
224+
}
225+
78226
static void print_top_failing_dir(const char *path)
79227
{
80228
__do_free char *copy = NULL;
@@ -574,9 +722,18 @@ int lxc_set_state(const char *name, struct lxc_handler *handler,
574722

575723
void *lxc_handler_mainloop_thread_fn(void *arg)
576724
{
725+
int ret;
577726
struct lxc_async_descr *descr = arg;
578727

579-
return INT_TO_PTR(lxc_mainloop(descr, -1));
728+
ret = lxc_mainloop_protect();
729+
if (ret < 0) {
730+
ERROR("Failed to protect the monitor process");
731+
goto out;
732+
}
733+
734+
ret = lxc_mainloop(descr, -1);
735+
out:
736+
return INT_TO_PTR(ret);
580737
}
581738

582739
int lxc_handler_mainloop(struct lxc_async_descr *descr, struct lxc_handler *handler)
@@ -585,6 +742,15 @@ int lxc_handler_mainloop(struct lxc_async_descr *descr, struct lxc_handler *hand
585742
int ret;
586743
pthread_t thread;
587744

745+
/* Skip protection if a seccomp proxy is setup. */
746+
if (!handler || !handler->conf || handler->conf->seccomp.notifier.proxy_fd > 0) {
747+
/* Landlock not supported when seccomp notify is in use. */
748+
SYSERROR("Skipping Landlock due to seccomp notify");
749+
750+
/* We don't need to use thread then */
751+
return lxc_mainloop(descr, -1);
752+
}
753+
588754
ret = pthread_create(&thread, NULL, lxc_handler_mainloop_thread_fn, (void *)descr);
589755
if (ret) {
590756
return log_error_errno(-1, ret,

0 commit comments

Comments
 (0)