summaryrefslogtreecommitdiff
path: root/security
diff options
context:
space:
mode:
Diffstat (limited to 'security')
-rw-r--r--security/landlock/audit.c16
-rw-r--r--security/landlock/domain.c2
-rw-r--r--security/landlock/domain.h11
-rw-r--r--security/landlock/limits.h7
-rw-r--r--security/landlock/syscalls.c39
5 files changed, 63 insertions, 12 deletions
diff --git a/security/landlock/audit.c b/security/landlock/audit.c
index 77d11355f6ed..7e5e0ed0e4e5 100644
--- a/security/landlock/audit.c
+++ b/security/landlock/audit.c
@@ -422,6 +422,9 @@ void landlock_log_denial(const struct landlock_cred_security *const subject,
get_hierarchy(subject->domain, youngest_layer);
}
+ if (READ_ONCE(youngest_denied->log_status) == LANDLOCK_LOG_DISABLED)
+ return;
+
/*
* Consistently keeps track of the number of denied access requests
* 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,
if (!audit_enabled)
return;
- /* Ignores denials after an execution. */
- if (!(subject->domain_exec & (1 << youngest_layer)))
- return;
+ /* Checks if the current exec was restricting itself. */
+ if (subject->domain_exec & (1 << youngest_layer)) {
+ /* Ignores denials for the same execution. */
+ if (!youngest_denied->log_same_exec)
+ return;
+ } else {
+ /* Ignores denials after a new execution. */
+ if (!youngest_denied->log_new_exec)
+ return;
+ }
/* Uses consistent allocation flags wrt common_lsm_audit(). */
ab = audit_log_start(audit_context(), GFP_ATOMIC | __GFP_NOWARN,
diff --git a/security/landlock/domain.c b/security/landlock/domain.c
index f61fa5ae8e56..bae2e9909013 100644
--- a/security/landlock/domain.c
+++ b/security/landlock/domain.c
@@ -127,6 +127,8 @@ int landlock_init_hierarchy_log(struct landlock_hierarchy *const hierarchy)
hierarchy->details = details;
hierarchy->id = landlock_get_id_range(1);
hierarchy->log_status = LANDLOCK_LOG_PENDING;
+ hierarchy->log_same_exec = true;
+ hierarchy->log_new_exec = false;
atomic64_set(&hierarchy->num_denials, 0);
return 0;
}
diff --git a/security/landlock/domain.h b/security/landlock/domain.h
index 96642dd87b33..ed0d348e214c 100644
--- a/security/landlock/domain.h
+++ b/security/landlock/domain.h
@@ -24,6 +24,7 @@
enum landlock_log_status {
LANDLOCK_LOG_PENDING = 0,
LANDLOCK_LOG_RECORDED,
+ LANDLOCK_LOG_DISABLED,
};
/**
@@ -103,6 +104,16 @@ struct landlock_hierarchy {
* @details: Information about the related domain.
*/
const struct landlock_details *details;
+ /**
+ * @log_same_exec: Set if the domain is *not* configured with
+ * %LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF. Set to true by default.
+ */
+ u32 log_same_exec : 1,
+ /**
+ * @log_new_exec: Set if the domain is configured with
+ * %LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON. Set to false by default.
+ */
+ log_new_exec : 1;
#endif /* CONFIG_AUDIT */
};
diff --git a/security/landlock/limits.h b/security/landlock/limits.h
index 15f7606066c8..404e880cccf9 100644
--- a/security/landlock/limits.h
+++ b/security/landlock/limits.h
@@ -1,9 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Landlock LSM - Limits for different components
+ * Landlock - Limits for different components
*
* Copyright © 2016-2020 Mickaël Salaün <mic@digikod.net>
* Copyright © 2018-2020 ANSSI
+ * Copyright © 2021-2025 Microsoft Corporation
*/
#ifndef _SECURITY_LANDLOCK_LIMITS_H
@@ -29,6 +30,10 @@
#define LANDLOCK_LAST_SCOPE LANDLOCK_SCOPE_SIGNAL
#define LANDLOCK_MASK_SCOPE ((LANDLOCK_LAST_SCOPE << 1) - 1)
#define LANDLOCK_NUM_SCOPE __const_hweight64(LANDLOCK_MASK_SCOPE)
+
+#define LANDLOCK_LAST_RESTRICT_SELF LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON
+#define LANDLOCK_MASK_RESTRICT_SELF ((LANDLOCK_LAST_RESTRICT_SELF << 1) - 1)
+
/* clang-format on */
#endif /* _SECURITY_LANDLOCK_LIMITS_H */
diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c
index b7b268f43a3b..75bc9fcd0a8f 100644
--- a/security/landlock/syscalls.c
+++ b/security/landlock/syscalls.c
@@ -1,9 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Landlock LSM - System call implementations and user space interfaces
+ * Landlock - System call implementations and user space interfaces
*
* Copyright © 2016-2020 Mickaël Salaün <mic@digikod.net>
* Copyright © 2018-2020 ANSSI
+ * Copyright © 2021-2025 Microsoft Corporation
*/
#include <asm/current.h>
@@ -28,6 +29,7 @@
#include <uapi/linux/landlock.h>
#include "cred.h"
+#include "domain.h"
#include "fs.h"
#include "limits.h"
#include "net.h"
@@ -151,7 +153,14 @@ static const struct file_operations ruleset_fops = {
.write = fop_dummy_write,
};
-#define LANDLOCK_ABI_VERSION 6
+/*
+ * The Landlock ABI version should be incremented for each new Landlock-related
+ * user space visible change (e.g. Landlock syscalls). This version should
+ * only be incremented once per Linux release, and the date in
+ * Documentation/userspace-api/landlock.rst should be updated to reflect the
+ * UAPI change.
+ */
+const int landlock_abi_version = 7;
/**
* sys_landlock_create_ruleset - Create a new ruleset
@@ -247,8 +256,6 @@ SYSCALL_DEFINE3(landlock_create_ruleset,
return ruleset_fd;
}
-const int landlock_abi_version = LANDLOCK_ABI_VERSION;
-
/*
* Returns an owned ruleset from a FD. It is thus needed to call
* landlock_put_ruleset() on the return value.
@@ -443,7 +450,10 @@ SYSCALL_DEFINE4(landlock_add_rule, const int, ruleset_fd,
* sys_landlock_restrict_self - Enforce a ruleset on the calling thread
*
* @ruleset_fd: File descriptor tied to the ruleset to merge with the target.
- * @flags: Must be 0.
+ * @flags: Supported values:
+ *
+ * - %LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF
+ * - %LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON
*
* This system call enables to enforce a Landlock ruleset on the current
* 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,
* Possible returned errors are:
*
* - %EOPNOTSUPP: Landlock is supported by the kernel but disabled at boot time;
- * - %EINVAL: @flags is not 0.
+ * - %EINVAL: @flags contains an unknown bit.
* - %EBADF: @ruleset_fd is not a file descriptor for the current thread;
* - %EBADFD: @ruleset_fd is not a ruleset file descriptor;
* - %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,
*ruleset __free(landlock_put_ruleset) = NULL;
struct cred *new_cred;
struct landlock_cred_security *new_llcred;
+ bool __maybe_unused log_same_exec, log_new_exec;
if (!is_initialized())
return -EOPNOTSUPP;
@@ -481,10 +492,15 @@ SYSCALL_DEFINE2(landlock_restrict_self, const int, ruleset_fd, const __u32,
!ns_capable_noaudit(current_user_ns(), CAP_SYS_ADMIN))
return -EPERM;
- /* No flag for now. */
- if (flags)
+ if ((flags | LANDLOCK_MASK_RESTRICT_SELF) !=
+ LANDLOCK_MASK_RESTRICT_SELF)
return -EINVAL;
+ /* Translates "off" flag to boolean. */
+ log_same_exec = !(flags & LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF);
+ /* Translates "on" flag to boolean. */
+ log_new_exec = !!(flags & LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON);
+
/* Gets and checks the ruleset. */
ruleset = get_ruleset_from_fd(ruleset_fd, FMODE_CAN_READ);
if (IS_ERR(ruleset))
@@ -507,6 +523,13 @@ SYSCALL_DEFINE2(landlock_restrict_self, const int, ruleset_fd, const __u32,
return PTR_ERR(new_dom);
}
+#ifdef CONFIG_AUDIT
+ new_dom->hierarchy->log_same_exec = log_same_exec;
+ new_dom->hierarchy->log_new_exec = log_new_exec;
+ if (!log_same_exec && !log_new_exec)
+ new_dom->hierarchy->log_status = LANDLOCK_LOG_DISABLED;
+#endif /* CONFIG_AUDIT */
+
/* Replaces the old (prepared) domain. */
landlock_put_ruleset(new_llcred->domain);
new_llcred->domain = new_dom;