Skip to content

Commit 369b48b

Browse files
tahifahimil0kod
authored andcommitted
samples/landlock: Add support for abstract UNIX socket scoping
The sandboxer can receive the character "a" as input from the environment variable LL_SCOPE to restrict sandboxed processes from connecting to an abstract UNIX socket created by a process outside of the sandbox. Example ======= Create an abstract UNIX socket to listen with socat(1): socat abstract-listen:mysocket - Create a sandboxed shell and pass the character "a" to LL_SCOPED: LL_FS_RO=/ LL_FS_RW=. LL_SCOPED="a" ./sandboxer /bin/bash Note that any other form of input (e.g. "a:a", "aa", etc) is not acceptable. If the sandboxed process tries to connect to the listening socket, the connection will fail: socat - abstract-connect:mysocket Signed-off-by: Tahera Fahimi <[email protected]> Link: https://lore.kernel.org/r/d8af908f00b77415caa3eb0f4de631c3794e4909.1725494372.git.fahimitahera@gmail.com [mic: Improve commit message, simplify check_ruleset_scope() with inverted error code and only one scoped change, always unset environment variable] Signed-off-by: Mickaël Salaün <[email protected]>
1 parent 644a728 commit 369b48b

File tree

1 file changed

+60
-4
lines changed

1 file changed

+60
-4
lines changed

samples/landlock/sandboxer.c

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <fcntl.h>
1515
#include <linux/landlock.h>
1616
#include <linux/prctl.h>
17+
#include <linux/socket.h>
1718
#include <stddef.h>
1819
#include <stdio.h>
1920
#include <stdlib.h>
@@ -22,6 +23,7 @@
2223
#include <sys/stat.h>
2324
#include <sys/syscall.h>
2425
#include <unistd.h>
26+
#include <stdbool.h>
2527

2628
#ifndef landlock_create_ruleset
2729
static inline int
@@ -55,6 +57,7 @@ static inline int landlock_restrict_self(const int ruleset_fd,
5557
#define ENV_FS_RW_NAME "LL_FS_RW"
5658
#define ENV_TCP_BIND_NAME "LL_TCP_BIND"
5759
#define ENV_TCP_CONNECT_NAME "LL_TCP_CONNECT"
60+
#define ENV_SCOPED_NAME "LL_SCOPED"
5861
#define ENV_DELIMITER ":"
5962

6063
static int parse_path(char *env_path, const char ***const path_list)
@@ -184,6 +187,48 @@ static int populate_ruleset_net(const char *const env_var, const int ruleset_fd,
184187
return ret;
185188
}
186189

190+
/* Returns true on error, false otherwise. */
191+
static bool check_ruleset_scope(const char *const env_var,
192+
struct landlock_ruleset_attr *ruleset_attr)
193+
{
194+
char *env_type_scope, *env_type_scope_next, *ipc_scoping_name;
195+
bool error = false;
196+
bool abstract_scoping = false;
197+
198+
/* Scoping is not supported by Landlock ABI */
199+
if (!(ruleset_attr->scoped & LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET))
200+
goto out_unset;
201+
202+
env_type_scope = getenv(env_var);
203+
/* Scoping is not supported by the user */
204+
if (!env_type_scope || strcmp("", env_type_scope) == 0)
205+
goto out_unset;
206+
207+
env_type_scope = strdup(env_type_scope);
208+
env_type_scope_next = env_type_scope;
209+
while ((ipc_scoping_name =
210+
strsep(&env_type_scope_next, ENV_DELIMITER))) {
211+
if (strcmp("a", ipc_scoping_name) == 0 && !abstract_scoping) {
212+
abstract_scoping = true;
213+
} else {
214+
fprintf(stderr, "Unknown or duplicate scope \"%s\"\n",
215+
ipc_scoping_name);
216+
error = true;
217+
goto out_free_name;
218+
}
219+
}
220+
221+
out_free_name:
222+
free(env_type_scope);
223+
224+
out_unset:
225+
if (!abstract_scoping)
226+
ruleset_attr->scoped &= ~LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET;
227+
228+
unsetenv(env_var);
229+
return error;
230+
}
231+
187232
/* clang-format off */
188233

189234
#define ACCESS_FS_ROUGHLY_READ ( \
@@ -208,7 +253,7 @@ static int populate_ruleset_net(const char *const env_var, const int ruleset_fd,
208253

209254
/* clang-format on */
210255

211-
#define LANDLOCK_ABI_LAST 5
256+
#define LANDLOCK_ABI_LAST 6
212257

213258
int main(const int argc, char *const argv[], char *const *const envp)
214259
{
@@ -223,14 +268,15 @@ int main(const int argc, char *const argv[], char *const *const envp)
223268
.handled_access_fs = access_fs_rw,
224269
.handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP |
225270
LANDLOCK_ACCESS_NET_CONNECT_TCP,
271+
.scoped = LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET,
226272
};
227273

228274
if (argc < 2) {
229275
fprintf(stderr,
230-
"usage: %s=\"...\" %s=\"...\" %s=\"...\" %s=\"...\"%s "
276+
"usage: %s=\"...\" %s=\"...\" %s=\"...\" %s=\"...\" %s=\"...\" %s "
231277
"<cmd> [args]...\n\n",
232278
ENV_FS_RO_NAME, ENV_FS_RW_NAME, ENV_TCP_BIND_NAME,
233-
ENV_TCP_CONNECT_NAME, argv[0]);
279+
ENV_TCP_CONNECT_NAME, ENV_SCOPED_NAME, argv[0]);
234280
fprintf(stderr,
235281
"Execute a command in a restricted environment.\n\n");
236282
fprintf(stderr,
@@ -251,15 +297,18 @@ int main(const int argc, char *const argv[], char *const *const envp)
251297
fprintf(stderr,
252298
"* %s: list of ports allowed to connect (client).\n",
253299
ENV_TCP_CONNECT_NAME);
300+
fprintf(stderr, "* %s: list of scoped IPCs.\n",
301+
ENV_SCOPED_NAME);
254302
fprintf(stderr,
255303
"\nexample:\n"
256304
"%s=\"${PATH}:/lib:/usr:/proc:/etc:/dev/urandom\" "
257305
"%s=\"/dev/null:/dev/full:/dev/zero:/dev/pts:/tmp\" "
258306
"%s=\"9418\" "
259307
"%s=\"80:443\" "
308+
"%s=\"a\" "
260309
"%s bash -i\n\n",
261310
ENV_FS_RO_NAME, ENV_FS_RW_NAME, ENV_TCP_BIND_NAME,
262-
ENV_TCP_CONNECT_NAME, argv[0]);
311+
ENV_TCP_CONNECT_NAME, ENV_SCOPED_NAME, argv[0]);
263312
fprintf(stderr,
264313
"This sandboxer can use Landlock features "
265314
"up to ABI version %d.\n",
@@ -327,6 +376,10 @@ int main(const int argc, char *const argv[], char *const *const envp)
327376
/* Removes LANDLOCK_ACCESS_FS_IOCTL_DEV for ABI < 5 */
328377
ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_IOCTL_DEV;
329378

379+
__attribute__((fallthrough));
380+
case 5:
381+
/* Removes LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET for ABI < 6 */
382+
ruleset_attr.scoped &= ~LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET;
330383
fprintf(stderr,
331384
"Hint: You should update the running kernel "
332385
"to leverage Landlock features "
@@ -358,6 +411,9 @@ int main(const int argc, char *const argv[], char *const *const envp)
358411
~LANDLOCK_ACCESS_NET_CONNECT_TCP;
359412
}
360413

414+
if (check_ruleset_scope(ENV_SCOPED_NAME, &ruleset_attr))
415+
return 1;
416+
361417
ruleset_fd =
362418
landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
363419
if (ruleset_fd < 0) {

0 commit comments

Comments
 (0)