W3C home > Mailing lists > Public > ietf-http-wg@w3.org > October to December 2013

Re: Security concern about open range integers (was: Question about: 4.1.1 Integer representation)

From: Fred Akalin <akalin@google.com>
Date: Mon, 21 Oct 2013 14:22:11 -0700
Message-ID: <CANUYc_QmpKuRSajqY6p-ZAoXxYfEnbNF0M3rV+X_+HMf-zbWyg@mail.gmail.com>
To: Martin Thomson <martin.thomson@gmail.com>
Cc: Roberto Peon <grmocg@gmail.com>, Frédéric Kayser <f.kayser@free.fr>, HTTP Working Group <ietf-http-wg@w3.org>
On Mon, Oct 21, 2013 at 2:15 PM, Martin Thomson <martin.thomson@gmail.com>wrote:

> On 21 October 2013 14:03, Fred Akalin <akalin@google.com> wrote:
> > I'm not sure I see the problem. While decoding a varint, you have to keep
> > track of amount to right-shift the low 7 bits of the next octet. You can
> > then check if doing so would overflow 32 bits, and abort if so.
>
> If you want to use all the 32 bits, then you have to check what bits are
> set.
>

I guess, but that doesn't seem too onerous?


> The bigger problem is the extra 2^N-1 you are required to add (255 for
> an 8-bit prefix), which will cause an overflow if you aren't careful.
> Hence the tricky little mask I used...
>

Unless I'm grossly misunderstanding the format, the varint format is
little-endian, so you fill in the lower bits first, so this shouldn't be a
concern.

I guess this argues for providing pseudocode for decoding a varint as well
as encoding it. To make things a little more concrete, here's the decoding
code from my JS implementation
https://github.com/akalin-chromium/httpbis-header-compression/blob/master/header_decoder.js
,
and I've highlighted the single place where one would insert the additional
check:

// Decodes the next integer based on the representation described in
// 4.1.1. N is the number of bits of the prefix as described in 4.1.1.
Decoder.prototype.decodeNextInteger_ = function(N) {
  var I = 0;
  var hasMore = true;
  var shift = N;

  if (N > 0) {
    var nextMarker = (1 << N) - 1;
    var nextOctet = this.decodeNextOctet_();
    I = nextOctet & nextMarker;
    hasMore = (I == nextMarker);
  }

  while (hasMore) {
    var nextOctet = this.decodeNextOctet_();
    // Check the high bit. (Remember that / in JavaScript is
    // floating-point division).
    hasMore = ((nextOctet & 0x80) != 0);
    *// If "(nextOctet % 128) << shift" won't fit in 32 bits, abort.*
    I += (nextOctet % 128) << shift;
    shift += 7;
  }

  return I;
};
Received on Monday, 21 October 2013 21:22:41 UTC

This archive was generated by hypermail 2.3.1 : Tuesday, 1 March 2016 11:11:18 UTC