From patchwork Fri Oct 25 11:29:13 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miklos Szeredi X-Patchwork-Id: 11212089 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 16502139A for ; Fri, 25 Oct 2019 11:29:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id E7DAF21D71 for ; Fri, 25 Oct 2019 11:29:43 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="RjHJgVde" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2439236AbfJYL30 (ORCPT ); Fri, 25 Oct 2019 07:29:26 -0400 Received: from us-smtp-1.mimecast.com ([205.139.110.61]:20887 "EHLO us-smtp-delivery-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S2436520AbfJYL3Z (ORCPT ); Fri, 25 Oct 2019 07:29:25 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1572002964; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=I33B+0F6drNe2DO1ImWZrj95FAKHCL4hyPcaly3kasA=; b=RjHJgVdeoZqBNgfJFU0FQcr/g3cNGFS3xEn95OYh1qd4ToizDJYfKTLE/B2DCqLzNutVKR 74bVg0KLyYikFKblm18BumWhFHM1RBicaT/QGJrVDU0TAldDujIVWU0vW0Xc5YvzZwp4dA ZhIvaRi4yIrCARwH/8Ts0+hozfe3U7g= Received: from mail-wm1-f69.google.com (mail-wm1-f69.google.com [209.85.128.69]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-300-ShbkPrLyO2y6cfVYf5uNbA-1; Fri, 25 Oct 2019 07:29:23 -0400 Received: by mail-wm1-f69.google.com with SMTP id f2so579390wmf.8 for ; Fri, 25 Oct 2019 04:29:22 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=d8l72uHGzG6m6K3/bpmVJ/Qpjsjtmq+Lqod9QQYQlTc=; b=WC7ei+P6F7zx7Lppj5VmuKnSaRQL37aoDj+gCDFqcUlbioFG/lp0yghVA2sHwuST02 rE7j8pH5lnxEWmmWIfhb/u/vr2jRbkEsK7+fAimBJGDavyVp63L1u7lD0gb0JRsfqSQD +tVObiflhXbDOlFrZPd3pKf/71QHPLGZXmiAPhl87+UdSx+Jg/xBCojk9gAXbmbE+9VD GCqIAZhhPG1CjKMd4aHVr72df6H99IVg8sFNF3JhthYv6H6R7W4CGySPkxzNGjWCS1Ih MNhD+EcZS/a/VROY6iG+8CUPDNIYBeMKZSMo4fyzu/JaJQy3taVNMIhnvz5xhLL3GSyQ jBMQ== X-Gm-Message-State: APjAAAXTqRT+KqLFKIo1VlNb2p07UFJBPQthYadx5CnrO8ZXqT+jPqFb /2NeTE/dEjYIr4/vKJTPV+3w2gYl9JOw1WaFUJD5MlxdhAUrZo1tBNYiSYRZVSWTGPMAZiehYG7 nlJUf69poktISHeI5v9az5QjREQ== X-Received: by 2002:a5d:6b0e:: with SMTP id v14mr2525706wrw.280.1572002961876; Fri, 25 Oct 2019 04:29:21 -0700 (PDT) X-Google-Smtp-Source: APXvYqxPpQGXTNJrxLkgVezHj1T1jGuquL8GQd5mEOwUp11MWfS05ZJe9b8tNYouTGJhnrGVK8HvrQ== X-Received: by 2002:a5d:6b0e:: with SMTP id v14mr2525688wrw.280.1572002961667; Fri, 25 Oct 2019 04:29:21 -0700 (PDT) Received: from miu.piliscsaba.redhat.com (185-79-95-246.pool.digikabel.hu. [185.79.95.246]) by smtp.gmail.com with ESMTPSA id l18sm3974080wrn.48.2019.10.25.04.29.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 25 Oct 2019 04:29:20 -0700 (PDT) From: Miklos Szeredi To: "Eric W . Biederman" Cc: linux-unionfs@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [RFC PATCH 1/5] ovl: document permission model Date: Fri, 25 Oct 2019 13:29:13 +0200 Message-Id: <20191025112917.22518-2-mszeredi@redhat.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191025112917.22518-1-mszeredi@redhat.com> References: <20191025112917.22518-1-mszeredi@redhat.com> MIME-Version: 1.0 X-MC-Unique: ShbkPrLyO2y6cfVYf5uNbA-1 X-Mimecast-Spam-Score: 0 Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org Add missing piece of documentation regarding how permissions are checked in overlayfs. Signed-off-by: Miklos Szeredi --- Documentation/filesystems/overlayfs.txt | 44 +++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/Documentation/filesystems/overlayfs.txt b/Documentation/filesystems/overlayfs.txt index 845d689e0fd7..674fc8b1e420 100644 --- a/Documentation/filesystems/overlayfs.txt +++ b/Documentation/filesystems/overlayfs.txt @@ -246,6 +246,50 @@ overlay filesystem (though an operation on the name of the file such as rename or unlink will of course be noticed and handled). +Permission model +---------------- + +Permission checking in the overlay filesystem follows these principles: + + 1) permission check SHOULD return the same result before and after copy up + + 2) task creating the overlay mount MUST NOT gain additional privileges + + 3) non-mounting task MAY gain additional privileges through the overlay, + compared to direct access on underlying lower or upper filesystems + +This is achieved by performing two permission checks on each access + + a) check if current task is allowed access based on local DAC (owner, + group, mode and posix acl), as well as MAC checks + + b) check if mounting task would be allowed real operation on lower or + upper layer based on underlying filesystem permissions, again including + MAC checks + +Check (a) ensures consistency (1) since owner, group, mode and posix acls +are copied up. On the other hand it can result in server enforced +permissions (used by NFS, for example) being ignored (3). + +Check (b) ensures that no task gains permissions to underlying layers that +the mounting task does not have (2). This also means that it is possible +to create setups where the consistency rule (1) does not hold; normally, +however, the mounting task will have sufficient privileges to perform all +operations. + +Another way to demonstrate this model is drawing parallels between + + mount -t overlay overlay -olowerdir=/lower,upperdir=/upper,... /merged + +and + + cp -a /lower /upper + mount --bind /upper /merged + +The resulting access permissions should be the same. The difference is in +the time of copy (on-demand vs. up-front). + + Multiple lower layers --------------------- From patchwork Fri Oct 25 11:29:14 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miklos Szeredi X-Patchwork-Id: 11212083 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B32841515 for ; Fri, 25 Oct 2019 11:29:36 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 8C3CB21D82 for ; Fri, 25 Oct 2019 11:29:36 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="Q6u2zjlg" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2439598AbfJYL3d (ORCPT ); Fri, 25 Oct 2019 07:29:33 -0400 Received: from us-smtp-2.mimecast.com ([205.139.110.61]:29505 "EHLO us-smtp-delivery-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S2439519AbfJYL33 (ORCPT ); Fri, 25 Oct 2019 07:29:29 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1572002968; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=uWR0FeiNl3309mlO6E0ZvUU8kwY1OBQz216A0AG4Xw4=; b=Q6u2zjlgy4VLV48H+12870yZplfNLD6uzROzUQZpqCDNFuBW89zmP4prKJDm/QVqH1LqEs 7PeGUuY7iUiEgzKwtsAdv5pnCCbeEagNo0/KfePFfVNOIfD+xGnAgfp5u+SnKqtAxonMpm gsQCSn/t469CXjFuyjPTLPJsI+zN18E= Received: from mail-wr1-f69.google.com (mail-wr1-f69.google.com [209.85.221.69]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-330-SkdqhMS4McmnaZP-9x9p_g-1; Fri, 25 Oct 2019 07:29:24 -0400 Received: by mail-wr1-f69.google.com with SMTP id e14so912659wrm.21 for ; Fri, 25 Oct 2019 04:29:23 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=ECMzKToI8lUs7uXqHIyGRHyiocaJAiDHNlfvJlo41SA=; b=Po31U2fHdfvOeODlQsv+KZuPZQ3o/Pm5fblf+9cg2xX4lttyyCHhS9eP1HdPqffiNh Lo0eA0KXOFolHIKQmbBYfmIvWtlI/LXMRAnZWD/SwOaHi+yEQ3ZbFuJEEag8nw+JItMq JGEztuAWbMAEAGt3XUh2YuAxYienkvDJ6lg3BxbLET7p21joF0Re9ondeffbMtbIcko1 nMklSG7dvvHdJFkZW2r83X2rClRDwgVjZ0wyWf9ALas6tMeHyNf+QbjPDDw0jkAGwBAk EFhkS9jQmRba+xC4j1fm/pWV55t2pFY3YUi1DMBXqgXq3PX/Bgch0TTVA5ntl4Zm5cTU psQw== X-Gm-Message-State: APjAAAXUely/H+tbPIjp/ZaSS0QN7WROHqSRCSxGmOAaFQ6uCKtl4Zr8 QKq9zo8qzuXdkuYQOcOQjHtSvf9j3cgBlHkodib2l41DKZgygFoxZczfgF2HfImN7w9sdiHuZBS 2809CcNzkaPPa0aoppQp5PtQaWg== X-Received: by 2002:a5d:4945:: with SMTP id r5mr2503168wrs.37.1572002962863; Fri, 25 Oct 2019 04:29:22 -0700 (PDT) X-Google-Smtp-Source: APXvYqxxZN9Mnc+StD4TaIv7j6jidJ6uc4Izr0imiWOZEmOA/aRp1o/R0zlvUyoK2S2AsyuHVsjk0Q== X-Received: by 2002:a5d:4945:: with SMTP id r5mr2503154wrs.37.1572002962677; Fri, 25 Oct 2019 04:29:22 -0700 (PDT) Received: from miu.piliscsaba.redhat.com (185-79-95-246.pool.digikabel.hu. [185.79.95.246]) by smtp.gmail.com with ESMTPSA id l18sm3974080wrn.48.2019.10.25.04.29.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 25 Oct 2019 04:29:22 -0700 (PDT) From: Miklos Szeredi To: "Eric W . Biederman" Cc: linux-unionfs@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [RFC PATCH 2/5] ovl: ignore failure to copy up unknown xattrs Date: Fri, 25 Oct 2019 13:29:14 +0200 Message-Id: <20191025112917.22518-3-mszeredi@redhat.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191025112917.22518-1-mszeredi@redhat.com> References: <20191025112917.22518-1-mszeredi@redhat.com> MIME-Version: 1.0 X-MC-Unique: SkdqhMS4McmnaZP-9x9p_g-1 X-Mimecast-Spam-Score: 0 Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org This issue came up with NFSv4 as the lower layer, which generates "system.nfs4_acl" xattrs (even for plain old unix permissions). Prior to this patch this prevented copy-up from succeeding. The overlayfs permission model mandates that permissions are checked locally for the task and remotely for the mounter(*). NFS4 ACLs are not supported by the Linux kernel currently, hence they cannot be enforced locally. Which means it is indifferent whether this attribute is copied or not. Generalize this to any xattr that is not used in access checking (i.e. it's not a POSIX ACL and not in the "security." namespace). Incidentally, best effort copying of xattrs seems to also be the behavior of "cp -a", which is what overlayfs tries to mimic. (*) Documentation/filesystems/overlayfs.txt#Permission model Signed-off-by: Miklos Szeredi --- fs/overlayfs/copy_up.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index b801c6353100..ed6e2d6cf7a1 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c @@ -36,6 +36,13 @@ static int ovl_ccup_get(char *buf, const struct kernel_param *param) module_param_call(check_copy_up, ovl_ccup_set, ovl_ccup_get, NULL, 0644); MODULE_PARM_DESC(check_copy_up, "Obsolete; does nothing"); +static bool ovl_must_copy_xattr(const char *name) +{ + return !strcmp(name, XATTR_POSIX_ACL_ACCESS) || + !strcmp(name, XATTR_POSIX_ACL_DEFAULT) || + !strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN); +} + int ovl_copy_xattr(struct dentry *old, struct dentry *new) { ssize_t list_size, size, value_size = 0; @@ -107,8 +114,13 @@ int ovl_copy_xattr(struct dentry *old, struct dentry *new) continue; /* Discard */ } error = vfs_setxattr(new, name, value, size, 0); - if (error) - break; + if (error) { + if (error != -EOPNOTSUPP || ovl_must_copy_xattr(name)) + break; + + /* Ignore failure to copy unknown xattrs */ + error = 0; + } } kfree(value); out: From patchwork Fri Oct 25 11:29:15 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miklos Szeredi X-Patchwork-Id: 11212081 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 835D2139A for ; Fri, 25 Oct 2019 11:29:36 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 562D621D71 for ; Fri, 25 Oct 2019 11:29:36 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="Yki28Swl" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2439530AbfJYL33 (ORCPT ); Fri, 25 Oct 2019 07:29:29 -0400 Received: from us-smtp-delivery-1.mimecast.com ([207.211.31.120]:58629 "EHLO us-smtp-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S2439401AbfJYL32 (ORCPT ); Fri, 25 Oct 2019 07:29:28 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1572002967; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=QILxa7RqQYQ4IyTulj5DZou1wI9mDMu/Shz+xSIroTs=; b=Yki28SwlpvgPoa8bOoQUGKeyPe2xwwUdZxgqwPyI50c70/m6N9AOwvCimUmF+ennc4iGSj qjqb/XBOEoizRHEqV6/w/QU5oHffM/o3hBe723YTmn/TGdltYQyFNeKdm8wIoWa7XaEwA0 sP1sTPdEAMO7D5wW+JlpBg1Rj5NBve4= Received: from mail-wr1-f71.google.com (mail-wr1-f71.google.com [209.85.221.71]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-281-hpaFzZRbOl6mklP6nqksVA-1; Fri, 25 Oct 2019 07:29:25 -0400 Received: by mail-wr1-f71.google.com with SMTP id z9so925610wrq.11 for ; Fri, 25 Oct 2019 04:29:24 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=+mLHdhKK+RTjZWJLR+Q9KPjFkxVfyw86WO5G8timrLo=; b=J+Wl+Tvd75wlOCnWzriFi4KG+W/mzuGIeEC7DcgB8WY9/G+NfXGITpc/0t8nC6POwR E2iQE2tFD8gRTxjB4DKKf9iAFNqC0rJbrykQQiBBlVOEJT5d68ckEow25iIBE9gjrxWN YjD1GY6fN/LQfbUq3Hhg2v9zMx+eUmm2uRTW4WPgMJW4hxd4ZoLkMv+fwQoUWXyjpBjH 6xycGudVe0Xc9/NTipLBwH4FYmpqvlhZrRiUl6EebGZHHVs+csqN0DoT9lTjgw5UAldA wf7A7QELALW2gZUAo3USyjP5/iSm1LpiYVR6Hhgo1OiaRVLfx/j8C5DXjXr+/PTFAWpc PfQw== X-Gm-Message-State: APjAAAWBFjbioxG98xC/5NJh48xIB7lqHSVeNTglNwuyp2dUL+EHNHLa 4hcfN2UXD2iSEiXTk2we2in9YTXaovqZZejpnES1Lw+8DpCdyZieidyhusX+fSnf9dY7MLSDAeZ 86dcZKeFNdXFLjtocaKwSKOGDlA== X-Received: by 2002:adf:9b9d:: with SMTP id d29mr2584472wrc.293.1572002963916; Fri, 25 Oct 2019 04:29:23 -0700 (PDT) X-Google-Smtp-Source: APXvYqw9N9CexvOHs1/1Nl23PU+f1edkwgpoJUCwGjuUM8lfcClQyivxqq8K4S/lkAW8ZRb5gVH90Q== X-Received: by 2002:adf:9b9d:: with SMTP id d29mr2584455wrc.293.1572002963729; Fri, 25 Oct 2019 04:29:23 -0700 (PDT) Received: from miu.piliscsaba.redhat.com (185-79-95-246.pool.digikabel.hu. [185.79.95.246]) by smtp.gmail.com with ESMTPSA id l18sm3974080wrn.48.2019.10.25.04.29.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 25 Oct 2019 04:29:23 -0700 (PDT) From: Miklos Szeredi To: "Eric W . Biederman" Cc: linux-unionfs@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [RFC PATCH 3/5] vfs: allow unprivileged whiteout creation Date: Fri, 25 Oct 2019 13:29:15 +0200 Message-Id: <20191025112917.22518-4-mszeredi@redhat.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191025112917.22518-1-mszeredi@redhat.com> References: <20191025112917.22518-1-mszeredi@redhat.com> MIME-Version: 1.0 X-MC-Unique: hpaFzZRbOl6mklP6nqksVA-1 X-Mimecast-Spam-Score: 0 Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org Whiteouts are special, but unlike real device nodes they should not require privileges to create. The 0 char device number should already be reserved, but make this explicit in cdev_add() to be on the safe side. Signed-off-by: Miklos Szeredi --- fs/char_dev.c | 3 +++ fs/namei.c | 17 ++++------------- include/linux/device_cgroup.h | 3 +++ 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/fs/char_dev.c b/fs/char_dev.c index 00dfe17871ac..8bf66f40e5e0 100644 --- a/fs/char_dev.c +++ b/fs/char_dev.c @@ -483,6 +483,9 @@ int cdev_add(struct cdev *p, dev_t dev, unsigned count) p->dev = dev; p->count = count; + if (WARN_ON(dev == WHITEOUT_DEV)) + return -EBUSY; + error = kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p); if (error) diff --git a/fs/namei.c b/fs/namei.c index 671c3c1a3425..05ca98595b62 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -3687,12 +3687,14 @@ EXPORT_SYMBOL(user_path_create); int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) { + bool is_whiteout = S_ISCHR(mode) && dev == WHITEOUT_DEV; int error = may_create(dir, dentry); if (error) return error; - if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD)) + if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD) && + !is_whiteout) return -EPERM; if (!dir->i_op->mknod) @@ -4527,9 +4529,6 @@ static int do_renameat2(int olddfd, const char __user *oldname, int newdfd, (flags & RENAME_EXCHANGE)) return -EINVAL; - if ((flags & RENAME_WHITEOUT) && !capable(CAP_MKNOD)) - return -EPERM; - if (flags & RENAME_EXCHANGE) target_flags = 0; @@ -4667,15 +4666,7 @@ SYSCALL_DEFINE2(rename, const char __user *, oldname, const char __user *, newna int vfs_whiteout(struct inode *dir, struct dentry *dentry) { - int error = may_create(dir, dentry); - if (error) - return error; - - if (!dir->i_op->mknod) - return -EPERM; - - return dir->i_op->mknod(dir, dentry, - S_IFCHR | WHITEOUT_MODE, WHITEOUT_DEV); + return vfs_mknod(dir, dentry, S_IFCHR | WHITEOUT_MODE, WHITEOUT_DEV); } EXPORT_SYMBOL(vfs_whiteout); diff --git a/include/linux/device_cgroup.h b/include/linux/device_cgroup.h index 8557efe096dc..fc989487c273 100644 --- a/include/linux/device_cgroup.h +++ b/include/linux/device_cgroup.h @@ -62,6 +62,9 @@ static inline int devcgroup_inode_mknod(int mode, dev_t dev) if (!S_ISBLK(mode) && !S_ISCHR(mode)) return 0; + if (S_ISCHR(mode) && dev == WHITEOUT_DEV) + return 0; + if (S_ISBLK(mode)) type = DEVCG_DEV_BLOCK; else From patchwork Fri Oct 25 11:29:16 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miklos Szeredi X-Patchwork-Id: 11212087 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 71FFF139A for ; Fri, 25 Oct 2019 11:29:39 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 322772070B for ; Fri, 25 Oct 2019 11:29:39 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="ep2tuKgC" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2501903AbfJYL3i (ORCPT ); Fri, 25 Oct 2019 07:29:38 -0400 Received: from us-smtp-2.mimecast.com ([205.139.110.61]:48866 "EHLO us-smtp-delivery-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S2439673AbfJYL3h (ORCPT ); Fri, 25 Oct 2019 07:29:37 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1572002974; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=UyrGPcKuXCpaWbrTq1rNsPhkOP4DpMOavc/jNfhdSsQ=; b=ep2tuKgCVNkUcZ6C4Htv5sBpchE9EON1Re8EPciMh8w8jgTDp285I+DElE+5pUGAYPcxWW xVmu7hUmiaZZe8MdfwAxCfapUQhtEn0fNNgpzQVCo9K3bso4CZNPTwaWFODUF0W6Ycmlkb basoar1nXj5kms+NQyWSE4hrLH4chXI= Received: from mail-wr1-f72.google.com (mail-wr1-f72.google.com [209.85.221.72]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-360-zwV7zNVIO4OlsuIReomdbg-1; Fri, 25 Oct 2019 07:29:27 -0400 Received: by mail-wr1-f72.google.com with SMTP id e14so912728wrm.21 for ; Fri, 25 Oct 2019 04:29:27 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=ERGnjFEQ8XEB9SBe97EFYt7XL75LKIU0O5Ymd9oarIE=; b=Mk9WT71HzFT+zFy/rS5sJKt+s+hG2GdOGkYw2S9VTzmhLW+Yd8BfL9koOz+ih+kGNW kBRILX4kqtGa6uGSZPuLBF1VVq84WjSmfV9uLo9vulBw3EvKdmE5jJDmjqEuNhzj5VI+ zakT5uv9rCIlaQY84KScWHwc3fPkY0P1drHYUwCwRPXoiduPLk8ci52sGSiqWthjcJdi 4gAz+x6VsBfHSW1F4QtpPYwQTj9xPDlqQyElAC/+ukideXvYVjA2tmuZeFUkn52zajbJ K8Vi81Jl46k0mR7Z6ckj80aSk/39X7lpuP1GOMAsrBn/Z4ARWRkgF/g8OV9P267W00Ac AsFw== X-Gm-Message-State: APjAAAWh83m+YAdbpkjKWJbHXsN2XDliAVOdA04cFbA56XjiqS0phPGl 8oT42hMb8mqUXY4kQppZ5JMwGkUbiyVuXqHjbl2mcGr+NE6jvPOlgrL2YPITx7X8QJeE/YDIZ3l w84OOi6itviDzNNuOZG2n3scTFQ== X-Received: by 2002:adf:fcc7:: with SMTP id f7mr2606657wrs.345.1572002965899; Fri, 25 Oct 2019 04:29:25 -0700 (PDT) X-Google-Smtp-Source: APXvYqzHTWJ+6JNVF2tZGyn1bS20ZPstuF8Bkvy0DQcVZbW9k6p2XSaSr2OEvpJDfp/yoldN4R/X2g== X-Received: by 2002:adf:fcc7:: with SMTP id f7mr2606588wrs.345.1572002964864; Fri, 25 Oct 2019 04:29:24 -0700 (PDT) Received: from miu.piliscsaba.redhat.com (185-79-95-246.pool.digikabel.hu. [185.79.95.246]) by smtp.gmail.com with ESMTPSA id l18sm3974080wrn.48.2019.10.25.04.29.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 25 Oct 2019 04:29:24 -0700 (PDT) From: Miklos Szeredi To: "Eric W . Biederman" Cc: linux-unionfs@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [RFC PATCH 4/5] ovl: user xattr Date: Fri, 25 Oct 2019 13:29:16 +0200 Message-Id: <20191025112917.22518-5-mszeredi@redhat.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191025112917.22518-1-mszeredi@redhat.com> References: <20191025112917.22518-1-mszeredi@redhat.com> MIME-Version: 1.0 X-MC-Unique: zwV7zNVIO4OlsuIReomdbg-1 X-Mimecast-Spam-Score: 0 Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org Optionally allow using "user.overlay" namespace instead of"trusted.overlay". This is necessary for overlayfs to be able to be mounted in an unprivileged namepsace. Make the option explicit, since it makes the filesystem format be incompatible. Signed-off-by: Miklos Szeredi --- fs/overlayfs/copy_up.c | 18 +++++---- fs/overlayfs/dir.c | 2 +- fs/overlayfs/export.c | 2 +- fs/overlayfs/inode.c | 39 +++++++++---------- fs/overlayfs/namei.c | 56 ++++++++++++++------------- fs/overlayfs/overlayfs.h | 81 +++++++++++++++++++++++++-------------- fs/overlayfs/ovl_entry.h | 1 + fs/overlayfs/readdir.c | 5 ++- fs/overlayfs/super.c | 52 ++++++++++++++++++------- fs/overlayfs/util.c | 82 ++++++++++++++++++++++++++++++++++------ 10 files changed, 229 insertions(+), 109 deletions(-) diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index ed6e2d6cf7a1..a1896ce25d35 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c @@ -43,7 +43,8 @@ static bool ovl_must_copy_xattr(const char *name) !strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN); } -int ovl_copy_xattr(struct dentry *old, struct dentry *new) +int ovl_copy_xattr(struct super_block *sb, struct dentry *old, + struct dentry *new) { ssize_t list_size, size, value_size = 0; char *buf, *name, *value = NULL; @@ -81,7 +82,7 @@ int ovl_copy_xattr(struct dentry *old, struct dentry *new) } list_size -= slen; - if (ovl_is_private_xattr(name)) + if (ovl_is_private_xattr(sb, name)) continue; retry: size = vfs_getxattr(old, name, value, value_size); @@ -320,7 +321,8 @@ int ovl_set_origin(struct dentry *dentry, struct dentry *lower, } /* Store file handle of @upper dir in @index dir entry */ -static int ovl_set_upper_fh(struct dentry *upper, struct dentry *index) +static int ovl_set_upper_fh(struct ovl_fs *ofs, struct dentry *upper, + struct dentry *index) { const struct ovl_fh *fh; int err; @@ -329,7 +331,7 @@ static int ovl_set_upper_fh(struct dentry *upper, struct dentry *index) if (IS_ERR(fh)) return PTR_ERR(fh); - err = ovl_do_setxattr(index, OVL_XATTR_UPPER, fh, fh->len, 0); + err = ovl_own_setxattr(ofs, index, OVL_XATTR_UPPER, fh, fh->len); kfree(fh); return err; @@ -343,6 +345,7 @@ static int ovl_set_upper_fh(struct dentry *upper, struct dentry *index) static int ovl_create_index(struct dentry *dentry, struct dentry *origin, struct dentry *upper) { + struct ovl_fs *ofs = dentry->d_sb->s_fs_info; struct dentry *indexdir = ovl_indexdir(dentry->d_sb); struct inode *dir = d_inode(indexdir); struct dentry *index = NULL; @@ -374,7 +377,7 @@ static int ovl_create_index(struct dentry *dentry, struct dentry *origin, if (IS_ERR(temp)) goto free_name; - err = ovl_set_upper_fh(upper, temp); + err = ovl_set_upper_fh(ofs, upper, temp); if (err) goto out; @@ -470,7 +473,7 @@ static int ovl_copy_up_inode(struct ovl_copy_up_ctx *c, struct dentry *temp) return err; } - err = ovl_copy_xattr(c->lowerpath.dentry, temp); + err = ovl_copy_xattr(c->dentry->d_sb, c->lowerpath.dentry, temp); if (err) return err; @@ -749,6 +752,7 @@ static bool ovl_need_meta_copy_up(struct dentry *dentry, umode_t mode, /* Copy up data of an inode which was copied up metadata only in the past. */ static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c) { + struct ovl_fs *ofs = c->dentry->d_sb->s_fs_info; struct path upperpath, datapath; int err; char *capability = NULL; @@ -785,7 +789,7 @@ static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c) } - err = vfs_removexattr(upperpath.dentry, OVL_XATTR_METACOPY); + err = ovl_own_removexattr(ofs, upperpath.dentry, OVL_XATTR_METACOPY); if (err) goto out_free; diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index 702aa63f6774..17ffaa67fdb3 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c @@ -365,7 +365,7 @@ static struct dentry *ovl_clear_empty(struct dentry *dentry, if (IS_ERR(opaquedir)) goto out_unlock; - err = ovl_copy_xattr(upper, opaquedir); + err = ovl_copy_xattr(dentry->d_sb, upper, opaquedir); if (err) goto out_cleanup; diff --git a/fs/overlayfs/export.c b/fs/overlayfs/export.c index 73c9775215b3..5cdcd42c6280 100644 --- a/fs/overlayfs/export.c +++ b/fs/overlayfs/export.c @@ -759,7 +759,7 @@ static struct dentry *ovl_lower_fh_to_d(struct super_block *sb, goto out_err; } if (index) { - err = ovl_verify_origin(index, origin.dentry, false); + err = ovl_verify_origin(ofs, index, origin.dentry, false); if (err) goto out_err; } diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index bc14781886bf..bf15ce4081ba 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -312,12 +312,6 @@ static const char *ovl_get_link(struct dentry *dentry, return p; } -bool ovl_is_private_xattr(const char *name) -{ - return strncmp(name, OVL_XATTR_PREFIX, - sizeof(OVL_XATTR_PREFIX) - 1) == 0; -} - int ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char *name, const void *value, size_t size, int flags) { @@ -376,15 +370,18 @@ int ovl_xattr_get(struct dentry *dentry, struct inode *inode, const char *name, return res; } -static bool ovl_can_list(const char *s) +static bool ovl_can_list(struct super_block *sb, const char *s) { + /* Never list private (.overlay) */ + if (ovl_is_private_xattr(sb, s)) + return false; + /* List all non-trusted xatts */ if (strncmp(s, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) != 0) return true; - /* Never list trusted.overlay, list other trusted for superuser only */ - return !ovl_is_private_xattr(s) && - ns_capable_noaudit(&init_user_ns, CAP_SYS_ADMIN); + /* list other trusted for superuser only */ + return ns_capable_noaudit(&init_user_ns, CAP_SYS_ADMIN); } ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size) @@ -410,7 +407,7 @@ ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size) return -EIO; len -= slen; - if (!ovl_can_list(s)) { + if (!ovl_can_list(dentry->d_sb, s)) { res -= slen; memmove(s, s + slen, len); } else { @@ -635,6 +632,7 @@ static int ovl_set_nlink_common(struct dentry *dentry, { struct inode *inode = d_inode(dentry); struct inode *realinode = d_inode(realdentry); + struct ovl_fs *ofs = inode->i_sb->s_fs_info; char buf[13]; int len; @@ -644,8 +642,8 @@ static int ovl_set_nlink_common(struct dentry *dentry, if (WARN_ON(len >= sizeof(buf))) return -EIO; - return ovl_do_setxattr(ovl_dentry_upper(dentry), - OVL_XATTR_NLINK, buf, len, 0); + return ovl_own_setxattr(ofs, ovl_dentry_upper(dentry), + OVL_XATTR_NLINK, buf, len); } int ovl_set_nlink_upper(struct dentry *dentry) @@ -658,7 +656,7 @@ int ovl_set_nlink_lower(struct dentry *dentry) return ovl_set_nlink_common(dentry, ovl_dentry_lower(dentry), "L%+i"); } -unsigned int ovl_get_nlink(struct dentry *lowerdentry, +unsigned int ovl_get_nlink(struct ovl_fs *ofs, struct dentry *lowerdentry, struct dentry *upperdentry, unsigned int fallback) { @@ -670,7 +668,8 @@ unsigned int ovl_get_nlink(struct dentry *lowerdentry, if (!lowerdentry || !upperdentry || d_inode(lowerdentry)->i_nlink == 1) return fallback; - err = vfs_getxattr(upperdentry, OVL_XATTR_NLINK, &buf, sizeof(buf) - 1); + err = ovl_own_getxattr(ofs, upperdentry, OVL_XATTR_NLINK, + &buf, sizeof(buf) - 1); if (err < 0) goto fail; @@ -868,6 +867,7 @@ static struct inode *ovl_iget5(struct super_block *sb, struct inode *newinode, struct inode *ovl_get_inode(struct super_block *sb, struct ovl_inode_params *oip) { + struct ovl_fs *ofs = sb->s_fs_info; struct dentry *upperdentry = oip->upperdentry; struct ovl_path *lowerpath = oip->lowerpath; struct inode *realinode = upperdentry ? d_inode(upperdentry) : NULL; @@ -915,7 +915,8 @@ struct inode *ovl_get_inode(struct super_block *sb, /* Recalculate nlink for non-dir due to indexing */ if (!is_dir) - nlink = ovl_get_nlink(lowerdentry, upperdentry, nlink); + nlink = ovl_get_nlink(ofs, lowerdentry, upperdentry, + nlink); set_nlink(inode, nlink); ino = key->i_ino; } else { @@ -929,14 +930,14 @@ struct inode *ovl_get_inode(struct super_block *sb, ovl_fill_inode(inode, realinode->i_mode, realinode->i_rdev, ino, fsid); ovl_inode_init(inode, upperdentry, lowerdentry, oip->lowerdata); - if (upperdentry && ovl_is_impuredir(upperdentry)) + if (upperdentry && ovl_is_impuredir(sb, upperdentry)) ovl_set_flag(OVL_IMPURE, inode); if (oip->index) ovl_set_flag(OVL_INDEX, inode); if (upperdentry) { - err = ovl_check_metacopy_xattr(upperdentry); + err = ovl_check_metacopy_xattr(ofs, upperdentry); if (err < 0) goto out_err; metacopy = err; @@ -952,7 +953,7 @@ struct inode *ovl_get_inode(struct super_block *sb, /* Check for non-merge dir that may have whiteouts */ if (is_dir) { if (((upperdentry && lowerdentry) || oip->numlower > 1) || - ovl_check_origin_xattr(upperdentry ?: lowerdentry)) { + ovl_check_origin_xattr(ofs, upperdentry ?: lowerdentry)) { ovl_set_flag(OVL_WHITEOUTS, inode); } } diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c index e9717c2f7d45..34712bd0cd3f 100644 --- a/fs/overlayfs/namei.c +++ b/fs/overlayfs/namei.c @@ -30,8 +30,9 @@ static int ovl_check_redirect(struct dentry *dentry, struct ovl_lookup_data *d, { int res; char *buf; + struct ovl_fs *ofs = d->sb->s_fs_info; - buf = ovl_get_redirect_xattr(dentry, prelen + strlen(post)); + buf = ovl_get_redirect_xattr(ofs, dentry, prelen + strlen(post)); if (IS_ERR_OR_NULL(buf)) return PTR_ERR(buf); @@ -104,12 +105,13 @@ int ovl_check_fh_len(struct ovl_fh *fh, int fh_len) return 0; } -static struct ovl_fh *ovl_get_fh(struct dentry *dentry, const char *name) +static struct ovl_fh *ovl_get_fh(struct ovl_fs *ofs, struct dentry *dentry, + enum ovl_xattr ox) { int res, err; struct ovl_fh *fh = NULL; - res = vfs_getxattr(dentry, name, NULL, 0); + res = ovl_own_getxattr(ofs, dentry, ox, NULL, 0); if (res < 0) { if (res == -ENODATA || res == -EOPNOTSUPP) return NULL; @@ -123,7 +125,7 @@ static struct ovl_fh *ovl_get_fh(struct dentry *dentry, const char *name) if (!fh) return ERR_PTR(-ENOMEM); - res = vfs_getxattr(dentry, name, fh, res); + res = ovl_own_getxattr(ofs, dentry, ox, fh, res); if (res < 0) goto fail; @@ -186,9 +188,9 @@ struct dentry *ovl_decode_real_fh(struct ovl_fh *fh, struct vfsmount *mnt, return real; } -static bool ovl_is_opaquedir(struct dentry *dentry) +static bool ovl_is_opaquedir(struct super_block *sb, struct dentry *dentry) { - return ovl_check_dir_xattr(dentry, OVL_XATTR_OPAQUE); + return ovl_check_dir_xattr(sb, dentry, OVL_XATTR_OPAQUE); } static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d, @@ -196,6 +198,7 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d, size_t prelen, const char *post, struct dentry **ret) { + struct ovl_fs *ofs = d->sb->s_fs_info; struct dentry *this; int err; bool last_element = !post[0]; @@ -233,7 +236,7 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d, d->stop = true; goto put_and_out; } - err = ovl_check_metacopy_xattr(this); + err = ovl_check_metacopy_xattr(ofs, this); if (err < 0) goto out_err; @@ -253,7 +256,7 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d, if (d->last) goto out; - if (ovl_is_opaquedir(this)) { + if (ovl_is_opaquedir(d->sb, this)) { d->stop = true; if (last_element) d->opaque = true; @@ -364,7 +367,7 @@ int ovl_check_origin_fh(struct ovl_fs *ofs, struct ovl_fh *fh, bool connected, static int ovl_check_origin(struct ovl_fs *ofs, struct dentry *upperdentry, struct ovl_path **stackp, unsigned int *ctrp) { - struct ovl_fh *fh = ovl_get_fh(upperdentry, OVL_XATTR_ORIGIN); + struct ovl_fh *fh = ovl_get_fh(ofs, upperdentry, OVL_XATTR_ORIGIN); int err; if (IS_ERR_OR_NULL(fh)) @@ -390,10 +393,10 @@ static int ovl_check_origin(struct ovl_fs *ofs, struct dentry *upperdentry, * Verify that @fh matches the file handle stored in xattr @name. * Return 0 on match, -ESTALE on mismatch, < 0 on error. */ -static int ovl_verify_fh(struct dentry *dentry, const char *name, - const struct ovl_fh *fh) +static int ovl_verify_fh(struct ovl_fs *ofs, struct dentry *dentry, + enum ovl_xattr ox, const struct ovl_fh *fh) { - struct ovl_fh *ofh = ovl_get_fh(dentry, name); + struct ovl_fh *ofh = ovl_get_fh(ofs, dentry, ox); int err = 0; if (!ofh) @@ -417,8 +420,9 @@ static int ovl_verify_fh(struct dentry *dentry, const char *name, * * Return 0 on match, -ESTALE on mismatch, -ENODATA on no xattr, < 0 on error. */ -int ovl_verify_set_fh(struct dentry *dentry, const char *name, - struct dentry *real, bool is_upper, bool set) +int ovl_verify_set_fh(struct ovl_fs *ofs, struct dentry *dentry, + enum ovl_xattr ox, struct dentry *real, bool is_upper, + bool set) { struct inode *inode; struct ovl_fh *fh; @@ -431,9 +435,9 @@ int ovl_verify_set_fh(struct dentry *dentry, const char *name, goto fail; } - err = ovl_verify_fh(dentry, name, fh); + err = ovl_verify_fh(ofs, dentry, ox, fh); if (set && err == -ENODATA) - err = ovl_do_setxattr(dentry, name, fh, fh->len, 0); + err = ovl_own_setxattr(ofs, dentry, ox, fh, fh->len); if (err) goto fail; @@ -458,7 +462,7 @@ struct dentry *ovl_index_upper(struct ovl_fs *ofs, struct dentry *index) if (!d_is_dir(index)) return dget(index); - fh = ovl_get_fh(index, OVL_XATTR_UPPER); + fh = ovl_get_fh(ofs, index, OVL_XATTR_UPPER); if (IS_ERR_OR_NULL(fh)) return ERR_CAST(fh); @@ -562,7 +566,7 @@ int ovl_verify_index(struct ovl_fs *ofs, struct dentry *index) goto fail; } - err = ovl_verify_fh(upper, OVL_XATTR_ORIGIN, fh); + err = ovl_verify_fh(ofs, upper, OVL_XATTR_ORIGIN, fh); dput(upper); if (err) goto fail; @@ -573,7 +577,7 @@ int ovl_verify_index(struct ovl_fs *ofs, struct dentry *index) if (err) goto fail; - if (ovl_get_nlink(origin.dentry, index, 0) == 0) + if (ovl_get_nlink(ofs, origin.dentry, index, 0) == 0) goto orphan; } @@ -733,7 +737,7 @@ struct dentry *ovl_lookup_index(struct ovl_fs *ofs, struct dentry *upper, } /* Verify that dir index 'upper' xattr points to upper dir */ - err = ovl_verify_upper(index, upper, false); + err = ovl_verify_upper(ofs, index, upper, false); if (err) { if (err == -ESTALE) { pr_warn_ratelimited("overlayfs: suspected multiply redirected dir found (upper=%pd2, origin=%pd2, index=%pd2).\n", @@ -782,12 +786,12 @@ int ovl_path_next(int idx, struct dentry *dentry, struct path *path) } /* Fix missing 'origin' xattr */ -static int ovl_fix_origin(struct dentry *dentry, struct dentry *lower, - struct dentry *upper) +static int ovl_fix_origin(struct ovl_fs *ofs, struct dentry *dentry, + struct dentry *lower, struct dentry *upper) { int err; - if (ovl_check_origin_xattr(upper)) + if (ovl_check_origin_xattr(ofs, upper)) return 0; err = ovl_want_write(dentry); @@ -909,7 +913,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, * of lower dir and set upper parent "impure". */ if (upperdentry && !ctr && !ofs->noxattr && d.is_dir) { - err = ovl_fix_origin(dentry, this, upperdentry); + err = ovl_fix_origin(ofs, dentry, this, upperdentry); if (err) { dput(this); goto out_put; @@ -928,7 +932,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, if (upperdentry && !ctr && ((d.is_dir && ovl_verify_lower(dentry->d_sb)) || (!d.is_dir && ofs->config.index && origin_path))) { - err = ovl_verify_origin(upperdentry, this, false); + err = ovl_verify_origin(ofs, upperdentry, this, false); if (err) { dput(this); if (d.is_dir) @@ -1049,7 +1053,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, ovl_dentry_set_upper_alias(dentry); else if (index) { upperdentry = dget(index); - upperredirect = ovl_get_redirect_xattr(upperdentry, 0); + upperredirect = ovl_get_redirect_xattr(ofs, upperdentry, 0); if (IS_ERR(upperredirect)) { err = PTR_ERR(upperredirect); upperredirect = NULL; diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index 6934bcf030f0..8d09bd92ec24 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -19,14 +19,27 @@ enum ovl_path_type { #define OVL_TYPE_MERGE(type) ((type) & __OVL_PATH_MERGE) #define OVL_TYPE_ORIGIN(type) ((type) & __OVL_PATH_ORIGIN) -#define OVL_XATTR_PREFIX XATTR_TRUSTED_PREFIX "overlay." -#define OVL_XATTR_OPAQUE OVL_XATTR_PREFIX "opaque" -#define OVL_XATTR_REDIRECT OVL_XATTR_PREFIX "redirect" -#define OVL_XATTR_ORIGIN OVL_XATTR_PREFIX "origin" -#define OVL_XATTR_IMPURE OVL_XATTR_PREFIX "impure" -#define OVL_XATTR_NLINK OVL_XATTR_PREFIX "nlink" -#define OVL_XATTR_UPPER OVL_XATTR_PREFIX "upper" -#define OVL_XATTR_METACOPY OVL_XATTR_PREFIX "metacopy" +#define OVL_XATTR_NAMESPACE "overlay." +#define OVL_XATTR_TRUSTED_PREFIX XATTR_TRUSTED_PREFIX OVL_XATTR_NAMESPACE +#define OVL_XATTR_USER_PREFIX XATTR_USER_PREFIX OVL_XATTR_NAMESPACE + +#define OVL_XATTR_OPAQUE_POSTFIX "opaque" +#define OVL_XATTR_REDIRECT_POSTFIX "redirect" +#define OVL_XATTR_ORIGIN_POSTFIX "origin" +#define OVL_XATTR_IMPURE_POSTFIX "impure" +#define OVL_XATTR_NLINK_POSTFIX "nlink" +#define OVL_XATTR_UPPER_POSTFIX "upper" +#define OVL_XATTR_METACOPY_POSTFIX "metacopy" + +enum ovl_xattr { + OVL_XATTR_OPAQUE, + OVL_XATTR_REDIRECT, + OVL_XATTR_ORIGIN, + OVL_XATTR_IMPURE, + OVL_XATTR_NLINK, + OVL_XATTR_UPPER, + OVL_XATTR_METACOPY, +}; enum ovl_inode_flag { /* Pure upper dir that may contain non pure upper entries */ @@ -256,10 +269,11 @@ struct file *ovl_path_open(struct path *path, int flags); int ovl_copy_up_start(struct dentry *dentry, int flags); void ovl_copy_up_end(struct dentry *dentry); bool ovl_already_copied_up(struct dentry *dentry, int flags); -bool ovl_check_origin_xattr(struct dentry *dentry); -bool ovl_check_dir_xattr(struct dentry *dentry, const char *name); +bool ovl_check_origin_xattr(struct ovl_fs *ofs, struct dentry *dentry); +bool ovl_check_dir_xattr(struct super_block *sb, struct dentry *dentry, + enum ovl_xattr ox); int ovl_check_setxattr(struct dentry *dentry, struct dentry *upperdentry, - const char *name, const void *value, size_t size, + enum ovl_xattr ox, const void *value, size_t size, int xerr); int ovl_set_impure(struct dentry *dentry, struct dentry *upperdentry); void ovl_set_flag(unsigned long flag, struct inode *inode); @@ -272,15 +286,24 @@ bool ovl_need_index(struct dentry *dentry); int ovl_nlink_start(struct dentry *dentry); void ovl_nlink_end(struct dentry *dentry); int ovl_lock_rename_workdir(struct dentry *workdir, struct dentry *upperdir); -int ovl_check_metacopy_xattr(struct dentry *dentry); +int ovl_check_metacopy_xattr(struct ovl_fs *ofs, struct dentry *dentry); bool ovl_is_metacopy_dentry(struct dentry *dentry); -char *ovl_get_redirect_xattr(struct dentry *dentry, int padding); -ssize_t ovl_getxattr(struct dentry *dentry, char *name, char **value, - size_t padding); - -static inline bool ovl_is_impuredir(struct dentry *dentry) +char *ovl_get_redirect_xattr(struct ovl_fs *ofs, struct dentry *dentry, + int padding); +ssize_t ovl_getxattr(struct dentry *dentry, const char *name, + char **value, size_t padding); +int ovl_own_setxattr(struct ovl_fs *ofs, struct dentry *dentry, + enum ovl_xattr ox, const void *value, size_t size); +int ovl_own_removexattr(struct ovl_fs *ofs, struct dentry *dentry, + enum ovl_xattr ox); +ssize_t ovl_own_getxattr(struct ovl_fs *ofs, struct dentry *dentry, + enum ovl_xattr ox, void *value, size_t size); +bool ovl_is_private_xattr(struct super_block *sb, const char *name); + +static inline bool ovl_is_impuredir(struct super_block *sb, + struct dentry *dentry) { - return ovl_check_dir_xattr(dentry, OVL_XATTR_IMPURE); + return ovl_check_dir_xattr(sb, dentry, OVL_XATTR_IMPURE); } static inline unsigned int ovl_xino_bits(struct super_block *sb) @@ -307,8 +330,9 @@ struct dentry *ovl_decode_real_fh(struct ovl_fh *fh, struct vfsmount *mnt, bool connected); int ovl_check_origin_fh(struct ovl_fs *ofs, struct ovl_fh *fh, bool connected, struct dentry *upperdentry, struct ovl_path **stackp); -int ovl_verify_set_fh(struct dentry *dentry, const char *name, - struct dentry *real, bool is_upper, bool set); +int ovl_verify_set_fh(struct ovl_fs *ofs, struct dentry *dentry, + enum ovl_xattr ox, struct dentry *real, bool is_upper, + bool set); struct dentry *ovl_index_upper(struct ovl_fs *ofs, struct dentry *index); int ovl_verify_index(struct ovl_fs *ofs, struct dentry *index); int ovl_get_index_name(struct dentry *origin, struct qstr *name); @@ -320,16 +344,17 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags); bool ovl_lower_positive(struct dentry *dentry); -static inline int ovl_verify_origin(struct dentry *upper, +static inline int ovl_verify_origin(struct ovl_fs *ofs, struct dentry *upper, struct dentry *origin, bool set) { - return ovl_verify_set_fh(upper, OVL_XATTR_ORIGIN, origin, false, set); + return ovl_verify_set_fh(ofs, upper, OVL_XATTR_ORIGIN, origin, + false, set); } -static inline int ovl_verify_upper(struct dentry *index, - struct dentry *upper, bool set) +static inline int ovl_verify_upper(struct ovl_fs *ofs, struct dentry *index, + struct dentry *upper, bool set) { - return ovl_verify_set_fh(index, OVL_XATTR_UPPER, upper, true, set); + return ovl_verify_set_fh(ofs, index, OVL_XATTR_UPPER, upper, true, set); } /* readdir.c */ @@ -346,7 +371,7 @@ int ovl_indexdir_cleanup(struct ovl_fs *ofs); /* inode.c */ int ovl_set_nlink_upper(struct dentry *dentry); int ovl_set_nlink_lower(struct dentry *dentry); -unsigned int ovl_get_nlink(struct dentry *lowerdentry, +unsigned int ovl_get_nlink(struct ovl_fs *ofs, struct dentry *lowerdentry, struct dentry *upperdentry, unsigned int fallback); int ovl_setattr(struct dentry *dentry, struct iattr *attr); @@ -360,7 +385,6 @@ int ovl_xattr_get(struct dentry *dentry, struct inode *inode, const char *name, ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size); struct posix_acl *ovl_get_acl(struct inode *inode, int type); int ovl_update_time(struct inode *inode, struct timespec64 *ts, int flags); -bool ovl_is_private_xattr(const char *name); struct ovl_inode_params { struct inode *newinode; @@ -422,7 +446,8 @@ int ovl_copy_up(struct dentry *dentry); int ovl_copy_up_with_data(struct dentry *dentry); int ovl_copy_up_flags(struct dentry *dentry, int flags); int ovl_maybe_copy_up(struct dentry *dentry, int flags); -int ovl_copy_xattr(struct dentry *old, struct dentry *new); +int ovl_copy_xattr(struct super_block *sb, struct dentry *old, + struct dentry *new); int ovl_set_attr(struct dentry *upper, struct kstat *stat); struct ovl_fh *ovl_encode_real_fh(struct dentry *real, bool is_upper); int ovl_set_origin(struct dentry *dentry, struct dentry *lower, diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h index a8279280e88d..e2ea474a2650 100644 --- a/fs/overlayfs/ovl_entry.h +++ b/fs/overlayfs/ovl_entry.h @@ -17,6 +17,7 @@ struct ovl_config { bool nfs_export; int xino; bool metacopy; + bool userxattr; }; struct ovl_sb { diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c index 47a91c9733a5..3cf24dffc3b9 100644 --- a/fs/overlayfs/readdir.c +++ b/fs/overlayfs/readdir.c @@ -591,6 +591,7 @@ static struct ovl_dir_cache *ovl_cache_get_impure(struct path *path) { int res; struct dentry *dentry = path->dentry; + struct ovl_fs *ofs = dentry->d_sb->s_fs_info; struct ovl_dir_cache *cache; cache = ovl_dir_cache(d_inode(dentry)); @@ -617,8 +618,8 @@ static struct ovl_dir_cache *ovl_cache_get_impure(struct path *path) * Removing the "impure" xattr is best effort. */ if (!ovl_want_write(dentry)) { - ovl_do_removexattr(ovl_dentry_upper(dentry), - OVL_XATTR_IMPURE); + ovl_own_removexattr(ofs, ovl_dentry_upper(dentry), + OVL_XATTR_IMPURE); ovl_drop_write(dentry); } ovl_clear_flag(OVL_IMPURE, d_inode(dentry)); diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index afbcb116a7f1..d122c07f2a43 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -403,6 +403,7 @@ enum { OPT_XINO_AUTO, OPT_METACOPY_ON, OPT_METACOPY_OFF, + OPT_USERXATTR, OPT_ERR, }; @@ -421,6 +422,7 @@ static const match_table_t ovl_tokens = { {OPT_XINO_AUTO, "xino=auto"}, {OPT_METACOPY_ON, "metacopy=on"}, {OPT_METACOPY_OFF, "metacopy=off"}, + {OPT_USERXATTR, "userxattr"}, {OPT_ERR, NULL} }; @@ -559,6 +561,10 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config) config->metacopy = false; break; + case OPT_USERXATTR: + config->userxattr = true; + break; + default: pr_err("overlayfs: unrecognized mount option \"%s\" or missing value\n", p); return -EINVAL; @@ -964,8 +970,14 @@ ovl_posix_acl_default_xattr_handler = { .set = ovl_posix_acl_xattr_set, }; -static const struct xattr_handler ovl_own_xattr_handler = { - .prefix = OVL_XATTR_PREFIX, +static const struct xattr_handler ovl_own_trusted_xattr_handler = { + .prefix = OVL_XATTR_TRUSTED_PREFIX, + .get = ovl_own_xattr_get, + .set = ovl_own_xattr_set, +}; + +static const struct xattr_handler ovl_own_user_xattr_handler = { + .prefix = OVL_XATTR_USER_PREFIX, .get = ovl_own_xattr_get, .set = ovl_own_xattr_set, }; @@ -976,12 +988,22 @@ static const struct xattr_handler ovl_other_xattr_handler = { .set = ovl_other_xattr_set, }; -static const struct xattr_handler *ovl_xattr_handlers[] = { +static const struct xattr_handler *ovl_trusted_xattr_handlers[] = { #ifdef CONFIG_FS_POSIX_ACL &ovl_posix_acl_access_xattr_handler, &ovl_posix_acl_default_xattr_handler, #endif - &ovl_own_xattr_handler, + &ovl_own_trusted_xattr_handler, + &ovl_other_xattr_handler, + NULL +}; + +static const struct xattr_handler *ovl_user_xattr_handlers[] = { +#ifdef CONFIG_FS_POSIX_ACL + &ovl_posix_acl_access_xattr_handler, + &ovl_posix_acl_default_xattr_handler, +#endif + &ovl_own_user_xattr_handler, &ovl_other_xattr_handler, NULL }; @@ -1121,7 +1143,7 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs, /* * Check if upper/work fs supports trusted.overlay.* xattr */ - err = ovl_do_setxattr(ofs->workdir, OVL_XATTR_OPAQUE, "0", 1, 0); + err = ovl_own_setxattr(ofs, ofs->workdir, OVL_XATTR_OPAQUE, "0", 1); if (err) { ofs->noxattr = true; ofs->config.index = false; @@ -1129,7 +1151,7 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs, pr_warn("overlayfs: upper fs does not support xattr, falling back to index=off and metacopy=off.\n"); err = 0; } else { - vfs_removexattr(ofs->workdir, OVL_XATTR_OPAQUE); + ovl_own_removexattr(ofs, ofs->workdir, OVL_XATTR_OPAQUE); } /* Check if upper/work fs supports file handles */ @@ -1207,8 +1229,8 @@ static int ovl_get_indexdir(struct super_block *sb, struct ovl_fs *ofs, return err; /* Verify lower root is upper root origin */ - err = ovl_verify_origin(upperpath->dentry, oe->lowerstack[0].dentry, - true); + err = ovl_verify_origin(ofs, upperpath->dentry, + oe->lowerstack[0].dentry, true); if (err) { pr_err("overlayfs: failed to verify upper root origin\n"); goto out; @@ -1229,13 +1251,15 @@ static int ovl_get_indexdir(struct super_block *sb, struct ovl_fs *ofs, * "trusted.overlay.upper" to indicate that index may have * directory entries. */ - if (ovl_check_origin_xattr(ofs->indexdir)) { - err = ovl_verify_set_fh(ofs->indexdir, OVL_XATTR_ORIGIN, + if (ovl_check_origin_xattr(ofs, ofs->indexdir)) { + err = ovl_verify_set_fh(ofs, ofs->indexdir, + OVL_XATTR_ORIGIN, upperpath->dentry, true, false); if (err) pr_err("overlayfs: failed to verify index dir 'origin' xattr\n"); } - err = ovl_verify_upper(ofs->indexdir, upperpath->dentry, true); + err = ovl_verify_upper(ofs, ofs->indexdir, upperpath->dentry, + true); if (err) pr_err("overlayfs: failed to verify index dir 'upper' xattr\n"); @@ -1588,7 +1612,6 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) pr_err("overlayfs: missing 'lowerdir'\n"); goto out_err; } - sb->s_stack_depth = 0; sb->s_maxbytes = MAX_LFS_FILESIZE; /* Assume underlaying fs uses 32bit inodes unless proven otherwise */ @@ -1667,7 +1690,8 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) cap_lower(cred->cap_effective, CAP_SYS_RESOURCE); sb->s_magic = OVERLAYFS_SUPER_MAGIC; - sb->s_xattr = ovl_xattr_handlers; + sb->s_xattr = ofs->config.userxattr ? ovl_user_xattr_handlers : + ovl_trusted_xattr_handlers; sb->s_fs_info = ofs; sb->s_flags |= SB_POSIXACL; @@ -1681,7 +1705,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) mntput(upperpath.mnt); if (upperpath.dentry) { ovl_dentry_set_upper_alias(root_dentry); - if (ovl_is_impuredir(upperpath.dentry)) + if (ovl_is_impuredir(sb, upperpath.dentry)) ovl_set_flag(OVL_IMPURE, d_inode(root_dentry)); } diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c index f5678a3f8350..5eaa92445fe2 100644 --- a/fs/overlayfs/util.c +++ b/fs/overlayfs/util.c @@ -535,11 +535,11 @@ void ovl_copy_up_end(struct dentry *dentry) ovl_inode_unlock(d_inode(dentry)); } -bool ovl_check_origin_xattr(struct dentry *dentry) +bool ovl_check_origin_xattr(struct ovl_fs *ofs, struct dentry *dentry) { int res; - res = vfs_getxattr(dentry, OVL_XATTR_ORIGIN, NULL, 0); + res = ovl_own_getxattr(ofs, dentry, OVL_XATTR_ORIGIN, NULL, 0); /* Zero size value means "copied up but origin unknown" */ if (res >= 0) @@ -548,27 +548,49 @@ bool ovl_check_origin_xattr(struct dentry *dentry) return false; } -bool ovl_check_dir_xattr(struct dentry *dentry, const char *name) +bool ovl_check_dir_xattr(struct super_block *sb, struct dentry *dentry, + enum ovl_xattr ox) { int res; char val; + struct ovl_fs *ofs = sb->s_fs_info; if (!d_is_dir(dentry)) return false; - res = vfs_getxattr(dentry, name, &val, 1); + res = ovl_own_getxattr(ofs, dentry, ox, &val, 1); if (res == 1 && val == 'y') return true; return false; } +#define OVL_XATTR_TAB_ENTRY(x) \ + [x] = { [false] = OVL_XATTR_TRUSTED_PREFIX x ## _POSTFIX, \ + [true] = OVL_XATTR_USER_PREFIX x ## _POSTFIX } + +static const char *ovl_xattr_table[][2] = { + OVL_XATTR_TAB_ENTRY(OVL_XATTR_OPAQUE), + OVL_XATTR_TAB_ENTRY(OVL_XATTR_REDIRECT), + OVL_XATTR_TAB_ENTRY(OVL_XATTR_ORIGIN), + OVL_XATTR_TAB_ENTRY(OVL_XATTR_IMPURE), + OVL_XATTR_TAB_ENTRY(OVL_XATTR_NLINK), + OVL_XATTR_TAB_ENTRY(OVL_XATTR_UPPER), + OVL_XATTR_TAB_ENTRY(OVL_XATTR_METACOPY), +}; + +static const char *ovl_xattr(struct ovl_fs *ofs, enum ovl_xattr ox) +{ + return ovl_xattr_table[ox][ofs->config.userxattr]; +} + int ovl_check_setxattr(struct dentry *dentry, struct dentry *upperdentry, - const char *name, const void *value, size_t size, + enum ovl_xattr ox, const void *value, size_t size, int xerr) { int err; struct ovl_fs *ofs = dentry->d_sb->s_fs_info; + const char *name = ovl_xattr(ofs, ox); if (ofs->noxattr) return xerr; @@ -584,6 +606,18 @@ int ovl_check_setxattr(struct dentry *dentry, struct dentry *upperdentry, return err; } +bool ovl_is_private_xattr(struct super_block *sb, const char *name) +{ + struct ovl_fs *ofs = sb->s_fs_info; + + if (ofs->config.userxattr) + return strncmp(name, OVL_XATTR_USER_PREFIX, + sizeof(OVL_XATTR_USER_PREFIX) - 1) == 0; + else + return strncmp(name, OVL_XATTR_TRUSTED_PREFIX, + sizeof(OVL_XATTR_TRUSTED_PREFIX) - 1) == 0; +} + int ovl_set_impure(struct dentry *dentry, struct dentry *upperdentry) { int err; @@ -835,7 +869,7 @@ int ovl_lock_rename_workdir(struct dentry *workdir, struct dentry *upperdir) } /* err < 0, 0 if no metacopy xattr, 1 if metacopy xattr found */ -int ovl_check_metacopy_xattr(struct dentry *dentry) +int ovl_check_metacopy_xattr(struct ovl_fs *ofs, struct dentry *dentry) { int res; @@ -843,7 +877,7 @@ int ovl_check_metacopy_xattr(struct dentry *dentry) if (!S_ISREG(d_inode(dentry)->i_mode)) return 0; - res = vfs_getxattr(dentry, OVL_XATTR_METACOPY, NULL, 0); + res = ovl_own_getxattr(ofs, dentry, OVL_XATTR_METACOPY, NULL, 0); if (res < 0) { if (res == -ENODATA || res == -EOPNOTSUPP) return 0; @@ -872,8 +906,8 @@ bool ovl_is_metacopy_dentry(struct dentry *dentry) return (oe->numlower > 1); } -ssize_t ovl_getxattr(struct dentry *dentry, char *name, char **value, - size_t padding) +ssize_t ovl_getxattr(struct dentry *dentry, const char *name, + char **value, size_t padding) { ssize_t res; char *buf = NULL; @@ -905,12 +939,14 @@ ssize_t ovl_getxattr(struct dentry *dentry, char *name, char **value, return res; } -char *ovl_get_redirect_xattr(struct dentry *dentry, int padding) +char *ovl_get_redirect_xattr(struct ovl_fs *ofs, struct dentry *dentry, + int padding) { int res; char *s, *next, *buf = NULL; + const char *name = ovl_xattr(ofs, OVL_XATTR_REDIRECT); - res = ovl_getxattr(dentry, OVL_XATTR_REDIRECT, &buf, padding + 1); + res = ovl_getxattr(dentry, name, &buf, padding + 1); if (res == -ENODATA) return NULL; if (res < 0) @@ -936,3 +972,27 @@ char *ovl_get_redirect_xattr(struct dentry *dentry, int padding) kfree(buf); return ERR_PTR(res); } + +int ovl_own_setxattr(struct ovl_fs *ofs, struct dentry *dentry, + enum ovl_xattr ox, const void *value, size_t size) +{ + const char *name = ovl_xattr(ofs, ox); + + return ovl_do_setxattr(dentry, name, value, size, 0); +} + +int ovl_own_removexattr(struct ovl_fs *ofs, struct dentry *dentry, + enum ovl_xattr ox) +{ + const char *name = ovl_xattr(ofs, ox); + + return ovl_do_removexattr(dentry, name); +} + +ssize_t ovl_own_getxattr(struct ovl_fs *ofs, struct dentry *dentry, + enum ovl_xattr ox, void *value, size_t size) +{ + const char *name = ovl_xattr(ofs, ox); + + return vfs_getxattr(dentry, name, value, size); +} From patchwork Fri Oct 25 11:29:17 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miklos Szeredi X-Patchwork-Id: 11212085 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 9A560139A for ; Fri, 25 Oct 2019 11:29:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 7839D21D82 for ; Fri, 25 Oct 2019 11:29:37 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="NQZikVbA" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2439584AbfJYL3d (ORCPT ); Fri, 25 Oct 2019 07:29:33 -0400 Received: from us-smtp-1.mimecast.com ([207.211.31.81]:59847 "EHLO us-smtp-1.mimecast.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2438379AbfJYL3c (ORCPT ); Fri, 25 Oct 2019 07:29:32 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1572002971; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=9uL6B8L1AUAy/UiZQvA9Cim16okzyI5YnHL1NCMV9QY=; b=NQZikVbApvjf3g6TlFLatZqFHHUClZqnx8yLEZDltrwCVYoBvaxCAffuKCiZdjBLexl8dG WuPoexLuCVi+miUQvE7913LEx84yvePRX9FxIn7WurcM9XO6Vw3GwS8neZaiXVdanet2Ij 7hrqI5Sdsw5QGaSp8CDB34o+IN8A/a8= Received: from mail-wm1-f71.google.com (mail-wm1-f71.google.com [209.85.128.71]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-15-rGxqbsUBM1WDzTSbVm0iwA-1; Fri, 25 Oct 2019 07:29:27 -0400 Received: by mail-wm1-f71.google.com with SMTP id 6so939329wmj.9 for ; Fri, 25 Oct 2019 04:29:27 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=1a/jvPs2SyoieuY5sUx5bSduqfiYAGGvkqIa6LCkCRY=; b=QD+OyloQhz6yJMCoUgn4jP3vmLXjP1u9DsVufyn9Jj8RbjdtL0AGjj6h1FSlg8ucBG n2X6z9ErOSoE078yM5BJ3T6ICgcEPNnfoNqD9SyPJeM1i7CYmuNqun+JI9LQ6kJNb9pV N0SoBOYR3MviBPj3VG/jD2zxuE4PimjVnpa+q7f3GHAwl7NYI3WbDc8cTKOUoHJ6aXSm ibZscnI7YkYNGLYusKc1uXSxJH8LLKIVUciqVJyv41ZxireGlI257zHk+9M8qoAHiQKY AgxcjGyooPawcHM3HxsJ854mLU69Ni8zIjil0Kgl1yR9hdfA4gNTZ+by+pYoFfaiLeNr /+ug== X-Gm-Message-State: APjAAAVXN+8CYBDBLNsGe856MWRENOQxKHJXdnTMniNBamK1glqzKPnr rr3xTaBE/jSuYBgjYOlgmVQtSSBswymHykd5pnlwql4d4sDiEMpBDhP6eIV/bHYVAMqr7Tgr5yx cpHaVIlUqQKpzsA9hemaRLevzRg== X-Received: by 2002:adf:e7cf:: with SMTP id e15mr2518272wrn.303.1572002965921; Fri, 25 Oct 2019 04:29:25 -0700 (PDT) X-Google-Smtp-Source: APXvYqwvfPJJ2c/wmZStZlRDQhI1hTNTMWyooEQFpsvxbtMEd+kN4kjZa+gDkGbcqMbI/WXcN+LFaw== X-Received: by 2002:adf:e7cf:: with SMTP id e15mr2518261wrn.303.1572002965778; Fri, 25 Oct 2019 04:29:25 -0700 (PDT) Received: from miu.piliscsaba.redhat.com (185-79-95-246.pool.digikabel.hu. [185.79.95.246]) by smtp.gmail.com with ESMTPSA id l18sm3974080wrn.48.2019.10.25.04.29.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 25 Oct 2019 04:29:25 -0700 (PDT) From: Miklos Szeredi To: "Eric W . Biederman" Cc: linux-unionfs@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [RFC PATCH 5/5] ovl: unprivieged mounts Date: Fri, 25 Oct 2019 13:29:17 +0200 Message-Id: <20191025112917.22518-6-mszeredi@redhat.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191025112917.22518-1-mszeredi@redhat.com> References: <20191025112917.22518-1-mszeredi@redhat.com> MIME-Version: 1.0 X-MC-Unique: rGxqbsUBM1WDzTSbVm0iwA-1 X-Mimecast-Spam-Score: 0 Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org Enable unprivileged user namespace mounts of overlayfs. Overlayfs's permission model (*) ensures that the mounter itself cannot gain additional privileges by the act of creating an overlayfs mount. This feature request is coming from the "rootless" container crowd. (*) Documentation/filesystems/overlayfs.txt#Permission model Signed-off-by: Miklos Szeredi --- fs/overlayfs/super.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index d122c07f2a43..c7f21a049c6b 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -1739,6 +1739,7 @@ static struct dentry *ovl_mount(struct file_system_type *fs_type, int flags, static struct file_system_type ovl_fs_type = { .owner = THIS_MODULE, .name = "overlay", + .fs_flags = FS_USERNS_MOUNT, .mount = ovl_mount, .kill_sb = kill_anon_super, };