Re: Outstanding question

adam morley <[email protected]> Sun, 9 Feb 2003 11:10:40 -0800
Newsgroups gmane.comp.djb.publicfile
Message-ID <[email protected]>
On Sun, Feb 09, 2003 at 03:24:09PM +0800, Adrian Ho wrote:
> On Sat, Feb 08, 2003 at 11:17:11PM -0500, marrandy wrote:
> > It reminded me that when I ps waux, I see it running as root although
> > it later sheds those privelidges.
> 
> No, you should be seeing /tcpserver/ running as root -- it spawns ftpd
> or httpd after accepting a connection.

This is how I thought it worked.

> 
> > My question is how do you verify that everything is working fine and it has 
> > shed privilidges etc.
> 
> As a one-off test, simply replace the call to httpd in your run script
> with /usr/bin/id (or whatever utility you use to determine the real and
> effective UIDs/GIDs on your system) and restart the service.  Then telnet
> to your httpd port and see for yourself.  Once you're satisfied, undo
> the above change and restart the service again.

Uh oh?  (or maybe I missed something):

# nc localhost 80
uid=0(root) gid=0(root)
# cat /home/public/httpd/run 
#!/bin/sh
exec 2>&1
exec envuidgid ftp softlimit -o20 -d50000 tcpserver -vDRHl0 -b50 -c100 0 80 /usr/bin/id
# cat /etc/passwd|grep ftp
ftp:x:21:21::/home/ftp:/bin/false
ftplog:x:1005:200::/home/public:
# tail -50 current
...
@400000003e46a0e21a0fca84 tcpserver: status: 0/100
@400000003e46a0ed0901debc tcpserver: status: 1/100
@400000003e46a0ed0904d874 tcpserver: pid 3452 from 127.0.0.1
@400000003e46a0ed0905b71c tcpserver: ok 3452 0:127.0.0.1:80 :127.0.0.1::58249
@400000003e46a0ed0c633de4 tcpserver: end 3452 status 0
@400000003e46a0ed0c635d24 tcpserver: status: 0/100
@400000003e46a1890e5b9efc tcpserver: status: 0/100
@400000003e46a18e2e7fa9e4 tcpserver: status: 1/100
@400000003e46a18e2e8297e4 tcpserver: pid 7831 from 127.0.0.1
@400000003e46a18e2e8372a4 tcpserver: ok 7831 0:127.0.0.1:80 :127.0.0.1::38284
@400000003e46a18e2eaa3484 tcpserver: end 7831 status 0
@400000003e46a18e2eaa4fdc tcpserver: status: 0/100
@400000003e46a1ac2ad34b84 tcpserver: status: 1/100
@400000003e46a1ac2ad6cdf4 tcpserver: pid 1893 from 129.22.134.15
@400000003e46a1ac2ad7b46c tcpserver: ok 1893 0:129.22.171.5:80 :129.22.134.15::41977
@400000003e46a1ac2afe62c4 tcpserver: end 1893 status 0
@400000003e46a1ac2afe7e1c tcpserver: status: 0/100
(notice I also came in from a machine offsite)

relevant straces for /usr/bin/httpd(this is on my linux laptop, fwiw):

tcpserver process:

accept(3, {sin_family=AF_INET, sin_port=htons(54539), sin_addr=inet_addr("127.0.0.1")}}, [16]) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], NULL, 8) = 0
write(2, "tcpserver: status: 1/100\n", 25) = 25
fork()                                  = 10888
close(0)                                = 0
rt_sigprocmask(SIG_UNBLOCK, [CHLD], NULL, 8) = 0
accept(3, 0xbffffd10, [16]) = ? ERESTARTSYS (To be restarted)
--- SIGCHLD (Child exited) ---
wait4(-1, [WIFEXITED(s) && WEXITSTATUS(s) == 0], WNOHANG, NULL) = 10888
write(2, "tcpserver: end 10888 status 0\n", 30) = 30
write(2, "tcpserver: status: 0/100\n", 25) = 25
wait4(-1, 0xbffffa04, WNOHANG, NULL)    = -1 ECHILD (No child processes)
sigreturn()                             = ? (mask now [])
rt_sigprocmask(SIG_BLOCK, [CHLD], NULL, 8) = 0
rt_sigprocmask(SIG_UNBLOCK, [CHLD], NULL, 8) = 0
accept(3,  <unfinished ...>

child httpd process:

close(3)                                = 0
getpid()                                = 10888
write(2, "tcpserver: pid 10888 from 127.0."..., 36) = 36
setsockopt(0, SOL_IP, IP_TOS, NULL, 0)  = 0
setsockopt(0, SOL_TCP, TCP_NODELAY, [1], 4) = 0
getsockname(0, {sin_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("127.0.0.1")}}, [16]) =
0
getpid()                                = 10888
write(2, "tcpserver: ok 10888 0:127.0.0.1:"..., 53) = 53
fcntl64(0, F_GETFL)                     = 0x2 (flags O_RDWR)
close(1)                                = -1 EBADF (Bad file descriptor)
fcntl64(0, F_DUPFD, 1)                  = 1
rt_sigaction(SIGCHLD, {SIG_DFL}, NULL, 8) = 0
rt_sigprocmask(SIG_UNBLOCK, [CHLD], NULL, 8) = 0
rt_sigaction(SIGTERM, {SIG_DFL}, NULL, 8) = 0
rt_sigaction(SIGPIPE, {SIG_DFL}, NULL, 8) = 0
execve("/usr/bin/httpd", ["/usr/bin/httpd", "/home/public/file"], [/* 20 vars */]) = 0
uname({sys="Linux", node="fedora", ...}) = 0
brk(0)                                  = 0x8050f20
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x4ee80000
open("/etc/ld.so.preload", O_RDONLY)    = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=2, ...}) = 0
mmap2(NULL, 2, PROT_READ|PROT_WRITE, MAP_PRIVATE, 3, 0) = 0x4ee81000
close(3)                                = 0
munmap(0x4ee81000, 2)                   = 0
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=87853, ...}) = 0
mmap2(NULL, 87853, PROT_READ, MAP_PRIVATE, 3, 0) = 0x4ee81000
close(3)                                = 0
open("/lib/libc.so.6", O_RDONLY)        = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\200Z\1"..., 1024) = 1024
fstat64(3, {st_mode=S_IFREG|0755, st_size=1450109, ...}) = 0
mmap2(NULL, 1235844, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x4ee97000
mprotect(0x4efbd000, 31620, PROT_NONE)  = 0
mmap2(0x4efbd000, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x125) = 0x4efbd000
mmap2(0x4efc1000, 15236, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x4efc
1000
close(3)                                = 0
munmap(0x4ee81000, 87853)               = 0
chdir("/home/public/file")              = 0
chroot(".")                             = 0
setgroups32(0x1, 0xbffffd30)            = 0
setgid32(0x15)                          = 0
setuid32(0x15)                          = 0
rt_sigaction(SIGPIPE, {SIG_IGN}, NULL, 8) = 0
select(1, [0], NULL, NULL, {60, 0})     = 1 (in [0], left {60, 0})
read(0, "GET / HTTP/1.1\r\nHost: 127.0.0.1\r"..., 512) = 446
open("./127.0.0.1/index.html", O_RDONLY|O_NONBLOCK) = -1 ENOENT (No such file or directory)
write(2, "127.0.0.1 read ./127.0.0.1/index"..., 72) = 72
time(NULL)                              = 1044816813
open("/etc/leapsecs.dat", O_RDONLY|O_NONBLOCK) = -1 ENOENT (No such file or directory)
select(2, NULL, [1], NULL, {60, 0})     = 1 (out [1], left {60, 0})
write(1, "HTTP/1.1 404 file does not exist"..., 204) = 204
shutdown(1, 1 /* send */)               = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigaction(SIGCHLD, NULL, {SIG_DFL}, 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
nanosleep({1, 0}, {1, 0})               = 0
_exit(0)                                = ?


(i notice the chroot and the setgroups, setgid, setuid calls)
now for a /usr/bin/id:

tcpserver process:

accept(3, {sin_family=AF_INET, sin_port=htons(42638), sin_addr=inet_addr("127.0.0.1")}}, [16]) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], NULL, 8) = 0
write(2, "tcpserver: status: 1/100\n", 25) = 25
fork()                                  = 2064
close(0)                                = 0
rt_sigprocmask(SIG_UNBLOCK, [CHLD], NULL, 8) = 0
accept(3, 0xbffffd20, [16]) = ? ERESTARTSYS (To be restarted)
--- SIGCHLD (Child exited) ---
wait4(-1, [WIFEXITED(s) && WEXITSTATUS(s) == 0], WNOHANG, NULL) = 2064
write(2, "tcpserver: end 2064 status 0\n", 29) = 29
write(2, "tcpserver: status: 0/100\n", 25) = 25
wait4(-1, 0xbffffa14, WNOHANG, NULL)    = -1 ECHILD (No child processes)
sigreturn()                             = ? (mask now [])
rt_sigprocmask(SIG_BLOCK, [CHLD], NULL, 8) = 0
rt_sigprocmask(SIG_UNBLOCK, [CHLD], NULL, 8) = 0
accept(3,  <unfinished ...>

id process:

close(3)                                = 0
getpid()                                = 2064
write(2, "tcpserver: pid 2064 from 127.0.0"..., 35) = 35
setsockopt(0, SOL_IP, IP_TOS, NULL, 0)  = 0
setsockopt(0, SOL_TCP, TCP_NODELAY, [1], 4) = 0
getsockname(0, {sin_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("127.0.0.1")}}, [16]) = 0
getpid()                                = 2064
write(2, "tcpserver: ok 2064 0:127.0.0.1:8"..., 52) = 52
fcntl64(0, F_GETFL)                     = 0x2 (flags O_RDWR)
close(1)                                = -1 EBADF (Bad file descriptor)
fcntl64(0, F_DUPFD, 1)                  = 1
rt_sigaction(SIGCHLD, {SIG_DFL}, NULL, 8) = 0
rt_sigprocmask(SIG_UNBLOCK, [CHLD], NULL, 8) = 0
rt_sigaction(SIGTERM, {SIG_DFL}, NULL, 8) = 0
rt_sigaction(SIGPIPE, {SIG_DFL}, NULL, 8) = 0
execve("/usr/bin/id", ["/usr/bin/id"], [/* 20 vars */]) = 0
uname({sys="Linux", node="fedora", ...}) = 0
brk(0)                                  = 0x804c868
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x49bb9000
open("/etc/ld.so.preload", O_RDONLY)    = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=2, ...}) = 0
mmap2(NULL, 2, PROT_READ|PROT_WRITE, MAP_PRIVATE, 3, 0) = 0x49bba000
close(3)                                = 0
munmap(0x49bba000, 2)                   = 0
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=87853, ...}) = 0
mmap2(NULL, 87853, PROT_READ, MAP_PRIVATE, 3, 0) = 0x49bba000
close(3)                                = 0
open("/lib/libc.so.6", O_RDONLY)        = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\200Z\1"..., 1024) = 1024
fstat64(3, {st_mode=S_IFREG|0755, st_size=1450109, ...}) = 0
mmap2(NULL, 1235844, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x49bd0000
mprotect(0x49cf6000, 31620, PROT_NONE)  = 0
mmap2(0x49cf6000, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x125) = 0x49cf6000
mmap2(0x49cfa000, 15236, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x49cfa000
close(3)                                = 0
munmap(0x49bba000, 87853)               = 0
brk(0)                                  = 0x804c868
brk(0x804d868)                          = 0x804d868
brk(0x804e000)                          = 0x804e000
geteuid32()                             = 0
getuid32()                              = 0
getegid32()                             = 0
getgid32()                              = 0
fstat64(1, {st_mode=S_IFSOCK|0777, st_size=0, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x49bba000
socket(PF_UNIX, SOCK_STREAM, 0)         = 3
connect(3, {sin_family=AF_UNIX, path="/var/run/.nscd_socket"}, 110) = -1 ENOENT (No such file or directory)
close(3)                                = 0
open("/etc/nsswitch.conf", O_RDONLY)    = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=498, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x49bbb000
read(3, "# /etc/nsswitch.conf:\n# $Header:"..., 4096) = 498
read(3, "", 4096)                       = 0
close(3)                                = 0
munmap(0x49bbb000, 4096)                = 0
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=87853, ...}) = 0
mmap2(NULL, 87853, PROT_READ, MAP_PRIVATE, 3, 0) = 0x49cfe000
close(3)                                = 0
open("/lib/libnss_compat.so.2", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\360\25"..., 1024) = 1024
fstat64(3, {st_mode=S_IFREG|0755, st_size=50470, ...}) = 0
mmap2(NULL, 46448, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x49bbb000
mprotect(0x49bc6000, 1392, PROT_NONE)   = 0
mmap2(0x49bc6000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0xa) = 0x49bc6000
close(3)                                = 0
open("/lib/libnsl.so.1", O_RDONLY)      = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\360;\0"..., 1024) = 1024
fstat64(3, {st_mode=S_IFREG|0755, st_size=89720, ...}) = 0
mmap2(NULL, 85376, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x49d14000
mprotect(0x49d26000, 11648, PROT_NONE)  = 0
mmap2(0x49d26000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x11) = 0x49d26000
mmap2(0x49d27000, 7552, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x49d27000
close(3)                                = 0
munmap(0x49cfe000, 87853)               = 0
uname({sys="Linux", node="fedora", ...}) = 0
open("/etc/passwd", O_RDONLY)           = 3
fcntl64(3, F_GETFD)                     = 0
fcntl64(3, F_SETFD, FD_CLOEXEC)         = 0
fstat64(3, {st_mode=S_IFREG|0644, st_size=1743, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x49bc7000
_llseek(3, 0, [0], SEEK_CUR)            = 0
read(3, "root:x:0:0:root:/root:/bin/bash\n"..., 4096) = 1743
close(3)                                = 0
munmap(0x49bc7000, 4096)                = 0
socket(PF_UNIX, SOCK_STREAM, 0)         = 3
connect(3, {sin_family=AF_UNIX, path="/var/run/.nscd_socket"}, 110) = -1 ENOENT (No such file or directory)
close(3)                                = 0
open("/etc/group", O_RDONLY)            = 3
fcntl64(3, F_GETFD)                     = 0
fcntl64(3, F_SETFD, FD_CLOEXEC)         = 0
fstat64(3, {st_mode=S_IFREG|0644, st_size=641, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x49bc7000
_llseek(3, 0, [0], SEEK_CUR)            = 0
read(3, "root::0:root\nbin::1:root,bin,dae"..., 4096) = 641
close(3)                                = 0
munmap(0x49bc7000, 4096)                = 0
getgroups32(0, 0)                       = 0
getgroups32(0, 0x804dcf8)               = 0
write(1, "uid=0(root) gid=0(root)\n", 24) = 24
close(1)                                = 0
munmap(0x49bba000, 4096)                = 0
_exit(0)                                = ?


Looks to me like httpd does do the proper setuid32 and setgid32 calls, but id does not.  Why?  Well, I looked at main.c from publicfile-0.52, and I found it was doing some testing with gid/uid, so I'm guessing thats where the setuid/setgid happen (but I could be wrong)


-- 
adam

To be the responsible big kid on the block is not to steal the little guys lunch money, but to ensure that people don't want to steal each others lunch money.