From patchwork Thu Apr 18 12:15:48 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Disseldorp X-Patchwork-Id: 10907161 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 5770913B5 for ; Thu, 18 Apr 2019 12:16:04 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 40BA628C0B for ; Thu, 18 Apr 2019 12:16:04 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 34DBD28C0E; Thu, 18 Apr 2019 12:16:04 +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=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, 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 C9E5628C0D for ; Thu, 18 Apr 2019 12:16:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388942AbfDRMQD (ORCPT ); Thu, 18 Apr 2019 08:16:03 -0400 Received: from mx2.suse.de ([195.135.220.15]:51628 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S2388933AbfDRMQC (ORCPT ); Thu, 18 Apr 2019 08:16:02 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 7A486B17A; Thu, 18 Apr 2019 12:16:01 +0000 (UTC) From: David Disseldorp To: ceph-devel@vger.kernel.org Cc: Patrick Donnelly , Ilya Dryomov , Gregory Farnum , ukernel@gmail.com, David Disseldorp Subject: [PATCH v3 4/5] ceph: fix listxattr vxattr buffer length calculation Date: Thu, 18 Apr 2019 14:15:48 +0200 Message-Id: <20190418121549.30128-5-ddiss@suse.de> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20190418121549.30128-1-ddiss@suse.de> References: <20190418121549.30128-1-ddiss@suse.de> Sender: ceph-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: ceph-devel@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP ceph_listxattr() incorrectly returns a length based on the static ceph_vxattrs_name_size() value, which only takes into account whether vxattrs are hidden, ignoring vxattr.exists_cb(). When filling the xattr buffer ceph_listxattr() checks VXATTR_FLAG_HIDDEN and vxattr.exists_cb(). If both are false, we return an incorrect (oversize) length. Fix this behaviour by always calculating the vxattrs length at runtime, taking both vxattr.hidden and vxattr.exists_cb() into account. This bug is only exposed with the new "ceph.snap.btime" vxattr, as all other vxattrs with a non-null exists_cb also carry VXATTR_FLAG_HIDDEN. Signed-off-by: David Disseldorp --- fs/ceph/xattr.c | 54 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c index d637aba6fd2a..69415d625cc5 100644 --- a/fs/ceph/xattr.c +++ b/fs/ceph/xattr.c @@ -924,10 +924,9 @@ ssize_t ceph_listxattr(struct dentry *dentry, char *names, size_t size) struct inode *inode = d_inode(dentry); struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_vxattr *vxattrs = ceph_inode_vxattrs(inode); - u32 vir_namelen = 0; + bool len_only = (size == 0); u32 namelen; int err; - u32 len; int i; spin_lock(&ci->i_ceph_lock); @@ -946,38 +945,45 @@ ssize_t ceph_listxattr(struct dentry *dentry, char *names, size_t size) err = __build_xattrs(inode); if (err < 0) goto out; - /* - * Start with virtual dir xattr names (if any) (including - * terminating '\0' characters for each). - */ - vir_namelen = ceph_vxattrs_name_size(vxattrs); - /* adding 1 byte per each variable due to the null termination */ + /* add 1 byte for each xattr due to the null termination */ namelen = ci->i_xattrs.names_size + ci->i_xattrs.count; - err = -ERANGE; - if (size && vir_namelen + namelen > size) - goto out; - - err = namelen + vir_namelen; - if (size == 0) - goto out; + if (!len_only) { + if (namelen > size) { + err = -ERANGE; + goto out; + } + names = __copy_xattr_names(ci, names); + size -= namelen; + } - names = __copy_xattr_names(ci, names); /* virtual xattr names, too */ - err = namelen; if (vxattrs) { for (i = 0; vxattrs[i].name; i++) { - if (!(vxattrs[i].flags & VXATTR_FLAG_HIDDEN) && - !(vxattrs[i].exists_cb && - !vxattrs[i].exists_cb(ci))) { - len = sprintf(names, "%s", vxattrs[i].name); - names += len + 1; - err += len + 1; + size_t this_len; + + if (vxattrs[i].flags & VXATTR_FLAG_HIDDEN) + continue; + if (vxattrs[i].exists_cb && !vxattrs[i].exists_cb(ci)) + continue; + + this_len = strlen(vxattrs[i].name) + 1; + namelen += this_len; + if (len_only) + continue; + + if (this_len > size) { + err = -ERANGE; + goto out; } + + memcpy(names, vxattrs[i].name, this_len); + names += this_len; + size -= this_len; } } - + err = namelen; out: spin_unlock(&ci->i_ceph_lock); return err;