Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
Bug 23064 - ttyname(3) return NULL when program is setgid and running on VT (not a xterm)
Summary: ttyname(3) return NULL when program is setgid and running on VT (not a xterm)
Status: RESOLVED WORKSFORME
Alias: None
Product: Gentoo Linux
Classification: Unclassified
Component: [OLD] Core system (show other bugs)
Hardware: x86 Linux
: High normal (vote)
Assignee: SpanKY
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2003-06-18 13:31 UTC by Defresne Sylvain (keiichi)
Modified: 2003-06-24 15:20 UTC (History)
1 user (show)

See Also:
Package list:
Runtime testing required: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Defresne Sylvain (keiichi) 2003-06-18 13:31:04 UTC
When a setgid program call 'ttyname', and running in a real console (not an
xterm or a ssh connection), the function returns 'NULL' instead of the tty path.
It work correctly when running in an xterm or when the program is not setgid.
This 'bug' was found when trying to run 'screen' in the console, and being hit
by a 'Must be connected to terminal.' (ouch) ...

Reproducible: Always
Steps to Reproduce:
1. $ cat ttyname.c
   #include <stdio.h>
   #include <unistd.h>
   int main() {
     printf("ttyname(0) = %s\n", ttyname(0));
     return 0;
   }
   $ gcc -o ttyname ttyname.c
   $ ls -l ttyname
   -rwxr-xr-x    1 user     users        5317 Jun 18 21:26 ttyname
   $ ./ttyname
   ttyname(0) = /dev/vc/6
2. $ su -c 'chown root:utmp ttyname && chmod 2755 ttyname'
   $ ls -l ttyname
   -rwxr-sr-x    1 root     utmp         5317 Jun 18 21:26 ttyname
   $ ./ttyname
   ttyname(0) = null
Actual Results:  
As you can see, when the 'ttyname' demo program is made setgid, running it on
the linux console make it fail. It is still working when run in a terminal
emulator such as xterm.

Expected Results:  
The output should not have changed between the two invocation of the program,
since the program should still have enough rights to access '/proc/<pid>/fd' as
the effective uid is not changed by the 'setgid' bit ... Or am I wrong doing
this last assumption ? If I'm wrong, the 'screen' ebuild must be changed to
either make 'screen' be a root setuid program, or to remove the setgid flag ...

Portage 2.0.48-r1 (default-x86-1.4, gcc-3.2.2, glibc-2.3.1-r4)
=================================================================
System uname: 2.4.20-gentoo-r2 i686 Intel(R) Pentium(R) 4 CPU 2.40GHz
GENTOO_MIRRORS="http://gentoo.oregonstate.edu
http://distro.ibiblio.org/pub/Linux/distributions/gentoo"
CONFIG_PROTECT="/etc /var/qmail/control /usr/share/config
/usr/kde/2/share/config /usr/kde/3/share/config /usr/X11R6/lib/X11/xkb"
CONFIG_PROTECT_MASK="/etc/gconf /etc/env.d"
PORTDIR="/usr/portage"
DISTDIR="/home/ftp/distfiles"
PKGDIR="/usr/portage/packages"
PORTAGE_TMPDIR="/tmp"
PORTDIR_OVERLAY="/home/keiichi/portage"
USE="x86 slang mozilla cdr crypt pam berkdb gdbm nls readline ncurses ssl ipv6
doc alsa oggvorbis zlib opengl xv dga truetype png jpeg tiff sdl radeon mmx sse
-tcpd -perl -python -X -gtk -gnome -esd -java"
COMPILER="gcc3"
CHOST="i686-pc-linux-gnu"
CFLAGS="-pipe -O3 -march=pentium3 -mcpu=pentium4 -mfpmath=sse -ffast-math
-falign-jumps=5 -falign-loops=5 -falign-functions=64"
CXXFLAGS="-pipe -O3 -march=pentium3 -mcpu=pentium4 -mfpmath=sse -ffast-math
-falign-jumps=5 -falign-loops=5 -falign-functions=64"
ACCEPT_KEYWORDS="x86"
MAKEOPTS="-j2"
AUTOCLEAN="yes"
SYNC="rsync://rsync.europe.gentoo.org/gentoo-portage"
FEATURES="sandbox ccache userpriv usersandbox notitles"

$ ls -la /proc/$$
-r--r--r--    1 user     users           0 Jun 18 22:29 cmdline
lrwxrwxrwx    1 user     users           0 Jun 18 22:29 cwd -> /home/user
-r--------    1 user     users           0 Jun 18 22:29 environ
lrwxrwxrwx    1 user     users           0 Jun 18 22:29 exe -> /bin/bash
dr-x------    2 user     users           0 Jun 18 22:29 fd
-r--r--r--    1 user     users           0 Jun 18 22:29 maps
-rw-------    1 user     users           0 Jun 18 22:29 mem
-r--r--r--    1 user     users           0 Jun 18 22:29 mounts
lrwxrwxrwx    1 user     users           0 Jun 18 22:29 root -> /
-r--r--r--    1 user     users           0 Jun 18 22:29 stat
-r--r--r--    1 user     users           0 Jun 18 22:29 statm
-r--r--r--    1 user     users           0 Jun 18 22:29 status
Comment 1 SpanKY gentoo-dev 2003-06-18 13:43:41 UTC
from screen ebuild:

pkg_postinst() {
        chmod 0775 /var/run/screen

        einfo "Some dangerous key bindings have been removed or changed to more safe values."
        einfo "For more info, please check /etc/screenrc"
        echo
        einfo "screen is not installed as setuid root, which effectively disables multi-user"
        einfo "mode. To enable it, run:"
        einfo ""
        einfo "\tchmod u+s /usr/bin/screen"
        einfo "\tchmod g-w /var/run/screen"
}
Comment 2 Defresne Sylvain (keiichi) 2003-06-18 23:25:25 UTC
I know that screen is intentionnaly not installed setuid root. But I think the bug is not in screen but in glibc. Otherwise why would my test program have such an aberrant behaviour :
 - from the linux console:
   $ ./ttyname
   ttyname(0)=(null)
 - from an xterm:
   $ ./ttyname
   ttyname(0)=/dev/pts/1
 - from the linux console:
   $ ssh localhost
   user@localhost's password:
   Last login: Thu Jun 19 08:22:21 2003 from localhost
   $ ./ttyname
   ttyname=/dev/pts/2

For information, ttyname is owned by root:utmp, setgid. In all case, the errno value is 'zero', even though the 'ttyname' manpage state that when ttyname return NULL, errno is set to either EBADF or ENOTTY ...
Comment 3 SpanKY gentoo-dev 2003-06-20 13:35:18 UTC
az: any thoughts ?
Comment 4 Defresne Sylvain (keiichi) 2003-06-20 17:00:47 UTC
After reading ttyname code, and some tests, it appear that if there is a bug, it is in the kernel. Or it is me that is wrong thinking that a program that is setgid  still have at least the same right as the user.

The following code try to mimic the ttyname implementation on linux (somewhat simplified by exec-ing 'ls', and getting its error description), that read the link '/proc/self/fd/<number>' or fall back on using the '/dev/pts' filesystem.
  $ cat ttyname.c
  #include <unistd.h>
  #include <sys/types.h>
  int main() {
    char *const envp[] = { NULL };
    char *const argv[] = { "/bin/ls", "-la", "/proc/self/fd", NULL };
    printf(" uid=%d,  gid=%d\n", getuid(), getgid());
    printf("euid=%d, egid=%d\n", geteuid(), get egid());
    return execve("/bin/ls", argv, envp);
  }
  $ gcc -o ttyname ttyname.c

Using this simple program, we get the following result:
- from the linux console, not setgid:
  $ ls -l ttyname
  -rwxr-xr-x    1 user     users        5683 Jun 21 01:38 ttyname
  $ ./ttyname
   uid=1000,  gid=100
  euid=1000, egid=100
  total 0
  dr-x------    2 user     users           0 Jun 21 01:48 .
  dr-xr-xr-x    3 user     users           0 Jun 21 01:48 ..
  lrwx------    1 user     users          64 Jun 21 01:48 0 -> /dev/vc/6
  lrwx------    1 user     users          64 Jun 21 01:48 1 -> /dev/vc/6
  lrwx------    1 user     users          64 Jun 21 01:48 2 -> /dev/vc/6
  lr-x------    1 user     users          64 Jun 21 01:48 3 -> /proc/5738/fd
- from the linux console, setgid:
    $ ls -l ttyname
  -rwxr-sr-x    1 root     utmp         5683 Jun 21 01:38 ttyname
  $ ./ttyname
   uid=1000,  gid=100
  euid=1000, egid=406
  /bin/ls: /proc/self/fd: Permission denied

When called from an xterm (or another terminal emulator using /dev/pts), the libc try to get the name from the '/dev/pts' virtual filesystem after failing from the '/proc' filesystem.

So there doesn't seem to be a bug in the glibc (sorry), but I don't understand why the 'setgid' program can't read the /proc/self/fd directory ? I though that a setgid program has the righ of the user + the right of the group, as if he is temporarily a member of this group. After all, the '/proc/self/fd' has the '-r-x------' right, that is the user (which is unchanged) is able to read it.
Weird ! It'll need some more investigation to see if it only appear on gentoo, or if this is the intended behaviour of the setgid bit ...
Comment 5 bartron 2003-06-23 17:56:41 UTC
  Looks like a devfsd misconfiguration.

  What does `ls -l /dev/tty6' say?

  In suid or sgid processes (or rather, if uid != euid OR 
gid != egid), the kernel sets permissions on `/proc/self/fd/' 
to "0500/root.root", which means it's unreadable if euid is 
anything but 0.  ttyname()s fallback strategy is to 
fstat() the fd passed to it and to stat() everything in /dev 
and /dev/pts until it finds a device file pointing to the 
same inode (/dev/tty6 if called from /dev/vc/6).
Comment 6 Defresne Sylvain (keiichi) 2003-06-24 14:48:11 UTC
Since MKOLDCOMPAT is disabled in my devfsd.conf, ls -l /dev/tty6 tell me:
  ls: /dev/tty6: No such file or directory
Otherwise, the /dev/vc/6 file has the mode 0600/user.users, but even when changing it to mode 0666/user.users and restoring MKOLDCOMPAT in devfsd.conf doesn't solve the ttyname problem (still return null). I must be missing something ... But I guess the bug can be cloed, since it seems to be a local misconfiguration than anything else.

Anyway, thanks for the precision on 'setgid/setuid' behaviour in linux kernel.
Comment 7 SpanKY gentoo-dev 2003-06-24 15:20:22 UTC
its all in the details ;)