Received: by 2002:ac0:aed5:0:0:0:0:0 with SMTP id t21csp2125371imb; Sun, 3 Mar 2019 19:09:13 -0800 (PST) X-Google-Smtp-Source: APXvYqxAISJUqTiBQgsVHul8dhtHcVv3dgPxLPIBQFW2LL4QGrFylgp306ahQaficIkK6CVU9mY2 X-Received: by 2002:a17:902:b904:: with SMTP id bf4mr17791447plb.273.1551668953212; Sun, 03 Mar 2019 19:09:13 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1551668953; cv=none; d=google.com; s=arc-20160816; b=JrDZ1Dq4N3BNl57LCGsBXHRlmN1sp7s9LXq04EmnYIhMYiRW47Shr1m9jDmLarCXjC f5k5cDxpfo1OBKB+MRfkSOYZfrXxqMFXT6PdTWQTJad3EKE112hbos7XEnEvj5GO0O+M QX50cBeT619CgcfOvm6h4UtzU97VZWX27yn2Vzk/de8AewaFkqUu9W3E4c/1K0N9UMcB zsSYuUYzOY98vq/6wnJ2A+ZzS0zZWAWdPbpKVxTV50N8jjMsmW6mIQnMLkRV+iUV68s0 XqL/ykV0+vbitCVZMLjY+QYodsGEhGloniNIoqSmH5LBjIFZvP/xJ8aid4HXIB3CxSAM z0ZQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:message-id:cc:subject:date :to:from; bh=eOZsPU9xtijFnpI/mqDrpIOWhhqnUFgVU/bDAXkh2U4=; b=FySpPeAnTUs+9UI7thHHnKXYyDI6gYjNAaAmVTe6hceNmqnKPXGrOO4hj+zX7SEAeJ ERdOUSHd2ihdQIY71m2SlKNpANdftlvDf2Tf6TDGWOgzufZICbGx0jRTHctztGLJ3NY0 KzsrAgnTLGF1ZbWoR5SmFxCchY/gd5rlv0Cs6Pmx+JZTwmCBX6OFJi6V78WwB8VxBWX/ wD0OKYxMD2T1hWj7Wos9g/TsQ2Y072ZxsBkuuCqxhDxJ3Eiz1UOzbfobELsGv6rKrTwd xu3nLwklYJE94MA2A+GcTH5NLRUdgwDvkq5/ANtsujTM8Wpk0Dml++j9TTWqO3i/sbPO zRhw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-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 w13si4010883pgr.356.2019.03.03.19.08.57; Sun, 03 Mar 2019 19:09:13 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-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-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726162AbfCDDIc (ORCPT + 99 others); Sun, 3 Mar 2019 22:08:32 -0500 Received: from mx2.suse.de ([195.135.220.15]:41782 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1725938AbfCDDIb (ORCPT ); Sun, 3 Mar 2019 22:08:31 -0500 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 622F1AEDF; Mon, 4 Mar 2019 03:08:30 +0000 (UTC) From: NeilBrown To: "J. Bruce Fields" , Jeff Layton Date: Mon, 04 Mar 2019 14:08:22 +1100 Subject: [PATCH] nfsd: fix memory corruption caused by readdir cc: linux-nfs@vger.kernel.org, linux-kernel@vger.kernel.org Message-ID: <87lg1vs5eh.fsf@notabene.neil.brown.name> MIME-Version: 1.0 Content-Type: multipart/signed; boundary="=-=-="; micalg=pgp-sha256; protocol="application/pgp-signature" Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org --=-=-= Content-Type: text/plain Content-Transfer-Encoding: quoted-printable If the result of an NFSv3 readdir{,plus} request results in the "offset" on one entry having to be split across 2 pages, and is sized so that the next directory entry doesn't fix in the requested size, then memory corruption can happen. When encode_entry() is called after encoding the last entry that fits, it notices that ->offset and ->offset1 are set, and so stores the offset value in the two pages as required. It clears ->offset1 but *does not* clear ->offset. Normally this omission doesn't matter as encode_entry_baggage() will be called, and will set ->offset to a suitable value (not on a page boundary). But in the case where cd->buflen < elen and nfserr_toosmall is returned, ->offset is not reset. This means that nfsd3proc_readdirplus will see ->offset with a value 4 bytes before the end of a page, and ->offset1 set to NULL. It will try to write 8bytes to ->offset. If we are lucky, the next page will be read-only, and the system will BUG: unable to handle kernel paging request at... If we are unlucky, some innocent page will have the first 4 bytes corrupted. nfsd3proc_readdir() doesn't even check for ->offset1, it just blindly writes 8 bytes to the offset wherever it is. Fix this by clearing ->offset after it is used, and copying the =2D>offset handling code from nfsd3_proc_readdirplus into nfsd3_proc_readdir. (Note that the commit hash in the Fixes tag is from the 'history' tree - this bug predates git). Fixes: eb229d253e6c ("[PATCH] kNFSd: fix two xdr-encode bugs for readdirplu= s reply") Cc: stable@vger.kernel.org (v2.6.12+) Signed-off-by: NeilBrown =2D-- Can I still get extra credit for fixing a bug that is 14.5 years old, if I'm the one who introduced it? fs/nfsd/nfs3proc.c | 16 ++++++++++++++-- fs/nfsd/nfs3xdr.c | 1 + 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index 9eb8086ea841..c9cf46e0c040 100644 =2D-- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c @@ -463,8 +463,19 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp) &resp->common, nfs3svc_encode_entry); memcpy(resp->verf, argp->verf, 8); resp->count =3D resp->buffer - argp->buffer; =2D if (resp->offset) =2D xdr_encode_hyper(resp->offset, argp->cookie); + if (resp->offset) { + loff_t offset =3D argp->cookie; + + if (unlikely(resp->offset1)) { + /* we ended up with offset on a page boundary */ + *resp->offset =3D htonl(offset >> 32); + *resp->offset1 =3D htonl(offset & 0xffffffff); + resp->offset1 =3D NULL; + } else { + xdr_encode_hyper(resp->offset, offset); + } + resp->offset =3D NULL; + } =20 RETURN_STATUS(nfserr); } @@ -533,6 +544,7 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp) } else { xdr_encode_hyper(resp->offset, offset); } + resp->offset =3D NULL; } =20 RETURN_STATUS(nfserr); diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 9b973f4f7d01..83919116d5cb 100644 =2D-- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -921,6 +921,7 @@ encode_entry(struct readdir_cd *ccd, const char *name, = int namlen, } else { xdr_encode_hyper(cd->offset, offset64); } + cd->offset =3D NULL; } =20 /* =2D-=20 2.14.0.rc0.dirty --=-=-= Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQIzBAEBCAAdFiEEG8Yp69OQ2HB7X0l6Oeye3VZigbkFAlx8lqcACgkQOeye3VZi gbmMZQ//X3PHTu3swQ0759WwQhkkdqXWlyt2uv8yzx3rcYeeP45AIzq2NS7tDsbJ JwD2qWS+QciC0VhizPVQ+pgPRJvGMrGOwTZGGiDxKIDVauCKTPLMLzSh2do8zO0o z9dyltflNwixZoeDp4l8mByQhx3Qh2yXkY6iHoNGmQVsnHltnC/t2akQDz2XlXJF /eoamBN6vmrjnniXTR5TivgygOC0LCBKnawbJNbWUPA7UhG+sP8mWiHTqz8jquym qOQRJnA7aOzxebA6RBTJScmcnT86S8bOFvY4lBbsxO6vVK9fsY0pQG2GALnT+S4R 8NMfGbO3dmcIn5ayCAEOYUp195O98PclJLeTqGyF9Pro25JCBI/9BUF2jQTSUhrh W8fNnGtGiEgMU25sX779q44jE4W20q/RENkyMH0u6bJUoaCc4mUVg0OTNRcO94NU 1ysnu3f6Pl90kwaWtS8xR0dZFOsiCTyZH2dKZQSOgfocM+pUk8wk4cCvkN2dcu6c H3oSPYP+lAIeFAuFWWljkHyIhheL6xAsP79548ixGiZDdebyMwt1b9zFDcF95aqV EsYaEmZaVmjDupPq/c9Kwhn8NUogK8E62wK6O0+D7wpntXB0y/TX5+3/j1e75qDD 0v3IguvlL30o62trjuLV/3vdPEiaeNPgML2QH9WyrtDBUKkVPXI= =D6y8 -----END PGP SIGNATURE----- --=-=-=--