Skip to content

Commit 12bfcda

Browse files
committed
landlock: Add LANDLOCK_RESTRICT_SELF_LOG_*_EXEC_* flags
Most of the time we want to log denied access because they should not happen and such information helps diagnose issues. However, when sandboxing processes that we know will try to access denied resources (e.g. unknown, bogus, or malicious binary), we might want to not log related access requests that might fill up logs. By default, denied requests are logged until the task call execve(2). If the LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF flag is set, denied requests will not be logged for the same executed file. If the LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON flag is set, denied requests from after an execve(2) call will be logged. The rationale is that a program should know its own behavior, but not necessarily the behavior of other programs. Because LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF is set for a specific Landlock domain, it makes it possible to selectively mask some access requests that would be logged by a parent domain, which might be handy for unprivileged processes to limit logs. However, system administrators should still use the audit filtering mechanism. There is intentionally no audit nor sysctl configuration to re-enable these logs. This is delegated to the user space program. Increment the Landlock ABI version to reflect this interface change. Cc: Günther Noack <[email protected]> Cc: Paul Moore <[email protected]> Link: https://lore.kernel.org/r/[email protected] [mic: Rename variables and fix __maybe_unused] Signed-off-by: Mickaël Salaün <[email protected]>
1 parent 1176a15 commit 12bfcda

File tree

7 files changed

+85
-13
lines changed

7 files changed

+85
-13
lines changed

include/uapi/linux/landlock.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*
55
* Copyright © 2017-2020 Mickaël Salaün <[email protected]>
66
* Copyright © 2018-2020 ANSSI
7+
* Copyright © 2021-2025 Microsoft Corporation
78
*/
89

910
#ifndef _UAPI_LINUX_LANDLOCK_H
@@ -64,6 +65,26 @@ struct landlock_ruleset_attr {
6465
#define LANDLOCK_CREATE_RULESET_ERRATA (1U << 1)
6566
/* clang-format on */
6667

68+
/*
69+
* sys_landlock_restrict_self() flags:
70+
*
71+
* - %LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF: Do not create any log related to the
72+
* enforced restrictions. This should only be set by tools launching unknown
73+
* or untrusted programs (e.g. a sandbox tool, container runtime, system
74+
* service manager). Because programs sandboxing themselves should fix any
75+
* denied access, they should not set this flag to be aware of potential
76+
* issues reported by system's logs (i.e. audit).
77+
* - %LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON: Explicitly ask to continue
78+
* logging denied access requests even after an :manpage:`execve(2)` call.
79+
* This flag should only be set if all the programs than can legitimately be
80+
* executed will not try to request a denied access (which could spam audit
81+
* logs).
82+
*/
83+
/* clang-format off */
84+
#define LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF (1U << 0)
85+
#define LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON (1U << 1)
86+
/* clang-format on */
87+
6788
/**
6889
* enum landlock_rule_type - Landlock rule type
6990
*

security/landlock/audit.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,9 @@ void landlock_log_denial(const struct landlock_cred_security *const subject,
422422
get_hierarchy(subject->domain, youngest_layer);
423423
}
424424

425+
if (READ_ONCE(youngest_denied->log_status) == LANDLOCK_LOG_DISABLED)
426+
return;
427+
425428
/*
426429
* Consistently keeps track of the number of denied access requests
427430
* even if audit is currently disabled, or if audit rules currently
@@ -433,9 +436,16 @@ void landlock_log_denial(const struct landlock_cred_security *const subject,
433436
if (!audit_enabled)
434437
return;
435438

436-
/* Ignores denials after an execution. */
437-
if (!(subject->domain_exec & (1 << youngest_layer)))
438-
return;
439+
/* Checks if the current exec was restricting itself. */
440+
if (subject->domain_exec & (1 << youngest_layer)) {
441+
/* Ignores denials for the same execution. */
442+
if (!youngest_denied->log_same_exec)
443+
return;
444+
} else {
445+
/* Ignores denials after a new execution. */
446+
if (!youngest_denied->log_new_exec)
447+
return;
448+
}
439449

440450
/* Uses consistent allocation flags wrt common_lsm_audit(). */
441451
ab = audit_log_start(audit_context(), GFP_ATOMIC | __GFP_NOWARN,

security/landlock/domain.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ int landlock_init_hierarchy_log(struct landlock_hierarchy *const hierarchy)
127127
hierarchy->details = details;
128128
hierarchy->id = landlock_get_id_range(1);
129129
hierarchy->log_status = LANDLOCK_LOG_PENDING;
130+
hierarchy->log_same_exec = true;
131+
hierarchy->log_new_exec = false;
130132
atomic64_set(&hierarchy->num_denials, 0);
131133
return 0;
132134
}

security/landlock/domain.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
enum landlock_log_status {
2525
LANDLOCK_LOG_PENDING = 0,
2626
LANDLOCK_LOG_RECORDED,
27+
LANDLOCK_LOG_DISABLED,
2728
};
2829

2930
/**
@@ -103,6 +104,16 @@ struct landlock_hierarchy {
103104
* @details: Information about the related domain.
104105
*/
105106
const struct landlock_details *details;
107+
/**
108+
* @log_same_exec: Set if the domain is *not* configured with
109+
* %LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF. Set to true by default.
110+
*/
111+
u32 log_same_exec : 1,
112+
/**
113+
* @log_new_exec: Set if the domain is configured with
114+
* %LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON. Set to false by default.
115+
*/
116+
log_new_exec : 1;
106117
#endif /* CONFIG_AUDIT */
107118
};
108119

security/landlock/limits.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
/* SPDX-License-Identifier: GPL-2.0-only */
22
/*
3-
* Landlock LSM - Limits for different components
3+
* Landlock - Limits for different components
44
*
55
* Copyright © 2016-2020 Mickaël Salaün <[email protected]>
66
* Copyright © 2018-2020 ANSSI
7+
* Copyright © 2021-2025 Microsoft Corporation
78
*/
89

910
#ifndef _SECURITY_LANDLOCK_LIMITS_H
@@ -29,6 +30,10 @@
2930
#define LANDLOCK_LAST_SCOPE LANDLOCK_SCOPE_SIGNAL
3031
#define LANDLOCK_MASK_SCOPE ((LANDLOCK_LAST_SCOPE << 1) - 1)
3132
#define LANDLOCK_NUM_SCOPE __const_hweight64(LANDLOCK_MASK_SCOPE)
33+
34+
#define LANDLOCK_LAST_RESTRICT_SELF LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON
35+
#define LANDLOCK_MASK_RESTRICT_SELF ((LANDLOCK_LAST_RESTRICT_SELF << 1) - 1)
36+
3237
/* clang-format on */
3338

3439
#endif /* _SECURITY_LANDLOCK_LIMITS_H */

security/landlock/syscalls.c

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
// SPDX-License-Identifier: GPL-2.0-only
22
/*
3-
* Landlock LSM - System call implementations and user space interfaces
3+
* Landlock - System call implementations and user space interfaces
44
*
55
* Copyright © 2016-2020 Mickaël Salaün <[email protected]>
66
* Copyright © 2018-2020 ANSSI
7+
* Copyright © 2021-2025 Microsoft Corporation
78
*/
89

910
#include <asm/current.h>
@@ -28,6 +29,7 @@
2829
#include <uapi/linux/landlock.h>
2930

3031
#include "cred.h"
32+
#include "domain.h"
3133
#include "fs.h"
3234
#include "limits.h"
3335
#include "net.h"
@@ -151,7 +153,14 @@ static const struct file_operations ruleset_fops = {
151153
.write = fop_dummy_write,
152154
};
153155

154-
#define LANDLOCK_ABI_VERSION 6
156+
/*
157+
* The Landlock ABI version should be incremented for each new Landlock-related
158+
* user space visible change (e.g. Landlock syscalls). This version should
159+
* only be incremented once per Linux release, and the date in
160+
* Documentation/userspace-api/landlock.rst should be updated to reflect the
161+
* UAPI change.
162+
*/
163+
const int landlock_abi_version = 7;
155164

156165
/**
157166
* sys_landlock_create_ruleset - Create a new ruleset
@@ -247,8 +256,6 @@ SYSCALL_DEFINE3(landlock_create_ruleset,
247256
return ruleset_fd;
248257
}
249258

250-
const int landlock_abi_version = LANDLOCK_ABI_VERSION;
251-
252259
/*
253260
* Returns an owned ruleset from a FD. It is thus needed to call
254261
* landlock_put_ruleset() on the return value.
@@ -443,7 +450,10 @@ SYSCALL_DEFINE4(landlock_add_rule, const int, ruleset_fd,
443450
* sys_landlock_restrict_self - Enforce a ruleset on the calling thread
444451
*
445452
* @ruleset_fd: File descriptor tied to the ruleset to merge with the target.
446-
* @flags: Must be 0.
453+
* @flags: Supported values:
454+
*
455+
* - %LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF
456+
* - %LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON
447457
*
448458
* This system call enables to enforce a Landlock ruleset on the current
449459
* thread. Enforcing a ruleset requires that the task has %CAP_SYS_ADMIN in its
@@ -453,7 +463,7 @@ SYSCALL_DEFINE4(landlock_add_rule, const int, ruleset_fd,
453463
* Possible returned errors are:
454464
*
455465
* - %EOPNOTSUPP: Landlock is supported by the kernel but disabled at boot time;
456-
* - %EINVAL: @flags is not 0.
466+
* - %EINVAL: @flags contains an unknown bit.
457467
* - %EBADF: @ruleset_fd is not a file descriptor for the current thread;
458468
* - %EBADFD: @ruleset_fd is not a ruleset file descriptor;
459469
* - %EPERM: @ruleset_fd has no read access to the underlying ruleset, or the
@@ -469,6 +479,7 @@ SYSCALL_DEFINE2(landlock_restrict_self, const int, ruleset_fd, const __u32,
469479
*ruleset __free(landlock_put_ruleset) = NULL;
470480
struct cred *new_cred;
471481
struct landlock_cred_security *new_llcred;
482+
bool __maybe_unused log_same_exec, log_new_exec;
472483

473484
if (!is_initialized())
474485
return -EOPNOTSUPP;
@@ -481,10 +492,15 @@ SYSCALL_DEFINE2(landlock_restrict_self, const int, ruleset_fd, const __u32,
481492
!ns_capable_noaudit(current_user_ns(), CAP_SYS_ADMIN))
482493
return -EPERM;
483494

484-
/* No flag for now. */
485-
if (flags)
495+
if ((flags | LANDLOCK_MASK_RESTRICT_SELF) !=
496+
LANDLOCK_MASK_RESTRICT_SELF)
486497
return -EINVAL;
487498

499+
/* Translates "off" flag to boolean. */
500+
log_same_exec = !(flags & LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF);
501+
/* Translates "on" flag to boolean. */
502+
log_new_exec = !!(flags & LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON);
503+
488504
/* Gets and checks the ruleset. */
489505
ruleset = get_ruleset_from_fd(ruleset_fd, FMODE_CAN_READ);
490506
if (IS_ERR(ruleset))
@@ -507,6 +523,13 @@ SYSCALL_DEFINE2(landlock_restrict_self, const int, ruleset_fd, const __u32,
507523
return PTR_ERR(new_dom);
508524
}
509525

526+
#ifdef CONFIG_AUDIT
527+
new_dom->hierarchy->log_same_exec = log_same_exec;
528+
new_dom->hierarchy->log_new_exec = log_new_exec;
529+
if (!log_same_exec && !log_new_exec)
530+
new_dom->hierarchy->log_status = LANDLOCK_LOG_DISABLED;
531+
#endif /* CONFIG_AUDIT */
532+
510533
/* Replaces the old (prepared) domain. */
511534
landlock_put_ruleset(new_llcred->domain);
512535
new_llcred->domain = new_dom;

tools/testing/selftests/landlock/base_test.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ TEST(abi_version)
7676
const struct landlock_ruleset_attr ruleset_attr = {
7777
.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,
7878
};
79-
ASSERT_EQ(6, landlock_create_ruleset(NULL, 0,
79+
ASSERT_EQ(7, landlock_create_ruleset(NULL, 0,
8080
LANDLOCK_CREATE_RULESET_VERSION));
8181

8282
ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0,

0 commit comments

Comments
 (0)