This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Running GCC as root


Zack Weinberg <zack@codesourcery.com> writes:

> $ sudo mknod null c 1 3
> $ sudo chmod 666 null
> $ strace as -Z test.s -o null 2>&1 | grep null | grep -v execve
> stat64("null", {st_mode=S_IFCHR|0666, st_rdev=makedev(1, 3), ...}) = 0
> open("null", O_RDWR|O_CREAT|O_TRUNC, 0666) = 3
> 
> so gas does seem to do the right thing in this case.  I also observe
> the same pattern for ld.

For the record, this happens because BFD only unlinks the file first
if the size is non-zero.  BFD considers unlinking the file to avoid
errors which arise when overwriting a running binary (e.g., on SunOS
this was permitted by the OS, but could sometimes cause signal
handlers to fail in the running binary; strange but true).  BFD does
not unlink an empty file because gcc will create the .o file first in
make_temp_file, and unlinking the file would cause the same race
condition which gcc is trying to avoid.  Of course the issue about a
running binary normally only arises with ld, but gas uses the same
routine the open the output file.

> There's a related problem, though: the opens are not using O_EXCL,
> which means there may be an exploitable race condition in here, if
> root is running the assembler or linker in /tmp:
> 
> process 1 (as, root):               process 2 (exploit, not-root):
>   stat("test.o") = nonexistent
>                                     symlink("/etc/passwd", "test.o")
>   open("test.o", O_RDWR|O_CREAT|O_TRUNC)
>     -- destroys /etc/passwd
> 
> Similar bugs were fixed in cc1 and the gcc driver many years ago.  (If
> it were me, I would be writing output to a temporary file and renaming
> it into place once it was complete, unless the output existed and was
> not a regular file, in which case the existing behavior is correct.)

Using O_EXCL in the assembler will fail exactly because this bug was
fixed in gcc: in the normal case gcc will have created the file
already.  Although I suppose we could only use O_EXCL in the case
where the stat failed.

In general writing to a temporary file and renaming does seem to be
the right approach here.

Ian


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]