comparison src/core/ngx_resolver.c @ 7048:80224192163c

Resolver: fixed possible use-after-free while resolving SRV. Resolving an SRV record includes resolving its host names in subrequests. Previously, if memory allocation failed while reporting a subrequest result after receiving a response from a DNS server, the SRV resolve handler was called immediately with the NGX_ERROR state. However, if the SRV record included another copy of the resolved name, it was reported once again. This could trigger the use-after-free memory access after SRV resolve handler freed the resolve context by calling ngx_resolve_name_done(). Now the SRV resolve handler is called only when all its subrequests are completed.
author Roman Arutyunyan <arut@nginx.com>
date Tue, 04 Jul 2017 18:07:29 +0300
parents d49b74a683b1
children 137c5be7df09
comparison
equal deleted inserted replaced
7047:3fef8c5caa75 7048:80224192163c
3032 3032
3033 ctx->valid = ngx_min(ctx->valid, cctx->valid); 3033 ctx->valid = ngx_min(ctx->valid, cctx->valid);
3034 3034
3035 addrs = ngx_resolver_calloc(r, cctx->naddrs * sizeof(ngx_addr_t)); 3035 addrs = ngx_resolver_calloc(r, cctx->naddrs * sizeof(ngx_addr_t));
3036 if (addrs == NULL) { 3036 if (addrs == NULL) {
3037 ngx_resolve_name_done(cctx); 3037 srv->state = NGX_ERROR;
3038 3038 goto done;
3039 ctx->state = NGX_ERROR;
3040 ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
3041
3042 ctx->handler(ctx);
3043 return;
3044 } 3039 }
3045 3040
3046 sockaddr = ngx_resolver_alloc(r, cctx->naddrs * sizeof(ngx_sockaddr_t)); 3041 sockaddr = ngx_resolver_alloc(r, cctx->naddrs * sizeof(ngx_sockaddr_t));
3047 if (sockaddr == NULL) { 3042 if (sockaddr == NULL) {
3048 ngx_resolver_free(r, addrs); 3043 ngx_resolver_free(r, addrs);
3049 ngx_resolve_name_done(cctx); 3044 srv->state = NGX_ERROR;
3050 3045 goto done;
3051 ctx->state = NGX_ERROR;
3052 ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
3053
3054 ctx->handler(ctx);
3055 return;
3056 } 3046 }
3057 3047
3058 for (i = 0; i < cctx->naddrs; i++) { 3048 for (i = 0; i < cctx->naddrs; i++) {
3059 addrs[i].sockaddr = &sockaddr[i].sockaddr; 3049 addrs[i].sockaddr = &sockaddr[i].sockaddr;
3060 addrs[i].socklen = cctx->addrs[i].socklen; 3050 addrs[i].socklen = cctx->addrs[i].socklen;
3066 } 3056 }
3067 3057
3068 srv->addrs = addrs; 3058 srv->addrs = addrs;
3069 srv->naddrs = cctx->naddrs; 3059 srv->naddrs = cctx->naddrs;
3070 } 3060 }
3061
3062 done:
3071 3063
3072 ngx_resolve_name_done(cctx); 3064 ngx_resolve_name_done(cctx);
3073 3065
3074 if (ctx->count == 0) { 3066 if (ctx->count == 0) {
3075 ngx_resolver_report_srv(r, ctx); 3067 ngx_resolver_report_srv(r, ctx);
4252 { 4244 {
4253 ngx_uint_t naddrs, nsrvs, nw, i, j, k, l, m, n, w; 4245 ngx_uint_t naddrs, nsrvs, nw, i, j, k, l, m, n, w;
4254 ngx_resolver_addr_t *addrs; 4246 ngx_resolver_addr_t *addrs;
4255 ngx_resolver_srv_name_t *srvs; 4247 ngx_resolver_srv_name_t *srvs;
4256 4248
4249 srvs = ctx->srvs;
4250 nsrvs = ctx->nsrvs;
4251
4257 naddrs = 0; 4252 naddrs = 0;
4258 4253
4259 for (i = 0; i < ctx->nsrvs; i++) { 4254 for (i = 0; i < nsrvs; i++) {
4260 naddrs += ctx->srvs[i].naddrs; 4255 if (srvs[i].state == NGX_ERROR) {
4256 ctx->state = NGX_ERROR;
4257 ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
4258
4259 ctx->handler(ctx);
4260 return;
4261 }
4262
4263 naddrs += srvs[i].naddrs;
4261 } 4264 }
4262 4265
4263 if (naddrs == 0) { 4266 if (naddrs == 0) {
4264 ctx->state = NGX_RESOLVE_NXDOMAIN; 4267 ctx->state = NGX_RESOLVE_NXDOMAIN;
4265 ctx->valid = ngx_time() + (r->valid ? r->valid : 10); 4268 ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
4274 ctx->valid = ngx_time() + (r->valid ? r->valid : 10); 4277 ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
4275 4278
4276 ctx->handler(ctx); 4279 ctx->handler(ctx);
4277 return; 4280 return;
4278 } 4281 }
4279
4280 srvs = ctx->srvs;
4281 nsrvs = ctx->nsrvs;
4282 4282
4283 i = 0; 4283 i = 0;
4284 n = 0; 4284 n = 0;
4285 4285
4286 do { 4286 do {