Bug 7535 - Server directory without execute (or list_directory) privileges results in empty directory rathere than access denied
Server directory without execute (or list_directory) privileges results in em...
Status: ASSIGNED
Product: CifsVFS
Classification: Unclassified
Component: kernel fs
2.6
x86 Linux
: P3 normal
: ---
Assigned To: Suresh Jayaraman (mail address is dead)
:
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2010-06-28 19:08 UTC by Tom Dexter
Modified: 2010-10-26 07:55 UTC (History)
2 users (show)

See Also:


Attachments
Proposed patch (2.04 KB, patch)
2010-10-01 10:56 UTC, Suresh Jayaraman (mail address is dead)
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Tom Dexter 2010-06-28 19:08:34 UTC
There appears to be a bug in the way the CIFS file system handles directory permissions.  This is specifically when the user doesn't have (in the case of a Linux Samba server) execute permissions or (in the case of a Windows server) LIST_DIRECTORY permissions on a directory under the mounted directory.

In that situation any attempt to open the directory or read the directory contents doesn't result in any sort of permission denied error, but instead silently reports it as an empty directory.  This is a bit of a problem in an application of mine that ideally needs to know the difference.

In my testing, mounting the same share from a Windows server and attempting to open the directory results in a permission denied error as I would expect.

Just to verify what was going on I installed sharkwire to see what occurred when I attempted to do an "ls -l" of the un-readable directory.  What I see is that the client sends a FIND_NEXT2 request with the directory pattern.  The server then sends a STATUS_ACCESS_DENIED response.  Then I see that the client is sending another FIND_NEXT2 request for which the server sends an STATUS_INVALID_HANDLE response.

I do notice that, in the case where the user has no read permissions on the directory I do in fact get a permission denied error as apposed to simply an empty directory.

Specifically I'm running 2.6.32-gentoo-r7 under Gentoo, but I see the same behavior in every kernel I've tried, and the same with the SMB file system as well.

I emailed Steve French regarding this and he suggested I log this bug. Thanks!
Comment 1 Tom Dexter 2010-06-29 15:48:51 UTC
Interestingly I just discovered that the FUSE (sshfs) file system behaves the same way.  It too only gives access denied for directories with no read permission but reports directories without execute permission as empty.  That may not be relevant to this at all but I figured there was an off chance that there's some sort of virtual file system code they share.
Comment 2 Tom Dexter 2010-07-16 13:04:12 UTC
I emailed the ssh fs devs and as it turns out, the FUSE/sshfs situation is quite different. That uses the sftp protocol which apparently MUST stat the files when it reads the directory and has no way of reporting that there are in fact files there that it can't stat.
Comment 3 Suresh Jayaraman (mail address is dead) 2010-10-01 10:56:20 UTC
Created attachment 5992 [details]
Proposed patch

The attached patch fixes the problem for me. Could you please try the attached patch and report?
Comment 4 Tom Dexter 2010-10-01 19:59:16 UTC
I tried the patch against 2.6.35-gentoo-r7 and here's what I found.  I'm a little confused by the way it's working.

I tested with a cifs mount that contains a directory with no read or execute permissions that contains one file.  Without the patch this acts just like an empty directory.  With it, if I cd to the non-readable directory (which it does let me do) and do ls I get this:

ls: reading directory .: Permission denied

However, any program that uses things like opendir/readdir are still able to open the directory but don't read any contents, just as though it was an empty directory.  Here are both perl and php scripts that show this.  Note that in this test ./mount is my mountpoint and the directory nogood within that is not readable:

Perl:

opendir(D, './mount/nogood') || die ("Can't open!\n");
print "Reading...\n";
@d = readdir(D);
print "@d\n";

Output:
perl test.pl
Reading...

PHP:

<?php
if (is_readable('./mount/nogood')) {
	if (($d = opendir('./mount/nogood')) === false) {
		print "Can't open dir!\n";
	} else {
		print "Reading...\n";
		while (($file = readdir($d)) !== FALSE) {
			print "FILE: $file\n";
		}
	}
} else {
	print "Not readable\n";
}
?>

Output:
php test.php
Reading...

Without the patch, the above programs would have found the entries . and .. but not the actual file within the directory.

Like I say, very confusing behavior.  I would expect the diropen to fail, just as when the ls attempts to read the '.' entry in the directory.

Comment 5 Jeff Layton 2010-10-05 06:19:42 UTC
Suresh, is this the same problem that your recent readdir patch was intended to fix?
Comment 6 Jeff Layton 2010-10-05 06:26:08 UTC
Ahh now that I look...

What we would ideally like to have happen is for the opendir call to fail. The tricky part though is that CIFS (the protocol) doesn't have an open/readdir equivalent. The first call is a TRANS2_FIND_FIRST. What we could consider is having opendir result in a small FIND_FIRST call (with a small SearchCount value). Then have the actual readdir call do a FIND_NEXT and continue the search.
Comment 7 Jeff Layton 2010-10-05 06:27:55 UTC
Note that that change is a bit of a project. Directory file descriptor handling could use some work.
Comment 8 Suresh Jayaraman (mail address is dead) 2010-10-05 09:02:22 UTC
(In reply to comment #4)
> I tried the patch against 2.6.35-gentoo-r7 and here's what I found.  I'm a
> little confused by the way it's working.
> 
> I tested with a cifs mount that contains a directory with no read or execute
> permissions that contains one file.  Without the patch this acts just like an
> empty directory.  With it, if I cd to the non-readable directory (which it does
> let me do) and do ls I get this:
> 
> ls: reading directory .: Permission denied
> 
> However, any program that uses things like opendir/readdir are still able to
> open the directory but don't read any contents, just as though it was an empty
> directory.  Here are both perl and php scripts that show this.  Note that in
> this test ./mount is my mountpoint and the directory nogood within that is not
> readable:
> 
> Perl:
> 
> opendir(D, './mount/nogood') || die ("Can't open!\n");
> print "Reading...\n";
> @d = readdir(D);
> print "@d\n";
> 
> Output:
> perl test.pl
> Reading...
> 
> PHP:
> 
> <?php
> if (is_readable('./mount/nogood')) {
>         if (($d = opendir('./mount/nogood')) === false) {
>                 print "Can't open dir!\n";
>         } else {
>                 print "Reading...\n";
>                 while (($file = readdir($d)) !== FALSE) {
>                         print "FILE: $file\n";
>                 }
>         }
> } else {
>         print "Not readable\n";
> }
> ?>
> 
> Output:
> php test.php
> Reading...
> 

Are you doing this as a non-root user or as a root user?

Because using the same program, it fails with "Can't open" error.

$ll
d-w------- 2 vguest users         0 2010-10-01 23:30 tdir

vguest@linux-duw1:/mnt/cifs> cd tdir/
-bash: cd: tdir/: Permission denied

vguest@linux-duw1:/mnt/cifs> ll tdir/
ls: cannot open directory tdir/: Permission denied

Comment 9 Tom Dexter 2010-10-05 14:06:04 UTC
Suresh: I was running my test program as a non-root user.  There are a whole lot of things complicating the permission issues with this test though:  I mounted as root as the current version of mount.cifs I have won't let me do otherwise.  Also note that I'm mounting a windows share, NOT another samba share.  That windows share has all access turned off for everything (even system).  The windows user I'm specifying in the mount.cifs command actually does have admin rights to the windows machine, but again the test directory has all access shut off.  Oddly though (and this must be related to windows security which I'll never understand), here's what ls (of the mount point) shows:

drwxr-xr-x 1 root root       0 Oct  1 19:30 nogood

That 'nogood' directory is the one with all access off.  Don't ask me what that's all about.  Again I can cd to it, but attempting to do ls within it gives me permission denied on '.', and the test programs can open the dir but never see any contents.

In any case, whatever is causing it, it seems that there are still situations where a non readable directory just looks empty, with the only difference being the absence of the ability to see any contents at all, even '.'.

It sounds to me like the approach Jeff mentioned may be the only real fix.
Comment 10 Suresh Jayaraman (mail address is dead) 2010-10-25 05:31:44 UTC
(In reply to comment #9)
> security which I'll never understand), here's what ls (of the mount point)
> shows:
> 
> drwxr-xr-x 1 root root       0 Oct  1 19:30 nogood
> 
> That 'nogood' directory is the one with all access off.  Don't ask me what
> that's all about.  Again I can cd to it, but attempting to do ls within it
> gives me permission denied on '.', and the test programs can open the dir but
> never see any contents.

Are you doing the above tests as root user or the non-root user you mounted as? 
As the user you mounted (username provided in "user=" during mount), can you try these tests and report?
(though you mount as root, you can access the mount point as the user you mounted)

 
> In any case, whatever is causing it, it seems that there are still situations
> where a non readable directory just looks empty, with the only difference being
> the absence of the ability to see any contents at all, even '.'.

If you try this as a root user in any disk based filesystem (e.g. ext3), the behavior is the same:

#ls -l 
d-w--w--w- 2 root   root       4096 Oct 25 15:57 cdir

#cd cdir  #no error
#ls cdir  #no error

So, in my testing I'm seeing the CIFS behavior similar to that of any disk based filesystem with the fix.

Let me know if something works or didn't work differently.
Comment 11 Tom Dexter 2010-10-26 07:55:53 UTC
As far as the user I was mounting as (the user=...), when you say "root user", again I'm mounting a Windows share, but yes that user had local admin rights to the box.  I redid the test specifying a non-admin Windows user.  With both the old and the patched kernels I tries three things: 1) a php script that did an opendir and printing a list of and files it found with readdir, 2) cd'ing to the directory, and 3) doing an ls in the directory.  Again, on the Windows side the directory ("nogood" in the code below) has all permissions off, and cannot be opened even by a user with local admin rights, and contains a text file.  Here's the test php code:

if (!($d = opendir('./mount/nogood'))) {
	print "NG!!\n";
} else {
	print "OK!\n";
	while ($f = readdir($d)) {
		print "FILE: $f\n";
	}
}

With the original kernel, the the php test did this:
OK!
FILE: .
FILE: ..

Entering the directory with cd gave no errors, and doing ls gave no errors.

With the patched kernel, the php test did this:
OK!
That is, the only difference was that readdir never saw . or ..

Entering the directory with cd gave no errors, but attempting ls gave:
ls: reading directory .: Permission denied

The original issue I reported however still remains.  That is, opendir succeeds but the directory appears to be empty, when it in fact contains files.  I know of no situation on a disk file system directory that could act that way.