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>
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+
7099lxc_log_define (start , lxc );
71100
72101extern void mod_all_rdeps (struct lxc_container * c , bool inc );
@@ -75,6 +104,125 @@ static int lxc_rmdir_onedev_wrapper(void *data);
75104static 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+
78226static 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
575723void * 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
582739int 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