From patchwork Tue Oct 18 18:22:06 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?G=C3=BCnther_Noack?= X-Patchwork-Id: 13010894 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 75802C433FE for ; Tue, 18 Oct 2022 18:22:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230185AbiJRSWe (ORCPT ); Tue, 18 Oct 2022 14:22:34 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42528 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230071AbiJRSWd (ORCPT ); Tue, 18 Oct 2022 14:22:33 -0400 Received: from mail-ed1-x52b.google.com (mail-ed1-x52b.google.com [IPv6:2a00:1450:4864:20::52b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 979E18262F; Tue, 18 Oct 2022 11:22:31 -0700 (PDT) Received: by mail-ed1-x52b.google.com with SMTP id a13so21816222edj.0; Tue, 18 Oct 2022 11:22:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=lNJPAP+B+nZkQ0xLazBwFAmPNa/89U43FNa6fG8R6oo=; b=cB4Cqi5178EoSpHAXn2/jwjciYonrcV/ENsgaULX1vvs64Yzgi58SLA9wlvOSA1bz4 dL8eoOGjiUeoG7fsIQaltSMPPncsSRsp+DqWkpOOqaqbz2uo18jV2tqwJOZmvN2mZLHV nrARunTn4LO+Om9KucVhPVMekZFSxLZUQZfPPnFJ5ByzIXHBkQa/CItQnY3A0DdggHsS BdWHq0naSu+LmmBBCKwY4EdBXayydlTnv4T29xNIm4GMmxlWzFVe6MzdYH0fKBs4cW46 r9IOtgB173qEzDAkDr0Yt5Rq+j4n1tQGaXgP3EVZQOihKJzI8AbK19oVcaRqZgsF518e LNAQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=lNJPAP+B+nZkQ0xLazBwFAmPNa/89U43FNa6fG8R6oo=; b=lqRGyCKdEjYaHP/wEUc2moExIwkC2BZWTlsWB1/rNL1vOrUaRqyBrquFpVeNlIrW87 GCfrpPxCoKPUH5iPF/u8tIyS88P2b7c5hR4Yp0EST7weMke9qMufiODJeHwD7dWP09m2 Mx9PFYM4xvZXXgCrTwLuuD+9HWP6Z7D98z4cBbkkH7Kd1VI8omZetO5xMCKvMbka5Dup V3tPwRTiT1j8WFrMrDLjPz8P75qzZPaq2YvL3KuljCIIphssr0EaxZE7YUM+lPR9F3/x ui8RrlqOQo/fF6p/aUjFcEGKpqHmm8E+Zb4LBqR09NJ8ADL9IfeCRF+rlxYL30lufQud a1Ng== X-Gm-Message-State: ACrzQf2XWbw/AcdwhZSj4Qs8x3PxcTLmg7DBJxGwormo/c3VniZlu8uD SAyfq6h8traPJU5cR5sTAanRlwmFAwU= X-Google-Smtp-Source: AMsMyM6uairr6FwBJKqyUcP2JdQ4FNIId9VIcjSxdtdXcatIp72A5HwaEGPE0qIcxpy+KgtBkJRVOw== X-Received: by 2002:a05:6402:42cf:b0:457:ae6f:e443 with SMTP id i15-20020a05640242cf00b00457ae6fe443mr3841568edc.299.1666117350194; Tue, 18 Oct 2022 11:22:30 -0700 (PDT) Received: from nuc.i.gnoack.org ([2a02:168:633b:1:1e69:7aff:fe05:97e6]) by smtp.gmail.com with ESMTPSA id i18-20020a0564020f1200b00458a03203b1sm9358395eda.31.2022.10.18.11.22.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 18 Oct 2022 11:22:29 -0700 (PDT) From: =?utf-8?q?G=C3=BCnther_Noack?= To: linux-security-module@vger.kernel.org Cc: =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= , James Morris , Paul Moore , "Serge E . Hallyn" , linux-fsdevel@vger.kernel.org, Konstantin Meskhidze , Nathan Chancellor , =?utf-8?q?G=C3=BCnther_Noack?= , Tetsuo Handa , John Johansen Subject: [PATCH v10 01/11] security: Create file_truncate hook from path_truncate hook Date: Tue, 18 Oct 2022 20:22:06 +0200 Message-Id: <20221018182216.301684-2-gnoack3000@gmail.com> X-Mailer: git-send-email 2.38.0 In-Reply-To: <20221018182216.301684-1-gnoack3000@gmail.com> References: <20221018182216.301684-1-gnoack3000@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: Like path_truncate, the file_truncate hook also restricts file truncation, but is called in the cases where truncation is attempted on an already-opened file. This is required in a subsequent commit to handle ftruncate() operations differently to truncate() operations. Acked-by: Tetsuo Handa Acked-by: John Johansen Acked-by: Paul Moore Signed-off-by: Günther Noack --- fs/namei.c | 2 +- fs/open.c | 2 +- include/linux/lsm_hook_defs.h | 1 + include/linux/lsm_hooks.h | 10 +++++++++- include/linux/security.h | 6 ++++++ security/apparmor/lsm.c | 6 ++++++ security/security.c | 5 +++++ security/tomoyo/tomoyo.c | 13 +++++++++++++ 8 files changed, 42 insertions(+), 3 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index 578c2110df02..85e9b9cc5c38 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -3211,7 +3211,7 @@ static int handle_truncate(struct user_namespace *mnt_userns, struct file *filp) if (error) return error; - error = security_path_truncate(path); + error = security_file_truncate(filp); if (!error) { error = do_truncate(mnt_userns, path->dentry, 0, ATTR_MTIME|ATTR_CTIME|ATTR_OPEN, diff --git a/fs/open.c b/fs/open.c index a81319b6177f..c92f76ab341a 100644 --- a/fs/open.c +++ b/fs/open.c @@ -188,7 +188,7 @@ long do_sys_ftruncate(unsigned int fd, loff_t length, int small) if (IS_APPEND(file_inode(f.file))) goto out_putf; sb_start_write(inode->i_sb); - error = security_path_truncate(&f.file->f_path); + error = security_file_truncate(f.file); if (!error) error = do_truncate(file_mnt_user_ns(f.file), dentry, length, ATTR_MTIME | ATTR_CTIME, f.file); diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h index ec119da1d89b..f67025823d92 100644 --- a/include/linux/lsm_hook_defs.h +++ b/include/linux/lsm_hook_defs.h @@ -177,6 +177,7 @@ LSM_HOOK(int, 0, file_send_sigiotask, struct task_struct *tsk, struct fown_struct *fown, int sig) LSM_HOOK(int, 0, file_receive, struct file *file) LSM_HOOK(int, 0, file_open, struct file *file) +LSM_HOOK(int, 0, file_truncate, struct file *file) LSM_HOOK(int, 0, task_alloc, struct task_struct *task, unsigned long clone_flags) LSM_HOOK(void, LSM_RET_VOID, task_free, struct task_struct *task) diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 4ec80b96c22e..fad93a6d5293 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -409,7 +409,9 @@ * @attr is the iattr structure containing the new file attributes. * Return 0 if permission is granted. * @path_truncate: - * Check permission before truncating a file. + * Check permission before truncating the file indicated by path. + * Note that truncation permissions may also be checked based on + * already opened files, using the @file_truncate hook. * @path contains the path structure for the file. * Return 0 if permission is granted. * @inode_getattr: @@ -598,6 +600,12 @@ * to receive an open file descriptor via socket IPC. * @file contains the file structure being received. * Return 0 if permission is granted. + * @file_truncate: + * Check permission before truncating a file, i.e. using ftruncate. + * Note that truncation permission may also be checked based on the path, + * using the @path_truncate hook. + * @file contains the file structure for the file. + * Return 0 if permission is granted. * @file_open: * Save open-time permission checking state for later use upon * file_permission, and recheck access if anything has changed diff --git a/include/linux/security.h b/include/linux/security.h index ca1b7109c0db..1b5de26bdb12 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -396,6 +396,7 @@ int security_file_send_sigiotask(struct task_struct *tsk, struct fown_struct *fown, int sig); int security_file_receive(struct file *file); int security_file_open(struct file *file); +int security_file_truncate(struct file *file); int security_task_alloc(struct task_struct *task, unsigned long clone_flags); void security_task_free(struct task_struct *task); int security_cred_alloc_blank(struct cred *cred, gfp_t gfp); @@ -1014,6 +1015,11 @@ static inline int security_file_open(struct file *file) return 0; } +static inline int security_file_truncate(struct file *file) +{ + return 0; +} + static inline int security_task_alloc(struct task_struct *task, unsigned long clone_flags) { diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index f56070270c69..be31549cfb40 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -329,6 +329,11 @@ static int apparmor_path_truncate(const struct path *path) return common_perm_cond(OP_TRUNC, path, MAY_WRITE | AA_MAY_SETATTR); } +static int apparmor_file_truncate(struct file *file) +{ + return apparmor_path_truncate(&file->f_path); +} + static int apparmor_path_symlink(const struct path *dir, struct dentry *dentry, const char *old_name) { @@ -1232,6 +1237,7 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(mmap_file, apparmor_mmap_file), LSM_HOOK_INIT(file_mprotect, apparmor_file_mprotect), LSM_HOOK_INIT(file_lock, apparmor_file_lock), + LSM_HOOK_INIT(file_truncate, apparmor_file_truncate), LSM_HOOK_INIT(getprocattr, apparmor_getprocattr), LSM_HOOK_INIT(setprocattr, apparmor_setprocattr), diff --git a/security/security.c b/security/security.c index 79d82cb6e469..b55596958d0c 100644 --- a/security/security.c +++ b/security/security.c @@ -1652,6 +1652,11 @@ int security_file_open(struct file *file) return fsnotify_perm(file, MAY_OPEN); } +int security_file_truncate(struct file *file) +{ + return call_int_hook(file_truncate, 0, file); +} + int security_task_alloc(struct task_struct *task, unsigned long clone_flags) { int rc = lsm_task_alloc(task); diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index 71e82d855ebf..af04a7b7eb28 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -134,6 +134,18 @@ static int tomoyo_path_truncate(const struct path *path) return tomoyo_path_perm(TOMOYO_TYPE_TRUNCATE, path, NULL); } +/** + * tomoyo_file_truncate - Target for security_file_truncate(). + * + * @file: Pointer to "struct file". + * + * Returns 0 on success, negative value otherwise. + */ +static int tomoyo_file_truncate(struct file *file) +{ + return tomoyo_path_truncate(&file->f_path); +} + /** * tomoyo_path_unlink - Target for security_path_unlink(). * @@ -545,6 +557,7 @@ static struct security_hook_list tomoyo_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(bprm_check_security, tomoyo_bprm_check_security), LSM_HOOK_INIT(file_fcntl, tomoyo_file_fcntl), LSM_HOOK_INIT(file_open, tomoyo_file_open), + LSM_HOOK_INIT(file_truncate, tomoyo_file_truncate), LSM_HOOK_INIT(path_truncate, tomoyo_path_truncate), LSM_HOOK_INIT(path_unlink, tomoyo_path_unlink), LSM_HOOK_INIT(path_mkdir, tomoyo_path_mkdir), From patchwork Tue Oct 18 18:22:07 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?G=C3=BCnther_Noack?= X-Patchwork-Id: 13010895 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3A7AFC4321E for ; Tue, 18 Oct 2022 18:22:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230190AbiJRSWf (ORCPT ); Tue, 18 Oct 2022 14:22:35 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42536 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230183AbiJRSWd (ORCPT ); Tue, 18 Oct 2022 14:22:33 -0400 Received: from mail-ed1-x533.google.com (mail-ed1-x533.google.com [IPv6:2a00:1450:4864:20::533]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 79CE18263C; Tue, 18 Oct 2022 11:22:32 -0700 (PDT) Received: by mail-ed1-x533.google.com with SMTP id m15so21728211edb.13; Tue, 18 Oct 2022 11:22:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=4FuCoIWD2t78PwWblywGhp3stRwE/o0mS9jcK6KpYrk=; b=hlksfLCc+twqaCOXME55MLK9avaFTa5AlpKRBTbqc7lKpvGajPI/NgaYTHiWov7jOd dseb1Wgxsx4myWjGAD2ylHdg4xfzcf0S6me0pZ5WU6jYPHetofZEUpjgVwsdjRCsuHvx ioWllCXh/ejODlxSCBl0a/a8++6jQYjx46ozj6ctW1u0LZY8/Q5H7/TCoNzZHym4oYBf uA1JEFuuN3NjFAggAd/10MVONTc0TLwAIv+8pxhgq+eVfgMoe7oe0zg6USOGGf6OkCJV k71zPBqr3vcg7pvOJeV8s2R3rPSLeaQrBrA313m9CVxGvVdZ7K5Abes4+deNBZdGX8pu phZw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=4FuCoIWD2t78PwWblywGhp3stRwE/o0mS9jcK6KpYrk=; b=KAi6rD/6LqTx3ZJ9KZ05epaCYiJ6YLvDtAsCX2cKCWkEjmedpx6m9/WN0X6ftsoiCE cBYp+ySx54FVf+q9jjsUWfSl9ZCqHJba5p9hlP7yXHkb+M7RdCBQp3IEX6QX8xO12F3H wWcCuRC++Iq2zSichs0XWev+JytrPu0yvUSgky4JwE8La+eKAG3NuLYJstVPoyNlXl8v wExV7kLA4Hi0uZUaA5JxvSXS699GcVTInEhGmQW6Lx3up9KXIaTi6SP07ohZQtl3iloo v1nmL1C9Bx/PBQZ0DsfhXCLQ37bN7oNHA45OJ9hb/iuT5WfGROANe4TTdKr6zacGO7x8 dUcw== X-Gm-Message-State: ACrzQf02kBXdAogw/wG1I5dKZdYTJ+Wz1lP1Pl6hnM3Hsdm9MpeUme5Z eoHkkpy0kDw6QjzIs/B/C41Op+erQQw= X-Google-Smtp-Source: AMsMyM5vAxWl3RzsN/dUY7VNMa50dPcKJe+ah01iBbwABq/l/tjAKRbYSMGVqo8bBFvbIYDzlt+0eg== X-Received: by 2002:aa7:dc10:0:b0:440:b446:c0cc with SMTP id b16-20020aa7dc10000000b00440b446c0ccmr3818157edu.34.1666117351009; Tue, 18 Oct 2022 11:22:31 -0700 (PDT) Received: from nuc.i.gnoack.org ([2a02:168:633b:1:1e69:7aff:fe05:97e6]) by smtp.gmail.com with ESMTPSA id i18-20020a0564020f1200b00458a03203b1sm9358395eda.31.2022.10.18.11.22.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 18 Oct 2022 11:22:30 -0700 (PDT) From: =?utf-8?q?G=C3=BCnther_Noack?= To: linux-security-module@vger.kernel.org Cc: =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= , James Morris , Paul Moore , "Serge E . Hallyn" , linux-fsdevel@vger.kernel.org, Konstantin Meskhidze , Nathan Chancellor , =?utf-8?q?G=C3=BCnther_Noack?= Subject: [PATCH v10 02/11] landlock: Refactor check_access_path_dual() into is_access_to_paths_allowed() Date: Tue, 18 Oct 2022 20:22:07 +0200 Message-Id: <20221018182216.301684-3-gnoack3000@gmail.com> X-Mailer: git-send-email 2.38.0 In-Reply-To: <20221018182216.301684-1-gnoack3000@gmail.com> References: <20221018182216.301684-1-gnoack3000@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: Rename check_access_path_dual() to is_access_to_paths_allowed(). Make it return true iff the access is allowed. Calculate the EXDEV/EACCES error code in the one place where it's needed. Suggested-by: Mickaël Salaün Signed-off-by: Günther Noack --- security/landlock/fs.c | 89 +++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 45 deletions(-) diff --git a/security/landlock/fs.c b/security/landlock/fs.c index 64ed7665455f..277868e3c6ce 100644 --- a/security/landlock/fs.c +++ b/security/landlock/fs.c @@ -430,7 +430,7 @@ is_eacces(const layer_mask_t (*const layer_masks)[LANDLOCK_NUM_ACCESS_FS], } /** - * check_access_path_dual - Check accesses for requests with a common path + * is_access_to_paths_allowed - Check accesses for requests with a common path * * @domain: Domain to check against. * @path: File hierarchy to walk through. @@ -465,14 +465,10 @@ is_eacces(const layer_mask_t (*const layer_masks)[LANDLOCK_NUM_ACCESS_FS], * allow the request. * * Returns: - * - 0 if the access request is granted; - * - -EACCES if it is denied because of access right other than - * LANDLOCK_ACCESS_FS_REFER; - * - -EXDEV if the renaming or linking would be a privileged escalation - * (according to each layered policies), or if LANDLOCK_ACCESS_FS_REFER is - * not allowed by the source or the destination. + * - true if the access request is granted; + * - false otherwise. */ -static int check_access_path_dual( +static bool is_access_to_paths_allowed( const struct landlock_ruleset *const domain, const struct path *const path, const access_mask_t access_request_parent1, @@ -492,17 +488,17 @@ static int check_access_path_dual( (*layer_masks_child2)[LANDLOCK_NUM_ACCESS_FS] = NULL; if (!access_request_parent1 && !access_request_parent2) - return 0; + return true; if (WARN_ON_ONCE(!domain || !path)) - return 0; + return true; if (is_nouser_or_private(path->dentry)) - return 0; + return true; if (WARN_ON_ONCE(domain->num_layers < 1 || !layer_masks_parent1)) - return -EACCES; + return false; if (unlikely(layer_masks_parent2)) { if (WARN_ON_ONCE(!dentry_child1)) - return -EACCES; + return false; /* * For a double request, first check for potential privilege * escalation by looking at domain handled accesses (which are @@ -513,7 +509,7 @@ static int check_access_path_dual( is_dom_check = true; } else { if (WARN_ON_ONCE(dentry_child1 || dentry_child2)) - return -EACCES; + return false; /* For a simple request, only check for requested accesses. */ access_masked_parent1 = access_request_parent1; access_masked_parent2 = access_request_parent2; @@ -622,24 +618,7 @@ static int check_access_path_dual( } path_put(&walker_path); - if (allowed_parent1 && allowed_parent2) - return 0; - - /* - * This prioritizes EACCES over EXDEV for all actions, including - * renames with RENAME_EXCHANGE. - */ - if (likely(is_eacces(layer_masks_parent1, access_request_parent1) || - is_eacces(layer_masks_parent2, access_request_parent2))) - return -EACCES; - - /* - * Gracefully forbids reparenting if the destination directory - * hierarchy is not a superset of restrictions of the source directory - * hierarchy, or if LANDLOCK_ACCESS_FS_REFER is not allowed by the - * source or the destination. - */ - return -EXDEV; + return allowed_parent1 && allowed_parent2; } static inline int check_access_path(const struct landlock_ruleset *const domain, @@ -649,8 +628,10 @@ static inline int check_access_path(const struct landlock_ruleset *const domain, layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = {}; access_request = init_layer_masks(domain, access_request, &layer_masks); - return check_access_path_dual(domain, path, access_request, - &layer_masks, NULL, 0, NULL, NULL); + if (is_access_to_paths_allowed(domain, path, access_request, + &layer_masks, NULL, 0, NULL, NULL)) + return 0; + return -EACCES; } static inline int current_check_access_path(const struct path *const path, @@ -711,8 +692,9 @@ static inline access_mask_t maybe_remove(const struct dentry *const dentry) * file. While walking from @dir to @mnt_root, we record all the domain's * allowed accesses in @layer_masks_dom. * - * This is similar to check_access_path_dual() but much simpler because it only - * handles walking on the same mount point and only checks one set of accesses. + * This is similar to is_access_to_paths_allowed() but much simpler because it + * only handles walking on the same mount point and only checks one set of + * accesses. * * Returns: * - true if all the domain access rights are allowed for @dir; @@ -857,10 +839,11 @@ static int current_check_refer_path(struct dentry *const old_dentry, access_request_parent1 = init_layer_masks( dom, access_request_parent1 | access_request_parent2, &layer_masks_parent1); - return check_access_path_dual(dom, new_dir, - access_request_parent1, - &layer_masks_parent1, NULL, 0, - NULL, NULL); + if (is_access_to_paths_allowed( + dom, new_dir, access_request_parent1, + &layer_masks_parent1, NULL, 0, NULL, NULL)) + return 0; + return -EACCES; } access_request_parent1 |= LANDLOCK_ACCESS_FS_REFER; @@ -886,11 +869,27 @@ static int current_check_refer_path(struct dentry *const old_dentry, * parent access rights. This will be useful to compare with the * destination parent access rights. */ - return check_access_path_dual(dom, &mnt_dir, access_request_parent1, - &layer_masks_parent1, old_dentry, - access_request_parent2, - &layer_masks_parent2, - exchange ? new_dentry : NULL); + if (is_access_to_paths_allowed( + dom, &mnt_dir, access_request_parent1, &layer_masks_parent1, + old_dentry, access_request_parent2, &layer_masks_parent2, + exchange ? new_dentry : NULL)) + return 0; + + /* + * This prioritizes EACCES over EXDEV for all actions, including + * renames with RENAME_EXCHANGE. + */ + if (likely(is_eacces(&layer_masks_parent1, access_request_parent1) || + is_eacces(&layer_masks_parent2, access_request_parent2))) + return -EACCES; + + /* + * Gracefully forbids reparenting if the destination directory + * hierarchy is not a superset of restrictions of the source directory + * hierarchy, or if LANDLOCK_ACCESS_FS_REFER is not allowed by the + * source or the destination. + */ + return -EXDEV; } /* Inode hooks */ From patchwork Tue Oct 18 18:22:08 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?G=C3=BCnther_Noack?= X-Patchwork-Id: 13010896 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id CD8BAC4332F for ; Tue, 18 Oct 2022 18:22:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229763AbiJRSWg (ORCPT ); Tue, 18 Oct 2022 14:22:36 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42544 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230186AbiJRSWe (ORCPT ); Tue, 18 Oct 2022 14:22:34 -0400 Received: from mail-ej1-x633.google.com (mail-ej1-x633.google.com [IPv6:2a00:1450:4864:20::633]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3093A537E3; Tue, 18 Oct 2022 11:22:33 -0700 (PDT) Received: by mail-ej1-x633.google.com with SMTP id 13so34278987ejn.3; Tue, 18 Oct 2022 11:22:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=LUBbOEFW53KqYnQJv0OgmvKNjQw4g+0MWXRaawv7+iQ=; b=nRpoRKZTK3LZz+cVRmefY9fdWuEY96VtZbCp3J9uXVdMtZk4tPgGaHL3Of5fthLpyV QldgMdRzgnzPaOL5BW8krhREVCVvaEbLWC13sQ+VLWMTf9H5+fSnpi6AFrbthq64NEPp Pvp/1xFy00hJPmKlo9+1dB1h2SNrBuUTom05zoevqp66PsvPls85cbCYySAmN06bTukZ AYpOfEjQY4Gq1g91O82SeAY5CbpTX6L44OrNl5VQ4q3SNt4INljse5V59/pAtB0gVSQc Im+OMo4CPH1y6Si6m8OsGgyqtaFMnZe2IUEIAi27IUf1AxAwB/Gzhcp2yvq9Lfuw3i5k GQmw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=LUBbOEFW53KqYnQJv0OgmvKNjQw4g+0MWXRaawv7+iQ=; b=yfky876OeyduWGXAaqMxXQzAR5WdEwLe/6vic/w1o6AVn4dOpCPh7aDrdkLE8iHC9j dqR5ogj42kEJM/GTNjCVibaxoLB0lBqboGDzAv5SYyPIM4uhRoogyVaBr6CaF7SzOq/k bXQMT7hpD5nqxOJeqokIDicfie22Gv/LKbvHaRDkZjCHnZTBc0DsdxMPMu4ZqT/MrUxS nQ1uXwKOM9+A5V2qYu5qA/HsWFiGWIAlNDgKCV/aQ/W01jX4cvbDud1H5ULVnLz8tacE cboGhjcVF+KGbpofCPohVTXN8aznju3d3eVbn2JQtbHLFo2RNXwgzhJ80yOElAsNaH0e oSKA== X-Gm-Message-State: ACrzQf1gk2ub0FeLUGsYMBEKjvpuAlVbo39ehEFXD3CyzSDZoxpfUabX rt4zI8ONvT24Ny36mdurkx7p1S1sD6k= X-Google-Smtp-Source: AMsMyM5GRSw2mW8kjwpc/pAo80lfYu2N8YUdTSW7HbqIHHuLGpjyZdXq7Xoal154wZPPhyO4ULO+zw== X-Received: by 2002:a17:906:7055:b0:78b:9148:6b41 with SMTP id r21-20020a170906705500b0078b91486b41mr3446006ejj.629.1666117351774; Tue, 18 Oct 2022 11:22:31 -0700 (PDT) Received: from nuc.i.gnoack.org ([2a02:168:633b:1:1e69:7aff:fe05:97e6]) by smtp.gmail.com with ESMTPSA id i18-20020a0564020f1200b00458a03203b1sm9358395eda.31.2022.10.18.11.22.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 18 Oct 2022 11:22:31 -0700 (PDT) From: =?utf-8?q?G=C3=BCnther_Noack?= To: linux-security-module@vger.kernel.org Cc: =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= , James Morris , Paul Moore , "Serge E . Hallyn" , linux-fsdevel@vger.kernel.org, Konstantin Meskhidze , Nathan Chancellor , =?utf-8?q?G=C3=BCnther_Noack?= Subject: [PATCH v10 03/11] landlock: Document init_layer_masks() helper Date: Tue, 18 Oct 2022 20:22:08 +0200 Message-Id: <20221018182216.301684-4-gnoack3000@gmail.com> X-Mailer: git-send-email 2.38.0 In-Reply-To: <20221018182216.301684-1-gnoack3000@gmail.com> References: <20221018182216.301684-1-gnoack3000@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: Add kernel-doc to the init_layer_masks() function. Signed-off-by: Günther Noack --- security/landlock/fs.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/security/landlock/fs.c b/security/landlock/fs.c index 277868e3c6ce..87fde50eb550 100644 --- a/security/landlock/fs.c +++ b/security/landlock/fs.c @@ -297,6 +297,19 @@ get_handled_accesses(const struct landlock_ruleset *const domain) return access_dom & LANDLOCK_MASK_ACCESS_FS; } +/** + * init_layer_masks - Initialize layer masks from an access request + * + * Populates @layer_masks such that for each access right in @access_request, + * the bits for all the layers are set where this access right is handled. + * + * @domain: The domain that defines the current restrictions. + * @access_request: The requested access rights to check. + * @layer_masks: The layer masks to populate. + * + * Returns: An access mask where each access right bit is set which is handled + * in any of the active layers in @domain. + */ static inline access_mask_t init_layer_masks(const struct landlock_ruleset *const domain, const access_mask_t access_request, From patchwork Tue Oct 18 18:22:09 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?G=C3=BCnther_Noack?= X-Patchwork-Id: 13010899 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id DB05AC43217 for ; Tue, 18 Oct 2022 18:23:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230230AbiJRSXJ (ORCPT ); Tue, 18 Oct 2022 14:23:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42608 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230199AbiJRSWh (ORCPT ); Tue, 18 Oct 2022 14:22:37 -0400 Received: from mail-ed1-x52c.google.com (mail-ed1-x52c.google.com [IPv6:2a00:1450:4864:20::52c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 610DC8263C; Tue, 18 Oct 2022 11:22:34 -0700 (PDT) Received: by mail-ed1-x52c.google.com with SMTP id s30so21778800eds.1; Tue, 18 Oct 2022 11:22:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Nxrb/R+LIlvDBRxezargrUidMjxxYVQiRlTvZstHXqI=; b=KT2lgZ7Pfg5gYwfhLrdDwEima5OcwqxFvBggyNUcYCaAXsi50/cVFzhbnS84HJilPH Qle2Tl1lKEou3FBuzI2enMEXP9Wi0Tzh7yiBQzRqAbIkDPsfvjokpyGrCMufnzRhC3e6 9g+VkViWf7otsjxRbGjNq5dfkuVdnhKH5MLgWB1HJlwHzcNNwdgEm+EOBzAOWMm1vtRS HXuaRnwmykOeSNjqBkl8qoZ6IrXANOg92f0xNQ8tVT4+TbMr/Rtt+CwxIzLN4ZaV04gN j2z1fjLKmaLSJ6Fn4XoerGQ+E29TLzBaHZoGImB+vNc2XPWfAu0Dgy9JZe79RyxpxCZd xp2A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Nxrb/R+LIlvDBRxezargrUidMjxxYVQiRlTvZstHXqI=; b=iSZ/md6cDL9RoGoH6sMVXh5/PLul2WU6KlVuJldq0ycWCSRjSn5TjaxNpiSZKa0HEa /xWWHRc/k8vyrHiZ4J6040gmSq7fovbJFYonhHTuH0cU5Z+uo+N7ndxIKeQ2+uDzs29r CG44PJ5bDoZBzHZbAhxJZab0Mm3jCgE0tSfo40rBPPpoxzRsv4YuXlck+cvA1r/bPGSp o+h5v+DoTv274iepc/Vyb3teoEtdQLZpjd1LZq/rGEdOQSePzABma2V+Zp43/Av2Pna8 y+bNtuxZBMmVan5BOxNSPHqCUoT9aHfB5alwzSbFO7JlAZcdTDqYFYEMzAk4/K5QqaDD MLww== X-Gm-Message-State: ACrzQf0F8EcZj3rzr3LgptfsUyUYLGSPQMiXde/lPzSfq5PBOamGY8YX N6OvxLY4fLzT+LQO8qPcHX/TvVE8RPg= X-Google-Smtp-Source: AMsMyM5cC5wFQRLQmMwzJH9K/WjTZ+lU22Gkeiv7xRBivDYrHCeb04Hki43trLxzLocmGlpjw/l5wA== X-Received: by 2002:a05:6402:3584:b0:45d:8fd7:f798 with SMTP id y4-20020a056402358400b0045d8fd7f798mr3790288edc.356.1666117352524; Tue, 18 Oct 2022 11:22:32 -0700 (PDT) Received: from nuc.i.gnoack.org ([2a02:168:633b:1:1e69:7aff:fe05:97e6]) by smtp.gmail.com with ESMTPSA id i18-20020a0564020f1200b00458a03203b1sm9358395eda.31.2022.10.18.11.22.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 18 Oct 2022 11:22:32 -0700 (PDT) From: =?utf-8?q?G=C3=BCnther_Noack?= To: linux-security-module@vger.kernel.org Cc: =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= , James Morris , Paul Moore , "Serge E . Hallyn" , linux-fsdevel@vger.kernel.org, Konstantin Meskhidze , Nathan Chancellor , =?utf-8?q?G=C3=BCnther_Noack?= Subject: [PATCH v10 04/11] landlock: Support file truncation Date: Tue, 18 Oct 2022 20:22:09 +0200 Message-Id: <20221018182216.301684-5-gnoack3000@gmail.com> X-Mailer: git-send-email 2.38.0 In-Reply-To: <20221018182216.301684-1-gnoack3000@gmail.com> References: <20221018182216.301684-1-gnoack3000@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: Introduce the LANDLOCK_ACCESS_FS_TRUNCATE flag for file truncation. This flag hooks into the path_truncate, file_truncate and file_alloc_security LSM hooks and covers file truncation using truncate(2), ftruncate(2), open(2) with O_TRUNC, as well as creat(). This change also increments the Landlock ABI version, updates corresponding selftests, and updates code documentation to document the flag. In security/security.c, allocate security blobs at pointer-aligned offsets. This fixes the problem where one LSM's security blob can shift another LSM's security blob to an unaligned address. (Reported by Nathan Chancellor) The following operations are restricted: open(2): requires the LANDLOCK_ACCESS_FS_TRUNCATE right if a file gets implicitly truncated as part of the open() (e.g. using O_TRUNC). Notable special cases: * open(..., O_RDONLY|O_TRUNC) can truncate files as well in Linux * open() with O_TRUNC does *not* need the TRUNCATE right when it creates a new file. truncate(2) (on a path): requires the LANDLOCK_ACCESS_FS_TRUNCATE right. ftruncate(2) (on a file): requires that the file had the TRUNCATE right when it was previously opened. File descriptors acquired by other means than open(2) (e.g. memfd_create(2)) continue to support truncation with ftruncate(2). Reported-by: Nathan Chancellor Signed-off-by: Günther Noack Acked-by: Paul Moore (LSM) --- include/uapi/linux/landlock.h | 21 +++- security/landlock/fs.c | 104 ++++++++++++++++++- security/landlock/fs.h | 24 +++++ security/landlock/limits.h | 2 +- security/landlock/setup.c | 1 + security/landlock/syscalls.c | 2 +- security/security.c | 11 +- tools/testing/selftests/landlock/base_test.c | 2 +- tools/testing/selftests/landlock/fs_test.c | 7 +- 9 files changed, 153 insertions(+), 21 deletions(-) diff --git a/include/uapi/linux/landlock.h b/include/uapi/linux/landlock.h index 9c4bcc37a455..f3223f964691 100644 --- a/include/uapi/linux/landlock.h +++ b/include/uapi/linux/landlock.h @@ -95,8 +95,19 @@ struct landlock_path_beneath_attr { * A file can only receive these access rights: * * - %LANDLOCK_ACCESS_FS_EXECUTE: Execute a file. - * - %LANDLOCK_ACCESS_FS_WRITE_FILE: Open a file with write access. + * - %LANDLOCK_ACCESS_FS_WRITE_FILE: Open a file with write access. Note that + * you might additionally need the %LANDLOCK_ACCESS_FS_TRUNCATE right in order + * to overwrite files with :manpage:`open(2)` using ``O_TRUNC`` or + * :manpage:`creat(2)`. * - %LANDLOCK_ACCESS_FS_READ_FILE: Open a file with read access. + * - %LANDLOCK_ACCESS_FS_TRUNCATE: Truncate a file with :manpage:`truncate(2)`, + * :manpage:`ftruncate(2)`, :manpage:`creat(2)`, or :manpage:`open(2)` with + * ``O_TRUNC``. Whether an opened file can be truncated with + * :manpage:`ftruncate(2)` is determined during :manpage:`open(2)`, in the + * same way as read and write permissions are checked during + * :manpage:`open(2)` using %LANDLOCK_ACCESS_FS_READ_FILE and + * %LANDLOCK_ACCESS_FS_WRITE_FILE. This access right is available since the + * third version of the Landlock ABI. * * A directory can receive access rights related to files or directories. The * following access right is applied to the directory itself, and the @@ -139,10 +150,9 @@ struct landlock_path_beneath_attr { * * It is currently not possible to restrict some file-related actions * accessible through these syscall families: :manpage:`chdir(2)`, - * :manpage:`truncate(2)`, :manpage:`stat(2)`, :manpage:`flock(2)`, - * :manpage:`chmod(2)`, :manpage:`chown(2)`, :manpage:`setxattr(2)`, - * :manpage:`utime(2)`, :manpage:`ioctl(2)`, :manpage:`fcntl(2)`, - * :manpage:`access(2)`. + * :manpage:`stat(2)`, :manpage:`flock(2)`, :manpage:`chmod(2)`, + * :manpage:`chown(2)`, :manpage:`setxattr(2)`, :manpage:`utime(2)`, + * :manpage:`ioctl(2)`, :manpage:`fcntl(2)`, :manpage:`access(2)`. * Future Landlock evolutions will enable to restrict them. */ /* clang-format off */ @@ -160,6 +170,7 @@ struct landlock_path_beneath_attr { #define LANDLOCK_ACCESS_FS_MAKE_BLOCK (1ULL << 11) #define LANDLOCK_ACCESS_FS_MAKE_SYM (1ULL << 12) #define LANDLOCK_ACCESS_FS_REFER (1ULL << 13) +#define LANDLOCK_ACCESS_FS_TRUNCATE (1ULL << 14) /* clang-format on */ #endif /* _UAPI_LINUX_LANDLOCK_H */ diff --git a/security/landlock/fs.c b/security/landlock/fs.c index 87fde50eb550..adcea0fe7e68 100644 --- a/security/landlock/fs.c +++ b/security/landlock/fs.c @@ -146,7 +146,8 @@ static struct landlock_object *get_inode_object(struct inode *const inode) #define ACCESS_FILE ( \ LANDLOCK_ACCESS_FS_EXECUTE | \ LANDLOCK_ACCESS_FS_WRITE_FILE | \ - LANDLOCK_ACCESS_FS_READ_FILE) + LANDLOCK_ACCESS_FS_READ_FILE | \ + LANDLOCK_ACCESS_FS_TRUNCATE) /* clang-format on */ /* @@ -1154,9 +1155,23 @@ static int hook_path_rmdir(const struct path *const dir, return current_check_access_path(dir, LANDLOCK_ACCESS_FS_REMOVE_DIR); } +static int hook_path_truncate(const struct path *const path) +{ + return current_check_access_path(path, LANDLOCK_ACCESS_FS_TRUNCATE); +} + /* File hooks */ -static inline access_mask_t get_file_access(const struct file *const file) +/** + * get_required_file_open_access - Get access needed to open a file + * + * @file: File being opened. + * + * Returns the access rights that are required for opening the given file, + * depending on the file type and open mode. + */ +static inline access_mask_t +get_required_file_open_access(const struct file *const file) { access_mask_t access = 0; @@ -1174,19 +1189,95 @@ static inline access_mask_t get_file_access(const struct file *const file) return access; } +static int hook_file_alloc_security(struct file *const file) +{ + /* + * Grants all access rights, even if most of them are not checked later + * on. It is more consistent. + * + * Notably, file descriptors for regular files can also be acquired + * without going through the file_open hook, for example when using + * memfd_create(2). + */ + landlock_file(file)->allowed_access = LANDLOCK_MASK_ACCESS_FS; + return 0; +} + static int hook_file_open(struct file *const file) { + layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = {}; + access_mask_t open_access_request, full_access_request, allowed_access; + const access_mask_t optional_access = LANDLOCK_ACCESS_FS_TRUNCATE; const struct landlock_ruleset *const dom = landlock_get_current_domain(); if (!dom) return 0; + /* - * Because a file may be opened with O_PATH, get_file_access() may - * return 0. This case will be handled with a future Landlock + * Because a file may be opened with O_PATH, get_required_file_open_access() + * may return 0. This case will be handled with a future Landlock * evolution. */ - return check_access_path(dom, &file->f_path, get_file_access(file)); + open_access_request = get_required_file_open_access(file); + + /* + * We look up more access than what we immediately need for open(), so + * that we can later authorize operations on opened files. + */ + full_access_request = open_access_request | optional_access; + + if (is_access_to_paths_allowed( + dom, &file->f_path, + init_layer_masks(dom, full_access_request, &layer_masks), + &layer_masks, NULL, 0, NULL, NULL)) { + allowed_access = full_access_request; + } else { + unsigned long access_bit; + const unsigned long access_req = full_access_request; + + /* + * Calculate the actual allowed access rights from layer_masks. + * Add each access right to allowed_access which has not been + * vetoed by any layer. + */ + allowed_access = 0; + for_each_set_bit(access_bit, &access_req, + ARRAY_SIZE(layer_masks)) { + if (!layer_masks[access_bit]) + allowed_access |= BIT_ULL(access_bit); + } + } + + /* + * For operations on already opened files (i.e. ftruncate()), it is the + * access rights at the time of open() which decide whether the + * operation is permitted. Therefore, we record the relevant subset of + * file access rights in the opened struct file. + */ + landlock_file(file)->allowed_access = allowed_access; + + if ((open_access_request & allowed_access) == open_access_request) + return 0; + + return -EACCES; +} + +static int hook_file_truncate(struct file *const file) +{ + /* + * Allows truncation if the truncate right was available at the time of + * opening the file, to get a consistent access check as for read, write + * and execute operations. + * + * Note: For checks done based on the file's Landlock allowed access, we + * enforce them independently of whether the current thread is in a + * Landlock domain, so that open files passed between independent + * processes retain their behaviour. + */ + if (landlock_file(file)->allowed_access & LANDLOCK_ACCESS_FS_TRUNCATE) + return 0; + return -EACCES; } static struct security_hook_list landlock_hooks[] __lsm_ro_after_init = { @@ -1206,8 +1297,11 @@ static struct security_hook_list landlock_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(path_symlink, hook_path_symlink), LSM_HOOK_INIT(path_unlink, hook_path_unlink), LSM_HOOK_INIT(path_rmdir, hook_path_rmdir), + LSM_HOOK_INIT(path_truncate, hook_path_truncate), + LSM_HOOK_INIT(file_alloc_security, hook_file_alloc_security), LSM_HOOK_INIT(file_open, hook_file_open), + LSM_HOOK_INIT(file_truncate, hook_file_truncate), }; __init void landlock_add_fs_hooks(void) diff --git a/security/landlock/fs.h b/security/landlock/fs.h index 8db7acf9109b..488e4813680a 100644 --- a/security/landlock/fs.h +++ b/security/landlock/fs.h @@ -36,6 +36,24 @@ struct landlock_inode_security { struct landlock_object __rcu *object; }; +/** + * struct landlock_file_security - File security blob + * + * This information is populated when opening a file in hook_file_open, and + * tracks the relevant Landlock access rights that were available at the time + * of opening the file. Other LSM hooks use these rights in order to authorize + * operations on already opened files. + */ +struct landlock_file_security { + /** + * @allowed_access: Access rights that were available at the time of + * opening the file. This is not necessarily the full set of access + * rights available at that time, but it's the necessary subset as + * needed to authorize later operations on the open file. + */ + access_mask_t allowed_access; +}; + /** * struct landlock_superblock_security - Superblock security blob * @@ -50,6 +68,12 @@ struct landlock_superblock_security { atomic_long_t inode_refs; }; +static inline struct landlock_file_security * +landlock_file(const struct file *const file) +{ + return file->f_security + landlock_blob_sizes.lbs_file; +} + static inline struct landlock_inode_security * landlock_inode(const struct inode *const inode) { diff --git a/security/landlock/limits.h b/security/landlock/limits.h index b54184ab9439..82288f0e9e5e 100644 --- a/security/landlock/limits.h +++ b/security/landlock/limits.h @@ -18,7 +18,7 @@ #define LANDLOCK_MAX_NUM_LAYERS 16 #define LANDLOCK_MAX_NUM_RULES U32_MAX -#define LANDLOCK_LAST_ACCESS_FS LANDLOCK_ACCESS_FS_REFER +#define LANDLOCK_LAST_ACCESS_FS LANDLOCK_ACCESS_FS_TRUNCATE #define LANDLOCK_MASK_ACCESS_FS ((LANDLOCK_LAST_ACCESS_FS << 1) - 1) #define LANDLOCK_NUM_ACCESS_FS __const_hweight64(LANDLOCK_MASK_ACCESS_FS) diff --git a/security/landlock/setup.c b/security/landlock/setup.c index f8e8e980454c..3f196d2ce4f9 100644 --- a/security/landlock/setup.c +++ b/security/landlock/setup.c @@ -19,6 +19,7 @@ bool landlock_initialized __lsm_ro_after_init = false; struct lsm_blob_sizes landlock_blob_sizes __lsm_ro_after_init = { .lbs_cred = sizeof(struct landlock_cred_security), + .lbs_file = sizeof(struct landlock_file_security), .lbs_inode = sizeof(struct landlock_inode_security), .lbs_superblock = sizeof(struct landlock_superblock_security), }; diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c index 2ca0ccbd905a..245cc650a4dc 100644 --- a/security/landlock/syscalls.c +++ b/security/landlock/syscalls.c @@ -129,7 +129,7 @@ static const struct file_operations ruleset_fops = { .write = fop_dummy_write, }; -#define LANDLOCK_ABI_VERSION 2 +#define LANDLOCK_ABI_VERSION 3 /** * sys_landlock_create_ruleset - Create a new ruleset diff --git a/security/security.c b/security/security.c index b55596958d0c..e0fe4ba39eb9 100644 --- a/security/security.c +++ b/security/security.c @@ -185,11 +185,12 @@ static void __init lsm_set_blob_size(int *need, int *lbs) { int offset; - if (*need > 0) { - offset = *lbs; - *lbs += *need; - *need = offset; - } + if (*need <= 0) + return; + + offset = ALIGN(*lbs, sizeof(void *)); + *lbs = offset + *need; + *need = offset; } static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed) diff --git a/tools/testing/selftests/landlock/base_test.c b/tools/testing/selftests/landlock/base_test.c index da9290817866..72cdae277b02 100644 --- a/tools/testing/selftests/landlock/base_test.c +++ b/tools/testing/selftests/landlock/base_test.c @@ -75,7 +75,7 @@ TEST(abi_version) const struct landlock_ruleset_attr ruleset_attr = { .handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE, }; - ASSERT_EQ(2, landlock_create_ruleset(NULL, 0, + ASSERT_EQ(3, landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION)); ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0, diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c index 45de42a027c5..87b28d14a1aa 100644 --- a/tools/testing/selftests/landlock/fs_test.c +++ b/tools/testing/selftests/landlock/fs_test.c @@ -406,9 +406,10 @@ TEST_F_FORK(layout1, inval) #define ACCESS_FILE ( \ LANDLOCK_ACCESS_FS_EXECUTE | \ LANDLOCK_ACCESS_FS_WRITE_FILE | \ - LANDLOCK_ACCESS_FS_READ_FILE) + LANDLOCK_ACCESS_FS_READ_FILE | \ + LANDLOCK_ACCESS_FS_TRUNCATE) -#define ACCESS_LAST LANDLOCK_ACCESS_FS_REFER +#define ACCESS_LAST LANDLOCK_ACCESS_FS_TRUNCATE #define ACCESS_ALL ( \ ACCESS_FILE | \ @@ -422,7 +423,7 @@ TEST_F_FORK(layout1, inval) LANDLOCK_ACCESS_FS_MAKE_FIFO | \ LANDLOCK_ACCESS_FS_MAKE_BLOCK | \ LANDLOCK_ACCESS_FS_MAKE_SYM | \ - ACCESS_LAST) + LANDLOCK_ACCESS_FS_REFER) /* clang-format on */ From patchwork Tue Oct 18 18:22:10 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?G=C3=BCnther_Noack?= X-Patchwork-Id: 13010897 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1BB5CC433FE for ; Tue, 18 Oct 2022 18:23:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230217AbiJRSXI (ORCPT ); Tue, 18 Oct 2022 14:23:08 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42604 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230196AbiJRSWh (ORCPT ); Tue, 18 Oct 2022 14:22:37 -0400 Received: from mail-ej1-x62e.google.com (mail-ej1-x62e.google.com [IPv6:2a00:1450:4864:20::62e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F382082875; Tue, 18 Oct 2022 11:22:34 -0700 (PDT) Received: by mail-ej1-x62e.google.com with SMTP id q9so34419978ejd.0; Tue, 18 Oct 2022 11:22:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=s+g3SXvO/8Bh7JPwh3SfT/06Lg3wGAqn3lvO15O0qAY=; b=h3BoIVSooh/6H3hxpPkhm+S8q4mflY3iIlShSWY7TsOUSheX4MTlhFvAwC8NDcENkd BhftMg4FdWP+xbZApdMzMOeIXKvTv350tqoOUy9qEkRBdg/GwXOlmoIKHnVySIWY54br Hf2+Mb0s2ImicToSUXi+t88pFs7vcaRnA2ERMtTiUEwb9H43/1LRWHT8N6n21wABnLyT 49JWQsHTlVJ+QsluBSZCzw06FBM1A0ssDi0VwHB1fPPUh0v2fbERwYsjOgwyRdFpmn5N Qm3PBpHYzLG+7WmG1hT0nZKQVk+I62yxI3tjY+iiYMnK/PtY+1NpDpESH2UVlqXZ1bto Fe1A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=s+g3SXvO/8Bh7JPwh3SfT/06Lg3wGAqn3lvO15O0qAY=; b=lBWe+yM5e1yRkFkcr9p+8Z7chOG8ZhOEMmbYY/cs3l84K5wH0XlvR156QO7D0JpxAc fYH6RZmpG7MErKPm0rgdqoaf8m4xMMB0Bz+Aqs7sHjDyWlHDSC67YQRrWjZG6J5IDfN3 EBPUmW14RYTpJjD+PTXfXfooLFPyCiqV58qIN90EAI30/j8gfOSkocDX3TEU6ur+Wiev wkD7mfa9hCRl6APhFgjczNJEDyIRwO0MZ7SlrYwzRYpoZ5bWw/0EKB+liRZErkHmQzxv yivnjL8ISaeGV4fY7rSYK5yg8uQbfev0801Z6kzxVYGoA0B6/hhCfzfaSv9rezYlfUiO 3RwA== X-Gm-Message-State: ACrzQf1hjvb4bVjAvFtUWTy41dKsTrcejjXidb7LAz7VVNaUT5OzO6xB lhwyCRWkdog1BygPUodO+Z084Awh4GI= X-Google-Smtp-Source: AMsMyM6Ogqf9uPcBncGnMZBYBgQgy++RIIly8fUUogv/VQyE8i3Z05mzNjNItOOJqCTQ6DGxvKzkuA== X-Received: by 2002:a17:906:58c9:b0:78d:b042:eecc with SMTP id e9-20020a17090658c900b0078db042eeccmr3577773ejs.658.1666117353352; Tue, 18 Oct 2022 11:22:33 -0700 (PDT) Received: from nuc.i.gnoack.org ([2a02:168:633b:1:1e69:7aff:fe05:97e6]) by smtp.gmail.com with ESMTPSA id i18-20020a0564020f1200b00458a03203b1sm9358395eda.31.2022.10.18.11.22.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 18 Oct 2022 11:22:33 -0700 (PDT) From: =?utf-8?q?G=C3=BCnther_Noack?= To: linux-security-module@vger.kernel.org Cc: =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= , James Morris , Paul Moore , "Serge E . Hallyn" , linux-fsdevel@vger.kernel.org, Konstantin Meskhidze , Nathan Chancellor , =?utf-8?q?G=C3=BCnther_Noack?= Subject: [PATCH v10 05/11] selftests/landlock: Test file truncation support Date: Tue, 18 Oct 2022 20:22:10 +0200 Message-Id: <20221018182216.301684-6-gnoack3000@gmail.com> X-Mailer: git-send-email 2.38.0 In-Reply-To: <20221018182216.301684-1-gnoack3000@gmail.com> References: <20221018182216.301684-1-gnoack3000@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: These tests exercise the following truncation operations: * truncate() (truncate by path) * ftruncate() (truncate by file descriptor) * open with the O_TRUNC flag * special case: creat(), which is open with O_CREAT|O_WRONLY|O_TRUNC. in the following scenarios: * Files with read, write and truncate rights. * Files with read and truncate rights. * Files with the truncate right. * Files without the truncate right. In particular, the following scenarios are enforced with the test: * open() with O_TRUNC requires the truncate right, if it truncates a file. open() already checks security_path_truncate() in this case, and it required no additional check in the Landlock LSM's file_open hook. * creat() requires the truncate right when called with an existing filename. * creat() does *not* require the truncate right when it's creating a new file. * ftruncate() requires that the file was opened by a thread that had the truncate right for the file at the time of open(). (The rights are carried along with the opened file.) Signed-off-by: Günther Noack --- tools/testing/selftests/landlock/fs_test.c | 287 +++++++++++++++++++++ 1 file changed, 287 insertions(+) diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c index 87b28d14a1aa..718543fd3dfc 100644 --- a/tools/testing/selftests/landlock/fs_test.c +++ b/tools/testing/selftests/landlock/fs_test.c @@ -58,6 +58,7 @@ static const char file1_s2d3[] = TMP_DIR "/s2d1/s2d2/s2d3/f1"; static const char file2_s2d3[] = TMP_DIR "/s2d1/s2d2/s2d3/f2"; static const char dir_s3d1[] = TMP_DIR "/s3d1"; +static const char file1_s3d1[] = TMP_DIR "/s3d1/f1"; /* dir_s3d2 is a mount point. */ static const char dir_s3d2[] = TMP_DIR "/s3d1/s3d2"; static const char dir_s3d3[] = TMP_DIR "/s3d1/s3d2/s3d3"; @@ -83,6 +84,7 @@ static const char dir_s3d3[] = TMP_DIR "/s3d1/s3d2/s3d3"; * │   ├── f1 * │   └── f2 * └── s3d1 + *    ├── f1 * └── s3d2 * └── s3d3 */ @@ -208,6 +210,7 @@ static void create_layout1(struct __test_metadata *const _metadata) create_file(_metadata, file1_s2d3); create_file(_metadata, file2_s2d3); + create_file(_metadata, file1_s3d1); create_directory(_metadata, dir_s3d2); set_cap(_metadata, CAP_SYS_ADMIN); ASSERT_EQ(0, mount("tmp", dir_s3d2, "tmpfs", 0, "size=4m,mode=700")); @@ -230,6 +233,7 @@ static void remove_layout1(struct __test_metadata *const _metadata) EXPECT_EQ(0, remove_path(file1_s2d2)); EXPECT_EQ(0, remove_path(file1_s2d1)); + EXPECT_EQ(0, remove_path(file1_s3d1)); EXPECT_EQ(0, remove_path(dir_s3d3)); set_cap(_metadata, CAP_SYS_ADMIN); umount(dir_s3d2); @@ -3158,6 +3162,289 @@ TEST_F_FORK(layout1, proc_pipe) ASSERT_EQ(0, close(pipe_fds[1])); } +/* Invokes truncate(2) and returns its errno or 0. */ +static int test_truncate(const char *const path) +{ + if (truncate(path, 10) < 0) + return errno; + return 0; +} + +/* + * Invokes creat(2) and returns its errno or 0. + * Closes the opened file descriptor on success. + */ +static int test_creat(const char *const path) +{ + int fd = creat(path, 0600); + + if (fd < 0) + return errno; + + /* + * Mixing error codes from close(2) and creat(2) should not lead to any + * (access type) confusion for this test. + */ + if (close(fd) < 0) + return errno; + return 0; +} + +/* + * Exercises file truncation when it's not restricted, + * as it was the case before LANDLOCK_ACCESS_FS_TRUNCATE existed. + */ +TEST_F_FORK(layout1, truncate_unhandled) +{ + const char *const file_r = file1_s1d1; + const char *const file_w = file2_s1d1; + const char *const file_none = file1_s1d2; + const struct rule rules[] = { + { + .path = file_r, + .access = LANDLOCK_ACCESS_FS_READ_FILE, + }, + { + .path = file_w, + .access = LANDLOCK_ACCESS_FS_WRITE_FILE, + }, + /* Implicitly: No rights for file_none. */ + {}, + }; + + const __u64 handled = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_WRITE_FILE; + int ruleset_fd; + + /* Enable Landlock. */ + ruleset_fd = create_ruleset(_metadata, handled, rules); + + ASSERT_LE(0, ruleset_fd); + enforce_ruleset(_metadata, ruleset_fd); + ASSERT_EQ(0, close(ruleset_fd)); + + /* + * Checks read right: truncate and open with O_TRUNC work, unless the + * file is attempted to be opened for writing. + */ + EXPECT_EQ(0, test_truncate(file_r)); + EXPECT_EQ(0, test_open(file_r, O_RDONLY | O_TRUNC)); + EXPECT_EQ(EACCES, test_open(file_r, O_WRONLY | O_TRUNC)); + EXPECT_EQ(EACCES, test_creat(file_r)); + + /* + * Checks write right: truncate and open with O_TRUNC work, unless the + * file is attempted to be opened for reading. + */ + EXPECT_EQ(0, test_truncate(file_w)); + EXPECT_EQ(EACCES, test_open(file_w, O_RDONLY | O_TRUNC)); + EXPECT_EQ(0, test_open(file_w, O_WRONLY | O_TRUNC)); + EXPECT_EQ(0, test_creat(file_w)); + + /* + * Checks "no rights" case: truncate works but all open attempts fail, + * including creat. + */ + EXPECT_EQ(0, test_truncate(file_none)); + EXPECT_EQ(EACCES, test_open(file_none, O_RDONLY | O_TRUNC)); + EXPECT_EQ(EACCES, test_open(file_none, O_WRONLY | O_TRUNC)); + EXPECT_EQ(EACCES, test_creat(file_none)); +} + +TEST_F_FORK(layout1, truncate) +{ + const char *const file_rwt = file1_s1d1; + const char *const file_rw = file2_s1d1; + const char *const file_rt = file1_s1d2; + const char *const file_t = file2_s1d2; + const char *const file_none = file1_s1d3; + const char *const dir_t = dir_s2d1; + const char *const file_in_dir_t = file1_s2d1; + const char *const dir_w = dir_s3d1; + const char *const file_in_dir_w = file1_s3d1; + const struct rule rules[] = { + { + .path = file_rwt, + .access = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_WRITE_FILE | + LANDLOCK_ACCESS_FS_TRUNCATE, + }, + { + .path = file_rw, + .access = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_WRITE_FILE, + }, + { + .path = file_rt, + .access = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_TRUNCATE, + }, + { + .path = file_t, + .access = LANDLOCK_ACCESS_FS_TRUNCATE, + }, + /* Implicitly: No access rights for file_none. */ + { + .path = dir_t, + .access = LANDLOCK_ACCESS_FS_TRUNCATE, + }, + { + .path = dir_w, + .access = LANDLOCK_ACCESS_FS_WRITE_FILE, + }, + {}, + }; + const __u64 handled = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_WRITE_FILE | + LANDLOCK_ACCESS_FS_TRUNCATE; + int ruleset_fd; + + /* Enable Landlock. */ + ruleset_fd = create_ruleset(_metadata, handled, rules); + + ASSERT_LE(0, ruleset_fd); + enforce_ruleset(_metadata, ruleset_fd); + ASSERT_EQ(0, close(ruleset_fd)); + + /* Checks read, write and truncate rights: truncation works. */ + EXPECT_EQ(0, test_truncate(file_rwt)); + EXPECT_EQ(0, test_open(file_rwt, O_RDONLY | O_TRUNC)); + EXPECT_EQ(0, test_open(file_rwt, O_WRONLY | O_TRUNC)); + + /* Checks read and write rights: no truncate variant works. */ + EXPECT_EQ(EACCES, test_truncate(file_rw)); + EXPECT_EQ(EACCES, test_open(file_rw, O_RDONLY | O_TRUNC)); + EXPECT_EQ(EACCES, test_open(file_rw, O_WRONLY | O_TRUNC)); + + /* + * Checks read and truncate rights: truncation works. + * + * Note: Files can get truncated using open() even with O_RDONLY. + */ + EXPECT_EQ(0, test_truncate(file_rt)); + EXPECT_EQ(0, test_open(file_rt, O_RDONLY | O_TRUNC)); + EXPECT_EQ(EACCES, test_open(file_rt, O_WRONLY | O_TRUNC)); + + /* Checks truncate right: truncate works, but can't open file. */ + EXPECT_EQ(0, test_truncate(file_t)); + EXPECT_EQ(EACCES, test_open(file_t, O_RDONLY | O_TRUNC)); + EXPECT_EQ(EACCES, test_open(file_t, O_WRONLY | O_TRUNC)); + + /* Checks "no rights" case: No form of truncation works. */ + EXPECT_EQ(EACCES, test_truncate(file_none)); + EXPECT_EQ(EACCES, test_open(file_none, O_RDONLY | O_TRUNC)); + EXPECT_EQ(EACCES, test_open(file_none, O_WRONLY | O_TRUNC)); + + /* + * Checks truncate right on directory: truncate works on contained + * files. + */ + EXPECT_EQ(0, test_truncate(file_in_dir_t)); + EXPECT_EQ(EACCES, test_open(file_in_dir_t, O_RDONLY | O_TRUNC)); + EXPECT_EQ(EACCES, test_open(file_in_dir_t, O_WRONLY | O_TRUNC)); + + /* + * Checks creat in dir_w: This requires the truncate right when + * overwriting an existing file, but does not require it when the file + * is new. + */ + EXPECT_EQ(EACCES, test_creat(file_in_dir_w)); + + ASSERT_EQ(0, unlink(file_in_dir_w)); + EXPECT_EQ(0, test_creat(file_in_dir_w)); +} + +/* Invokes ftruncate(2) and returns its errno or 0. */ +static int test_ftruncate(int fd) +{ + if (ftruncate(fd, 10) < 0) + return errno; + return 0; +} + +TEST_F_FORK(layout1, ftruncate) +{ + /* + * This test opens a new file descriptor at different stages of + * Landlock restriction: + * + * without restriction: ftruncate works + * something else but truncate restricted: ftruncate works + * truncate restricted and permitted: ftruncate works + * truncate restricted and not permitted: ftruncate fails + * + * Whether this works or not is expected to depend on the time when the + * FD was opened, not to depend on the time when ftruncate() was + * called. + */ + const char *const path = file1_s1d1; + const __u64 handled1 = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_WRITE_FILE; + const struct rule layer1[] = { + { + .path = path, + .access = LANDLOCK_ACCESS_FS_WRITE_FILE, + }, + {}, + }; + const __u64 handled2 = LANDLOCK_ACCESS_FS_TRUNCATE; + const struct rule layer2[] = { + { + .path = path, + .access = LANDLOCK_ACCESS_FS_TRUNCATE, + }, + {}, + }; + const __u64 handled3 = LANDLOCK_ACCESS_FS_TRUNCATE | + LANDLOCK_ACCESS_FS_WRITE_FILE; + const struct rule layer3[] = { + { + .path = path, + .access = LANDLOCK_ACCESS_FS_WRITE_FILE, + }, + {}, + }; + int fd_layer0, fd_layer1, fd_layer2, fd_layer3, ruleset_fd; + + fd_layer0 = open(path, O_WRONLY); + EXPECT_EQ(0, test_ftruncate(fd_layer0)); + + ruleset_fd = create_ruleset(_metadata, handled1, layer1); + ASSERT_LE(0, ruleset_fd); + enforce_ruleset(_metadata, ruleset_fd); + ASSERT_EQ(0, close(ruleset_fd)); + + fd_layer1 = open(path, O_WRONLY); + EXPECT_EQ(0, test_ftruncate(fd_layer0)); + EXPECT_EQ(0, test_ftruncate(fd_layer1)); + + ruleset_fd = create_ruleset(_metadata, handled2, layer2); + ASSERT_LE(0, ruleset_fd); + enforce_ruleset(_metadata, ruleset_fd); + ASSERT_EQ(0, close(ruleset_fd)); + + fd_layer2 = open(path, O_WRONLY); + EXPECT_EQ(0, test_ftruncate(fd_layer0)); + EXPECT_EQ(0, test_ftruncate(fd_layer1)); + EXPECT_EQ(0, test_ftruncate(fd_layer2)); + + ruleset_fd = create_ruleset(_metadata, handled3, layer3); + ASSERT_LE(0, ruleset_fd); + enforce_ruleset(_metadata, ruleset_fd); + ASSERT_EQ(0, close(ruleset_fd)); + + fd_layer3 = open(path, O_WRONLY); + EXPECT_EQ(0, test_ftruncate(fd_layer0)); + EXPECT_EQ(0, test_ftruncate(fd_layer1)); + EXPECT_EQ(0, test_ftruncate(fd_layer2)); + EXPECT_EQ(EACCES, test_ftruncate(fd_layer3)); + + ASSERT_EQ(0, close(fd_layer0)); + ASSERT_EQ(0, close(fd_layer1)); + ASSERT_EQ(0, close(fd_layer2)); + ASSERT_EQ(0, close(fd_layer3)); +} + /* clang-format off */ FIXTURE(layout1_bind) {}; /* clang-format on */ From patchwork Tue Oct 18 18:22:11 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?G=C3=BCnther_Noack?= X-Patchwork-Id: 13010898 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 07145C4321E for ; Tue, 18 Oct 2022 18:23:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229874AbiJRSXK (ORCPT ); Tue, 18 Oct 2022 14:23:10 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42522 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229526AbiJRSWw (ORCPT ); Tue, 18 Oct 2022 14:22:52 -0400 Received: from mail-ed1-x530.google.com (mail-ed1-x530.google.com [IPv6:2a00:1450:4864:20::530]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D40D682D17; Tue, 18 Oct 2022 11:22:35 -0700 (PDT) Received: by mail-ed1-x530.google.com with SMTP id a67so21724122edf.12; Tue, 18 Oct 2022 11:22:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=U7EZyBx7bCF7vqPgVGnwZCbGudLlBsaHfU69mkM4HyE=; b=EFgGOkHS5IKWaZDq1hhu4EfwcDUXmoGHBUJEgdApYbXePgsaRf7dWOlrQ31zLB/29X +FPWRzOsX0bQc0Wjdh9aBc2lqaPEgJYxQV1QU5/zc3dwbU9vEREOHQX5ZhKZrtEFBZLf 8+0kDS+ofrC00JYtiJg6c+nMDf6wA/WuNUZzw0cQkAyWSrnEqoz9SsE/+X39fmJ2O6rt K9Vb5gYLRksgZZFkdr6D0XnVDMMt8x4uoOgPIp+xke9uFRYm73Uem6+AvYQ+/DrOTgfQ ud0gUnYhwvCLQu3dbUBj+1bNl7idDMm/9STqtVTCkL6U1XweWyxEtjzHtxlI7rRvNYdR rFpA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=U7EZyBx7bCF7vqPgVGnwZCbGudLlBsaHfU69mkM4HyE=; b=N86QoADHPBqxtehxK4h7CoiJKWBJeaqmxyfjmoUdqTdKTrslY6DJzp2wZNq0pDBfxH MqZqunjtHT1BR4/VLwv2HVgAieDvAOREcnl2b/mE5xinavmW1o/mIr8EfKWQNJn1jnVP Jd9OBg7btggtRSNfx4+XG3QPtpgbXFeXZn5G9G9jgR+sDNtQAvIT11VHDKOLdC1XgG4I SKjGT0CtvspwvzykFVKClsWiUTMzU2/dM4MFkVMi2LGYtw6prdnwMCR7s4BFlyp8A2NH RKWAXrZwHtTJMcLqIReJuxwhzTH0xg9rSDgZS0gEGf7begkCodAwOXLzyaftmXQ6pXgc LhRg== X-Gm-Message-State: ACrzQf3R86QDZzCQV7gUHXvpJpXXe2NRsXzzh3b7dZOCt7j6d8xT2hnN vk6+n3ptKp33tw4BOa1nK6BBHHzhQqE= X-Google-Smtp-Source: AMsMyM5gIxzIgujRafkmWOhc9gf4BuqEf2y3KAewCwwvaq7mTWI9a9hYTPvMGmSlZAiywMu/bm0AYA== X-Received: by 2002:a05:6402:34c7:b0:45c:c02c:e256 with SMTP id w7-20020a05640234c700b0045cc02ce256mr3973128edc.198.1666117354031; Tue, 18 Oct 2022 11:22:34 -0700 (PDT) Received: from nuc.i.gnoack.org ([2a02:168:633b:1:1e69:7aff:fe05:97e6]) by smtp.gmail.com with ESMTPSA id i18-20020a0564020f1200b00458a03203b1sm9358395eda.31.2022.10.18.11.22.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 18 Oct 2022 11:22:33 -0700 (PDT) From: =?utf-8?q?G=C3=BCnther_Noack?= To: linux-security-module@vger.kernel.org Cc: =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= , James Morris , Paul Moore , "Serge E . Hallyn" , linux-fsdevel@vger.kernel.org, Konstantin Meskhidze , Nathan Chancellor , =?utf-8?q?G=C3=BCnther_Noack?= Subject: [PATCH v10 06/11] selftests/landlock: Test open() and ftruncate() in multiple scenarios Date: Tue, 18 Oct 2022 20:22:11 +0200 Message-Id: <20221018182216.301684-7-gnoack3000@gmail.com> X-Mailer: git-send-email 2.38.0 In-Reply-To: <20221018182216.301684-1-gnoack3000@gmail.com> References: <20221018182216.301684-1-gnoack3000@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: This test uses multiple fixture variants to exercise a broader set of scnenarios. Signed-off-by: Günther Noack --- tools/testing/selftests/landlock/fs_test.c | 96 ++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c index 718543fd3dfc..308f6f36e8c0 100644 --- a/tools/testing/selftests/landlock/fs_test.c +++ b/tools/testing/selftests/landlock/fs_test.c @@ -3445,6 +3445,102 @@ TEST_F_FORK(layout1, ftruncate) ASSERT_EQ(0, close(fd_layer3)); } +/* clang-format off */ +FIXTURE(ftruncate) {}; +/* clang-format on */ + +FIXTURE_SETUP(ftruncate) +{ + prepare_layout(_metadata); + create_file(_metadata, file1_s1d1); +} + +FIXTURE_TEARDOWN(ftruncate) +{ + EXPECT_EQ(0, remove_path(file1_s1d1)); + cleanup_layout(_metadata); +} + +FIXTURE_VARIANT(ftruncate) +{ + const __u64 handled; + const __u64 permitted; + const int expected_open_result; + const int expected_ftruncate_result; +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(ftruncate, w_w) { + /* clang-format on */ + .handled = LANDLOCK_ACCESS_FS_WRITE_FILE, + .permitted = LANDLOCK_ACCESS_FS_WRITE_FILE, + .expected_open_result = 0, + .expected_ftruncate_result = 0, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(ftruncate, t_t) { + /* clang-format on */ + .handled = LANDLOCK_ACCESS_FS_TRUNCATE, + .permitted = LANDLOCK_ACCESS_FS_TRUNCATE, + .expected_open_result = 0, + .expected_ftruncate_result = 0, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(ftruncate, wt_w) { + /* clang-format on */ + .handled = LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_TRUNCATE, + .permitted = LANDLOCK_ACCESS_FS_WRITE_FILE, + .expected_open_result = 0, + .expected_ftruncate_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(ftruncate, wt_wt) { + /* clang-format on */ + .handled = LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_TRUNCATE, + .permitted = LANDLOCK_ACCESS_FS_WRITE_FILE | + LANDLOCK_ACCESS_FS_TRUNCATE, + .expected_open_result = 0, + .expected_ftruncate_result = 0, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(ftruncate, wt_t) { + /* clang-format on */ + .handled = LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_TRUNCATE, + .permitted = LANDLOCK_ACCESS_FS_TRUNCATE, + .expected_open_result = EACCES, +}; + +TEST_F_FORK(ftruncate, open_and_ftruncate) +{ + const char *const path = file1_s1d1; + const struct rule rules[] = { + { + .path = path, + .access = variant->permitted, + }, + {}, + }; + int fd, ruleset_fd; + + /* Enable Landlock. */ + ruleset_fd = create_ruleset(_metadata, variant->handled, rules); + ASSERT_LE(0, ruleset_fd); + enforce_ruleset(_metadata, ruleset_fd); + ASSERT_EQ(0, close(ruleset_fd)); + + fd = open(path, O_WRONLY); + EXPECT_EQ(variant->expected_open_result, (fd < 0 ? errno : 0)); + if (fd >= 0) { + EXPECT_EQ(variant->expected_ftruncate_result, + test_ftruncate(fd)); + ASSERT_EQ(0, close(fd)); + } +} + /* clang-format off */ FIXTURE(layout1_bind) {}; /* clang-format on */ From patchwork Tue Oct 18 18:22:12 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?G=C3=BCnther_Noack?= X-Patchwork-Id: 13010900 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8A724C4167D for ; Tue, 18 Oct 2022 18:23:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229775AbiJRSXL (ORCPT ); Tue, 18 Oct 2022 14:23:11 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42890 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229698AbiJRSWw (ORCPT ); Tue, 18 Oct 2022 14:22:52 -0400 Received: from mail-ej1-x633.google.com (mail-ej1-x633.google.com [IPv6:2a00:1450:4864:20::633]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 52B7882D28; Tue, 18 Oct 2022 11:22:36 -0700 (PDT) Received: by mail-ej1-x633.google.com with SMTP id bj12so34295346ejb.13; Tue, 18 Oct 2022 11:22:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=NAI6zB9+0AGnJiVMY5vVZsK//rjwT955A9i61fTtXGs=; b=QpyJUiJgAOm6xg6LjQTb8ftXMa1W1PYjo23TdPFEyBv068T7+Acr5f0woWYvlW3VQS LEe/SLug4cxutjrfe/5mXjs/23BYU20l+thdslH3YYlr0Lf7YEcGykLg1I7qL+ggud+B HkCRzf7N7cCi8p9vvi4UqUaX/5upoosVRmtboIYbW+xLmPGxEczYlKSfPV7Q/EmHifQp yD97HqE4XDx9PStUiZ4fNwKdhnx7GIZ2N1SJb3wn8UPTyKENERJt1UTVzFkBTrz0ce6b /qYCLNPaecIvizPPIo3HR4B/ScSQgzWqGs8KRlESbzsCXpR9ziTG0QrXl1IvJFLte0/j BLTA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=NAI6zB9+0AGnJiVMY5vVZsK//rjwT955A9i61fTtXGs=; b=wojKI42B7bBauva0lJt+T0I/h3ObaMf1xwpNtqvsxwivsgiqeyXCaajESc6jmP7XXB bYg/gPWMqQCtBDJc1Fq8BoIBds0xFdF4ybWh6hpgaZ0Jm1QiTfDwzCjtno1qxeqVAWq9 JgrQnbtvaEFBszc/gCd1uOTP2GMXa2dRlJq6CmCO0+987kocG8MSi34FxS6qYlN8Z2E/ A1vP52y1v/HrJlwCBz6u+ZL5gE4FLOcNBdOV7iDa/S8Gk2/ihRFT+5NtB+FNa86DUgXm gO1ANbXnEpxysiwvHHdZlSdFOmFoDbBFKrbTZenbxNTI9pMQVHTR6zAydsWh89eultFc rhfA== X-Gm-Message-State: ACrzQf0BQu4PPXBTBUtxDo7xltOj3gKNIlDs0RbJ5aJMjSUGr2VQ/KJ8 aAGkTdjmBKNVYo62WiDUQt+auhE5Pew= X-Google-Smtp-Source: AMsMyM5NFg89XvH3cwG50d0PpNs0qMzQZtInxphbecoM39pTWCJu6TxFQm5LKfaFO4Gs/CbHAxjDQQ== X-Received: by 2002:a17:906:9b92:b0:791:9355:cb89 with SMTP id dd18-20020a1709069b9200b007919355cb89mr3476654ejc.498.1666117354785; Tue, 18 Oct 2022 11:22:34 -0700 (PDT) Received: from nuc.i.gnoack.org ([2a02:168:633b:1:1e69:7aff:fe05:97e6]) by smtp.gmail.com with ESMTPSA id i18-20020a0564020f1200b00458a03203b1sm9358395eda.31.2022.10.18.11.22.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 18 Oct 2022 11:22:34 -0700 (PDT) From: =?utf-8?q?G=C3=BCnther_Noack?= To: linux-security-module@vger.kernel.org Cc: =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= , James Morris , Paul Moore , "Serge E . Hallyn" , linux-fsdevel@vger.kernel.org, Konstantin Meskhidze , Nathan Chancellor , =?utf-8?q?G=C3=BCnther_Noack?= Subject: [PATCH v10 07/11] selftests/landlock: Locally define __maybe_unused Date: Tue, 18 Oct 2022 20:22:12 +0200 Message-Id: <20221018182216.301684-8-gnoack3000@gmail.com> X-Mailer: git-send-email 2.38.0 In-Reply-To: <20221018182216.301684-1-gnoack3000@gmail.com> References: <20221018182216.301684-1-gnoack3000@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: The checkpatch tool started to flag __attribute__(__unused__), which we previously used. The header where this is normally defined is not currently compatible with selftests. This is the same approach as used in selftests/net/psock_lib.h. Signed-off-by: Günther Noack --- tools/testing/selftests/landlock/common.h | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/tools/testing/selftests/landlock/common.h b/tools/testing/selftests/landlock/common.h index 7ba18eb23783..7d34592471db 100644 --- a/tools/testing/selftests/landlock/common.h +++ b/tools/testing/selftests/landlock/common.h @@ -17,6 +17,10 @@ #include "../kselftest_harness.h" +#ifndef __maybe_unused +#define __maybe_unused __attribute__((__unused__)) +#endif + /* * TEST_F_FORK() is useful when a test drop privileges but the corresponding * FIXTURE_TEARDOWN() requires them (e.g. to remove files from a directory @@ -140,14 +144,12 @@ static void _init_caps(struct __test_metadata *const _metadata, bool drop_all) } /* We cannot put such helpers in a library because of kselftest_harness.h . */ -__attribute__((__unused__)) static void -disable_caps(struct __test_metadata *const _metadata) +static void __maybe_unused disable_caps(struct __test_metadata *const _metadata) { _init_caps(_metadata, false); } -__attribute__((__unused__)) static void -drop_caps(struct __test_metadata *const _metadata) +static void __maybe_unused drop_caps(struct __test_metadata *const _metadata) { _init_caps(_metadata, true); } @@ -176,14 +178,14 @@ static void _effective_cap(struct __test_metadata *const _metadata, } } -__attribute__((__unused__)) static void -set_cap(struct __test_metadata *const _metadata, const cap_value_t caps) +static void __maybe_unused set_cap(struct __test_metadata *const _metadata, + const cap_value_t caps) { _effective_cap(_metadata, caps, CAP_SET); } -__attribute__((__unused__)) static void -clear_cap(struct __test_metadata *const _metadata, const cap_value_t caps) +static void __maybe_unused clear_cap(struct __test_metadata *const _metadata, + const cap_value_t caps) { _effective_cap(_metadata, caps, CAP_CLEAR); } From patchwork Tue Oct 18 18:22:13 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?G=C3=BCnther_Noack?= X-Patchwork-Id: 13010902 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 994FCC43219 for ; Tue, 18 Oct 2022 18:23:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230107AbiJRSXM (ORCPT ); Tue, 18 Oct 2022 14:23:12 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42892 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229993AbiJRSWx (ORCPT ); Tue, 18 Oct 2022 14:22:53 -0400 Received: from mail-ej1-x632.google.com (mail-ej1-x632.google.com [IPv6:2a00:1450:4864:20::632]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 37FCA82D31; Tue, 18 Oct 2022 11:22:37 -0700 (PDT) Received: by mail-ej1-x632.google.com with SMTP id d26so34345645ejc.8; Tue, 18 Oct 2022 11:22:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=MCmk/tBVjbF+7TqU0s2kMsuRpHDv0d5bCD7ppPQIYwk=; b=GtZbUbYF28+5CArUm/WNPK3vK0N723pKcNBQvf104FiKmQANCy1VTwlAO4Cu+JJZk6 w6ftxBK4KU+8jyPT5FMBwROGnjgrZ3ScY3qRH+g0mmK/zwlW/8kxRzfFoUGTkSccP6KJ mSgkXd/QSBkgVPUvR+4JMYIASz0r8G091AyCz8Ptg+m4db3sAigUBsXAL4CTIyIrKNTd bruA3uajcCUEnVOpiN6Z1z8GwT3bS7DZhmAqjHzPsx8LTX5za6ITZurb95OLhVKVEoZ6 NyoqzGFn6br+Wvp97Qd3qNV8+70SaA8lgETiKxrCkSSLB69F9Cd7wC1yjx02Sdm/RzSF daGw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=MCmk/tBVjbF+7TqU0s2kMsuRpHDv0d5bCD7ppPQIYwk=; b=K2eWt5SahQIhSNjflHNiojcoz8IwQfhO3C0smzWqselig56ekjxFMyd17LUl/3hTHm 0H7DFrk5f27fX/+CsLaN6hd09RLZgJ+oGBKz7QSEBu4xLWUJZYRWOYEVkKj8nMTrJ/cv a04ID/9M4Rbioobd75Bynr2cZSVVX8fend8DaHImrDT0KxbNP+qYt8r8fOA1Rzj6aBFg MQ0RYE25nvGB5gvrrCPKtomtFNdnPKjWoqR8v2ZcFwZmiK68uXdOT4M5PPXxzQAYsvL0 SPYt6+WlsEVIiblzQ2v4KD073eynNQdh6ByxvAtbM4BQb8N2zs+x9WOUXZZv9Wl67J4p zrYA== X-Gm-Message-State: ACrzQf3ASHmgxijZGaRtHr4KEKvLSY1tUs1VFnLeIQhQ5JrBDnifQEi+ 0Vt9t2v+62Q1ePH84+PnjIVpZiIrXqY= X-Google-Smtp-Source: AMsMyM540Q7sIwvy6TqBizL+2L5fg+bkhXI11tykwXL57S02YTyUHCuBgWP590Dm41V1/zPJRO8/gg== X-Received: by 2002:a17:907:980e:b0:78d:b6ea:25b3 with SMTP id ji14-20020a170907980e00b0078db6ea25b3mr3584810ejc.98.1666117355599; Tue, 18 Oct 2022 11:22:35 -0700 (PDT) Received: from nuc.i.gnoack.org ([2a02:168:633b:1:1e69:7aff:fe05:97e6]) by smtp.gmail.com with ESMTPSA id i18-20020a0564020f1200b00458a03203b1sm9358395eda.31.2022.10.18.11.22.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 18 Oct 2022 11:22:35 -0700 (PDT) From: =?utf-8?q?G=C3=BCnther_Noack?= To: linux-security-module@vger.kernel.org Cc: =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= , James Morris , Paul Moore , "Serge E . Hallyn" , linux-fsdevel@vger.kernel.org, Konstantin Meskhidze , Nathan Chancellor , =?utf-8?q?G=C3=BCnther_Noack?= Subject: [PATCH v10 08/11] selftests/landlock: Test FD passing from restricted to unrestricted processes Date: Tue, 18 Oct 2022 20:22:13 +0200 Message-Id: <20221018182216.301684-9-gnoack3000@gmail.com> X-Mailer: git-send-email 2.38.0 In-Reply-To: <20221018182216.301684-1-gnoack3000@gmail.com> References: <20221018182216.301684-1-gnoack3000@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: A file descriptor created in a restricted process carries Landlock restrictions with it which will apply even if the same opened file is used from an unrestricted process. This change extracts suitable FD-passing helpers from base_test.c and moves them to common.h. We use the fixture variants from the ftruncate fixture to exercise the same scenarios as in the open_and_ftruncate test, but doing the Landlock restriction and open() in a different process than the ftruncate() call. Signed-off-by: Günther Noack --- tools/testing/selftests/landlock/base_test.c | 36 +---------- tools/testing/selftests/landlock/common.h | 67 ++++++++++++++++++++ tools/testing/selftests/landlock/fs_test.c | 62 ++++++++++++++++++ 3 files changed, 132 insertions(+), 33 deletions(-) diff --git a/tools/testing/selftests/landlock/base_test.c b/tools/testing/selftests/landlock/base_test.c index 72cdae277b02..792c3f0a59b4 100644 --- a/tools/testing/selftests/landlock/base_test.c +++ b/tools/testing/selftests/landlock/base_test.c @@ -263,23 +263,6 @@ TEST(ruleset_fd_transfer) .allowed_access = LANDLOCK_ACCESS_FS_READ_DIR, }; int ruleset_fd_tx, dir_fd; - union { - /* Aligned ancillary data buffer. */ - char buf[CMSG_SPACE(sizeof(ruleset_fd_tx))]; - struct cmsghdr _align; - } cmsg_tx = {}; - char data_tx = '.'; - struct iovec io = { - .iov_base = &data_tx, - .iov_len = sizeof(data_tx), - }; - struct msghdr msg = { - .msg_iov = &io, - .msg_iovlen = 1, - .msg_control = &cmsg_tx.buf, - .msg_controllen = sizeof(cmsg_tx.buf), - }; - struct cmsghdr *cmsg; int socket_fds[2]; pid_t child; int status; @@ -298,33 +281,20 @@ TEST(ruleset_fd_transfer) &path_beneath_attr, 0)); ASSERT_EQ(0, close(path_beneath_attr.parent_fd)); - cmsg = CMSG_FIRSTHDR(&msg); - ASSERT_NE(NULL, cmsg); - cmsg->cmsg_len = CMSG_LEN(sizeof(ruleset_fd_tx)); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - memcpy(CMSG_DATA(cmsg), &ruleset_fd_tx, sizeof(ruleset_fd_tx)); - /* Sends the ruleset FD over a socketpair and then close it. */ ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, socket_fds)); - ASSERT_EQ(sizeof(data_tx), sendmsg(socket_fds[0], &msg, 0)); + ASSERT_EQ(0, send_fd(socket_fds[0], ruleset_fd_tx)); ASSERT_EQ(0, close(socket_fds[0])); ASSERT_EQ(0, close(ruleset_fd_tx)); child = fork(); ASSERT_LE(0, child); if (child == 0) { - int ruleset_fd_rx; + const int ruleset_fd_rx = recv_fd(socket_fds[1]); - *(char *)msg.msg_iov->iov_base = '\0'; - ASSERT_EQ(sizeof(data_tx), - recvmsg(socket_fds[1], &msg, MSG_CMSG_CLOEXEC)); - ASSERT_EQ('.', *(char *)msg.msg_iov->iov_base); + ASSERT_LE(0, ruleset_fd_rx); ASSERT_EQ(0, close(socket_fds[1])); - cmsg = CMSG_FIRSTHDR(&msg); - ASSERT_EQ(cmsg->cmsg_len, CMSG_LEN(sizeof(ruleset_fd_tx))); - memcpy(&ruleset_fd_rx, CMSG_DATA(cmsg), sizeof(ruleset_fd_tx)); /* Enforces the received ruleset on the child. */ ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)); diff --git a/tools/testing/selftests/landlock/common.h b/tools/testing/selftests/landlock/common.h index 7d34592471db..d7987ae8d7fc 100644 --- a/tools/testing/selftests/landlock/common.h +++ b/tools/testing/selftests/landlock/common.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -189,3 +190,69 @@ static void __maybe_unused clear_cap(struct __test_metadata *const _metadata, { _effective_cap(_metadata, caps, CAP_CLEAR); } + +/* Receives an FD from a UNIX socket. Returns the received FD, or -errno. */ +static int __maybe_unused recv_fd(int usock) +{ + int fd_rx; + union { + /* Aligned ancillary data buffer. */ + char buf[CMSG_SPACE(sizeof(fd_rx))]; + struct cmsghdr _align; + } cmsg_rx = {}; + char data = '\0'; + struct iovec io = { + .iov_base = &data, + .iov_len = sizeof(data), + }; + struct msghdr msg = { + .msg_iov = &io, + .msg_iovlen = 1, + .msg_control = &cmsg_rx.buf, + .msg_controllen = sizeof(cmsg_rx.buf), + }; + struct cmsghdr *cmsg; + int res; + + res = recvmsg(usock, &msg, MSG_CMSG_CLOEXEC); + if (res < 0) + return -errno; + + cmsg = CMSG_FIRSTHDR(&msg); + if (cmsg->cmsg_len != CMSG_LEN(sizeof(fd_rx))) + return -EIO; + + memcpy(&fd_rx, CMSG_DATA(cmsg), sizeof(fd_rx)); + return fd_rx; +} + +/* Sends an FD on a UNIX socket. Returns 0 on success or -errno. */ +static int __maybe_unused send_fd(int usock, int fd_tx) +{ + union { + /* Aligned ancillary data buffer. */ + char buf[CMSG_SPACE(sizeof(fd_tx))]; + struct cmsghdr _align; + } cmsg_tx = {}; + char data_tx = '.'; + struct iovec io = { + .iov_base = &data_tx, + .iov_len = sizeof(data_tx), + }; + struct msghdr msg = { + .msg_iov = &io, + .msg_iovlen = 1, + .msg_control = &cmsg_tx.buf, + .msg_controllen = sizeof(cmsg_tx.buf), + }; + struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); + + cmsg->cmsg_len = CMSG_LEN(sizeof(fd_tx)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + memcpy(CMSG_DATA(cmsg), &fd_tx, sizeof(fd_tx)); + + if (sendmsg(usock, &msg, 0) < 0) + return -errno; + return 0; +} diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c index 308f6f36e8c0..f8aae01a2409 100644 --- a/tools/testing/selftests/landlock/fs_test.c +++ b/tools/testing/selftests/landlock/fs_test.c @@ -3541,6 +3541,68 @@ TEST_F_FORK(ftruncate, open_and_ftruncate) } } +TEST_F_FORK(ftruncate, open_and_ftruncate_in_different_processes) +{ + int child, fd, status; + int socket_fds[2]; + + ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, + socket_fds)); + + child = fork(); + ASSERT_LE(0, child); + if (child == 0) { + /* + * Enables Landlock in the child process, open a file descriptor + * where truncation is forbidden and send it to the + * non-landlocked parent process. + */ + const char *const path = file1_s1d1; + const struct rule rules[] = { + { + .path = path, + .access = variant->permitted, + }, + {}, + }; + int fd, ruleset_fd; + + ruleset_fd = create_ruleset(_metadata, variant->handled, rules); + ASSERT_LE(0, ruleset_fd); + enforce_ruleset(_metadata, ruleset_fd); + ASSERT_EQ(0, close(ruleset_fd)); + + fd = open(path, O_WRONLY); + ASSERT_EQ(variant->expected_open_result, (fd < 0 ? errno : 0)); + + if (fd >= 0) { + ASSERT_EQ(0, send_fd(socket_fds[0], fd)); + ASSERT_EQ(0, close(fd)); + } + + ASSERT_EQ(0, close(socket_fds[0])); + + _exit(_metadata->passed ? EXIT_SUCCESS : EXIT_FAILURE); + return; + } + + if (variant->expected_open_result == 0) { + fd = recv_fd(socket_fds[1]); + ASSERT_LE(0, fd); + + EXPECT_EQ(variant->expected_ftruncate_result, + test_ftruncate(fd)); + ASSERT_EQ(0, close(fd)); + } + + ASSERT_EQ(child, waitpid(child, &status, 0)); + ASSERT_EQ(1, WIFEXITED(status)); + ASSERT_EQ(EXIT_SUCCESS, WEXITSTATUS(status)); + + ASSERT_EQ(0, close(socket_fds[0])); + ASSERT_EQ(0, close(socket_fds[1])); +} + /* clang-format off */ FIXTURE(layout1_bind) {}; /* clang-format on */ From patchwork Tue Oct 18 18:22:14 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?G=C3=BCnther_Noack?= X-Patchwork-Id: 13010901 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D529CC4332F for ; Tue, 18 Oct 2022 18:23:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230004AbiJRSXM (ORCPT ); Tue, 18 Oct 2022 14:23:12 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42546 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229963AbiJRSWx (ORCPT ); Tue, 18 Oct 2022 14:22:53 -0400 Received: from mail-ej1-x630.google.com (mail-ej1-x630.google.com [IPv6:2a00:1450:4864:20::630]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A7A228285D; Tue, 18 Oct 2022 11:22:37 -0700 (PDT) Received: by mail-ej1-x630.google.com with SMTP id fy4so34325045ejc.5; Tue, 18 Oct 2022 11:22:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=TcJinYSqP/P8butZE17/ltEboJUG5yfSi0K+q7kH9Mo=; b=C/BrBsO/fjmYpEtPhev7MOzB19mSNdrIy2k0A0Upgmqcq2RPMYEpWE0oaQqaF80V+v oGt2OZmIBmPOsFAbSuT2k81SlVlQH+ruIb9EGHWVWf2B8wOVfHA4Bs7VJFSQgA2ZKvEQ UyYzO8ZvjA4KPYA3Nlt7biDfdpLxVnU3UMW4a5LVbbE2yC02rsrFJ/NgOylfeRggxg5I PEZ6dFGWus/GEtqZlw3wiuy2TI2DpJTCFpEFsGBo30mCFub4Tzl/KYzIIGN0pSJqJtdV clQssrqRJyf/Ub1LXNVn8bJvRO1sRYVzFJG5xJOQPQY/oOC8V6j5uTHBv1a49vNHNAA4 p+cQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=TcJinYSqP/P8butZE17/ltEboJUG5yfSi0K+q7kH9Mo=; b=RvWX/rK7+s4lv7OGwxyOGaji7/VFUY71MFGLDYPoFFclvUDmbd7NeTumtK+2+DAH4a Q7H76q7LU33EuKZUAD2z/DOsx5OZJf7EEOozcp8x4KvCtylfbKdKeCPcp+8jYxgetGxS z/l90RANuHaMkYDCQKA+loQWYb9BrlYql6vyXMHEYqRQ9xY1ZO8vlLRoPLgcRUhTCo84 uShipNpEfHVNlDdW3o9T3TK1O6lPiNUeqv1VtBrmm72pHM6Qt7khP9sB+BwEf5AjJuw8 eXfdNvhvWnRhUFhlbhvZm1VHsHE6usxUHB/7bHlybSida/4bO25ohFh2R7ffn7C5Rzn9 fAQA== X-Gm-Message-State: ACrzQf03mfrxGTe1yN0/L+eePrEUZFWqj49lXQbfH9zySlidqDygYzPG bnOEiXRyoJt8U6FzY1OFe4e1dLuxLfQ= X-Google-Smtp-Source: AMsMyM4a7MYzCA6gtauY4jAJgKFn0FbIHpNjVzv6uPJZ8QQOtLRtUGZzVuCktsxw+IcepgObczuy4w== X-Received: by 2002:a17:907:6eac:b0:78d:ce9c:3761 with SMTP id sh44-20020a1709076eac00b0078dce9c3761mr3475496ejc.738.1666117356268; Tue, 18 Oct 2022 11:22:36 -0700 (PDT) Received: from nuc.i.gnoack.org ([2a02:168:633b:1:1e69:7aff:fe05:97e6]) by smtp.gmail.com with ESMTPSA id i18-20020a0564020f1200b00458a03203b1sm9358395eda.31.2022.10.18.11.22.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 18 Oct 2022 11:22:35 -0700 (PDT) From: =?utf-8?q?G=C3=BCnther_Noack?= To: linux-security-module@vger.kernel.org Cc: =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= , James Morris , Paul Moore , "Serge E . Hallyn" , linux-fsdevel@vger.kernel.org, Konstantin Meskhidze , Nathan Chancellor , =?utf-8?q?G=C3=BCnther_Noack?= Subject: [PATCH v10 09/11] selftests/landlock: Test ftruncate on FDs created by memfd_create(2) Date: Tue, 18 Oct 2022 20:22:14 +0200 Message-Id: <20221018182216.301684-10-gnoack3000@gmail.com> X-Mailer: git-send-email 2.38.0 In-Reply-To: <20221018182216.301684-1-gnoack3000@gmail.com> References: <20221018182216.301684-1-gnoack3000@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: All file descriptors that are truncatable need to have the Landlock access rights set correctly on the file's Landlock security blob. This is also the case for files that are opened by other means than open(2). Signed-off-by: Günther Noack --- tools/testing/selftests/landlock/fs_test.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c index f8aae01a2409..d5dab986f612 100644 --- a/tools/testing/selftests/landlock/fs_test.c +++ b/tools/testing/selftests/landlock/fs_test.c @@ -3603,6 +3603,22 @@ TEST_F_FORK(ftruncate, open_and_ftruncate_in_different_processes) ASSERT_EQ(0, close(socket_fds[1])); } +TEST(memfd_ftruncate) +{ + int fd; + + fd = memfd_create("name", MFD_CLOEXEC); + ASSERT_LE(0, fd); + + /* + * Checks that ftruncate is permitted on file descriptors that are + * created in ways other than open(2). + */ + EXPECT_EQ(0, test_ftruncate(fd)); + + ASSERT_EQ(0, close(fd)); +} + /* clang-format off */ FIXTURE(layout1_bind) {}; /* clang-format on */ From patchwork Tue Oct 18 18:22:15 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?G=C3=BCnther_Noack?= X-Patchwork-Id: 13010903 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 59F5DC4321E for ; Tue, 18 Oct 2022 18:23:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230098AbiJRSXO (ORCPT ); Tue, 18 Oct 2022 14:23:14 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42896 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230083AbiJRSWx (ORCPT ); Tue, 18 Oct 2022 14:22:53 -0400 Received: from mail-ed1-x52b.google.com (mail-ed1-x52b.google.com [IPv6:2a00:1450:4864:20::52b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DF0FD82849; Tue, 18 Oct 2022 11:22:38 -0700 (PDT) Received: by mail-ed1-x52b.google.com with SMTP id u21so21747208edi.9; Tue, 18 Oct 2022 11:22:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=ihEjAwkgFK6TMTS0NNrc4Hr909XAXppfc/t74qtEVys=; b=hm5SalgVJtJmHnDHWw7DNtxG5TjZGfWiRzk/SyjKR3zw3yE1D4HSdfixYfRt3/dENO JN+ENtEe1pHIIkJRb+v/19xLRt+s58gvM+PLXPiOGykMke3+kwKHcdIJbfYMjFl2xhHq zcWgNuYHyJV3UOCC/+78HkcHxaO5YW8UsOGyi5tSzdxYN2i20ki/O+oDbOepshAalyVJ rZiNmKN7oIUvOfZ20uDjqET13wggCBxRUP7Zi8tMpoCgSPyNPJgY/O97LNgILXqf9dhi L16apGRjzhKSzCFQaXF7XEuz9t8RecW448eYP/R+/ZRQfB9YnJcYrSw22sW+SsBz4/Ot qNdg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=ihEjAwkgFK6TMTS0NNrc4Hr909XAXppfc/t74qtEVys=; b=jTqg+NV0qp4QAvlH/Bo+GaCiWEhEEbzO8mAQgY3ApwUOW++N+oc3AaHAXHWOnUe2o0 iBrV4CtqxwaZdsBCu1XFUghlFlr17a7TfL4zFabFJ8F3z2e0uwS6nWE8pvwka0LpQ7bt 0LPubL5vYJu2XE23ZSEKQyj83XdNomVI5YSb8AuwBpdJzGW6pubkVTteYURMqbFi3HSm 7GWINrzar9XMyyjzVFJy19czJNdP1JZgr/DY9Lrh2JYLi2tgadfrC8DnAuhgwRMnbfgf 90Gep9GK6Q0Mg6pnrBO9j3KJwdshy5r/ORjaP7nIvm3CrJSBrcXRN9sN2VszCCz5ILBA WaHg== X-Gm-Message-State: ACrzQf0NRiDJIJlf/+su5+hQptA1DwASmuKU2sJpqC/a1FpHfg0HBHMW g3M5sv5IGxqee0HghAKqzMJsnUWzBUg= X-Google-Smtp-Source: AMsMyM4HYpmSv8b3sH3Y33hT1hxyRrc9VzF5B8y4LPkHenO3SUFJEdx/TBmJW9+voJE28xkNCTbXOA== X-Received: by 2002:a05:6402:42c7:b0:45c:a6f1:c0af with SMTP id i7-20020a05640242c700b0045ca6f1c0afmr3764963edc.75.1666117356946; Tue, 18 Oct 2022 11:22:36 -0700 (PDT) Received: from nuc.i.gnoack.org ([2a02:168:633b:1:1e69:7aff:fe05:97e6]) by smtp.gmail.com with ESMTPSA id i18-20020a0564020f1200b00458a03203b1sm9358395eda.31.2022.10.18.11.22.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 18 Oct 2022 11:22:36 -0700 (PDT) From: =?utf-8?q?G=C3=BCnther_Noack?= To: linux-security-module@vger.kernel.org Cc: =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= , James Morris , Paul Moore , "Serge E . Hallyn" , linux-fsdevel@vger.kernel.org, Konstantin Meskhidze , Nathan Chancellor , =?utf-8?q?G=C3=BCnther_Noack?= Subject: [PATCH v10 10/11] samples/landlock: Extend sample tool to support LANDLOCK_ACCESS_FS_TRUNCATE Date: Tue, 18 Oct 2022 20:22:15 +0200 Message-Id: <20221018182216.301684-11-gnoack3000@gmail.com> X-Mailer: git-send-email 2.38.0 In-Reply-To: <20221018182216.301684-1-gnoack3000@gmail.com> References: <20221018182216.301684-1-gnoack3000@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: Update the sandboxer sample to restrict truncate actions. This is automatically enabled by default if the running kernel supports LANDLOCK_ACCESS_FS_TRUNCATE, except for the paths listed in the LL_FS_RW environment variable. Signed-off-by: Günther Noack --- samples/landlock/sandboxer.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/samples/landlock/sandboxer.c b/samples/landlock/sandboxer.c index f29bb3c72230..fd4237c64fb2 100644 --- a/samples/landlock/sandboxer.c +++ b/samples/landlock/sandboxer.c @@ -76,7 +76,8 @@ static int parse_path(char *env_path, const char ***const path_list) #define ACCESS_FILE ( \ LANDLOCK_ACCESS_FS_EXECUTE | \ LANDLOCK_ACCESS_FS_WRITE_FILE | \ - LANDLOCK_ACCESS_FS_READ_FILE) + LANDLOCK_ACCESS_FS_READ_FILE | \ + LANDLOCK_ACCESS_FS_TRUNCATE) /* clang-format on */ @@ -160,11 +161,12 @@ static int populate_ruleset(const char *const env_var, const int ruleset_fd, LANDLOCK_ACCESS_FS_MAKE_FIFO | \ LANDLOCK_ACCESS_FS_MAKE_BLOCK | \ LANDLOCK_ACCESS_FS_MAKE_SYM | \ - LANDLOCK_ACCESS_FS_REFER) + LANDLOCK_ACCESS_FS_REFER | \ + LANDLOCK_ACCESS_FS_TRUNCATE) /* clang-format on */ -#define LANDLOCK_ABI_LAST 2 +#define LANDLOCK_ABI_LAST 3 int main(const int argc, char *const argv[], char *const *const envp) { @@ -234,6 +236,10 @@ int main(const int argc, char *const argv[], char *const *const envp) case 1: /* Removes LANDLOCK_ACCESS_FS_REFER for ABI < 2 */ ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_REFER; + __attribute__((fallthrough)); + case 2: + /* Removes LANDLOCK_ACCESS_FS_TRUNCATE for ABI < 3 */ + ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_TRUNCATE; fprintf(stderr, "Hint: You should update the running kernel " From patchwork Tue Oct 18 18:22:16 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?G=C3=BCnther_Noack?= X-Patchwork-Id: 13010904 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 319FDC433FE for ; Tue, 18 Oct 2022 18:23:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229470AbiJRSXP (ORCPT ); Tue, 18 Oct 2022 14:23:15 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42614 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229886AbiJRSXH (ORCPT ); Tue, 18 Oct 2022 14:23:07 -0400 Received: from mail-ej1-x632.google.com (mail-ej1-x632.google.com [IPv6:2a00:1450:4864:20::632]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4576D83F04; Tue, 18 Oct 2022 11:22:39 -0700 (PDT) Received: by mail-ej1-x632.google.com with SMTP id ot12so34435706ejb.1; Tue, 18 Oct 2022 11:22:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=BCqE9e12XoBqA5RscNmFvGeITIorfGLdOj2bFbTji74=; b=Xh4SLMDAcfIHODE+7dLbrJE99J02JXGbPmWUTXjbs8GMNN+oGlJDBrBRpQJHJYrE04 Z49RCEvP0T7snGzhSK9WI1YIeujmUc9eC29I8V7SQp6l+SMXe6CsqlL8xsrH9vS5EC2U TiojafYGD1R/cUD+GakOvDyg5fOwaWDZSRdx0GyFhiLUVVOfWqob4E2CsZaBDdHA3rn5 tKB26ndirT9XiJeMs3ZOf30fDdTO2zi5hIvr5kBP04X9j5sl7bARJYbeGJLxOgmwwMu/ IjfbfAsgcc/73eZCs2dHsB65R9ofimrIpPubp3XuxU9R0cjqgLx/NM4UKgbOLFiCh9Ej bQ1Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=BCqE9e12XoBqA5RscNmFvGeITIorfGLdOj2bFbTji74=; b=DElvfuR0pC/NOysKHiHERZyeiytHAk8SBCnUq45nj+jK++LC9pTozaGcXPKzHsj8J6 xtEsInnZGq5d/hWyxGxh8EWWwK0NHqoySjTHrj50pyr31pHUpxJYZdwSMf7yRHxnjsZX D8B72IsMFKpQt32lwgBMm7RjgSSUksyMGWQYXs+DJgoIetgmOLq/joOWIPIhWtneoN13 MXg33PP4MeLDFauO39gsXOr/V3vHm01URPDL9EfMlBbUU4aZ8AP1l2B+HGdSZ4JIGTcK MWl8asskCLVLsdeRbWazlIK9zR9zjsHfA0L05s3vUi9wftPoZrXj7CAlNI3zXsEMXTt3 VOqw== X-Gm-Message-State: ACrzQf24RsLerjrtpvSlSK7pL0Kd+SjbzjOEczgDcRxNYP0QvUrDWNbE fPSwFkJ21udh3+G3VLX2Ftq4Ac9iAjc= X-Google-Smtp-Source: AMsMyM6ngBDuCs9bZkg2u2GgKTojp9eEeHWIMdrCpDs+kXycH9fYKxgTnyNd/cy175OLVRLHlGRJOA== X-Received: by 2002:a17:907:1c28:b0:78d:4616:e6b6 with SMTP id nc40-20020a1709071c2800b0078d4616e6b6mr3356096ejc.257.1666117357707; Tue, 18 Oct 2022 11:22:37 -0700 (PDT) Received: from nuc.i.gnoack.org ([2a02:168:633b:1:1e69:7aff:fe05:97e6]) by smtp.gmail.com with ESMTPSA id i18-20020a0564020f1200b00458a03203b1sm9358395eda.31.2022.10.18.11.22.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 18 Oct 2022 11:22:37 -0700 (PDT) From: =?utf-8?q?G=C3=BCnther_Noack?= To: linux-security-module@vger.kernel.org Cc: =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= , James Morris , Paul Moore , "Serge E . Hallyn" , linux-fsdevel@vger.kernel.org, Konstantin Meskhidze , Nathan Chancellor , =?utf-8?q?G=C3=BCnther_Noack?= Subject: [PATCH v10 11/11] landlock: Document Landlock's file truncation support Date: Tue, 18 Oct 2022 20:22:16 +0200 Message-Id: <20221018182216.301684-12-gnoack3000@gmail.com> X-Mailer: git-send-email 2.38.0 In-Reply-To: <20221018182216.301684-1-gnoack3000@gmail.com> References: <20221018182216.301684-1-gnoack3000@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: Use the LANDLOCK_ACCESS_FS_TRUNCATE flag in the tutorial. Adapt the backwards compatibility example and discussion to remove the truncation flag where needed. Point out potential surprising behaviour related to truncate. Signed-off-by: Günther Noack --- Documentation/userspace-api/landlock.rst | 67 +++++++++++++++++++++--- 1 file changed, 60 insertions(+), 7 deletions(-) diff --git a/Documentation/userspace-api/landlock.rst b/Documentation/userspace-api/landlock.rst index cec780c2f497..d8cd8cd9ce25 100644 --- a/Documentation/userspace-api/landlock.rst +++ b/Documentation/userspace-api/landlock.rst @@ -8,7 +8,7 @@ Landlock: unprivileged access control ===================================== :Author: Mickaël Salaün -:Date: September 2022 +:Date: October 2022 The goal of Landlock is to enable to restrict ambient rights (e.g. global filesystem access) for a set of processes. Because Landlock is a stackable @@ -60,7 +60,8 @@ the need to be explicit about the denied-by-default access rights. LANDLOCK_ACCESS_FS_MAKE_FIFO | LANDLOCK_ACCESS_FS_MAKE_BLOCK | LANDLOCK_ACCESS_FS_MAKE_SYM | - LANDLOCK_ACCESS_FS_REFER, + LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_TRUNCATE, }; Because we may not know on which kernel version an application will be @@ -69,16 +70,28 @@ should try to protect users as much as possible whatever the kernel they are using. To avoid binary enforcement (i.e. either all security features or none), we can leverage a dedicated Landlock command to get the current version of the Landlock ABI and adapt the handled accesses. Let's check if we should -remove the ``LANDLOCK_ACCESS_FS_REFER`` access right which is only supported -starting with the second version of the ABI. +remove the ``LANDLOCK_ACCESS_FS_REFER`` or ``LANDLOCK_ACCESS_FS_TRUNCATE`` +access rights, which are only supported starting with the second and third +version of the ABI. .. code-block:: c int abi; abi = landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION); - if (abi < 2) { + if (abi < 0) { + /* Degrades gracefully if Landlock is not handled. */ + perror("The running kernel does not enable to use Landlock"); + return 0; + } + switch (abi) { + case 1: + /* Removes LANDLOCK_ACCESS_FS_REFER for ABI < 2 */ ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_REFER; + __attribute__((fallthrough)); + case 2: + /* Removes LANDLOCK_ACCESS_FS_TRUNCATE for ABI < 3 */ + ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_TRUNCATE; } This enables to create an inclusive ruleset that will contain our rules. @@ -127,8 +140,8 @@ descriptor. It may also be required to create rules following the same logic as explained for the ruleset creation, by filtering access rights according to the Landlock -ABI version. In this example, this is not required because -``LANDLOCK_ACCESS_FS_REFER`` is not allowed by any rule. +ABI version. In this example, this is not required because all of the requested +``allowed_access`` rights are already available in ABI 1. We now have a ruleset with one rule allowing read access to ``/usr`` while denying all other handled accesses for the filesystem. The next step is to @@ -252,6 +265,37 @@ To be allowed to use :manpage:`ptrace(2)` and related syscalls on a target process, a sandboxed process should have a subset of the target process rules, which means the tracee must be in a sub-domain of the tracer. +Truncating files +---------------- + +The operations covered by ``LANDLOCK_ACCESS_FS_WRITE_FILE`` and +``LANDLOCK_ACCESS_FS_TRUNCATE`` both change the contents of a file and sometimes +overlap in non-intuitive ways. It is recommended to always specify both of +these together. + +A particularly surprising example is :manpage:`creat(2)`. The name suggests +that this system call requires the rights to create and write files. However, +it also requires the truncate right if an existing file under the same name is +already present. + +It should also be noted that truncating files does not require the +``LANDLOCK_ACCESS_FS_WRITE_FILE`` right. Apart from the :manpage:`truncate(2)` +system call, this can also be done through :manpage:`open(2)` with the flags +``O_RDONLY | O_TRUNC``. + +When opening a file, the availability of the ``LANDLOCK_ACCESS_FS_TRUNCATE`` +right is associated with the newly created file descriptor and will be used for +subsequent truncation attempts using :manpage:`ftruncate(2)`. The behavior is +similar to opening a file for reading or writing, where permissions are checked +during :manpage:`open(2)`, but not during the subsequent :manpage:`read(2)` and +:manpage:`write(2)` calls. + +As a consequence, it is possible to have multiple open file descriptors for the +same file, where one grants the right to truncate the file and the other does +not. It is also possible to pass such file descriptors between processes, +keeping their Landlock properties, even when these processes do not have an +enforced Landlock ruleset. + Compatibility ============= @@ -398,6 +442,15 @@ Starting with the Landlock ABI version 2, it is now possible to securely control renaming and linking thanks to the new ``LANDLOCK_ACCESS_FS_REFER`` access right. +File truncation (ABI < 3) +------------------------- + +File truncation could not be denied before the third Landlock ABI, so it is +always allowed when using a kernel that only supports the first or second ABI. + +Starting with the Landlock ABI version 3, it is now possible to securely control +truncation thanks to the new ``LANDLOCK_ACCESS_FS_TRUNCATE`` access right. + .. _kernel_support: Kernel support