2a185a25344404ec1708ec6e55f4bc3c14fb9eab
[openwrt-packages.git] /
1 commit a64e5574e40e3e0819c82e35a7e3d2fa65febc73
2 Author: Willy Tarreau <w@1wt.eu>
3 Date:   Fri Jan 11 19:38:25 2019 +0100
4
5     BUG/MAJOR: cache: fix confusion between zero and uninitialized cache key
6     
7     The cache uses the first 32 bits of the uri's hash as the key to reference
8     the object in the cache. It makes a special case of the value zero to mean
9     that the object is not in the cache anymore. The problem is that when an
10     object hashes as zero, it's still inserted but the eb32_delete() call is
11     skipped, resulting in the object still being chained in the memory area
12     while the block has been reclaimed and used for something else. Then when
13     objects which were chained below it (techically any object since zero is
14     at the root) are deleted, the walk through the upper object may encounter
15     corrupted values where valid pointers were expected.
16     
17     But while this should only happen statically once on 4 billion, the problem
18     gets worse when the cache-use conditions don't match the cache-store ones,
19     because cache-store runs with an uninitialized key, which can create objects
20     that will never be found by the lookup code, or worse, entries with a zero
21     key preventing eviction of the tree node and resulting in a crash. It's easy
22     to accidently end up on such a config because the request rules generally
23     can't be used to decide on the response :
24     
25       http-request  cache-use cache   if { path_beg /images }
26       http-response cache-store cache
27     
28     In this test, mixing traffic with /images/$RANDOM and /foo/$RANDOM will
29     result in random keys being inserted, some of them possibly being zero,
30     and crashes will quickly happen.
31     
32     The fix consists in 1) always initializing the transaction's cache_hash
33     to zero, and 2) never storing a response for which the hash has not been
34     calculated, as indicated by the value zero.
35     
36     It is worth noting that objects hashing as value zero will never be cached,
37     but given that there's only one chance among 4 billion that this happens,
38     this is totally harmless.
39     
40     This fix must be backported to 1.9 and 1.8.
41     
42     (cherry picked from commit c9036c00044a8d81561113886ecec9a9ce71bd3b)
43     Signed-off-by: Willy Tarreau <w@1wt.eu>
44     (cherry picked from commit 5a6279fcc16da479304bcabc1705e8653f274337)
45     Signed-off-by: William Lallemand <wlallemand@haproxy.org>
46
47 diff --git a/src/cache.c b/src/cache.c
48 index 667cede3..3d8ed241 100644
49 --- a/src/cache.c
50 +++ b/src/cache.c
51 @@ -400,7 +400,7 @@ enum act_return http_action_store_cache(struct act_rule *rule, struct proxy *px,
52         struct cache *cache = (struct cache *)rule->arg.act.p[0];
53         struct shared_context *shctx = shctx_ptr(cache);
54         struct cache_entry *object;
55 -
56 +       unsigned int key = *(unsigned int *)txn->cache_hash;
57  
58         /* Don't cache if the response came from a cache */
59         if ((obj_type(s->target) == OBJ_TYPE_APPLET) &&
60 @@ -420,6 +420,10 @@ enum act_return http_action_store_cache(struct act_rule *rule, struct proxy *px,
61         if (txn->meth != HTTP_METH_GET)
62                 goto out;
63  
64 +       /* cache key was not computed */
65 +       if (!key)
66 +               goto out;
67 +
68         /* cache only 200 status code */
69         if (txn->status != 200)
70                 goto out;
71 @@ -478,7 +482,7 @@ enum act_return http_action_store_cache(struct act_rule *rule, struct proxy *px,
72  
73                                         cache_ctx->first_block = first;
74  
75 -                                       object->eb.key = (*(unsigned int *)&txn->cache_hash);
76 +                                       object->eb.key = key;
77                                         memcpy(object->hash, txn->cache_hash, sizeof(object->hash));
78                                         /* Insert the node later on caching success */
79  
80 diff --git a/src/proto_http.c b/src/proto_http.c
81 index 7e4a8351..29a1083a 100644
82 --- a/src/proto_http.c
83 +++ b/src/proto_http.c
84 @@ -8210,6 +8210,7 @@ void http_init_txn(struct stream *s)
85  
86         txn->flags = 0;
87         txn->status = -1;
88 +       *(unsigned int *)txn->cache_hash = 0;
89  
90         txn->cookie_first_date = 0;
91         txn->cookie_last_date = 0;
git clone https://git.99rst.org/PROJECT