From mboxrd@z Thu Jan 1 00:00:00 1970 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 850E3C04E69 for ; Thu, 10 Aug 2023 09:00:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232929AbjHJJAt (ORCPT ); Thu, 10 Aug 2023 05:00:49 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46914 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233007AbjHJJAs (ORCPT ); Thu, 10 Aug 2023 05:00:48 -0400 Received: from mail-vs1-xe2d.google.com (mail-vs1-xe2d.google.com [IPv6:2607:f8b0:4864:20::e2d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2A95A2686 for ; Thu, 10 Aug 2023 02:00:48 -0700 (PDT) Received: by mail-vs1-xe2d.google.com with SMTP id ada2fe7eead31-44768609e0bso290657137.0 for ; Thu, 10 Aug 2023 02:00:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sargun.me; s=google; t=1691658047; x=1692262847; 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=YxV+g6cPuWZGz1us/p/P3KzaSA95f9jXZ60+ia8kzG4=; b=NZtQXyZavyKjXJQlLCbLMp8JQx4Bv6vfUlOxfmeTF7HXbqEybjwKBO0L5ZZ/BxqmGd mzt0Ne7r3nJ3mRWcONk65SCwIoTpSuNvReJVwRHPsaXct5B834tiu8jHUjWc4eR8b/+u JTqTSYw7DwsoR2TBoOpaWDG8gR/R8eqGGMpm0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1691658047; x=1692262847; 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=YxV+g6cPuWZGz1us/p/P3KzaSA95f9jXZ60+ia8kzG4=; b=cOhPAniPJBIjM6ZbWsWrabR9kd1EnJVQfQbhdMJDSyu1X0f+pekSkwpMeqcp34/Hs8 trDscEpnH6ZvSLVC/FP49BFr9gl5v/LR30rDJKRvaGM+r/yp8ky92Lu9i2eJy0Eloy2V ZzTsIdgjU4I4BN4/xrkitf2ikyt9WSogpkPb75cdXFHJaG5PR7NGmc5zrUJZkYpPAnax O1qE85EVYKngo3dMycqo17FTgvE6+4g4VB4FGiyMzPLgY4mXU1hFOARuW2baNyKQ8pI6 HiSbdpk6+cV4kL+4e3hatzy/xv+9fpKeWUSBxtlRgrEys/lBu/wWowSyZsJj+KWyzxh/ pEtw== X-Gm-Message-State: AOJu0YzCDH9RBu3jwMnNo5PnXgk74LmDxZpWOCR6tIWGTHYoDrkKyKcm pF1McEVlELkJz2pnIwJR3iHiyPHeV1shXiAQ5Z8= X-Google-Smtp-Source: AGHT+IE7qwq6W9dMp9jYpbuNuY+FW2lZK7aXPCfjfJmPodbQRRlJpyd8iTgCZqA/OnGdWV3shelY2w== X-Received: by 2002:a05:6102:3bca:b0:443:7935:6eb5 with SMTP id a10-20020a0561023bca00b0044379356eb5mr1089841vsv.15.1691658047256; Thu, 10 Aug 2023 02:00:47 -0700 (PDT) Received: from localhost (fwdproxy-frc-020.fbsv.net. [2a03:2880:21ff:14::face:b00c]) by smtp.gmail.com with ESMTPSA id 207-20020a250bd8000000b00d1e6e93e8f5sm249600ybl.51.2023.08.10.02.00.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 10 Aug 2023 02:00:46 -0700 (PDT) From: Sargun Dhillon To: linux-fsdevel@vger.kernel.org, linux-api@vger.kernel.org Cc: Aleksa Sarai , Christoph Hellwig , Christian Brauner Subject: [PATCH 2/3] fs: Allow user to lock mount attributes with mount_setattr Date: Thu, 10 Aug 2023 02:00:43 -0700 Message-Id: <20230810090044.1252084-2-sargun@sargun.me> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20230810090044.1252084-1-sargun@sargun.me> References: <20230810090044.1252084-1-sargun@sargun.me> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-api@vger.kernel.org We support locking certain mount attributes in the kernel. This API isn't directly exposed to users. Right now, users can lock mount attributes by going through the process of creating a new user namespaces, and when the mounts are copied to the "lower privilege" domain, they're locked. The mount can be reopened, and passed around as a "locked mount". Locked mounts are useful, for example, in container execution without user namespaces, where you may want to expose some host data as read only without allowing the container to remount the mount as mutable. The API currently requires that the given privilege is taken away while or before locking the flag in the less privileged position. This could be relaxed in the future, where the user is allowed to remount the mount as read only, but once they do, they cannot make it read only again. Right now, this allows for all flags that are lockable via the userns unshare trick to be locked, other than the atime related ones. This is because the semantics of what the "less privileged" position is around the atime flags is unclear. Signed-off-by: Sargun Dhillon --- fs/namespace.c | 40 +++++++++++++++++++++++++++++++++++--- include/uapi/linux/mount.h | 2 ++ 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/fs/namespace.c b/fs/namespace.c index 54847db5b819..5396e544ac84 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -78,6 +78,7 @@ static LIST_HEAD(ex_mountpoints); /* protected by namespace_sem */ struct mount_kattr { unsigned int attr_set; unsigned int attr_clr; + unsigned int attr_lock; unsigned int propagation; unsigned int lookup_flags; bool recurse; @@ -3608,6 +3609,9 @@ SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, #define MOUNT_SETATTR_PROPAGATION_FLAGS \ (MS_UNBINDABLE | MS_PRIVATE | MS_SLAVE | MS_SHARED) +#define MOUNT_SETATTR_VALID_LOCK_FLAGS \ + (MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOSUID | MOUNT_ATTR_NODEV | \ + MOUNT_ATTR_NOEXEC) static unsigned int attr_flags_to_mnt_flags(u64 attr_flags) { @@ -3629,6 +3633,22 @@ static unsigned int attr_flags_to_mnt_flags(u64 attr_flags) return mnt_flags; } +static unsigned int attr_flags_to_mnt_lock_flags(u64 attr_flags) +{ + unsigned int mnt_flags = 0; + + if (attr_flags & MOUNT_ATTR_RDONLY) + mnt_flags |= MNT_LOCK_READONLY; + if (attr_flags & MOUNT_ATTR_NOSUID) + mnt_flags |= MNT_LOCK_NOSUID; + if (attr_flags & MOUNT_ATTR_NODEV) + mnt_flags |= MNT_LOCK_NODEV; + if (attr_flags & MOUNT_ATTR_NOEXEC) + mnt_flags |= MNT_LOCK_NOEXEC; + + return mnt_flags; +} + /* * Create a kernel mount representation for a new, prepared superblock * (specified by fs_fd) and attach to an open_tree-like file descriptor. @@ -4037,11 +4057,18 @@ static int mount_setattr_prepare(struct mount_kattr *kattr, struct mount *mnt) int err; for (m = mnt; m; m = next_mnt(m, mnt)) { - if (!can_change_locked_flags(m, recalc_flags(kattr, m))) { + int new_mount_flags = recalc_flags(kattr, m); + + if (!can_change_locked_flags(m, new_mount_flags)) { err = -EPERM; break; } + if ((new_mount_flags & kattr->attr_lock) != kattr->attr_lock) { + err = -EINVAL; + break; + } + err = can_idmap_mount(kattr, m); if (err) break; @@ -4278,8 +4305,14 @@ static int build_mount_kattr(const struct mount_attr *attr, size_t usize, if ((attr->attr_set | attr->attr_clr) & ~MOUNT_SETATTR_VALID_FLAGS) return -EINVAL; + if (attr->attr_lock & ~MOUNT_SETATTR_VALID_LOCK_FLAGS) + return -EINVAL; + kattr->attr_set = attr_flags_to_mnt_flags(attr->attr_set); kattr->attr_clr = attr_flags_to_mnt_flags(attr->attr_clr); + kattr->attr_lock = attr_flags_to_mnt_flags(attr->attr_lock); + kattr->attr_set |= attr_flags_to_mnt_lock_flags(attr->attr_lock); + /* * Since the MOUNT_ATTR_ values are an enum, not a bitmap, @@ -4337,7 +4370,7 @@ SYSCALL_DEFINE5(mount_setattr, int, dfd, const char __user *, path, struct mount_attr attr; struct mount_kattr kattr; - BUILD_BUG_ON(sizeof(struct mount_attr) != MOUNT_ATTR_SIZE_VER0); + BUILD_BUG_ON(sizeof(struct mount_attr) != MOUNT_ATTR_SIZE_VER1); if (flags & ~(AT_EMPTY_PATH | AT_RECURSIVE | @@ -4360,7 +4393,8 @@ SYSCALL_DEFINE5(mount_setattr, int, dfd, const char __user *, path, /* Don't bother walking through the mounts if this is a nop. */ if (attr.attr_set == 0 && attr.attr_clr == 0 && - attr.propagation == 0) + attr.propagation == 0 && + attr.attr_lock == 0) return 0; err = build_mount_kattr(&attr, usize, &kattr, flags); diff --git a/include/uapi/linux/mount.h b/include/uapi/linux/mount.h index 4d93967f8aea..de667c4f852d 100644 --- a/include/uapi/linux/mount.h +++ b/include/uapi/linux/mount.h @@ -131,9 +131,11 @@ struct mount_attr { __u64 attr_clr; __u64 propagation; __u64 userns_fd; + __u64 attr_lock; }; /* List of all mount_attr versions. */ #define MOUNT_ATTR_SIZE_VER0 32 /* sizeof first published struct */ +#define MOUNT_ATTR_SIZE_VER1 40 #endif /* _UAPI_LINUX_MOUNT_H */ -- 2.39.3