public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: "Mickaël Salaün" <mic@digikod.net>
To: "Christian Brauner" <brauner@kernel.org>,
	"Günther Noack" <gnoack@google.com>
Cc: "Mickaël Salaün" <mic@digikod.net>,
	"Charles Zaffery" <czaffery@roblox.com>,
	"Daniel Burgener" <dburgener@linux.microsoft.com>,
	"Francis Laniel" <flaniel@linux.microsoft.com>,
	"James Morris" <jmorris@namei.org>,
	"Jann Horn" <jannh@google.com>, "Jeff Xu" <jeffxu@google.com>,
	"Kees Cook" <kees@kernel.org>,
	"Luca Boccassi" <luca.boccassi@gmail.com>,
	"Mikhail Ivanov" <ivanov.mikhail1@huawei-partners.com>,
	"Praveen K Paladugu" <prapal@linux.microsoft.com>,
	"Robert Salvet" <robert.salvet@roblox.com>,
	"Shervin Oloumi" <enlightened@google.com>,
	"Tyler Hicks" <code@tyhicks.com>,
	linux-kernel@vger.kernel.org,
	linux-security-module@vger.kernel.org
Subject: [RFC PATCH v1 2/3] pidfd: Extend PIDFD_GET_INFO with PIDFD_INFO_LANDLOCK_*_DOMAIN
Date: Fri, 31 Jan 2025 17:34:46 +0100	[thread overview]
Message-ID: <20250131163447.1140564-3-mic@digikod.net> (raw)
In-Reply-To: <20250131163447.1140564-1-mic@digikod.net>

Because Landlock enables users to create nested sandboxes (i.e.
domains), we might need to identify the domain with all restrictions
(latest), or the domain we created (i.e. closest domain).  Indeed,
because any process can create its own domain, the latest domain may not
be known by the requester.

The PIDFD_INFO_LANDLOCK_LAST_DOMAIN flag enables user space to get the
latest (i.e. most nested) Landlock domain ID related to a sandboxed
task, if any.  The domain ID is set in the pidfd_info's
landlock_last_domain field according to the related mask.

The PIDFD_INFO_LANDLOCK_FIRST_DOMAIN flag enables user space to get the
closest (i.e. first hierarchy relative to the pidfd's credentials)
Landlock domain ID related to a sandboxed task, if any.  The domain ID
is set in the pidfd_info's landlock_first_domain field according to the
related mask.

It is only allowed to get information about a Landlock domain if the
task's domain that created the pidfd is a parent of the PID's domain.
Following the object-capability model, the pidfd's credentials are used
instead of the caller's credentials.  This makes this command
idenmpotent wrt the referenced process's state.

If Landlock is not supported or if access to this information is denied,
then the IOCTL does not set the PIDFD_INFO_LANDLOCK_*_DOMAIN flag in the
returned mask.

If PIDFD_INFO_LANDLOCK_LAST_DOMAIN or PIDFD_INFO_LANDLOCK_FIRST_DOMAIN
is specified but the provided struct pidfd_info is not large enough to
contain the related field, then -EINVAL is returned.

Cc: Christian Brauner <brauner@kernel.org>
Cc: Günther Noack <gnoack@google.com>
Cc: Luca Boccassi <luca.boccassi@gmail.com>
Cc: Praveen K Paladugu <prapal@linux.microsoft.com>
Closes: https://github.com/landlock-lsm/linux/issues/26
Signed-off-by: Mickaël Salaün <mic@digikod.net>
Link: https://lore.kernel.org/r/20250131163447.1140564-3-mic@digikod.net
---
 fs/pidfs.c                 | 24 ++++++++++++++++++++++--
 include/uapi/linux/pidfd.h |  4 ++++
 2 files changed, 26 insertions(+), 2 deletions(-)

diff --git a/fs/pidfs.c b/fs/pidfs.c
index 049352f973de..4ff5b6c776ce 100644
--- a/fs/pidfs.c
+++ b/fs/pidfs.c
@@ -20,6 +20,7 @@
 #include <linux/time_namespace.h>
 #include <linux/utsname.h>
 #include <net/net_namespace.h>
+#include <linux/landlock.h>
 
 #include "internal.h"
 #include "mount.h"
@@ -207,7 +208,8 @@ static __poll_t pidfd_poll(struct file *file, struct poll_table_struct *pts)
 	return poll_flags;
 }
 
-static long pidfd_info(struct task_struct *task, unsigned int cmd, unsigned long arg)
+static long pidfd_info(const struct cred *cred, struct task_struct *task,
+		       unsigned int cmd, unsigned long arg)
 {
 	struct pidfd_info __user *uinfo = (struct pidfd_info __user *)arg;
 	size_t usize = _IOC_SIZE(cmd);
@@ -227,6 +229,14 @@ static long pidfd_info(struct task_struct *task, unsigned int cmd, unsigned long
 	if (copy_from_user(&mask, &uinfo->mask, sizeof(mask)))
 		return -EFAULT;
 
+	if ((mask & PIDFD_INFO_LANDLOCK_LAST_DOMAIN) &&
+	    usize < offsetofend(typeof(*uinfo), landlock_last_domain))
+		return -EINVAL;
+
+	if ((mask & PIDFD_INFO_LANDLOCK_FIRST_DOMAIN) &&
+	    usize < offsetofend(typeof(*uinfo), landlock_first_domain))
+		return -EINVAL;
+
 	c = get_task_cred(task);
 	if (!c)
 		return -ESRCH;
@@ -253,6 +263,16 @@ static long pidfd_info(struct task_struct *task, unsigned int cmd, unsigned long
 	rcu_read_unlock();
 #endif
 
+	if ((mask & PIDFD_INFO_LANDLOCK_LAST_DOMAIN) &&
+	    !landlock_read_domain_id(cred, task, true,
+				     &kinfo.landlock_last_domain))
+		kinfo.mask |= PIDFD_INFO_LANDLOCK_LAST_DOMAIN;
+
+	if ((mask & PIDFD_INFO_LANDLOCK_FIRST_DOMAIN) &&
+	    !landlock_read_domain_id(cred, task, false,
+				     &kinfo.landlock_first_domain))
+		kinfo.mask |= PIDFD_INFO_LANDLOCK_FIRST_DOMAIN;
+
 	/*
 	 * Copy pid/tgid last, to reduce the chances the information might be
 	 * stale. Note that it is not possible to ensure it will be valid as the
@@ -328,7 +348,7 @@ static long pidfd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
 	/* Extensible IOCTL that does not open namespace FDs, take a shortcut */
 	if (_IOC_NR(cmd) == _IOC_NR(PIDFD_GET_INFO))
-		return pidfd_info(task, cmd, arg);
+		return pidfd_info(file->f_cred, task, cmd, arg);
 
 	if (arg)
 		return -EINVAL;
diff --git a/include/uapi/linux/pidfd.h b/include/uapi/linux/pidfd.h
index 4540f6301b8c..267991bd266c 100644
--- a/include/uapi/linux/pidfd.h
+++ b/include/uapi/linux/pidfd.h
@@ -20,6 +20,8 @@
 #define PIDFD_INFO_PID			(1UL << 0) /* Always returned, even if not requested */
 #define PIDFD_INFO_CREDS		(1UL << 1) /* Always returned, even if not requested */
 #define PIDFD_INFO_CGROUPID		(1UL << 2) /* Always returned if available, even if not requested */
+#define PIDFD_INFO_LANDLOCK_LAST_DOMAIN	(1UL << 3) /* Only returned if requested */
+#define PIDFD_INFO_LANDLOCK_FIRST_DOMAIN	(1UL << 4) /* Only returned if requested */
 
 #define PIDFD_INFO_SIZE_VER0		64 /* sizeof first published struct */
 
@@ -63,6 +65,8 @@ struct pidfd_info {
 	__u32 fsuid;
 	__u32 fsgid;
 	__u32 spare0[1];
+	__u64 landlock_last_domain;
+	__u64 landlock_first_domain;
 };
 
 #define PIDFS_IOCTL_MAGIC 0xFF
-- 
2.48.1


  parent reply	other threads:[~2025-01-31 16:34 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-01-31 16:34 [RFC PATCH v1 0/3] Expose Landlock domain IDs via pidfd Mickaël Salaün
2025-01-31 16:34 ` [RFC PATCH v1 1/3] landlock: Add landlock_read_domain_id() Mickaël Salaün
2025-01-31 16:34 ` Mickaël Salaün [this message]
2025-01-31 19:02   ` [RFC PATCH v1 2/3] pidfd: Extend PIDFD_GET_INFO with PIDFD_INFO_LANDLOCK_*_DOMAIN Paul Moore
2025-02-01 10:28     ` Mickaël Salaün
2025-02-01 11:09       ` Christian Brauner
2025-02-01 23:48       ` Paul Moore
2025-01-31 16:34 ` [RFC PATCH v1 3/3] samples/landlock: Print domain ID Mickaël Salaün
2025-01-31 17:35 ` [RFC PATCH v1 0/3] Expose Landlock domain IDs via pidfd Mickaël Salaün

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250131163447.1140564-3-mic@digikod.net \
    --to=mic@digikod.net \
    --cc=brauner@kernel.org \
    --cc=code@tyhicks.com \
    --cc=czaffery@roblox.com \
    --cc=dburgener@linux.microsoft.com \
    --cc=enlightened@google.com \
    --cc=flaniel@linux.microsoft.com \
    --cc=gnoack@google.com \
    --cc=ivanov.mikhail1@huawei-partners.com \
    --cc=jannh@google.com \
    --cc=jeffxu@google.com \
    --cc=jmorris@namei.org \
    --cc=kees@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=luca.boccassi@gmail.com \
    --cc=prapal@linux.microsoft.com \
    --cc=robert.salvet@roblox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox