Skip to content

Commit 1422dd6

Browse files
committed
samples/landlock: Add support for abstract UNIX socket scoping
JIRA: https://issues.redhat.com/browse/RHEL-94688 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 <fahimitahera@gmail.com> 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 <mic@digikod.net> (cherry picked from commit 369b48b) Signed-off-by: Ryan Sullivan <rysulliv@redhat.com>
1 parent 7130231 commit 1422dd6

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 str2num(const char *numstr, __u64 *num_dst)
@@ -212,6 +215,48 @@ static int populate_ruleset_net(const char *const env_var, const int ruleset_fd,
212215
return ret;
213216
}
214217

218+
/* Returns true on error, false otherwise. */
219+
static bool check_ruleset_scope(const char *const env_var,
220+
struct landlock_ruleset_attr *ruleset_attr)
221+
{
222+
char *env_type_scope, *env_type_scope_next, *ipc_scoping_name;
223+
bool error = false;
224+
bool abstract_scoping = false;
225+
226+
/* Scoping is not supported by Landlock ABI */
227+
if (!(ruleset_attr->scoped & LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET))
228+
goto out_unset;
229+
230+
env_type_scope = getenv(env_var);
231+
/* Scoping is not supported by the user */
232+
if (!env_type_scope || strcmp("", env_type_scope) == 0)
233+
goto out_unset;
234+
235+
env_type_scope = strdup(env_type_scope);
236+
env_type_scope_next = env_type_scope;
237+
while ((ipc_scoping_name =
238+
strsep(&env_type_scope_next, ENV_DELIMITER))) {
239+
if (strcmp("a", ipc_scoping_name) == 0 && !abstract_scoping) {
240+
abstract_scoping = true;
241+
} else {
242+
fprintf(stderr, "Unknown or duplicate scope \"%s\"\n",
243+
ipc_scoping_name);
244+
error = true;
245+
goto out_free_name;
246+
}
247+
}
248+
249+
out_free_name:
250+
free(env_type_scope);
251+
252+
out_unset:
253+
if (!abstract_scoping)
254+
ruleset_attr->scoped &= ~LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET;
255+
256+
unsetenv(env_var);
257+
return error;
258+
}
259+
215260
/* clang-format off */
216261

217262
#define ACCESS_FS_ROUGHLY_READ ( \
@@ -236,7 +281,7 @@ static int populate_ruleset_net(const char *const env_var, const int ruleset_fd,
236281

237282
/* clang-format on */
238283

239-
#define LANDLOCK_ABI_LAST 5
284+
#define LANDLOCK_ABI_LAST 6
240285

241286
int main(const int argc, char *const argv[], char *const *const envp)
242287
{
@@ -251,14 +296,15 @@ int main(const int argc, char *const argv[], char *const *const envp)
251296
.handled_access_fs = access_fs_rw,
252297
.handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP |
253298
LANDLOCK_ACCESS_NET_CONNECT_TCP,
299+
.scoped = LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET,
254300
};
255301

256302
if (argc < 2) {
257303
fprintf(stderr,
258-
"usage: %s=\"...\" %s=\"...\" %s=\"...\" %s=\"...\"%s "
304+
"usage: %s=\"...\" %s=\"...\" %s=\"...\" %s=\"...\" %s=\"...\" %s "
259305
"<cmd> [args]...\n\n",
260306
ENV_FS_RO_NAME, ENV_FS_RW_NAME, ENV_TCP_BIND_NAME,
261-
ENV_TCP_CONNECT_NAME, argv[0]);
307+
ENV_TCP_CONNECT_NAME, ENV_SCOPED_NAME, argv[0]);
262308
fprintf(stderr,
263309
"Execute a command in a restricted environment.\n\n");
264310
fprintf(stderr,
@@ -279,15 +325,18 @@ int main(const int argc, char *const argv[], char *const *const envp)
279325
fprintf(stderr,
280326
"* %s: list of ports allowed to connect (client).\n",
281327
ENV_TCP_CONNECT_NAME);
328+
fprintf(stderr, "* %s: list of scoped IPCs.\n",
329+
ENV_SCOPED_NAME);
282330
fprintf(stderr,
283331
"\nexample:\n"
284332
"%s=\"${PATH}:/lib:/usr:/proc:/etc:/dev/urandom\" "
285333
"%s=\"/dev/null:/dev/full:/dev/zero:/dev/pts:/tmp\" "
286334
"%s=\"9418\" "
287335
"%s=\"80:443\" "
336+
"%s=\"a\" "
288337
"%s bash -i\n\n",
289338
ENV_FS_RO_NAME, ENV_FS_RW_NAME, ENV_TCP_BIND_NAME,
290-
ENV_TCP_CONNECT_NAME, argv[0]);
339+
ENV_TCP_CONNECT_NAME, ENV_SCOPED_NAME, argv[0]);
291340
fprintf(stderr,
292341
"This sandboxer can use Landlock features "
293342
"up to ABI version %d.\n",
@@ -355,6 +404,10 @@ int main(const int argc, char *const argv[], char *const *const envp)
355404
/* Removes LANDLOCK_ACCESS_FS_IOCTL_DEV for ABI < 5 */
356405
ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_IOCTL_DEV;
357406

407+
__attribute__((fallthrough));
408+
case 5:
409+
/* Removes LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET for ABI < 6 */
410+
ruleset_attr.scoped &= ~LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET;
358411
fprintf(stderr,
359412
"Hint: You should update the running kernel "
360413
"to leverage Landlock features "
@@ -386,6 +439,9 @@ int main(const int argc, char *const argv[], char *const *const envp)
386439
~LANDLOCK_ACCESS_NET_CONNECT_TCP;
387440
}
388441

442+
if (check_ruleset_scope(ENV_SCOPED_NAME, &ruleset_attr))
443+
return 1;
444+
389445
ruleset_fd =
390446
landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
391447
if (ruleset_fd < 0) {

0 commit comments

Comments
 (0)