android_kernel_oneplus_msm8998/fs/cifs
Aurelien Aptel ec2a4f06e3 smb2: fix missing files in root share directory listing
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
<bootmgr>      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
<file> off=7
<fsx>  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 <aaptel@suse.com>
Signed-off-by: Paulo Alcantara <palcantara@suse.deR>
Reviewed-by: Ronnie Sahlberg <lsahlber@redhat.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
CC: Stable <stable@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-10-10 08:52:13 +02:00
..
asn1.c
cache.c
cifs_debug.c smb3: fix reset of bytes read and written stats 2018-09-15 09:40:39 +02:00
cifs_debug.h lib: update single-char callers of strtobool() 2016-10-28 03:01:30 -04:00
cifs_dfs_ref.c Fix that several functions handle incorrect value of mapchars 2015-05-10 19:56:35 -05:00
cifs_fs_sb.h fs/cifs: make share unaccessible at root level mountable 2016-08-20 18:09:20 +02:00
cifs_ioctl.h Add way to query server fs info for smb3 2015-08-20 10:19:25 -05:00
cifs_spnego.c KEYS: Merge the type-specific data with the payload data 2015-10-21 15:18:36 +01:00
cifs_spnego.h
cifs_unicode.c fs/cifs: don't translate SFM_SLASH (U+F026) to backslash 2018-10-10 08:52:11 +02:00
cifs_unicode.h CIFS: add misssing SFM mapping for doublequote 2017-05-20 14:27:01 +02:00
cifs_uniupr.h
cifsacl.c KEYS: Merge the type-specific data with the payload data 2015-10-21 15:18:36 +01:00
cifsacl.h
cifsencrypt.c CIFS: zero sensitive data when freeing 2018-02-16 20:09:39 +01:00
cifsfs.c SMB3: GUIDs should be constructed as random but valid uuids 2016-10-28 03:01:32 -04:00
cifsfs.h Fix cifs_uniqueid_to_ino_t() function for s390x 2016-03-09 15:34:50 -08:00
cifsglob.h CIFS: Reconnect expired SMB sessions 2017-10-18 09:20:40 +02:00
cifspdu.h Add way to query server fs info for smb3 2015-08-20 10:19:25 -05:00
cifsproto.h CIFS: Fix a possible memory corruption during reconnect 2017-01-06 11:16:15 +01:00
cifssmb.c fs/cifs: suppress a string overflow warning 2018-10-10 08:52:12 +02:00
connect.c CIFS: zero sensitive data when freeing 2018-02-16 20:09:39 +01:00
dir.c cifs: do not allow creating sockets except with SMB1 posix exensions 2018-04-29 07:50:01 +02:00
dns_resolve.c
dns_resolve.h
export.c
file.c CIFS: silence lockdep splat in cifs_relock_file() 2018-04-13 19:50:03 +02:00
fscache.c NFS client updates for Linux 3.13 2013-11-08 05:57:46 +09:00
fscache.h CIFS: FS-Cache: Uncache unread pages in cifs_readpages() before freeing them 2013-09-18 10:17:03 -05:00
inode.c smb3: Do not send SMB3 SET_INFO if nothing changed 2018-09-05 09:18:37 +02:00
ioctl.c cifs: fix CIFS_IOC_GET_MNT_INFO oops 2017-05-20 14:27:01 +02:00
Kconfig Allow parsing vers=3.11 on cifs mount 2015-06-27 20:23:32 -07:00
link.c smb3: don't request leases in symlink creation and query 2018-09-05 09:18:37 +02:00
Makefile cifs: add new case-insensitive conversion routines that are based on wchar_t's 2013-09-08 14:38:05 -05:00
misc.c cifs: read overflow in is_valid_oplock_break() 2018-10-10 08:52:12 +02:00
netmisc.c cifs: small underflow in cnvrtDosUnixTm() 2018-03-24 10:58:46 +01:00
nterr.c
nterr.h
ntlmssp.h cifs: dynamic allocation of ntlmssp blob 2016-07-27 09:47:39 -07:00
readdir.c cifs: prevent integer overflow in nxt_dir_entry() 2018-09-26 08:35:08 +02:00
rfc1002pdu.h
sess.c cifs: check kmalloc before use 2018-09-05 09:18:37 +02:00
smb1ops.c CIFS: Improve readdir verbosity 2017-06-29 12:48:51 +02:00
smb2file.c CIFS: Fix a possible memory corruption in push locks 2017-01-06 11:16:16 +01:00
smb2glob.h cifs: Limit the overall credit acquired 2016-10-28 03:01:32 -04:00
smb2inode.c smb3: Do not send SMB3 SET_INFO if nothing changed 2018-09-05 09:18:37 +02:00
smb2maperror.c Fix problem recognizing symlinks 2014-10-02 14:10:04 -05:00
smb2misc.c cifs: check if SMB2 PDU size has been padded and suppress the warning 2018-09-15 09:40:37 +02:00
smb2ops.c smb2: fix missing files in root share directory listing 2018-10-10 08:52:13 +02:00
smb2pdu.c CIFS: fix wrapping bugs in num_entries() 2018-09-26 08:35:08 +02:00
smb2pdu.h CIFS: Fix maximum SMB2 header size 2017-09-07 08:34:09 +02:00
smb2proto.h Handle mismatched open calls 2017-05-08 07:46:01 +02:00
smb2status.h
smb2transport.c Handle mismatched open calls 2017-05-08 07:46:01 +02:00
smbencrypt.c cifs: use memzero_explicit to clear stack buffer 2015-01-19 15:32:13 -06:00
smberr.h
smbfsctl.h [SMB3] Send durable handle v2 contexts when use of persistent handles required 2015-11-03 09:26:27 -06:00
transport.c Handle mismatched open calls 2017-05-08 07:46:01 +02:00
winucase.c [CIFS] quiet sparse compile warning 2013-09-08 14:54:24 -05:00
xattr.c VFS: normal filesystems (and lustre): d_inode() annotations 2015-04-15 15:06:57 -04:00