Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp2970806imu; Sun, 9 Dec 2018 13:59:08 -0800 (PST) X-Google-Smtp-Source: AFSGD/WrBaT6P4T1nfojgmBVFbQZqaS5Fi2djR0kP5dWKHLWkXoGiGvn5srBhxEHI/ebdEwmXVgi X-Received: by 2002:a63:ae01:: with SMTP id q1mr8621157pgf.402.1544392748539; Sun, 09 Dec 2018 13:59:08 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1544392748; cv=none; d=google.com; s=arc-20160816; b=x7IaHv/Eb04xayAQTuNmi9IyXmb8AyY7/ojrhrdhlznx3egndSPHLT1mMxphZDZgom JmZij2R8BGpiZE+yJnbG+7w0jTkCYI3XLmATd7wjBJ8SDw0SWkH4DGkDbLp+1CsJD3ti TGXNRr43ogG22WAhd6QCu6ILg3kQGoqIWKpI2Rk8rv3KtmlxD1hCgSPPPX4Q9cZKn5FD swCzOAjLcBa04pewZ6FNvGFyKlYxdX6Vf7mSsVU0zY/d1mac3OXsSAT5q9zV9DGX7UT5 5PWeVsDW8O0inB12Bo1SKuTS93YZoHJmuqCWcxqIkUzF0SFTX55AgDd5r6TfGmAAMB1d 7q5A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:in-reply-to:subject:message-id:date:cc:to :from:mime-version:content-transfer-encoding:content-disposition; bh=nteCVf7mqLwi+lBW21FT3XnBBRSNx5ihBWgFGos6Wq8=; b=A19xExLK73XAHcGKBENaNyDLltbsKlctnQPJzXcWychHmPedo+1gR+BvO8j5/uxuXg DWqBVGpRox+GKJIyYbFU0/kBaeJ5wxKkJZY1/khilAxtgwBaZg5Dzhea96JLR4pY8I0R npOsZn77gDN9VSqlaTOIyKkobs4BweuS3yId/ccn9+XDhRbLwYKUuLZbzi5vrrLxHE77 1OCTwGSLbzAprjbAH8eEJabfICiRGBJ+3JZo63Fz53au84dZJn4TUzVwb4D2tW4pPm/k jpZZiSXmwZtHkbomMSkb0BTNViu+l2rB5VRxnQ6o+yfThEsxkr9ZJtR25FZHbF6hLsP1 lZvg== 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 g124si7814948pgc.568.2018.12.09.13.58.53; Sun, 09 Dec 2018 13:59:08 -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 S1726788AbeLIVzk (ORCPT + 99 others); Sun, 9 Dec 2018 16:55:40 -0500 Received: from shadbolt.e.decadent.org.uk ([88.96.1.126]:35342 "EHLO shadbolt.e.decadent.org.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726539AbeLIVzY (ORCPT ); Sun, 9 Dec 2018 16:55:24 -0500 Received: from pub.yeoldevic.com ([81.174.156.145] helo=deadeye) by shadbolt.decadent.org.uk with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.89) (envelope-from ) id 1gW72n-0002ij-9g; Sun, 09 Dec 2018 21:55:21 +0000 Received: from ben by deadeye with local (Exim 4.91) (envelope-from ) id 1gW72k-0003e9-F5; Sun, 09 Dec 2018 21:55:18 +0000 Content-Type: text/plain; charset="UTF-8" Content-Disposition: inline Content-Transfer-Encoding: 8bit MIME-Version: 1.0 From: Ben Hutchings To: linux-kernel@vger.kernel.org, stable@vger.kernel.org CC: akpm@linux-foundation.org, "Steve French" , "Paulo Alcantara" , "Ronnie Sahlberg" , "Aurelien Aptel" Date: Sun, 09 Dec 2018 21:50:33 +0000 Message-ID: X-Mailer: LinuxStableQueue (scripts by bwh) X-Patchwork-Hint: ignore Subject: [PATCH 3.16 291/328] smb2: fix missing files in root share directory listing In-Reply-To: X-SA-Exim-Connect-IP: 81.174.156.145 X-SA-Exim-Mail-From: ben@decadent.org.uk X-SA-Exim-Scanned: No (on shadbolt.decadent.org.uk); SAEximRunCond expanded to false Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 3.16.62-rc1 review patch. If anyone has any objections, please let me know. ------------------ From: Aurelien Aptel commit 0595751f267994c3c7027377058e4185b3a28e75 upstream. When mounting a Windows share that is the root of a drive (eg. C$) the server does not return . and .. directory entries. This results in the smb2 code path erroneously skipping the 2 first entries. Pseudo-code of the readdir() code path: cifs_readdir(struct file, struct dir_context) initiate_cifs_search <-- if no reponse cached yet server->ops->query_dir_first dir_emit_dots dir_emit <-- adds "." and ".." if we're at pos=0 find_cifs_entry initiate_cifs_search <-- if pos < start of current response (restart search) server->ops->query_dir_next <-- if pos > end of current response (fetch next search res) for(...) <-- loops over cur response entries starting at pos cifs_filldir <-- skip . and .., emit entry cifs_fill_dirent dir_emit pos++ A) dir_emit_dots() always adds . & .. and sets the current dir pos to 2 (0 and 1 are done). Therefore we always want the index_to_find to be 2 regardless of if the response has . and .. B) smb1 code initializes index_of_last_entry with a +2 offset in cifssmb.c CIFSFindFirst(): psrch_inf->index_of_last_entry = 2 /* skip . and .. */ + psrch_inf->entries_in_buffer; Later in find_cifs_entry() we want to find the next dir entry at pos=2 as a result of (A) first_entry_in_buffer = cfile->srch_inf.index_of_last_entry - cfile->srch_inf.entries_in_buffer; This var is the dir pos that the first entry in the buffer will have therefore it must be 2 in the first call. If we don't offset index_of_last_entry by 2 (like in (B)), first_entry_in_buffer=0 but we were instructed to get pos=2 so this code in find_cifs_entry() skips the 2 first which is ok for non-root shares, as it skips . and .. from the response but is not ok for root shares where the 2 first are actual files pos_in_buf = index_to_find - first_entry_in_buffer; // pos_in_buf=2 // we skip 2 first response entries :( for (i = 0; (i < (pos_in_buf)) && (cur_ent != NULL); i++) { /* go entry by entry figuring out which is first */ cur_ent = nxt_dir_entry(cur_ent, end_of_smb, cfile->srch_inf.info_level); } C) cifs_filldir() skips . and .. so we can safely ignore them for now. Sample program: int main(int argc, char **argv) { const char *path = argc >= 2 ? argv[1] : "."; DIR *dh; struct dirent *de; printf("listing path <%s>\n", path); dh = opendir(path); if (!dh) { printf("opendir error %d\n", errno); return 1; } while (1) { de = readdir(dh); if (!de) { if (errno) { printf("readdir error %d\n", errno); return 1; } printf("end of listing\n"); break; } printf("off=%lu <%s>\n", de->d_off, de->d_name); } return 0; } Before the fix with SMB1 on root shares: <.> off=1 <..> off=2 <$Recycle.Bin> off=3 off=4 and on non-root shares: <.> off=1 <..> off=4 <-- after adding .., the offsets jumps to +2 because <2536> off=5 we skipped . and .. from response buffer (C) <411> off=6 but still incremented pos off=7 off=8 Therefore the fix for smb2 is to mimic smb1 behaviour and offset the index_of_last_entry by 2. Test results comparing smb1 and smb2 before/after the fix on root share, non-root shares and on large directories (ie. multi-response dir listing): PRE FIX ======= pre-1-root VS pre-2-root: ERR pre-2-root is missing [bootmgr, $Recycle.Bin] pre-1-nonroot VS pre-2-nonroot: OK~ same files, same order, different offsets pre-1-nonroot-large VS pre-2-nonroot-large: OK~ same files, same order, different offsets POST FIX ======== post-1-root VS post-2-root: OK same files, same order, same offsets post-1-nonroot VS post-2-nonroot: OK same files, same order, same offsets post-1-nonroot-large VS post-2-nonroot-large: OK same files, same order, same offsets REGRESSION? =========== pre-1-root VS post-1-root: OK same files, same order, same offsets pre-1-nonroot VS post-1-nonroot: OK same files, same order, same offsets BugLink: https://bugzilla.samba.org/show_bug.cgi?id=13107 Signed-off-by: Aurelien Aptel Signed-off-by: Paulo Alcantara Reviewed-by: Ronnie Sahlberg Signed-off-by: Steve French Signed-off-by: Ben Hutchings --- fs/cifs/smb2ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -743,7 +743,7 @@ smb2_query_dir_first(const unsigned int } srch_inf->entries_in_buffer = 0; - srch_inf->index_of_last_entry = 0; + srch_inf->index_of_last_entry = 2; rc = SMB2_query_directory(xid, tcon, fid->persistent_fid, fid->volatile_fid, 0, srch_inf);