Re: possible use of unitialized value in v2.0-dev0-274-g1a0fe3be

2019-02-08 Thread Ricardo Nabinger Sanchez
On Wed, 6 Feb 2019 19:12:31 +0100
Tim Düsterhus  wrote:

> Line 4398 is missing here, it appends a marker (empty string) to mark
> the end of the array.
> 
> > ...
> > 
> > 4450 /* look for the Host header and place it in :authority 
> > */
> > 4451 auth = ist2(NULL, 0);
> > 4452 for (hdr = 0; hdr < sizeof(list)/sizeof(list[0]); 
> > hdr++) {
> > 4453 if (isteq(list[hdr].n, ist("")))
> > // (here, assume the condition is false, so control keeps in this block...) 
> >  
> 
> We established that `list` is an array without holes terminated by an
> empty string.
> 
> Thus either:
> 1. The Condition is false, then the value must be initialized
> or
> 2. The Condition is true, then the loop is exited.
> 
> Thus I believe this is a false-positive.

Thank you for checking this out and, by extension, Willy on his set of
replise.  I missed the marker (and apparently, so did Clang).

Cheers,

-- 
Ricardo Nabinger Sanchez http://www.taghos.com.br/




Re: possible use of unitialized value in v2.0-dev0-274-g1a0fe3be

2019-02-07 Thread Willy Tarreau
On Wed, Feb 06, 2019 at 07:12:31PM +0100, Tim Düsterhus wrote:
(...)
> Thus I believe this is a false-positive.

I should have read the whole thread, it would have saved me a reply :-)

Willy



Re: possible use of unitialized value in v2.0-dev0-274-g1a0fe3be

2019-02-07 Thread Willy Tarreau
Hello,

On Wed, Feb 06, 2019 at 02:28:27PM -0200, Ricardo Nabinger Sanchez wrote:
> Hello,
> 
> scan-build found a 28-step path where an unitialized value could be used in
> h2s_htx_bck_make_req_headers().
> 
> Here is a shortened version:
> 
> 4378 idx = htx_get_head(htx); // returns the SL that we skip
> 4379 while ((idx = htx_get_next(htx, idx)) != -1) {
> 4380 blk = htx_get_blk(htx, idx);
> 4381 type = htx_get_blk_type(blk);
> 4382 
> 4383 if (type == HTX_BLK_UNUSED)
> 4384 continue;
> 4385 
> 4386 if (type != HTX_BLK_HDR)
> // (here, assume condition is true, so control leaves the loop...)
> 4387 break;
> 4388 
> 4389 if (unlikely(hdr >= sizeof(list)/sizeof(list[0]) - 1))
> 4390 goto fail;
> 4391 
> // (... and list will not be initialized.)
> 4392 list[hdr].n = htx_get_blk_name(htx, blk);
> 4393 list[hdr].v = htx_get_blk_value(htx, blk);
> 4394 hdr++;
> 4395 }
> 
> ...

The most important piece was skipped here :

/* marker for end of headers */
list[hdr].n = ist("");

So the list is *always* terminated.

> 4450 /* look for the Host header and place it in :authority */
> 4451 auth = ist2(NULL, 0);
> 4452 for (hdr = 0; hdr < sizeof(list)/sizeof(list[0]); hdr++) 
> {
> 4453 if (isteq(list[hdr].n, ist("")))
> // (here, assume the condition is false, so control keeps in this block...)
> 4454 break; // end

Here the only way to reach this point is to have met an initialized
element, since the first one after the last initialized one sets the
name to the empty string and causes the break to happen.

> 4455 
> 4456 if (isteq(list[hdr].n, ist("host"))) {
> 4457 auth = list[hdr].v;
> // (... auth receives an uninitialized value from list ...)

Thus no by definition.

> 4458 break;
> 4459 }
> 4460 }
> 4461 }
(...)
> While this feels like a convoluted or unlikely scenario, the path leading
> to the use of uninitialized value seems to be correctly unearthed by
> scan-build.

Fortunately no, it's a classical false positive instead.

Thanks!
Willy



Re: possible use of unitialized value in v2.0-dev0-274-g1a0fe3be

2019-02-06 Thread Tim Düsterhus
Ricardo,

Am 06.02.19 um 17:28 schrieb Ricardo Nabinger Sanchez:
> Hello,
> 
> scan-build found a 28-step path where an unitialized value could be used in
> h2s_htx_bck_make_req_headers().
> 
> Here is a shortened version:
> 
> 4378 idx = htx_get_head(htx); // returns the SL that we skip
> 4379 while ((idx = htx_get_next(htx, idx)) != -1) {
> 4380 blk = htx_get_blk(htx, idx);
> 4381 type = htx_get_blk_type(blk);
> 4382 
> 4383 if (type == HTX_BLK_UNUSED)
> 4384 continue;
> 4385 
> 4386 if (type != HTX_BLK_HDR)
> // (here, assume condition is true, so control leaves the loop...)
> 4387 break;
> 4388 
> 4389 if (unlikely(hdr >= sizeof(list)/sizeof(list[0]) - 1))
> 4390 goto fail;
> 4391 
> // (... and list will not be initialized.)

Yes, but hdr will not be incremented either. Thus `list` is an array
without holes.

> 4392 list[hdr].n = htx_get_blk_name(htx, blk);
> 4393 list[hdr].v = htx_get_blk_value(htx, blk);
> 4394 hdr++;
> 4395 }

Line 4398 is missing here, it appends a marker (empty string) to mark
the end of the array.

> ...
> 
> 4450 /* look for the Host header and place it in :authority */
> 4451 auth = ist2(NULL, 0);
> 4452 for (hdr = 0; hdr < sizeof(list)/sizeof(list[0]); hdr++) 
> {
> 4453 if (isteq(list[hdr].n, ist("")))
> // (here, assume the condition is false, so control keeps in this block...)

We established that `list` is an array without holes terminated by an
empty string.

Thus either:
1. The Condition is false, then the value must be initialized
or
2. The Condition is true, then the loop is exited.

Thus I believe this is a false-positive.

Best regards
Tim Düsterhus



possible use of unitialized value in v2.0-dev0-274-g1a0fe3be

2019-02-06 Thread Ricardo Nabinger Sanchez
Hello,

scan-build found a 28-step path where an unitialized value could be used in
h2s_htx_bck_make_req_headers().

Here is a shortened version:

4378 idx = htx_get_head(htx); // returns the SL that we skip
4379 while ((idx = htx_get_next(htx, idx)) != -1) {
4380 blk = htx_get_blk(htx, idx);
4381 type = htx_get_blk_type(blk);
4382 
4383 if (type == HTX_BLK_UNUSED)
4384 continue;
4385 
4386 if (type != HTX_BLK_HDR)
// (here, assume condition is true, so control leaves the loop...)
4387 break;
4388 
4389 if (unlikely(hdr >= sizeof(list)/sizeof(list[0]) - 1))
4390 goto fail;
4391 
// (... and list will not be initialized.)
4392 list[hdr].n = htx_get_blk_name(htx, blk);
4393 list[hdr].v = htx_get_blk_value(htx, blk);
4394 hdr++;
4395 }

...

4450 /* look for the Host header and place it in :authority */
4451 auth = ist2(NULL, 0);
4452 for (hdr = 0; hdr < sizeof(list)/sizeof(list[0]); hdr++) {
4453 if (isteq(list[hdr].n, ist("")))
// (here, assume the condition is false, so control keeps in this block...)
4454 break; // end
4455 
4456 if (isteq(list[hdr].n, ist("host"))) {
4457 auth = list[hdr].v;
// (... auth receives an uninitialized value from list ...)
4458 break;
4459 }
4460 }
4461 }
4462 else {
4463 /* for CONNECT, :authority is taken from the path */
4464 auth = path;
4465 }
4466 
// (... and here auth is evaluated, but it contains whatever uninitialized
//  data that list had, because its initialization has been jumped over.)
4467 if (auth.ptr && !hpack_encode_header(, ist(":authority"), 
auth)) {
4468 /* output full */
4469 if (b_space_wraps(>mbuf))
4470 goto realign_again;
4471 goto full;
4472 }

While this feels like a convoluted or unlikely scenario, the path leading
to the use of uninitialized value seems to be correctly unearthed by
scan-build.  Also, there might be a chance that this path invokes undefined
behavior, leading to further surprises.

Does this make sense?

Cheers,

-- 
Ricardo Nabinger Sanchez http://www.taghos.com.br/