From Bugzilla Helper: User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.12) Gecko/20050922 Fedora/1.0.7-1.1.fc4 Firefox/1.0.7 Description of problem: When the filedescriptor first argument to tcgetattr() is not a tty, then tcgetattr stores uninitialized values into the structure pointed to by the second argument. Version-Release number of selected component (if applicable): glibc-2.3.90-29 How reproducible: Always Steps to Reproduce: 1. Run internal testcase stdio-common/scanf4 and observe when __isatty() checks on a filedescriptor for /dev/null. 2. 3. Actual Results: Uninitialized values from the local stack frame of __tcgetattr are copied to *termios_p. Expected Results: Do not store uninitialized values into *termios_p. Either don't store into *termios_p when the ioctl fails, or clear the local k_termios struct before making the call (so that the values will be initialized in case the ioctl() fails.) Additional info: -----sysdeps/unix/sysv/linux/tcgetattr.c line 34 __tcgetattr (fd, termios_p) int fd; struct termios *termios_p; { struct __kernel_termios k_termios; int retval; retval = INLINE_SYSCALL (ioctl, 3, fd, TCGETS, &k_termios); termios_p->c_iflag = k_termios.c_iflag; /* <<<<< here, and following */ termios_p->c_oflag = k_termios.c_oflag; termios_p->c_cflag = k_termios.c_cflag; termios_p->c_lflag = k_termios.c_lflag; termios_p->c_line = k_termios.c_line; -----
Why is that a problem? To my knowledge the content of the struct pointed by the termios_p argument is undefined after failed call.
It is a problem because tcgetattr itself is introducing more undefinedness than is already given by the OS kernel. Namely, the returned values are pieces of the uninitialized local stack frame of tcgetattr, not the values (whether defined or undefined) left by the kernel. Although it is a good idea for the kernel to avoid storing anything if the system call fails, for tcgetattr I cannot find a specification that requires this. Also, the manual page for tcgetattr does not say that the structure is "output only." So the kernel could read some of the members before deciding to return an error, then write some subset of the members, leaving other members with original user-mode values. The current tcgetattr fails if *termios_p is not output only. In order to guarantee that tcgetattr does not introduce any new undefinedness, then tcgetattr must first copy in the values from *termios_p to k_termios, perform the system call, then copy out the values from k_termios to *termios_p. If a specification were to rquire that *termios_p be output only, then tcgetattr still should minimize the introduction of new undefinedness. This helps glibc clients that are trying to be robust in the face of runtime errors, and improves maintainability and supportability, by reducing the uncontrolled fanout from unexpected situations.
I changed the code upstream.
Should be fixed in glibc-2.4.90-7 in rawhide.