annotate src/core/ngx_rwlock.c @ 7674:7731c710796f

Memcached: protect from too long responses. If a memcached response was followed by a correct trailer, and then the NUL character followed by some extra data - this was accepted by the trailer checking code. This in turn resulted in ctx->rest underflow and caused negative size buffer on the next reading from the upstream, followed by the "negative size buf in writer" alert. Fix is to always check for too long responses, so a correct trailer cannot be followed by extra data.
author Maxim Dounin <mdounin@mdounin.ru>
date Mon, 06 Jul 2020 18:36:17 +0300
parents d1816a2696de
children 7752d8523066
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
6101
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
1
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
2 /*
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
3 * Copyright (C) Ruslan Ermilov
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
4 * Copyright (C) Nginx, Inc.
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
5 */
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
6
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
7
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
8 #include <ngx_config.h>
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
9 #include <ngx_core.h>
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
10
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
11
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
12 #if (NGX_HAVE_ATOMIC_OPS)
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
13
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
14
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
15 #define NGX_RWLOCK_SPIN 2048
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
16 #define NGX_RWLOCK_WLOCK ((ngx_atomic_uint_t) -1)
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
17
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
18
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
19 void
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
20 ngx_rwlock_wlock(ngx_atomic_t *lock)
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
21 {
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
22 ngx_uint_t i, n;
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
23
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
24 for ( ;; ) {
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
25
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
26 if (*lock == 0 && ngx_atomic_cmp_set(lock, 0, NGX_RWLOCK_WLOCK)) {
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
27 return;
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
28 }
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
29
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
30 if (ngx_ncpu > 1) {
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
31
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
32 for (n = 1; n < NGX_RWLOCK_SPIN; n <<= 1) {
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
33
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
34 for (i = 0; i < n; i++) {
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
35 ngx_cpu_pause();
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
36 }
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
37
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
38 if (*lock == 0
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
39 && ngx_atomic_cmp_set(lock, 0, NGX_RWLOCK_WLOCK))
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
40 {
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
41 return;
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
42 }
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
43 }
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
44 }
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
45
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
46 ngx_sched_yield();
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
47 }
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
48 }
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
49
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
50
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
51 void
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
52 ngx_rwlock_rlock(ngx_atomic_t *lock)
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
53 {
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
54 ngx_uint_t i, n;
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
55 ngx_atomic_uint_t readers;
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
56
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
57 for ( ;; ) {
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
58 readers = *lock;
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
59
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
60 if (readers != NGX_RWLOCK_WLOCK
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
61 && ngx_atomic_cmp_set(lock, readers, readers + 1))
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
62 {
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
63 return;
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
64 }
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
65
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
66 if (ngx_ncpu > 1) {
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
67
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
68 for (n = 1; n < NGX_RWLOCK_SPIN; n <<= 1) {
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
69
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
70 for (i = 0; i < n; i++) {
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
71 ngx_cpu_pause();
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
72 }
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
73
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
74 readers = *lock;
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
75
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
76 if (readers != NGX_RWLOCK_WLOCK
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
77 && ngx_atomic_cmp_set(lock, readers, readers + 1))
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
78 {
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
79 return;
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
80 }
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
81 }
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
82 }
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
83
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
84 ngx_sched_yield();
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
85 }
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
86 }
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
87
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
88
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
89 void
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
90 ngx_rwlock_unlock(ngx_atomic_t *lock)
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
91 {
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
92 ngx_atomic_uint_t readers;
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
93
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
94 readers = *lock;
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
95
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
96 if (readers == NGX_RWLOCK_WLOCK) {
7037
12efcdcb8a4b Added memory barrier semantics to ngx_rwlock_unlock().
Ruslan Ermilov <ru@nginx.com>
parents: 6270
diff changeset
97 (void) ngx_atomic_cmp_set(lock, NGX_RWLOCK_WLOCK, 0);
6101
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
98 return;
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
99 }
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
100
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
101 for ( ;; ) {
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
102
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
103 if (ngx_atomic_cmp_set(lock, readers, readers - 1)) {
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
104 return;
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
105 }
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
106
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
107 readers = *lock;
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
108 }
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
109 }
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
110
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
111
7038
d1816a2696de Introduced ngx_rwlock_downgrade().
Ruslan Ermilov <ru@nginx.com>
parents: 7037
diff changeset
112 void
d1816a2696de Introduced ngx_rwlock_downgrade().
Ruslan Ermilov <ru@nginx.com>
parents: 7037
diff changeset
113 ngx_rwlock_downgrade(ngx_atomic_t *lock)
d1816a2696de Introduced ngx_rwlock_downgrade().
Ruslan Ermilov <ru@nginx.com>
parents: 7037
diff changeset
114 {
d1816a2696de Introduced ngx_rwlock_downgrade().
Ruslan Ermilov <ru@nginx.com>
parents: 7037
diff changeset
115 if (*lock == NGX_RWLOCK_WLOCK) {
d1816a2696de Introduced ngx_rwlock_downgrade().
Ruslan Ermilov <ru@nginx.com>
parents: 7037
diff changeset
116 *lock = 1;
d1816a2696de Introduced ngx_rwlock_downgrade().
Ruslan Ermilov <ru@nginx.com>
parents: 7037
diff changeset
117 }
d1816a2696de Introduced ngx_rwlock_downgrade().
Ruslan Ermilov <ru@nginx.com>
parents: 7037
diff changeset
118 }
d1816a2696de Introduced ngx_rwlock_downgrade().
Ruslan Ermilov <ru@nginx.com>
parents: 7037
diff changeset
119
d1816a2696de Introduced ngx_rwlock_downgrade().
Ruslan Ermilov <ru@nginx.com>
parents: 7037
diff changeset
120
6103
79ddb0bdb273 Upstream: the "zone" directive.
Ruslan Ermilov <ru@nginx.com>
parents: 6101
diff changeset
121 #else
79ddb0bdb273 Upstream: the "zone" directive.
Ruslan Ermilov <ru@nginx.com>
parents: 6101
diff changeset
122
6270
e769cc88f996 Core: read/write locks are also required by the Stream module.
Piotr Sikora <piotrsikora@google.com>
parents: 6103
diff changeset
123 #if (NGX_HTTP_UPSTREAM_ZONE || NGX_STREAM_UPSTREAM_ZONE)
6103
79ddb0bdb273 Upstream: the "zone" directive.
Ruslan Ermilov <ru@nginx.com>
parents: 6101
diff changeset
124
79ddb0bdb273 Upstream: the "zone" directive.
Ruslan Ermilov <ru@nginx.com>
parents: 6101
diff changeset
125 #error ngx_atomic_cmp_set() is not defined!
79ddb0bdb273 Upstream: the "zone" directive.
Ruslan Ermilov <ru@nginx.com>
parents: 6101
diff changeset
126
6101
682d8222c6b1 Core: read/write locks.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
127 #endif
6103
79ddb0bdb273 Upstream: the "zone" directive.
Ruslan Ermilov <ru@nginx.com>
parents: 6101
diff changeset
128
79ddb0bdb273 Upstream: the "zone" directive.
Ruslan Ermilov <ru@nginx.com>
parents: 6101
diff changeset
129 #endif