Weak-etag not being handled correctly - bug found in source code

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Title: Normal

I’ve been investigating why weak eTags aren’t being handled properly, specifically why we always get a status 200 when we include a weak eTag, and only get a status 304 when we delete the weak eTag and use the last modified date instead, or make the eTag strong.  I’ve found the bug: it’s because the W tag is upper case, and Apache seems to assume all headers are lower case.  However, I don’t know where the best place is to fix the bug, as discussed below. 

 

The bug is in the source code as follows:-

 

The response is evaluated in http_protocol in a function called ap_meets_conditions(), as follows

http_protocol.c: v2.2.16, line 355

not_modified = ap_find_list_item(r->pool, if_nonematch, etag);

 

This line of code is executed for both strong and weak eTags for full Get requests (ie not Range requests, which are caught by a previous if-statement).  The call to ap_find_list_item is used to compare the etag in the resource to the one in the request (held in a hash table pointed to by the char *if_nonematch)

 

Ap_find_list_item exits in the util.c file.

util.c:  v2.2.16, line 1372

good = good && (*pos++ == apr_tolower(*ptr));

 

The for-loop surrounding this line of code walks through the characters in the two strings, comparing them character-by-character.  It maintains some state variables, such as in_qstr that tracks whether or not the pointer is currently within a quote.  If it is within a quote, it compares the two characters directly; if not within quotes, it executes line 1372 that lower-cases *ptr value.  This assumes that the *pos value is already lower case.  However, the weak eTag is defined by protocol as beginning with the uppercase letter W, and it appears that uppercase W is indeed what is stored in the hash table pointed to by if_nonematch and pos. 

 

Testing this, my colleagues have created eTags with values such as

“W1234-123123”

W/”1234-123123”

w/”1234-123123”

 

We have found that provided the eTag is fully quoted, or preceded by a lowercase w, httpd works as we would expect and returns a 304 to a conditional Get.  However, if the eTag is preceded by an uppercase W, as per the protocol, then httpd always returns 200.  It appears as if the cache is not working, but that is not the problem – it is the comparison of the W that is failing and causing the behaviour.

 

A targeted fix is to lowercase if_nonematch just prior to calling ap_find_list_item().  Because if_nonematch is a pointer, this may have an undesirable side-effect elsewhere in the code, so a “safer” approach is first to copy the string into a local variable, then lowercase the W, and then call ap_find_list_item().  However, I wonder if a more natural home for the fix would be to make the W lowercase when the hash table is loaded? 

 

Could someone who knows the code much better than me take up this issue, decide the best location for a fix, and implement it? 

Many thanks,

Ben Cooper

Please consider the environment before printing this email.

This message should be regarded as confidential. If you have received this email in error please notify the sender and destroy it immediately.
Statements of intent shall only become binding when confirmed in hard copy by an authorised signatory.  The contents of this email may relate to dealings with other companies within the Detica Limited group of companies.

Detica Limited is registered in England under No: 1337451.

Registered offices: Surrey Research Park, Guildford, Surrey, GU2 7YP, England.


[Index of Archives]     [Open SSH Users]     [Linux ACPI]     [Linux Kernel]     [Linux Laptop]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Squid]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]

  Powered by Linux