Bug 10284

Summary: executables with read bit 'off' cannot open /dev/stdin
Product: File System Reporter: Joe Carlson (joe)
Component: devfsAssignee: fs_devfs
Status: CLOSED PATCH_ALREADY_AVAILABLE    
Severity: normal CC: randy.dunlap
Priority: P1    
Hardware: All   
OS: Linux   
Kernel Version: 2.6.16.27-0.9-smp Subsystem:
Regression: --- Bisected commit-id:

Description Joe Carlson 2008-03-19 13:15:35 UTC
Latest working kernel version: 2.6.16.27
Earliest failing kernel version: 2.4.21
Distribution: suse
Hardware Environment: x86_64
Software Environment:
Problem Description: if the read bit of a binary executable is off, then open() on /dev/stdin fails with a EACCES error.

Steps to reproduce:
A short program that calls open on /dev/stdin:

cat open_stdin.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
 
int main(int argc, char **argv) {
  open("/dev/stdin",O_RDONLY);
  return 0;
}

tracing system calls with normal operation shows that this completes successfully. But: 

chmod -r open_stdin
strace ./open_stdin
execve("./open_stdin", ["./open_stdin"], [/* 96 vars */]) = 0
brk(0)                                  = 0x501000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b25d01b6000
uname({sys="Linux", node="lush", ...})  = 0
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
... (open's on .so's deleted) ...
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=158841, ...}) = 0
mmap(NULL, 158841, PROT_READ, MAP_PRIVATE, 3, 0) = 0x2b25d01b7000
close(3)                                = 0
open("/lib64/libc.so.6", O_RDONLY)      = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\322\1\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1475924, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b25d01de000
mmap(NULL, 2289896, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x2b25d02b8000
madvise(0x2b25d02b8000, 2289896, MADV_SEQUENTIAL|0x1) = 0
mprotect(0x2b25d03df000, 1044480, PROT_NONE) = 0
mmap(0x2b25d04de000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x126000) = 0x2b25d04de000
mmap(0x2b25d04e3000, 16616, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x2b25d04e3000close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b25d04e8000
arch_prctl(ARCH_SET_FS, 0x2b25d04e86d0) = 0
mprotect(0x2b25d04de000, 12288, PROT_READ) = 0
munmap(0x2b25d01b7000, 158841)          = 0
open("/dev/stdin", O_RDONLY)            = -1 EACCES (Permission denied)


The last line shows a Permission denied error on opening /dev/stdin. If a normal filesystem (i.e. not-/dev/) filename is used, the open works normally.

I have reproduced this on 2.4 and 2.6 kernels
Just a guess here: is an error flag from attempting to read the binary not getting cleared and is being reported when trying to open stdin?
Comment 1 Anonymous Emailer 2008-03-19 14:31:11 UTC
Reply-To: akpm@linux-foundation.org


(switched to email.  Please respond via emailed reply-to-all, not via the
bugzilla web interface).

On Wed, 19 Mar 2008 13:15:36 -0700 (PDT)
bugme-daemon@bugzilla.kernel.org wrote:

> http://bugzilla.kernel.org/show_bug.cgi?id=10284
> 
>            Summary: executables with read bit 'off' cannot open /dev/stdin
>            Product: File System
>            Version: 2.5
>      KernelVersion: 2.6.16.27-0.9-smp
>           Platform: All
>         OS/Version: Linux
>               Tree: Mainline
>             Status: NEW
>           Severity: normal
>           Priority: P1
>          Component: devfs
>         AssignedTo: fs_devfs@kernel-bugs.osdl.org
>         ReportedBy: joe@fruitfly.org
> 
> 
> Latest working kernel version: 2.6.16.27
> Earliest failing kernel version: 2.4.21
> Distribution: suse
> Hardware Environment: x86_64
> Software Environment:
> Problem Description: if the read bit of a binary executable is off, then
> open()
> on /dev/stdin fails with a EACCES error.

This is, umm, unexpected?

> Steps to reproduce:
> A short program that calls open on /dev/stdin:
> 
> cat open_stdin.c
> #include <stdio.h>
> #include <stdlib.h>
> #include <sys/types.h>
> #include <sys/stat.h>
> #include <fcntl.h>
> 
> int main(int argc, char **argv) {
>   open("/dev/stdin",O_RDONLY);
>   return 0;
> }
> 
> tracing system calls with normal operation shows that this completes
> successfully. But: 
> 
> chmod -r open_stdin
> strace ./open_stdin
> execve("./open_stdin", ["./open_stdin"], [/* 96 vars */]) = 0
> brk(0)                                  = 0x501000
> mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =
> 0x2b25d01b6000
> uname({sys="Linux", node="lush", ...})  = 0
> access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or
> directory)
> ... (open's on .so's deleted) ...
> open("/etc/ld.so.cache", O_RDONLY)      = 3
> fstat(3, {st_mode=S_IFREG|0644, st_size=158841, ...}) = 0
> mmap(NULL, 158841, PROT_READ, MAP_PRIVATE, 3, 0) = 0x2b25d01b7000
> close(3)                                = 0
> open("/lib64/libc.so.6", O_RDONLY)      = 3
> read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\322\1\0"..., 832) =
> 832
> fstat(3, {st_mode=S_IFREG|0755, st_size=1475924, ...}) = 0
> mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =
> 0x2b25d01de000
> mmap(NULL, 2289896, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) =
> 0x2b25d02b8000
> madvise(0x2b25d02b8000, 2289896, MADV_SEQUENTIAL|0x1) = 0
> mprotect(0x2b25d03df000, 1044480, PROT_NONE) = 0
> mmap(0x2b25d04de000, 20480, PROT_READ|PROT_WRITE,
> MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x126000) = 0x2b25d04de000
> mmap(0x2b25d04e3000, 16616, PROT_READ|PROT_WRITE,
> MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x2b25d04e3000close(3)          
>                     = 0
> mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =
> 0x2b25d04e8000
> arch_prctl(ARCH_SET_FS, 0x2b25d04e86d0) = 0
> mprotect(0x2b25d04de000, 12288, PROT_READ) = 0
> munmap(0x2b25d01b7000, 158841)          = 0
> open("/dev/stdin", O_RDONLY)            = -1 EACCES (Permission denied)
> 
> 
> The last line shows a Permission denied error on opening /dev/stdin. If a
> normal filesystem (i.e. not-/dev/) filename is used, the open works normally.
> 
> I have reproduced this on 2.4 and 2.6 kernels
> Just a guess here: is an error flag from attempting to read the binary not
> getting cleared and is being reported when trying to open stdin?
> 
Comment 2 Joe Carlson 2008-03-19 14:45:38 UTC
On Wed, 2008-03-19 at 14:31 -0700, bugme-daemon@bugzilla.kernel.org
wrote:
> http://bugzilla.kernel.org/show_bug.cgi?id=10284
> 
> 
> 
> 
> 
> ------- Comment #1 from anonymous@kernel-bugs.osdl.org  2008-03-19 14:31
> -------
> Reply-To: akpm@linux-foundation.org
> 
> 
> (switched to email.  Please respond via emailed reply-to-all, not via the
> bugzilla web interface).
> 
> On Wed, 19 Mar 2008 13:15:36 -0700 (PDT)
> bugme-daemon@bugzilla.kernel.org wrote:
> 
> > http://bugzilla.kernel.org/show_bug.cgi?id=10284
> > 
> >            Summary: executables with read bit 'off' cannot open /dev/stdin
> >            Product: File System
> >            Version: 2.5
> >      KernelVersion: 2.6.16.27-0.9-smp
> >           Platform: All
> >         OS/Version: Linux
> >               Tree: Mainline
> >             Status: NEW
> >           Severity: normal
> >           Priority: P1
> >          Component: devfs
> >         AssignedTo: fs_devfs@kernel-bugs.osdl.org
> >         ReportedBy: joe@fruitfly.org
> > 
> > 
> > Latest working kernel version: 2.6.16.27
> > Earliest failing kernel version: 2.4.21
> > Distribution: suse
> > Hardware Environment: x86_64
> > Software Environment:
> > Problem Description: if the read bit of a binary executable is off, then
> open()
> > on /dev/stdin fails with a EACCES error.
> 
> This is, umm, unexpected?
> 

this is, well duh, unexpected.

./here_is_my_program_that_reads_a_file my_file

works OK.

./here_is_my_program_that_reads_a_file /dev/stdin < my_file

gets a permission denied error.

This seems like normal behavior? If so, you should contact Sun. They've
clearly gotten it wrong.

> > Steps to reproduce:
> > A short program that calls open on /dev/stdin:
> > 
> > cat open_stdin.c
> > #include <stdio.h>
> > #include <stdlib.h>
> > #include <sys/types.h>
> > #include <sys/stat.h>
> > #include <fcntl.h>
> > 
> > int main(int argc, char **argv) {
> >   open("/dev/stdin",O_RDONLY);
> >   return 0;
> > }
> > 
> > tracing system calls with normal operation shows that this completes
> > successfully. But: 
> > 
> > chmod -r open_stdin
> > strace ./open_stdin
> > execve("./open_stdin", ["./open_stdin"], [/* 96 vars */]) = 0
> > brk(0)                                  = 0x501000
> > mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =
> > 0x2b25d01b6000
> > uname({sys="Linux", node="lush", ...})  = 0
> > access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or
> directory)
> > ... (open's on .so's deleted) ...
> > open("/etc/ld.so.cache", O_RDONLY)      = 3
> > fstat(3, {st_mode=S_IFREG|0644, st_size=158841, ...}) = 0
> > mmap(NULL, 158841, PROT_READ, MAP_PRIVATE, 3, 0) = 0x2b25d01b7000
> > close(3)                                = 0
> > open("/lib64/libc.so.6", O_RDONLY)      = 3
> > read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\322\1\0"..., 832)
> =
> > 832
> > fstat(3, {st_mode=S_IFREG|0755, st_size=1475924, ...}) = 0
> > mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =
> > 0x2b25d01de000
> > mmap(NULL, 2289896, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) =
> > 0x2b25d02b8000
> > madvise(0x2b25d02b8000, 2289896, MADV_SEQUENTIAL|0x1) = 0
> > mprotect(0x2b25d03df000, 1044480, PROT_NONE) = 0
> > mmap(0x2b25d04de000, 20480, PROT_READ|PROT_WRITE,
> > MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x126000) = 0x2b25d04de000
> > mmap(0x2b25d04e3000, 16616, PROT_READ|PROT_WRITE,
> > MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x2b25d04e3000close(3)        
> >                     = 0
> > mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =
> > 0x2b25d04e8000
> > arch_prctl(ARCH_SET_FS, 0x2b25d04e86d0) = 0
> > mprotect(0x2b25d04de000, 12288, PROT_READ) = 0
> > munmap(0x2b25d01b7000, 158841)          = 0
> > open("/dev/stdin", O_RDONLY)            = -1 EACCES (Permission denied)
> > 
> > 
> > The last line shows a Permission denied error on opening /dev/stdin. If a
> > normal filesystem (i.e. not-/dev/) filename is used, the open works
> normally.
> > 
> > I have reproduced this on 2.4 and 2.6 kernels
> > Just a guess here: is an error flag from attempting to read the binary not
> > getting cleared and is being reported when trying to open stdin?
> > 
> 
> 
Comment 3 Matthew Wilcox 2008-03-19 15:28:59 UTC
On Wed, Mar 19, 2008 at 02:31:08PM -0700, Andrew Morton wrote:
> > Problem Description: if the read bit of a binary executable is off, then
> open()
> > on /dev/stdin fails with a EACCES error.
> 
> This is, umm, unexpected?

I'm not sure it's unexpected.  It's undesirable, certainly.

> > open("/dev/stdin", O_RDONLY)            = -1 EACCES (Permission denied)
> > 
> > The last line shows a Permission denied error on opening /dev/stdin. If a
> > normal filesystem (i.e. not-/dev/) filename is used, the open works
> normally.
> > 
> > I have reproduced this on 2.4 and 2.6 kernels
> > Just a guess here: is an error flag from attempting to read the binary not
> > getting cleared and is being reported when trying to open stdin?

I think the guess is faulty.  Could you show ls -l /dev/stdin ?  On my
system, it reports:

lrwxrwxrwx 1 root root 15 2008-03-10 11:03 /dev/stdin -> /proc/self/fd/0

Wild guess: Users can't access /proc/ directories of executables with the
read-bit clear in order to prevent users from reading the state anyway.

I wonder how effective clearing the read-bit is these days.
Don't we all have source to all the applications anyway?  ;-)
Comment 4 Joe Carlson 2008-03-19 16:06:52 UTC
On Wed, 2008-03-19 at 15:28 -0700, bugme-daemon@bugzilla.kernel.org
wrote:
> http://bugzilla.kernel.org/show_bug.cgi?id=10284
> 
> 
> 
> 
> 
> ------- Comment #3 from matthew@wil.cx  2008-03-19 15:28 -------
> On Wed, Mar 19, 2008 at 02:31:08PM -0700, Andrew Morton wrote:
> > > Problem Description: if the read bit of a binary executable is off, then
> open()
> > > on /dev/stdin fails with a EACCES error.
> > 
> > This is, umm, unexpected?
> 
> I'm not sure it's unexpected.  It's undesirable, certainly.
> 
> > > open("/dev/stdin", O_RDONLY)            = -1 EACCES (Permission denied)
> > > 
> > > The last line shows a Permission denied error on opening /dev/stdin. If a
> > > normal filesystem (i.e. not-/dev/) filename is used, the open works
> normally.
> > > 
> > > I have reproduced this on 2.4 and 2.6 kernels
> > > Just a guess here: is an error flag from attempting to read the binary
> not
> > > getting cleared and is being reported when trying to open stdin?
> 
> I think the guess is faulty.  Could you show ls -l /dev/stdin ?  On my
> system, it reports:
> 
> lrwxrwxrwx 1 root root 15 2008-03-10 11:03 /dev/stdin -> /proc/self/fd/0
> 
> Wild guess: Users can't access /proc/ directories of executables with the
> read-bit clear in order to prevent users from reading the state anyway.
> 

 ls -l /dev/stdin
lrwxrwxrwx 1 root root 15 2007-04-13 01:08 /dev/stdin -> /proc/self/fd/0
 ls -l /proc/self/fd/0
lrwx------ 1 joe genome 64 2008-03-19 22:24 /proc/self/fd/0 -> /dev/pts/0
 ls -l /dev/pts/0
crw--w---- 1 joe tty 136, 0 2008-03-19 22:31 /dev/pts/0

permissions look OK to me. In any case, why should toggling the read bit
on the executable affect this?

> I wonder how effective clearing the read-bit is these days.
> Don't we all have source to all the applications anyway?  ;-)
> 
> 
I'll work on clearing the read bit if you work on rewriting the unix
books.
Comment 5 Matthew Wilcox 2008-03-19 18:57:10 UTC
On Wed, Mar 19, 2008 at 02:31:08PM -0700, Andrew Morton wrote:
> (switched to email.  Please respond via emailed reply-to-all, not via the
> bugzilla web interface).

Unfortunately, Joe seems not to be able to follow that instruction.
He's left two comments in bugzilla which are not reflected in this email
thread.

> >      KernelVersion: 2.6.16.27-0.9-smp
> > A short program that calls open on /dev/stdin:
> > 
> > cat open_stdin.c
> > #include <stdio.h>
> > #include <stdlib.h>
> > #include <sys/types.h>
> > #include <sys/stat.h>
> > #include <fcntl.h>
> > 
> > int main(int argc, char **argv) {
> >   open("/dev/stdin",O_RDONLY);
> >   return 0;
> > }

I've tried this program on 2.6.25-rc3-00093-g59e1338-dirty and it does
not fail.

> > open("/dev/stdin", O_RDONLY)            = -1 EACCES (Permission denied)

Specifically, my tests show:

open-stdin-readable:open("/dev/stdin", O_RDONLY)            = 3
open-stdin-unreadable:open("/dev/stdin", O_RDONLY)            = 3

Joe, can you try a more recent kernel?

Another thing to try would be opening /proc/self/fd/0 or /dev/pts/0
in your program and seeing whether those fail.
Comment 6 Arjan van de Ven 2008-03-19 21:04:08 UTC
On Wed, 19 Mar 2008 19:56:50 -0600
Matthew Wilcox <matthew@wil.cx> wrote:


> I've tried this program on 2.6.25-rc3-00093-g59e1338-dirty and it does
> not fail.
> 
> > > open("/dev/stdin", O_RDONLY)            = -1 EACCES (Permission
> > > denied)
> 
> Specifically, my tests show:
> 
> open-stdin-readable:open("/dev/stdin", O_RDONLY)            = 3
> open-stdin-unreadable:open("/dev/stdin", O_RDONLY)            = 3
> 
> Joe, can you try a more recent kernel?

another interesting question is if you're using some special LSM/security stuff..
Comment 7 Joe Carlson 2008-03-20 10:12:43 UTC
On Wed, 2008-03-19 at 18:57 -0700, bugme-daemon@bugzilla.kernel.org
wrote:
> http://bugzilla.kernel.org/show_bug.cgi?id=10284
> 
> 
> 
> 
> 
> ------- Comment #5 from matthew@wil.cx  2008-03-19 18:57 -------
> On Wed, Mar 19, 2008 at 02:31:08PM -0700, Andrew Morton wrote:
> > (switched to email.  Please respond via emailed reply-to-all, not via the
> > bugzilla web interface).
> 
> Unfortunately, Joe seems not to be able to follow that instruction.
> He's left two comments in bugzilla which are not reflected in this email
> thread.
> 

I'm honestly puzzled by this remark. What two comments are you referring
to?


> > >      KernelVersion: 2.6.16.27-0.9-smp
> > > A short program that calls open on /dev/stdin:
> > > 
> > > cat open_stdin.c
> > > #include <stdio.h>
> > > #include <stdlib.h>
> > > #include <sys/types.h>
> > > #include <sys/stat.h>
> > > #include <fcntl.h>
> > > 
> > > int main(int argc, char **argv) {
> > >   open("/dev/stdin",O_RDONLY);
> > >   return 0;
> > > }
> 
> I've tried this program on 2.6.25-rc3-00093-g59e1338-dirty and it does
> not fail.
> 
> > > open("/dev/stdin", O_RDONLY)            = -1 EACCES (Permission denied)
> 
> Specifically, my tests show:
> 
> open-stdin-readable:open("/dev/stdin", O_RDONLY)            = 3
> open-stdin-unreadable:open("/dev/stdin", O_RDONLY)            = 3
> 
> Joe, can you try a more recent kernel?
> 
> Another thing to try would be opening /proc/self/fd/0 or /dev/pts/0
> in your program and seeing whether those fail.
> 
> 

I'm collecting data from the available systems here. I'm trying to
the /dev/stdin or the device file that /dev/stdin points to. I chase the
link untill it terminates. Chasing the link is different on the
different machines. 

In all cases ls -l shows owner read/write permissions on the device.
There are no special security modules installed and these are all
out-of-the-box kernels. With the read bit set on the binary it works in
all cases.

old kernel 2.4.21-231-smp i686 SUSE distribution
	with read bit clear:
		/dev/stdin EACCESS
		/dev/fd/0 EACCESS
		/dev/pts/5 success

2.6.8-24-default i686 SUSE distribution
	with read bit clear:
		/dev/stdin success
		/dev/fd/0 success
		/dev/pts/5 success

2.6.16.27-0.9-smp x86_64 SUSE distribution.
	with read bit clear:
		/dev/stdin EACCESS
		/proc/self/fd/0 EACCESS
		/dev/pts/0 success

2.6.22-14-generic i686 Ubuntu		
	with read bit clear:
		/dev/stdin success
		/proc/self/fd/0 success
		/dev/pts/10 success

In summary: broken in my 2.4 kernel, fixed in 2.6.8, broke in 2.6.16 and
fixed in 2.6.22