From patchwork Thu Feb 9 14:22:38 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christoph Hellwig X-Patchwork-Id: 9564715 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 16330601C3 for ; Thu, 9 Feb 2017 14:40:51 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id F3911284D1 for ; Thu, 9 Feb 2017 14:40:50 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E84C728503; Thu, 9 Feb 2017 14:40:50 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 80387284D1 for ; Thu, 9 Feb 2017 14:40:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752282AbdBIOkt (ORCPT ); Thu, 9 Feb 2017 09:40:49 -0500 Received: from bombadil.infradead.org ([65.50.211.133]:59305 "EHLO bombadil.infradead.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752656AbdBIOkr (ORCPT ); Thu, 9 Feb 2017 09:40:47 -0500 Received: from clnet-p099-196.ikbnet.co.at ([83.175.99.196] helo=localhost) by bombadil.infradead.org with esmtpsa (Exim 4.87 #1 (Red Hat Linux)) id 1cbpcP-0006x6-Qt; Thu, 09 Feb 2017 14:22:42 +0000 From: Christoph Hellwig To: bfields@fieldses.org Cc: chucklever@gmail.com, linux-nfs@vger.kernel.org Subject: [PATCH] nfsd: restore owner override for truncate Date: Thu, 9 Feb 2017 15:22:38 +0100 Message-Id: <20170209142238.5322-1-hch@lst.de> X-Mailer: git-send-email 2.11.0 X-SRS-Rewrite: SMTP reverse-path rewritten from by bombadil.infradead.org. See http://www.infradead.org/rpr.html Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The switch to vfs_truncate in nfsd_setattr dropped the owner override used for NFS permissions. Add a copy of vfs_truncate with it restored to the nfsd code for now as it's very late in the cycle, but there should be a way to consolidate it back in the future. Fixes: 41f53350 ("nfsd: special case truncates some more") Signed-off-by: Christoph Hellwig Reported-by: Chuck Lever --- fs/nfsd/vfs.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index a974368026a1..fd4a32e0b0b4 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -332,6 +332,85 @@ nfsd_sanitize_attrs(struct inode *inode, struct iattr *iap) } } +/* copy of vfs_truncate with NFS owner override hacked in, sigh.. */ +static long nfsd_truncate(const struct path *path, loff_t length) +{ + struct inode *inode; + struct dentry *upperdentry; + long error; + + inode = path->dentry->d_inode; + + /* For directories it's -EISDIR, for other non-regulars - -EINVAL */ + if (S_ISDIR(inode->i_mode)) + return -EISDIR; + if (!S_ISREG(inode->i_mode)) + return -EINVAL; + + error = mnt_want_write(path->mnt); + if (error) + goto out; + + /* + * The file owner always gets access permission for accesses that + * would normally be checked at open time. This is to make + * file access work even when the client has done a fchmod(fd, 0). + * + * However, `cp foo bar' should fail nevertheless when bar is + * readonly. A sensible way to do this might be to reject all + * attempts to truncate a read-only file, because a creat() call + * always implies file truncation. + * ... but this isn't really fair. A process may reasonably call + * ftruncate on an open file descriptor on a file with perm 000. + * We must trust the client to do permission checking - using "ACCESS" + * with NFSv3. + */ + if (!uid_eq(inode->i_uid, current_fsuid())) { + error = inode_permission(inode, MAY_WRITE); + if (error) + goto mnt_drop_write_and_out; + } + + error = -EPERM; + if (IS_APPEND(inode)) + goto mnt_drop_write_and_out; + + /* + * If this is an overlayfs then do as if opening the file so we get + * write access on the upper inode, not on the overlay inode. For + * non-overlay filesystems d_real() is an identity function. + */ + upperdentry = d_real(path->dentry, NULL, O_WRONLY); + error = PTR_ERR(upperdentry); + if (IS_ERR(upperdentry)) + goto mnt_drop_write_and_out; + + error = get_write_access(upperdentry->d_inode); + if (error) + goto mnt_drop_write_and_out; + + /* + * Make sure that there are no leases. get_write_access() protects + * against the truncate racing with a lease-granting setlease(). + */ + error = break_lease(inode, O_WRONLY); + if (error) + goto put_write_and_out; + + error = locks_verify_truncate(inode, NULL, length); + if (!error) + error = security_path_truncate(path); + if (!error) + error = do_truncate(path->dentry, length, 0, NULL); + +put_write_and_out: + put_write_access(upperdentry->d_inode); +mnt_drop_write_and_out: + mnt_drop_write(path->mnt); +out: + return error; +} + /* * Set various file attributes. After this call fhp needs an fh_put. */ @@ -398,7 +477,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, ((iap->ia_valid & ~(ATTR_SIZE | ATTR_MTIME)) == 0)) implicit_mtime = true; - host_err = vfs_truncate(&path, iap->ia_size); + host_err = nfsd_truncate(&path, iap->ia_size); if (host_err) goto out_host_err;