Mercurial > hg > nginx
annotate src/os/unix/ngx_file_aio_read.c @ 9112:d59277dd3d8c
QUIC: fixed post-close use-after-free.
Previously, ngx_quic_close_connection() could be called in a way that QUIC
connection was accessed after the call. In most cases the connection is not
closed right away, but close timeout is scheduled. However, it's not always
the case. Also, if the close process started earlier for a different reason,
calling ngx_quic_close_connection() may actually close the connection. The
connection object should not be accessed after that.
Now, when possible, return statement is added to eliminate post-close connection
object access. In other places ngx_quic_close_connection() is substituted with
posting close event.
Also, the new way of closing connection in ngx_quic_stream_cleanup_handler()
fixes another problem in this function. Previously it passed stream connection
instead of QUIC connection to ngx_quic_close_connection(). This could result
in incomplete connection shutdown. One consequence of that could be that QUIC
streams were freed without shutting down their application contexts. This could
result in another use-after-free.
Found by Coverity (CID 1530402).
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Mon, 22 May 2023 15:59:42 +0400 |
parents | 7f035fd1ec7b |
children |
rev | line source |
---|---|
3052 | 1 |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4412 | 4 * Copyright (C) Nginx, Inc. |
3052 | 5 */ |
6 | |
7 | |
8 #include <ngx_config.h> | |
9 #include <ngx_core.h> | |
10 #include <ngx_event.h> | |
11 | |
12 | |
13 /* | |
14 * FreeBSD file AIO features and quirks: | |
15 * | |
16 * if an asked data are already in VM cache, then aio_error() returns 0, | |
17 * and the data are already copied in buffer; | |
18 * | |
3065 | 19 * aio_read() preread in VM cache as minimum 16K (probably BKVASIZE); |
20 * the first AIO preload may be up to 128K; | |
3052 | 21 * |
22 * aio_read/aio_error() may return EINPROGRESS for just written data; | |
23 * | |
24 * kqueue EVFILT_AIO filter is level triggered only: an event repeats | |
25 * until aio_return() will be called; | |
26 * | |
4133
59b99f217c6d
Replaced "can not" with "cannot" and "could not" in a bunch of places.
Ruslan Ermilov <ru@nginx.com>
parents:
4076
diff
changeset
|
27 * aio_cancel() cannot cancel file AIO: it returns AIO_NOTCANCELED always. |
3052 | 28 */ |
29 | |
30 | |
31 extern int ngx_kqueue; | |
32 | |
33 | |
34 static ssize_t ngx_file_aio_result(ngx_file_t *file, ngx_event_aio_t *aio, | |
35 ngx_event_t *ev); | |
36 static void ngx_file_aio_event_handler(ngx_event_t *ev); | |
37 | |
38 | |
5980
ccad84a174e0
Refactored sendfile() AIO preload.
Valentin Bartenev <vbart@nginx.com>
parents:
4415
diff
changeset
|
39 ngx_int_t |
ccad84a174e0
Refactored sendfile() AIO preload.
Valentin Bartenev <vbart@nginx.com>
parents:
4415
diff
changeset
|
40 ngx_file_aio_init(ngx_file_t *file, ngx_pool_t *pool) |
ccad84a174e0
Refactored sendfile() AIO preload.
Valentin Bartenev <vbart@nginx.com>
parents:
4415
diff
changeset
|
41 { |
ccad84a174e0
Refactored sendfile() AIO preload.
Valentin Bartenev <vbart@nginx.com>
parents:
4415
diff
changeset
|
42 ngx_event_aio_t *aio; |
ccad84a174e0
Refactored sendfile() AIO preload.
Valentin Bartenev <vbart@nginx.com>
parents:
4415
diff
changeset
|
43 |
ccad84a174e0
Refactored sendfile() AIO preload.
Valentin Bartenev <vbart@nginx.com>
parents:
4415
diff
changeset
|
44 aio = ngx_pcalloc(pool, sizeof(ngx_event_aio_t)); |
ccad84a174e0
Refactored sendfile() AIO preload.
Valentin Bartenev <vbart@nginx.com>
parents:
4415
diff
changeset
|
45 if (aio == NULL) { |
ccad84a174e0
Refactored sendfile() AIO preload.
Valentin Bartenev <vbart@nginx.com>
parents:
4415
diff
changeset
|
46 return NGX_ERROR; |
ccad84a174e0
Refactored sendfile() AIO preload.
Valentin Bartenev <vbart@nginx.com>
parents:
4415
diff
changeset
|
47 } |
ccad84a174e0
Refactored sendfile() AIO preload.
Valentin Bartenev <vbart@nginx.com>
parents:
4415
diff
changeset
|
48 |
ccad84a174e0
Refactored sendfile() AIO preload.
Valentin Bartenev <vbart@nginx.com>
parents:
4415
diff
changeset
|
49 aio->file = file; |
ccad84a174e0
Refactored sendfile() AIO preload.
Valentin Bartenev <vbart@nginx.com>
parents:
4415
diff
changeset
|
50 aio->fd = file->fd; |
ccad84a174e0
Refactored sendfile() AIO preload.
Valentin Bartenev <vbart@nginx.com>
parents:
4415
diff
changeset
|
51 aio->event.data = aio; |
ccad84a174e0
Refactored sendfile() AIO preload.
Valentin Bartenev <vbart@nginx.com>
parents:
4415
diff
changeset
|
52 aio->event.ready = 1; |
ccad84a174e0
Refactored sendfile() AIO preload.
Valentin Bartenev <vbart@nginx.com>
parents:
4415
diff
changeset
|
53 aio->event.log = file->log; |
ccad84a174e0
Refactored sendfile() AIO preload.
Valentin Bartenev <vbart@nginx.com>
parents:
4415
diff
changeset
|
54 |
ccad84a174e0
Refactored sendfile() AIO preload.
Valentin Bartenev <vbart@nginx.com>
parents:
4415
diff
changeset
|
55 file->aio = aio; |
ccad84a174e0
Refactored sendfile() AIO preload.
Valentin Bartenev <vbart@nginx.com>
parents:
4415
diff
changeset
|
56 |
ccad84a174e0
Refactored sendfile() AIO preload.
Valentin Bartenev <vbart@nginx.com>
parents:
4415
diff
changeset
|
57 return NGX_OK; |
ccad84a174e0
Refactored sendfile() AIO preload.
Valentin Bartenev <vbart@nginx.com>
parents:
4415
diff
changeset
|
58 } |
ccad84a174e0
Refactored sendfile() AIO preload.
Valentin Bartenev <vbart@nginx.com>
parents:
4415
diff
changeset
|
59 |
ccad84a174e0
Refactored sendfile() AIO preload.
Valentin Bartenev <vbart@nginx.com>
parents:
4415
diff
changeset
|
60 |
3052 | 61 ssize_t |
62 ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset, | |
63 ngx_pool_t *pool) | |
64 { | |
3294
04cfc09b8b8d
export aio presence knowledge to prevent using "aio sendfile",
Igor Sysoev <igor@sysoev.ru>
parents:
3065
diff
changeset
|
65 int n; |
04cfc09b8b8d
export aio presence knowledge to prevent using "aio sendfile",
Igor Sysoev <igor@sysoev.ru>
parents:
3065
diff
changeset
|
66 ngx_event_t *ev; |
04cfc09b8b8d
export aio presence knowledge to prevent using "aio sendfile",
Igor Sysoev <igor@sysoev.ru>
parents:
3065
diff
changeset
|
67 ngx_event_aio_t *aio; |
3052 | 68 |
3294
04cfc09b8b8d
export aio presence knowledge to prevent using "aio sendfile",
Igor Sysoev <igor@sysoev.ru>
parents:
3065
diff
changeset
|
69 if (!ngx_file_aio) { |
3052 | 70 return ngx_read_file(file, buf, size, offset); |
71 } | |
72 | |
5980
ccad84a174e0
Refactored sendfile() AIO preload.
Valentin Bartenev <vbart@nginx.com>
parents:
4415
diff
changeset
|
73 if (file->aio == NULL && ngx_file_aio_init(file, pool) != NGX_OK) { |
ccad84a174e0
Refactored sendfile() AIO preload.
Valentin Bartenev <vbart@nginx.com>
parents:
4415
diff
changeset
|
74 return NGX_ERROR; |
3052 | 75 } |
76 | |
5980
ccad84a174e0
Refactored sendfile() AIO preload.
Valentin Bartenev <vbart@nginx.com>
parents:
4415
diff
changeset
|
77 aio = file->aio; |
3052 | 78 ev = &aio->event; |
79 | |
80 if (!ev->ready) { | |
81 ngx_log_error(NGX_LOG_ALERT, file->log, 0, | |
82 "second aio post for \"%V\"", &file->name); | |
83 return NGX_AGAIN; | |
84 } | |
85 | |
86 ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0, | |
6480 | 87 "aio complete:%d @%O:%uz %V", |
3052 | 88 ev->complete, offset, size, &file->name); |
89 | |
90 if (ev->complete) { | |
91 ev->complete = 0; | |
92 ngx_set_errno(aio->err); | |
93 | |
94 if (aio->err == 0) { | |
95 return aio->nbytes; | |
96 } | |
97 | |
4076
37da005a5808
Bugfix: open_file_cache lost is_directio flag.
Maxim Dounin <mdounin@mdounin.ru>
parents:
3294
diff
changeset
|
98 ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, |
37da005a5808
Bugfix: open_file_cache lost is_directio flag.
Maxim Dounin <mdounin@mdounin.ru>
parents:
3294
diff
changeset
|
99 "aio read \"%s\" failed", file->name.data); |
37da005a5808
Bugfix: open_file_cache lost is_directio flag.
Maxim Dounin <mdounin@mdounin.ru>
parents:
3294
diff
changeset
|
100 |
3052 | 101 return NGX_ERROR; |
102 } | |
103 | |
104 ngx_memzero(&aio->aiocb, sizeof(struct aiocb)); | |
105 | |
106 aio->aiocb.aio_fildes = file->fd; | |
107 aio->aiocb.aio_offset = offset; | |
108 aio->aiocb.aio_buf = buf; | |
109 aio->aiocb.aio_nbytes = size; | |
110 #if (NGX_HAVE_KQUEUE) | |
111 aio->aiocb.aio_sigevent.sigev_notify_kqueue = ngx_kqueue; | |
112 aio->aiocb.aio_sigevent.sigev_notify = SIGEV_KEVENT; | |
7448
7f035fd1ec7b
Fixed portability issues with union sigval.
Sergey Kandaurov <pluknet@nginx.com>
parents:
6480
diff
changeset
|
113 aio->aiocb.aio_sigevent.sigev_value.sival_ptr = ev; |
3052 | 114 #endif |
115 ev->handler = ngx_file_aio_event_handler; | |
116 | |
117 n = aio_read(&aio->aiocb); | |
118 | |
119 if (n == -1) { | |
120 n = ngx_errno; | |
121 | |
122 if (n == NGX_EAGAIN) { | |
123 return ngx_read_file(file, buf, size, offset); | |
124 } | |
125 | |
126 ngx_log_error(NGX_LOG_CRIT, file->log, n, | |
127 "aio_read(\"%V\") failed", &file->name); | |
128 | |
129 if (n == NGX_ENOSYS) { | |
3294
04cfc09b8b8d
export aio presence knowledge to prevent using "aio sendfile",
Igor Sysoev <igor@sysoev.ru>
parents:
3065
diff
changeset
|
130 ngx_file_aio = 0; |
3052 | 131 return ngx_read_file(file, buf, size, offset); |
132 } | |
133 | |
134 return NGX_ERROR; | |
135 } | |
136 | |
137 ngx_log_debug2(NGX_LOG_DEBUG_CORE, file->log, 0, | |
138 "aio_read: fd:%d %d", file->fd, n); | |
139 | |
140 ev->active = 1; | |
141 ev->ready = 0; | |
142 ev->complete = 0; | |
143 | |
144 return ngx_file_aio_result(aio->file, aio, ev); | |
145 } | |
146 | |
147 | |
148 static ssize_t | |
149 ngx_file_aio_result(ngx_file_t *file, ngx_event_aio_t *aio, ngx_event_t *ev) | |
150 { | |
151 int n; | |
152 ngx_err_t err; | |
153 | |
154 n = aio_error(&aio->aiocb); | |
155 | |
156 ngx_log_debug2(NGX_LOG_DEBUG_CORE, file->log, 0, | |
157 "aio_error: fd:%d %d", file->fd, n); | |
158 | |
159 if (n == -1) { | |
160 err = ngx_errno; | |
161 aio->err = err; | |
162 | |
163 ngx_log_error(NGX_LOG_ALERT, file->log, err, | |
164 "aio_error(\"%V\") failed", &file->name); | |
165 return NGX_ERROR; | |
166 } | |
167 | |
4415
30eff7580d0c
Fixed AIO error handling on FreeBSD.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4412
diff
changeset
|
168 if (n == NGX_EINPROGRESS) { |
30eff7580d0c
Fixed AIO error handling on FreeBSD.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4412
diff
changeset
|
169 if (ev->ready) { |
30eff7580d0c
Fixed AIO error handling on FreeBSD.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4412
diff
changeset
|
170 ev->ready = 0; |
30eff7580d0c
Fixed AIO error handling on FreeBSD.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4412
diff
changeset
|
171 ngx_log_error(NGX_LOG_ALERT, file->log, n, |
30eff7580d0c
Fixed AIO error handling on FreeBSD.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4412
diff
changeset
|
172 "aio_read(\"%V\") still in progress", |
30eff7580d0c
Fixed AIO error handling on FreeBSD.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4412
diff
changeset
|
173 &file->name); |
3052 | 174 } |
175 | |
4415
30eff7580d0c
Fixed AIO error handling on FreeBSD.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4412
diff
changeset
|
176 return NGX_AGAIN; |
3052 | 177 } |
178 | |
179 n = aio_return(&aio->aiocb); | |
180 | |
181 if (n == -1) { | |
182 err = ngx_errno; | |
183 aio->err = err; | |
4415
30eff7580d0c
Fixed AIO error handling on FreeBSD.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4412
diff
changeset
|
184 ev->ready = 1; |
3052 | 185 |
4415
30eff7580d0c
Fixed AIO error handling on FreeBSD.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4412
diff
changeset
|
186 ngx_log_error(NGX_LOG_CRIT, file->log, err, |
3052 | 187 "aio_return(\"%V\") failed", &file->name); |
188 return NGX_ERROR; | |
189 } | |
190 | |
191 aio->err = 0; | |
192 aio->nbytes = n; | |
193 ev->ready = 1; | |
194 ev->active = 0; | |
195 | |
196 ngx_log_debug2(NGX_LOG_DEBUG_CORE, file->log, 0, | |
197 "aio_return: fd:%d %d", file->fd, n); | |
198 | |
199 return n; | |
200 } | |
201 | |
202 | |
203 static void | |
204 ngx_file_aio_event_handler(ngx_event_t *ev) | |
205 { | |
206 ngx_event_aio_t *aio; | |
207 | |
208 aio = ev->data; | |
209 | |
210 ngx_log_debug2(NGX_LOG_DEBUG_CORE, ev->log, 0, | |
211 "aio event handler fd:%d %V", aio->fd, &aio->file->name); | |
212 | |
213 if (ngx_file_aio_result(aio->file, aio, ev) != NGX_AGAIN) { | |
214 aio->handler(ev); | |
215 } | |
216 } |