[RFC PATCH 07/10] landlock: Add the new domain to landlock_cred_security
Tingmao Wang
m at maowtm.org
Wed May 21 19:32:03 UTC 2025
We add a new field domain2 that will eventually replace the old struct
landlock_ruleset domain. Also add get/put to appropriate places where
this struct is copied/freed.
In a future patch, this domain2 will be renamed to domain.
Signed-off-by: Tingmao Wang <m at maowtm.org>
---
security/landlock/cred.c | 8 ++++----
security/landlock/cred.h | 1 +
security/landlock/domain.c | 17 +++++++++++++++++
security/landlock/domain.h | 32 +++++++++++++++++++++++---------
security/landlock/fs.c | 5 +++++
5 files changed, 50 insertions(+), 13 deletions(-)
diff --git a/security/landlock/cred.c b/security/landlock/cred.c
index 0cb3edde4d18..e08c9e206350 100644
--- a/security/landlock/cred.c
+++ b/security/landlock/cred.c
@@ -13,6 +13,7 @@
#include "common.h"
#include "cred.h"
+#include "domain.h"
#include "ruleset.h"
#include "setup.h"
@@ -24,6 +25,7 @@ static void hook_cred_transfer(struct cred *const new,
if (old_llcred->domain) {
landlock_get_ruleset(old_llcred->domain);
+ landlock_get_domain(old_llcred->domain2);
*landlock_cred(new) = *old_llcred;
}
}
@@ -37,10 +39,8 @@ static int hook_cred_prepare(struct cred *const new,
static void hook_cred_free(struct cred *const cred)
{
- struct landlock_ruleset *const dom = landlock_cred(cred)->domain;
-
- if (dom)
- landlock_put_ruleset_deferred(dom);
+ landlock_put_ruleset_deferred(landlock_cred(cred)->domain);
+ landlock_put_domain_deferred(landlock_cred(cred)->domain2);
}
#ifdef CONFIG_AUDIT
diff --git a/security/landlock/cred.h b/security/landlock/cred.h
index c82fe63ec598..b13b4c2e21aa 100644
--- a/security/landlock/cred.h
+++ b/security/landlock/cred.h
@@ -32,6 +32,7 @@ struct landlock_cred_security {
* @domain: Immutable ruleset enforced on a task.
*/
struct landlock_ruleset *domain;
+ struct landlock_domain *domain2;
#ifdef CONFIG_AUDIT
/**
diff --git a/security/landlock/domain.c b/security/landlock/domain.c
index 180ed75da9e2..321c52b275fc 100644
--- a/security/landlock/domain.c
+++ b/security/landlock/domain.c
@@ -60,6 +60,23 @@ void landlock_put_domain(struct landlock_domain *const domain)
}
}
+static void free_domain_work(struct work_struct *const work)
+{
+ struct landlock_domain *domain;
+
+ domain = container_of(work, struct landlock_domain, work_free);
+ free_domain(domain);
+}
+
+/* Only called by hook_cred_free(). */
+void landlock_put_domain_deferred(struct landlock_domain *const domain)
+{
+ if (domain && refcount_dec_and_test(&domain->usage)) {
+ INIT_WORK(&domain->work_free, free_domain_work);
+ schedule_work(&domain->work_free);
+ }
+}
+
#ifdef CONFIG_AUDIT
/**
diff --git a/security/landlock/domain.h b/security/landlock/domain.h
index ed685f8ad52e..944420231040 100644
--- a/security/landlock/domain.h
+++ b/security/landlock/domain.h
@@ -18,6 +18,7 @@
#include <linux/refcount.h>
#include <linux/sched.h>
#include <linux/slab.h>
+#include <linux/workqueue.h>
#include "access.h"
#include "audit.h"
@@ -26,15 +27,26 @@
struct landlock_domain {
struct landlock_hashtable inode_table;
- /**
- * @usage: Reference count for this struct.
- */
- refcount_t usage;
-
- /**
- * @num_layers: Number of layers in this domain.
- */
- u16 num_layers;
+ union {
+ /**
+ * @work_free: Enables to free a ruleset within a lockless
+ * section. This is only used by
+ * landlock_put_domain_deferred() when @usage reaches zero.
+ */
+ struct work_struct work_free;
+
+ struct {
+ /**
+ * @usage: Reference count for this struct.
+ */
+ refcount_t usage;
+
+ /**
+ * @num_layers: Number of layers in this domain.
+ */
+ u16 num_layers;
+ };
+ };
};
struct landlock_domain *landlock_alloc_domain(size_t num_inode_entries,
@@ -48,6 +60,8 @@ static inline void landlock_get_domain(struct landlock_domain *const domain)
void landlock_put_domain(struct landlock_domain *const domain);
+void landlock_put_domain_deferred(struct landlock_domain *const domain);
+
enum landlock_log_status {
LANDLOCK_LOG_PENDING = 0,
LANDLOCK_LOG_RECORDED,
diff --git a/security/landlock/fs.c b/security/landlock/fs.c
index b407c644ac65..c4f442093c6e 100644
--- a/security/landlock/fs.c
+++ b/security/landlock/fs.c
@@ -1844,6 +1844,7 @@ static bool control_current_fowner(struct fown_struct *const fown)
static void hook_file_set_fowner(struct file *file)
{
struct landlock_ruleset *prev_dom;
+ struct landlock_domain *prev_dom2;
struct landlock_cred_security fown_subject = {};
size_t fown_layer = 0;
@@ -1856,11 +1857,13 @@ static void hook_file_set_fowner(struct file *file)
current_cred(), signal_scope, &fown_layer);
if (new_subject) {
landlock_get_ruleset(new_subject->domain);
+ landlock_get_domain(new_subject->domain2);
fown_subject = *new_subject;
}
}
prev_dom = landlock_file(file)->fown_subject.domain;
+ prev_dom2 = landlock_file(file)->fown_subject.domain2;
landlock_file(file)->fown_subject = fown_subject;
#ifdef CONFIG_AUDIT
landlock_file(file)->fown_layer = fown_layer;
@@ -1868,11 +1871,13 @@ static void hook_file_set_fowner(struct file *file)
/* May be called in an RCU read-side critical section. */
landlock_put_ruleset_deferred(prev_dom);
+ landlock_put_domain_deferred(prev_dom2);
}
static void hook_file_free_security(struct file *file)
{
landlock_put_ruleset_deferred(landlock_file(file)->fown_subject.domain);
+ landlock_put_domain_deferred(landlock_file(file)->fown_subject.domain2);
}
static struct security_hook_list landlock_hooks[] __ro_after_init = {
--
2.49.0
More information about the Linux-security-module-archive
mailing list