On Wed, Aug 10, 2022 at 02:23:08PM -0600, Theo de Raadt wrote:
> Scott Cheloha <scottchel...@gmail.com> wrote:
> 
> > On Wed, Aug 10, 2022 at 12:26:17PM -0600, Theo de Raadt wrote:
> > > Scott Cheloha <scottchel...@gmail.com> wrote:
> > > 
> > > > We're sorta-kinda circling around adding the missing (?) stdio error
> > > > checking to other utilities in bin/ and usr.bin/, no?  I want to be
> > > > sure I understand how to do the next patch, because if we do that it
> > > > will probably be a bunch of programs all at once.
> > > 
> > > This specific program has not checked for this condition since at least
> > > 2 AT&T UNIX.
> > > 
> > > Your change does not just add a new warning.  It adds a new exit code
> > > condition.
> > > 
> > > Some scripts using echo, which accepted the condition because echo would
> > > exit 0 and not check for this condition, will now see this exit 1.  Some
> > > scripts will abort, because they use "set -o errexit" or similar.
> > > 
> > > You are changing the exit code for a command which is used a lot.
> > > 
> > > POSIX does not require or specify exit 1 for this condition.  If you
> > > disagree, please show where it says so.
> > 
> > It's the usual thing.  >0 if "an error occurred".
> 
> The 40 year old code base says otherwise.
> 
> > Here is my thinking:
> > 
> >     echo(1) has ONE job: print the arguments given.
> > 
> > If it fails to print those arguments, shouldn't we signal that to the
> > program that forked echo(1)?
> 
> Only if you validate all callers can handle this change in behaviour.
> 
> > How is echo(1) supposed to differentiate between a write(2) that is
> > allowed to fail, e.g. a diagnostic printout from fw_update to the
> > user's stderr, and one that is not allowed to fail?
> 
> Perhaps it is not supposed to validate this problem  in 2022, because it
> didn't validate it for 40 years.
> 
> > Consider this scenario:
> > 
> > 1.  A shell script uses echo(1) to write something to a file.
> > 
> >     /bin/echo foo.dat >> /var/workerd/data-processing-list
> > 
> > 2.  The bytes don't arrive on disk because the file system is full.
> > 
> > 3.  The shell script succeeds because echo(1) can't fail, even if
> >     it fails to do what it was told to do.
> > 
> > Isn't that bad?
> > 
> > And it isn't necessarily true that some other thing will fail later
> > and the whole interlocking system will fail.  ENOSPC is a transient
> > condition.  One write(2) can fail and the next write(2) can succeed.
> 
> Yet, for 40 years noone complained.
> 
> Consider the situation you break and change the behaviour of 1000's of
> shell scripts, and haven'd lifted your finger once to review all the
> shell scripts that call echo.
> 
> Have you even compared this behaviour to the echo built-ins in all
> the shells?

I assume what you mean to say is, roughly:

        Gee, this seems risky.

        What do other echo implementations do?

1. Our ksh(1) already checks for stdout errors in the echo builtin.

2. FreeBSD's /bin/echo has checked for writev(2) errors in /bin/echo
   since 2003:

https://cgit.freebsd.org/src/commit/bin/echo/echo.c?id=91b7d6dc5871f532b1a86ee76389a9bc348bdf58

3. NetBSD's /bin/echo has checked for stdout errors with ferror(3)
   since 2008:

http://cvsweb.netbsd.org/bsdweb.cgi/src/bin/echo/echo.c?rev=1.18&content-type=text/x-cvsweb-markup&only_with_tag=MAIN

4. NetBSD's /bin/sh echo builtin has checked for write errors since
   2008:

http://cvsweb.netbsd.org/bsdweb.cgi/src/bin/sh/bltin/echo.c?rev=1.14&content-type=text/x-cvsweb-markup&only_with_tag=MAIN

5. OpenSolaris has checked for fflush(3) errors in /usr/bin/echo since
   2005 (OpenSolaris launch):

https://github.com/illumos/illumos-gate/blob/7c478bd95313f5f23a4c958a745db2134aa03244/usr/src/cmd/echo/echo.c#L144

6. Looking forward, illumos inherited and retains the behavior in
   their /usr/bin/echo.

7. Extrapolating backward, we can assume Solaris did that checking in
   /usr/bin/echo prior to 2005.

8. GNU Coreutils echo has checked for fflush(3) and fclose(3) errors on
   stdout since 2000:

https://git.savannah.gnu.org/cgit/coreutils.git/commit/src/echo.c?id=d3683509b3953beb014e540f6d6194658ede1dea

   They use close_stdout() in an atexit(3) hook.  close_stdout() is a
   convenience function provided by gnulib since 1998 that does what I
   described:

https://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=commitdiff;h=23928550db5d400f27fa67de29c738ca324a31ea;hp=f76477e515b36a1e10f7734aac3c5478ccf75989

   Maybe of note is that they do this atexit(3) stdout flush/close
   error checking for many of their utilities.

9. The GNU Bash echo builtin has checked for write errors since v2.04,
   in 2000:

https://git.savannah.gnu.org/cgit/bash.git/commit/builtins/echo.def?id=bb70624e964126b7ac4ff085ba163a9c35ffa18f

   They even noted it in the CHANGES file for that release:

https://git.savannah.gnu.org/cgit/bash.git/commit/CHANGES?id=bb70624e964126b7ac4ff085ba163a9c35ffa18f

--

I don't think that we are first movers in this case.

Reply via email to