From patchwork Fri Jan 31 16:34:45 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= X-Patchwork-Id: 13955565 Received: from smtp-42ab.mail.infomaniak.ch (smtp-42ab.mail.infomaniak.ch [84.16.66.171]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9A5B21F55E4 for ; Fri, 31 Jan 2025 16:34:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=84.16.66.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738341299; cv=none; b=cidDnxnDN7Fh/xTu2+PidgRf8nWWR/FZUf/sEhH83KXTBcNYCfO99iKR3mTYhfyDFQI/m6qZOynvhgmy72K2l7OGRIQGuC7nlNtn9qg9yV8HkS+O7WfqduaBT/XhdnNHYj2faOo7OP9HauelOxwsf82Ept7GWHbk48gfACKCeBk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738341299; c=relaxed/simple; bh=armgMynyhbaJWif0AxnvKnIExXEE9FpW6K2Fc/eMi3Y=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=pGC4B3ad37KNv33yQ+QyMRVvaEwYunZA3OC6UWiKlwXaZcWuoOCFFfc0np8o/Zb09KbghwvTbHxDBycqPNzx4zgMfmxRHbSTkNh/dX87xoFpD52PyTkh1zzy6X1BMs+TXDNnHIRAzIkufvbbI+JLvOjoWoYkTZjoGz9ho52L+sM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=digikod.net; spf=pass smtp.mailfrom=digikod.net; dkim=pass (1024-bit key) header.d=digikod.net header.i=@digikod.net header.b=oAclw7bY; arc=none smtp.client-ip=84.16.66.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=digikod.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=digikod.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=digikod.net header.i=@digikod.net header.b="oAclw7bY" Received: from smtp-4-0000.mail.infomaniak.ch (smtp-4-0000.mail.infomaniak.ch [10.7.10.107]) by smtp-4-3000.mail.infomaniak.ch (Postfix) with ESMTPS id 4Yl1hH0HG6zClW; Fri, 31 Jan 2025 17:34:55 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=digikod.net; s=20191114; t=1738341294; bh=EoG7lKIcgzOE6DS13t1+RUuwwP5OY6Prk56tBe+01WE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=oAclw7bYFiox7QNFFAULTE6AcnVHfMco7MCqaHPZ+Q+O+B9wGMovQ2WtGkpEQyBr2 v4k665iAENAk6n29ul5xAAR1ZQYjUye8/6Ji8Co7PDVbtZF6x/wvmwhBh4/phcOuNp fnMxILrvM7v/N3GLw6lJ655imt4VhsgEct8BhgK0= Received: from unknown by smtp-4-0000.mail.infomaniak.ch (Postfix) with ESMTPA id 4Yl1hG15xvzZcy; Fri, 31 Jan 2025 17:34:54 +0100 (CET) From: =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= To: Christian Brauner , =?utf-8?q?G=C3=BCnther_Noack?= Cc: =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= , Charles Zaffery , Daniel Burgener , Francis Laniel , James Morris , Jann Horn , Jeff Xu , Kees Cook , Luca Boccassi , Mikhail Ivanov , Praveen K Paladugu , Robert Salvet , Shervin Oloumi , Tyler Hicks , linux-kernel@vger.kernel.org, linux-security-module@vger.kernel.org Subject: [RFC PATCH v1 1/3] landlock: Add landlock_read_domain_id() Date: Fri, 31 Jan 2025 17:34:45 +0100 Message-ID: <20250131163447.1140564-2-mic@digikod.net> In-Reply-To: <20250131163447.1140564-1-mic@digikod.net> References: <20250131163447.1140564-1-mic@digikod.net> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Infomaniak-Routing: alpha This public landlock_read_domain_id() helper will be used in the next commit by the PIDFD_GET_INFO IOCTL to read a task's domain ID. A task is only allowed to get information about its nested domains. Being able to read tasks' domain IDs is useful for telemetry, debugging, and tests. It enables users: - to know if a task is well sandboxed; - to know which tasks are part of the same sandbox; - to map Landlock audit logs to running processes. Future changes will leverage this feature to improve Landlock observability. Landlock domain IDs are now always generated at domain creation time. Cc: Christian Brauner Cc: Günther Noack Cc: Luca Boccassi Cc: Praveen K Paladugu Signed-off-by: Mickaël Salaün Link: https://lore.kernel.org/r/20250131163447.1140564-2-mic@digikod.net --- include/linux/landlock.h | 26 +++++++++++++ security/landlock/Makefile | 12 ++++-- security/landlock/domain.c | 2 - security/landlock/domain.h | 8 ++-- security/landlock/ruleset.c | 2 + security/landlock/syscalls.c | 75 ++++++++++++++++++++++++++++++++++++ 6 files changed, 116 insertions(+), 9 deletions(-) create mode 100644 include/linux/landlock.h diff --git a/include/linux/landlock.h b/include/linux/landlock.h new file mode 100644 index 000000000000..a091deee9ad7 --- /dev/null +++ b/include/linux/landlock.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Landlock public helpers + * + * Copyright © 2025 Microsoft Corporation + */ + +#include +#include + +#ifdef CONFIG_SECURITY_LANDLOCK + +int landlock_read_domain_id(const struct cred *const cred, + struct task_struct *const task, const bool last, + u64 *const id); + +#else /* CONFIG_SECURITY_LANDLOCK */ + +static inline int landlock_read_domain_id(const struct cred *const cred, + struct task_struct *const task, + const bool last, u64 *const id) +{ + return -EOPNOTSUPP; +} + +#endif /* CONFIG_SECURITY_LANDLOCK */ diff --git a/security/landlock/Makefile b/security/landlock/Makefile index 3160c2bdac1d..5db653a1717e 100644 --- a/security/landlock/Makefile +++ b/security/landlock/Makefile @@ -1,11 +1,17 @@ obj-$(CONFIG_SECURITY_LANDLOCK) := landlock.o -landlock-y := setup.o syscalls.o object.o ruleset.o \ - cred.o task.o fs.o +landlock-y := \ + setup.o \ + syscalls.o \ + object.o \ + ruleset.o \ + cred.o \ + task.o \ + fs.o \ + id.o landlock-$(CONFIG_INET) += net.o landlock-$(CONFIG_AUDIT) += \ - id.o \ audit.o \ domain.o diff --git a/security/landlock/domain.c b/security/landlock/domain.c index 49ccb0f72e53..782cc4ef73e0 100644 --- a/security/landlock/domain.c +++ b/security/landlock/domain.c @@ -21,7 +21,6 @@ #include "common.h" #include "domain.h" #include "fs.h" -#include "id.h" #ifdef CONFIG_AUDIT @@ -125,7 +124,6 @@ int landlock_init_hierarchy_log(struct landlock_hierarchy *const hierarchy) return PTR_ERR(details); hierarchy->details = details; - hierarchy->id = landlock_get_id_range(1); hierarchy->log_status = LANDLOCK_LOG_PENDING; hierarchy->quiet_subdomains = false; hierarchy->log_cross_exec = false; diff --git a/security/landlock/domain.h b/security/landlock/domain.h index 06b213aa7579..3f678caddaff 100644 --- a/security/landlock/domain.h +++ b/security/landlock/domain.h @@ -78,6 +78,10 @@ struct landlock_hierarchy { * Landlock domain. */ struct landlock_hierarchy *parent; + /** + * @id: Landlock domain ID, sets once at domain creation time. + */ + u64 id; /** * @usage: Number of potential children domains plus their parent * domain. @@ -96,10 +100,6 @@ struct landlock_hierarchy { * Masked (i.e. never logged) denials are still counted. */ atomic64_t num_denials; - /** - * @id: Landlock domain ID, sets once at domain creation time. - */ - u64 id; /** * @details: Information about the related domain. */ diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c index de41e8bde2e4..e42933361c32 100644 --- a/security/landlock/ruleset.c +++ b/security/landlock/ruleset.c @@ -25,6 +25,7 @@ #include "access.h" #include "audit.h" #include "domain.h" +#include "id.h" #include "limits.h" #include "object.h" #include "ruleset.h" @@ -576,6 +577,7 @@ landlock_merge_ruleset(struct landlock_ruleset *const parent, if (err) return ERR_PTR(err); + new_dom->hierarchy->id = landlock_get_id_range(1); return no_free_ptr(new_dom); } diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c index 5709a53c4a09..060ac9d52527 100644 --- a/security/landlock/syscalls.c +++ b/security/landlock/syscalls.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -538,3 +539,77 @@ SYSCALL_DEFINE2(landlock_restrict_self, const int, ruleset_fd, const __u32, return commit_creds(new_cred); } + +/** + * landlock_read_domain_id - Read the domain ID of a task + * + * @cred: The credential used to check permission. + * @task: Task to read the domain ID from. + * @last: Either get the ID of the last or the closest nested domain relative + * to @cred. + * @id: Returned domain ID on success. + * + * @cred is only allowed to get information about its nested domains. + * + * Any error returned by this function just translates to non-information in a + * PIDFD_GET_INFO's PIDFD_INFO_LANDLOCK_LAST_DOMAIN or + * PIDFD_INFO_LANDLOCK_FIRST_DOMAIN request. + * + * Returns: 0 on success, or -errno on error. + */ +int landlock_read_domain_id(const struct cred *const cred, + struct task_struct *const task, const bool last, + u64 *const id) +{ + const struct landlock_ruleset *cred_dom, *task_dom; + const struct landlock_hierarchy *walker, *prev; + bool is_allowed; + + if (!is_initialized()) + return -EOPNOTSUPP; + + cred_dom = landlock_cred(cred)->domain; + + guard(rcu)(); + task_dom = landlock_get_task_domain(task); + + /* + * Domain introspection is denied to not leak information about the + * current restrictions. However, a task can open a pidfd to itself, + * sandbox itself, and then read its domain ID from the previously + * opened pidfd. This is OK because the task already knows its + * sandbox, which might not be the case for its children. + * + * For consistency wrt sandboxed and non-sandboxed tasks, any task + * should get the same result when directly reading its own domain. A + * non-sandboxed task requesting to read another non-sandboxed task + * should then also be denied (i.e. cred_dom == task_dom == NULL). + */ + if (cred_dom == task_dom) + return -EPERM; + + if (!task_dom) + return -EPERM; + + /* Reading properties of @cred's nested domains is allowed. */ + is_allowed = !cred_dom; + prev = task_dom->hierarchy; + for (walker = prev; walker; walker = walker->parent) { + if (cred_dom && walker == cred_dom->hierarchy) { + is_allowed = true; + break; + } + + prev = walker; + } + + if (!is_allowed) + return -EPERM; + + if (last) + *id = task_dom->hierarchy->id; + else + *id = prev->id; + + return 0; +} From patchwork Fri Jan 31 16:34:46 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= X-Patchwork-Id: 13955566 Received: from smtp-1909.mail.infomaniak.ch (smtp-1909.mail.infomaniak.ch [185.125.25.9]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EAAA21F560F for ; Fri, 31 Jan 2025 16:34:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.125.25.9 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738341301; cv=none; b=N4Co+aPvgVt8+EkjbebmuPse7DVd5Z+ZwUqVZylhLPYsUl43WABRGKkz/ooesjMJfEv584KeMRNiLeyFX1MyPI21lhphKIBq/xlfx6ylXX1319hWx6eRsDgTHV+V+wMaIMA2sXVqT+ojYyp+56+Ev5vtoYtOYM2lAZMd1yLFsG0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738341301; c=relaxed/simple; bh=M3xYE8SlhylDM+mAearAhaWUgjUUsDjknhDvjQeCk9E=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=rkYNE9GoecOsN0+lRyHlEN+nwploMbplpLEVZHdBtuEHo7ybpYhLxKwrOVZpVFrjyhkrwnxO/3fC1VtgSgq/XH/nXwUZDsXmrPDwEl7+TIIJlCGkULQQicLzROFhRXyImnC2Sg17tj39XGKN8v8607UXTVkVRvdxpZ7ylw0GuhE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=digikod.net; spf=pass smtp.mailfrom=digikod.net; dkim=pass (1024-bit key) header.d=digikod.net header.i=@digikod.net header.b=OIeF5STx; arc=none smtp.client-ip=185.125.25.9 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=digikod.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=digikod.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=digikod.net header.i=@digikod.net header.b="OIeF5STx" Received: from smtp-4-0000.mail.infomaniak.ch (unknown [IPv6:2001:1600:7:10:40ca:feff:fe05:0]) by smtp-4-3000.mail.infomaniak.ch (Postfix) with ESMTPS id 4Yl1hK1NzPzClY; Fri, 31 Jan 2025 17:34:57 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=digikod.net; s=20191114; t=1738341297; bh=CpxlXkuvz87N63qJ7t8LlIMfS7wGPmR7iFRhFxMRGL0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=OIeF5STx/b5nhQSik1FOLn/iOsijc0av0KAM+Y7fuhW47qiaoMmXBwqKzuifbDT5/ Kti4V19xuGYZWKGn/hbntKCKOP2nOTiKNb/bNeVzNf3hecMAH6iqkw6TBy5uFpQ6at B3gHFPao1GaQEftUgX296nwe40Rm4N21hy7Izr00= Received: from unknown by smtp-4-0000.mail.infomaniak.ch (Postfix) with ESMTPA id 4Yl1hJ0qMLzbmv; Fri, 31 Jan 2025 17:34:56 +0100 (CET) From: =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= To: Christian Brauner , =?utf-8?q?G=C3=BCnther_Noack?= Cc: =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= , Charles Zaffery , Daniel Burgener , Francis Laniel , James Morris , Jann Horn , Jeff Xu , Kees Cook , Luca Boccassi , Mikhail Ivanov , Praveen K Paladugu , Robert Salvet , Shervin Oloumi , Tyler Hicks , 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 Message-ID: <20250131163447.1140564-3-mic@digikod.net> In-Reply-To: <20250131163447.1140564-1-mic@digikod.net> References: <20250131163447.1140564-1-mic@digikod.net> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Infomaniak-Routing: alpha 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 Cc: Günther Noack Cc: Luca Boccassi Cc: Praveen K Paladugu Closes: https://github.com/landlock-lsm/linux/issues/26 Signed-off-by: Mickaël Salaün 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 #include #include +#include #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 From patchwork Fri Jan 31 16:34:47 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= X-Patchwork-Id: 13955567 Received: from smtp-bc09.mail.infomaniak.ch (smtp-bc09.mail.infomaniak.ch [45.157.188.9]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6AAD51F12E5 for ; Fri, 31 Jan 2025 16:35:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.157.188.9 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738341303; cv=none; b=cl/TVrd3y8M6nuJN+4YSM9OMzX5x6fBHSzrBG4wkLnoRbCXh3hJKnW4qL9KuKMXQOwlF4fAIJN/7eJo97Q/OtoOG3nIykzeoo0PGu7MQiuB6C7gwaqB0l63X/QPOTE7hPr2JrN6gIEF6S3ns+aakrwXis6+G1HHjZM+lRmoZKZg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738341303; c=relaxed/simple; bh=s3V32RxTc9rjwEdIymNuOJwJkTxz3xJgXjeJ8V2zx7I=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Hb3ScXmn77YVgwoQPGmiW+jfQSuC2OYV3eyZpzYc3rSWk/PRSDsuZwAoaQlwR2h43ri06q94SiQaoe+ulWl8xLedI1kua2aaXv9gmZAuTQjiGGRSf/xyr2rOvVzAh+GVr795j4xfvWAfUZ0NkIOtF9SCV7VB6fzOBE673LmzTzM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=digikod.net; spf=pass smtp.mailfrom=digikod.net; dkim=pass (1024-bit key) header.d=digikod.net header.i=@digikod.net header.b=F2Acy9Sp; arc=none smtp.client-ip=45.157.188.9 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=digikod.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=digikod.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=digikod.net header.i=@digikod.net header.b="F2Acy9Sp" Received: from smtp-4-0000.mail.infomaniak.ch (smtp-4-0000.mail.infomaniak.ch [10.7.10.107]) by smtp-4-3000.mail.infomaniak.ch (Postfix) with ESMTPS id 4Yl1hM5wFFz17kX; Fri, 31 Jan 2025 17:34:59 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=digikod.net; s=20191114; t=1738341299; bh=WO2vAsxZVdDDoK6+XBTdTT+unawoC0QprK0aBSpqsk0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=F2Acy9SplbTktfS6Obk+lbE1XOfnJN+cQT6vUMJ9qmF56SDhIDo+FT9ImLUmUFDUm 4LDdJlzTjfL9KLZeUjsVXVuY62st90Y6fVKe87+2EVfQ9vl71Qns7a4Ljzf0gXupjA kC/ITpnrhYkkDPckEkg1sF3HUIjdsE/3OGc/aSHA= Received: from unknown by smtp-4-0000.mail.infomaniak.ch (Postfix) with ESMTPA id 4Yl1hM0jBtzbTy; Fri, 31 Jan 2025 17:34:59 +0100 (CET) From: =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= To: Christian Brauner , =?utf-8?q?G=C3=BCnther_Noack?= Cc: =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= , Charles Zaffery , Daniel Burgener , Francis Laniel , James Morris , Jann Horn , Jeff Xu , Kees Cook , Luca Boccassi , Mikhail Ivanov , Praveen K Paladugu , Robert Salvet , Shervin Oloumi , Tyler Hicks , linux-kernel@vger.kernel.org, linux-security-module@vger.kernel.org Subject: [RFC PATCH v1 3/3] samples/landlock: Print domain ID Date: Fri, 31 Jan 2025 17:34:47 +0100 Message-ID: <20250131163447.1140564-4-mic@digikod.net> In-Reply-To: <20250131163447.1140564-1-mic@digikod.net> References: <20250131163447.1140564-1-mic@digikod.net> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Infomaniak-Routing: alpha If the PIDFD_GET_INFO IOCTL command and the related PIDFD_INFO_LANDLOCK_FIRST_DOMAIN flag are supported, print the newly created domain before launching the sandboxed program. Cc: Günther Noack Cc: Praveen K Paladugu Signed-off-by: Mickaël Salaün Link: https://lore.kernel.org/r/20250131163447.1140564-4-mic@digikod.net --- samples/landlock/sandboxer.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/samples/landlock/sandboxer.c b/samples/landlock/sandboxer.c index 68a5f16bacd5..018bafaa470a 100644 --- a/samples/landlock/sandboxer.c +++ b/samples/landlock/sandboxer.c @@ -15,15 +15,20 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include #include -#include + +/* Avoids conflict with fcntl.h */ +#define _LINUX_FCNTL_H +#include #ifndef landlock_create_ruleset static inline int @@ -53,6 +58,11 @@ static inline int landlock_restrict_self(const int ruleset_fd, } #endif +static inline int sys_pidfd_open(const pid_t pid, const unsigned int flags) +{ + return syscall(__NR_pidfd_open, pid, flags); +} + #define ENV_FS_RO_NAME "LL_FS_RO" #define ENV_FS_RW_NAME "LL_FS_RW" #define ENV_TCP_BIND_NAME "LL_TCP_BIND" @@ -343,7 +353,7 @@ int main(const int argc, char *const argv[], char *const *const envp) { const char *cmd_path; char *const *cmd_argv; - int ruleset_fd, abi; + int ruleset_fd, abi, pidfd; char *env_port_name, *env_force_log; __u64 access_fs_ro = ACCESS_FS_ROUGHLY_READ, access_fs_rw = ACCESS_FS_ROUGHLY_READ | ACCESS_FS_ROUGHLY_WRITE; @@ -510,6 +520,9 @@ int main(const int argc, char *const argv[], char *const *const envp) goto err_close_ruleset; } + /* Opens our own pidfd before sandboxing, if supported. */ + pidfd = sys_pidfd_open(getpid(), 0); + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { perror("Failed to restrict privileges"); goto err_close_ruleset; @@ -520,6 +533,18 @@ int main(const int argc, char *const argv[], char *const *const envp) } close(ruleset_fd); + if (pidfd >= 0) { + struct pidfd_info info = { + .mask = PIDFD_INFO_LANDLOCK_FIRST_DOMAIN, + }; + + if (!ioctl(pidfd, PIDFD_GET_INFO, &info) && + (info.mask & PIDFD_INFO_LANDLOCK_FIRST_DOMAIN)) { + fprintf(stderr, "Entered the Landlock domain %llx.\n", + info.landlock_first_domain); + } + } + cmd_path = argv[1]; cmd_argv = argv + 1; fprintf(stderr, "Executing the sandboxed command...\n");