On Wed, 18 May 2016, Bruce Evans wrote:

On Tue, 17 May 2016, Bryan Drewery wrote:

On 5/17/16 4:07 PM, Gleb Smirnoff wrote:
On Tue, May 17, 2016 at 03:59:26PM -0700, Bryan Drewery wrote:
B> > Author: glebius
B> > Date: Tue May 17 22:28:36 2016
B> > New Revision: 300088
B> > URL: https://svnweb.freebsd.org/changeset/base/300088
B> >
B> > Log:
B> > - Use unsigned version of min() when handling arguments of SETFKEY ioctl.
B> >   - Validate that user supplied control message length in sendmsg(2)
B> >     is not negative.
B>
B> The sendmsg(2) change is not included here (9.3) nor in the advisory but
B> is in the commit log.  Was it intended to be changed in 9.3?

That was my failure to mention SA-16:19 in commit message for 9.3. It doesn't
apply to 9.x.

B> Plus the only consumer I see is sendit() which seems to be protected
B> already from negative values when not using COMPAT_43:
B>
B> >                  if (mp->msg_controllen < sizeof(struct cmsghdr)
B> >  #ifdef COMPAT_OLDSOCK
B> >                      && mp->msg_flags != MSG_COMPAT
B> >  #endif
B> >                  ) {
B> >                          error = EINVAL;
B> >                          goto bad;
B> >                  }
B> >                  error = sockargs(&control, mp->msg_control,
B> >                      mp->msg_controllen, MT_CONTROL);

No, it isn't protected. In the comparison (mp->msg_controllen < sizeof(struct cmsghdr))
both values are unsigned. Later in sockargs() it is treated as signed.

But it is protected (except on exotic unsupported arches).  The above is
a complete bounds check for mp->msg_controllen, written in an obfuscated
way using an unsigned type botch/hack.  Negative values are normally
promoted to large unsigned values, so they fail this check and sockargs()
is never called with them.

On exotic arches, the analysis is more complicated and the hack doesn't
work.  ...

Oops.  I read this sort of backwards.  The unsign botches are somewhat
larger, and more like the one in kbd.c:
- this only checks the lower bound, so if the operands were negative then
  they would pass instead of fail the check after bogus unsign extension
- the operands are actually both unsigned, since msg_controllen already
  has unsigned poisoning.  It was poisoned even in FreeBSD-1.  It was
  u_int then.  It is still u_int in 4.4BSD-Lite*.  Now it is socklen_t,
  which is uint32_t.  POSIX has messes for this.  At least in the 2001
  version, it doesn't seem to require the poisoning, but recommends that
  applications not use values above 2**31-1 [since these values require
  the poisoning to represent, and are not very useful except for opening
  security holes like here].
- so after passing the lower bound check, msg_controllen may have a large
  unsigned 32-bit value.  Undefined behaviour occurs when we pass this
  to sockargs() which doesn't have unsign poisoning.  Except on unsupported
  exotic arches, the behaviour is to overflow to a negative value.
- sockargs() then checks the overflowed value.  This is robust enough if
  the overflow gives any value at all, but still bogus.

Correct code would do bounds checks before calling sockargs (of the
form val >= min && val <= INT_MAX), but there are several callers and
it is convenient to check only in sockargs().  For that, sockargs must
take a parameter with the same type as msg_controllen, although old
unsign botches force this to be unsigned (precisely socklen_t).  It is
too late to change socklen_t back to int.

Bruce
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to