Received: by 2002:a25:7ec1:0:0:0:0:0 with SMTP id z184csp3678772ybc; Thu, 14 Nov 2019 12:56:13 -0800 (PST) X-Google-Smtp-Source: APXvYqyzq5pXqtBbu5TVu0I0MEvTYKEWEhTy/r+a3vgnVs7+SB7QskN5IUqoI+NsNkmT1IjWz1xp X-Received: by 2002:a05:600c:2383:: with SMTP id m3mr9875663wma.66.1573764973642; Thu, 14 Nov 2019 12:56:13 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1573764973; cv=none; d=google.com; s=arc-20160816; b=tzKmkwkm6vFZj8OKVmDHhmduOWaYRuP96AJ4JEz6g9R16MNmXZ1sldvQ+60L1KjwM6 SxVwVI0chsGB29QKtQKsMqo89C89gUs7F1u10N2N4Mf1dBeODoyU3e3iLlycw9TCUSAE FqEv2/403dETkiokKwupRWx3W/pnPrPWTfwC+xOO1kAfnxz26lI6zzowoJv3z8Azl7n3 UqxghI++wpjmRGsoX13BPa5qxTKVjyYl2REu9l646AQlm3aKjlNAeVWS8q72zdOJC+M0 gA9gz4q3MWZRhksVlZJlqkFij8l1JwSEFxW9SOCO/9ehlsDyvw55SHMcADJx21etix7g mh1Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:user-agent:in-reply-to :content-disposition:mime-version:references:message-id:subject:cc :to:from:date; bh=6hZncG08gkHgIhlm1+Ij0tX0AoJd/xG/wNC3WEUUuyc=; b=eFmVNVj0C/FBP6drdBz0iCtALSPBa15eWOGm7KpYSmZkGETIKWpZG8ebGpqhq92vpD gLX+Cbx6rJOEp3FVLuWlFijSzkmjRHLMnHZfCL8ELqXP7JaslbmlYE/m2Ny121HFNW4T +nT3X555Sp26nYt1AWf/UgjvF7lZjcevO4PATV9ZkNQMHbp/1sqlKYHB9zEpA3JT1JiO g++sshAKgs9SI+fbZkZbEJK16c+HEl+/91ADOSXuq7oyetD8jOPcP4ppCpMzjrJ4BqjN KLaBgEDhstVgymCHGpeF3C9fDX2iRREhboSF7jORA19hoHd9ZEk068ijy35C9Sx+n0Et 3jWA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-nfs-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-nfs-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id f12si4320310edy.41.2019.11.14.12.55.35; Thu, 14 Nov 2019 12:56:13 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-nfs-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-nfs-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-nfs-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726613AbfKNUza (ORCPT + 99 others); Thu, 14 Nov 2019 15:55:30 -0500 Received: from zeniv.linux.org.uk ([195.92.253.2]:46642 "EHLO ZenIV.linux.org.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726597AbfKNUza (ORCPT ); Thu, 14 Nov 2019 15:55:30 -0500 Received: from viro by ZenIV.linux.org.uk with local (Exim 4.92.3 #3 (Red Hat Linux)) id 1iVM9G-0002GF-05; Thu, 14 Nov 2019 20:55:26 +0000 Date: Thu, 14 Nov 2019 20:55:25 +0000 From: Al Viro To: Miklos Szeredi Cc: Amir Goldstein , linux-fsdevel@vger.kernel.org, linux-nfs@vger.kernel.org, "J. Bruce Fields" Subject: Re: [RFC] is ovl_fh->fid really intended to be misaligned? Message-ID: <20191114205525.GK26530@ZenIV.linux.org.uk> References: <20191114154723.GJ26530@ZenIV.linux.org.uk> <20191114195544.GB5569@miu.piliscsaba.redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20191114195544.GB5569@miu.piliscsaba.redhat.com> User-Agent: Mutt/1.12.1 (2019-06-15) Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org On Thu, Nov 14, 2019 at 08:55:44PM +0100, Miklos Szeredi wrote: > BUILD_BUG_ON(MAX_HANDLE_SZ + offsetof(struct ovl_fh, fid) > 255); > fh_len = offsetof(struct ovl_fh, fid) + buflen; IOW, 3 bytes longer now. OK... > - fh = kmalloc(fh_len, GFP_KERNEL); > + fh = kzalloc(fh_len, GFP_KERNEL); > if (!fh) { > fh = ERR_PTR(-ENOMEM); > goto out; > @@ -271,7 +271,7 @@ struct ovl_fh *ovl_encode_real_fh(struct dentry *real, bool is_upper) > */ > if (is_upper) > fh->flags |= OVL_FH_FLAG_PATH_UPPER; > - fh->len = fh_len; > + fh->len = fh_len - OVL_FH_WIRE_OFFSET; ... same value as before > fh->uuid = *uuid; > memcpy(fh->fid, buf, buflen); Is there any point to two allocations + memcpy here? It's not as if you kept those ovl_fh instances allocated for a long time - the caller frees them shortly. So why bother with buf at all? Just allocate your fh max-sized and bloody pass &fh->fid to exportfs_encode_fh() there. I would suggest this for declaration, if you want to pad it in front: struct ovl_fh { u8 __pad[OVL_FH_WIRE_OFFSET]; u8 version; /* 0 */ u8 magic; /* 0xfb */ u8 len; /* size of this header + size of fid */ u8 flags; /* OVL_FH_FLAG_* */ u8 type; /* fid_type of fid */ uuid_t uuid; /* uuid of filesystem */ union { struct fid fid; /* file identifier */ u8 storage[]; }; } __packed; with BUILD_BUG_ON(offsetof(struct ovl_fh, fid) % 4); somewhere in there. Size calculation would be fh_len = offsetof(struct ovl_fh, storage[MAX_HANDLE_SIZE]); And check that resulting fhandle size does *not* exceed 32 words, just to make sure. > @@ -234,7 +234,7 @@ static int ovl_d_to_fh(struct dentry *dentry, char *buf, int buflen) > if (fh->len > buflen) > goto fail; > > - memcpy(buf, (char *)fh, fh->len); > + memcpy(buf, OVL_FH_START(fh), fh->len); > err = fh->len; Incidentally, memcpy() doesn't need any casts - it takes any data pointer types just fine... > out: > @@ -260,6 +260,7 @@ static int ovl_dentry_to_fh(struct dentry *dentry, u32 *fid, int *max_len) > > /* Round up to dwords */ > *max_len = (len + 3) >> 2; > + memset(fid + len, 0, (*max_len << 2) - len); No. This is broken - fid is u32 pointer. What you want here is memcpy(fid, OVL_FH_START(fh), fh->len); memset((char *)fid + fh->len, 0, OVL_FH_START(fh), OVL_FH_WIRE_OFFSET); len = fh->len + OVL_FH_WIRE_OFFSET; in the d_to_fh part, then just have *max_len = len / 4; Or just do the max-sized allocation for fh and have ovl_encode_real_fh() zero everything past fh->len; then this would just be a plain memcpy() and to hell with separate memset()... Incidentally, I really don't understand why these three functions separated from each other. Why not do all of that in ovl_encode_fh()? AFAICS, the logics gets simpler than way. > return OVL_FILEID; > } > @@ -781,7 +782,7 @@ static struct dentry *ovl_fh_to_dentry(struct super_block *sb, struct fid *fid, > int fh_len, int fh_type) > { > struct dentry *dentry = NULL; > - struct ovl_fh *fh = (struct ovl_fh *) fid; > + struct ovl_fh *fh = (void *) fid - OVL_FH_WIRE_OFFSET; Not enough, I'm afraid... Look what happens when you get to passing the payload to ovl_decode_real_fh(). You pass a misaligned pointer (1 mod 4) in there, then an equally misaligned pointer is passed to exportfs_decode_fh(). You really need to move that sucker here - the underlying fhandle is really misaligned in what gets passed to you. > @@ -119,11 +120,11 @@ static struct ovl_fh *ovl_get_fh(struct dentry *dentry, const char *name) > if (res == 0) > return NULL; > > - fh = kzalloc(res, GFP_KERNEL); > + fh = kzalloc(res + OVL_FH_WIRE_OFFSET, GFP_KERNEL); > if (!fh) > return ERR_PTR(-ENOMEM); > > - res = vfs_getxattr(dentry, name, fh, res); > + res = vfs_getxattr(dentry, name, fh + OVL_FH_WIRE_OFFSET, res); > if (res < 0) > goto fail; BTW, is there any point in precisely-sized allocations here? Again, the result won't live long, and we know the upper limit on the size, so why bother with two vfs_getxattr() calls, etc?