<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <div class="moz-cite-prefix">On 3/12/24 00:43, Rich Felker wrote:<br>
    </div>
    <blockquote type="cite"
      cite="mid:20240312004309.GZ4163@brightrain.aerifal.cx">
      <pre class="moz-quote-pre" wrap="">On Tue, Mar 12, 2024 at 12:18:24AM +0000, Gabriel Ravier wrote:
</pre>
      <blockquote type="cite">
        <pre class="moz-quote-pre" wrap="">On 3/11/24 19:47, Rich Felker wrote:
</pre>
        <blockquote type="cite">
          <pre class="moz-quote-pre" wrap="">On Mon, Mar 11, 2024 at 11:30:04AM -0400, Skyler Ferrante (RIT Student) wrote:
</pre>
          <blockquote type="cite">
            <pre class="moz-quote-pre" wrap="">Hmm, maybe I'm missing something, but it seems you can close(fd) for
the standard fds and then call execve, and the new process image will
have no fd 0,1,2. I've tried this on a default Ubuntu 22.04 system.
This seems to affect shadow-utils and other setuid/setgid binaries.

Here is a repo I built for testing,
<a class="moz-txt-link-freetext" href="https://github.com/skyler-ferrante/fd_omission/">https://github.com/skyler-ferrante/fd_omission/</a>. What is the correct
glibc behavior? Am I misunderstanding something?
</pre>
          </blockquote>
          <pre class="moz-quote-pre" wrap="">As Florian noted, you're missing that strace cannot invoke it suid.
POSIX explicitly permits the implementation to open these fds if they
started closed in suid execs, and IIRC indicates as a future direction
that it might be permitted for all execs. We do the same in musl in
the suid case. So really the only way that "writing attacker
controlled prefix strings to fd 2" becomes an issue is if the
application erroneously closes fd 2 and lets something else get opened
on it.

(Aside: making _FORTIFY_SOURCE>1 trap close(n) with n<3 would be an
interesting idea... :)
</pre>
        </blockquote>
        <pre class="moz-quote-pre" wrap="">
Doing this would break many programs, such as:
- most of coreutils, e.g. programs like ls, cat or head, since they
always `close` their input and output descriptors (when they've
written or read something) to make sure to diagnose all errors
- grep
- xargs
- find
</pre>
      </blockquote>
      <pre class="moz-quote-pre" wrap="">
This makes it so they can malfunction during exit when it
flushes/closes the corresponding stdio FILEs. If nothing else has been
opened in the mean time, under typical implementations it should be
safe, but I think per 2.5.1 Interaction of File Descriptors and
Standard I/O Streams:

<a class="moz-txt-link-freetext" href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_05_01">https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_05_01</a>

it's undefined.

The safe way to do what they want is to dup the fd they want to
close-and-check-for-errors, open /dev/null, dup2 that over the
original fd, then close the first dup.

Or, don't exit()/return-from-main, but instead _exit, so there's no
subsequent access to the FILE.</pre>
    </blockquote>
    <p><br>
    </p>
    <p>Those applications above (though some of those below appear to do
      raw <i>close</i> calls) all circumvent your objection by calling
      <i>fclose</i> on the standard streams rather than <i>close</i>-ing
      the file descriptors directly, which seems legal according to
      POSIX given otherwise the following quote would make no sense:</p>
    <p>> Since after the call to <i>fclose</i>( ) any use of stream
      results in undefined behavior, <i>fclose</i>( ) should not be
      used on <i>stdin</i>, <i>stdout</i>, or <i>stderr</i> except
      immediately before process termination (see XBD Section 3.287, on
      page 73), so as to avoid triggering undefined behavior in other
      standard interfaces that rely on these streams. If there are any <i>atexit</i>(
      ) handlers registered by the application, such a call to <i>fclose</i>()
      should not occur until the last handler is finishing.<br>
      - POSIX, <i>System Interfaces</i>, <b>fclose( )</b>, <b>APPLICATION
        USAGE</b><br>
    </p>
    <p>and all of those applications listed above do the <i>fclose</i>
      at the end of their <i>atexit</i> handlers - the wording implies
      the fact they return from that <i>atexit</i> handler when the <i>fclose</i>
      succeeds is fine too since it's done when "the last handler is
      finishing" (i.e. after all other usage of standard interfaces
      which may use the standard streams)), which seems to imply calling
      <i>exit</i> after <i>fclose</i>-ing one of the standard streams
      should be legal.</p>
    <p><br>
    </p>
    <p>Furthermore, the description of <i>close</i> also states:</p>
    <p>> Usage of <i>close</i>( ) on file descriptors STDIN_FILENO,
      STDOUT_FILENO, or STDERR_FILENO should immediately be followed by
      an operation to reopen these file descriptors. Unexpected behavior
      will result if any of these file descriptors is left in a closed
      state (for example, an [EBADF] error from <i>perror</i>( )) or if
      an unrelated <i>open</i>( ) or similar call later in the
      application accidentally allocates a file to one of these
      well-known file descriptors. Furthermore, a <i>close</i>( )
      followed by a reopen operation (e.g., <i>open</i>( ), <i>dup</i>(
      ), etc.) is not atomic; <i>dup2</i>( ) should be used to change
      standard file descriptors.<br>
      - POSIX, <i>System Interfaces</i>, <b>fclose( )</b>, <b>APPLICATION
        USAGE</b><br>
    </p>
    <p>which simply points out "unexpected" (which does not appear to
      mean "undefined") behavior along with examples of some of the
      potential consequences and points out replacing those descriptors
      after the <i>close</i> is not atomic and that <i>dup2</i> should
      be used instead - but "should" is not the same word as "must", so
      this seems to implicitly allow not using <i>dup2</i> or even not
      reopening the file descriptors at all - which seems accurate to
      me, I can't see anything in the standard, including in that <b>Interaction
        of File Descriptors and Standard I/O Streams</b> section you
      mentioned earlier, that would result in undefined behavior upon <i>close</i>-ing
      the file descriptors before <i>fclose</i>, except that that
      section seems to indicate the application must not leave data
      buffered in the stream (which does not seem to be something any of
      the applications I've mentioned before or after this do - though
      it's not like I've engaged in exhaustive program analysis to
      ensure this is the case either, so that's more of an assumption
      than anything else, but the scenarios in which they close these
      streams (near the beginning or termination of the application)
      seem like they should make it quite likely this is not the case).</p>
    <p>It seems to me as though further use of a <i>FILE</i> after its
      file descriptor was <i>close</i>-ed would simply result in
      [EBADF] errors (...which could obviously also easily lead to
      issues involving having multiple active handles on the same file
      if someone else was to call <i>open</i> afterwards, but that's a
      separate issue).<br>
    </p>
    <p><br>
    </p>
    <blockquote type="cite"
      cite="mid:20240312004309.GZ4163@brightrain.aerifal.cx">
      <pre class="moz-quote-pre" wrap="">

</pre>
      <blockquote type="cite">
        <pre class="moz-quote-pre" wrap="">- strace, which (using the half-closed self-pipe trick mentioned
earlier in this thread to avoid reusing them later btw) closes the
standard descriptors, to avoid changing the behavior of programs
calling it if e.g. its input is a pipe (where if it left the fds
open that'd mean the writer would get SIGPIPE later than if the
program was ran without strace)
- tcsh, which deliberately does `close(n)` with `n < 3` to make it
so all the standard FDs point to `/dev/null`
- troff and groff (and thus man)
- git
- many more... I have found these by simply stracing random programs
as found on my system with `ls /bin/ | shuf -n1`
</pre>
      </blockquote>
      <pre class="moz-quote-pre" wrap="">
Yes, I'm quite aware it's commonplace, but it would be something nice
to get cleaned up...

Rich</pre>
    </blockquote>
    <br>
  </body>
</html>