Mercurial > hg > nginx-quic
view src/core/ngx_resolver.h @ 6351:497d0cff8ace
Resolver: fixed use-after-free memory accesses with CNAME.
When several requests were waiting for a response, then after getting
a CNAME response only the last request's context had the name updated.
Contexts of other requests had the wrong name. This name was used by
ngx_resolve_name_done() to find the node to remove the request context
from. When the name was wrong, the request could not be properly
cancelled, its context was freed but stayed linked to the node's waiting
list. This happened e.g. when the first request was aborted or timed
out before the resolving completed. When it completed, this triggered
a use-after-free memory access by calling ctx->handler of already freed
request context. The bug manifests itself by
"could not cancel <name> resolving" alerts in error_log.
When a request was responded with a CNAME, the request context kept
the pointer to the original node's rn->u.cname. If the original node
expired before the resolving timed out or completed with an error,
this would trigger a use-after-free memory access via ctx->name in
ctx->handler().
The fix is to keep ctx->name unmodified. The name from context
is no longer used by ngx_resolve_name_done(). Instead, we now keep
the pointer to resolver node to which this request is linked.
Keeping the original name intact also improves logging.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Tue, 26 Jan 2016 16:46:59 +0300 |
parents | 7316c57e4fe7 |
children | 69977457e1a6 |
line wrap: on
line source
/* * Copyright (C) Igor Sysoev * Copyright (C) Nginx, Inc. */ #include <ngx_config.h> #include <ngx_core.h> #ifndef _NGX_RESOLVER_H_INCLUDED_ #define _NGX_RESOLVER_H_INCLUDED_ #define NGX_RESOLVE_A 1 #define NGX_RESOLVE_CNAME 5 #define NGX_RESOLVE_PTR 12 #define NGX_RESOLVE_MX 15 #define NGX_RESOLVE_TXT 16 #if (NGX_HAVE_INET6) #define NGX_RESOLVE_AAAA 28 #endif #define NGX_RESOLVE_DNAME 39 #define NGX_RESOLVE_FORMERR 1 #define NGX_RESOLVE_SERVFAIL 2 #define NGX_RESOLVE_NXDOMAIN 3 #define NGX_RESOLVE_NOTIMP 4 #define NGX_RESOLVE_REFUSED 5 #define NGX_RESOLVE_TIMEDOUT NGX_ETIMEDOUT #define NGX_NO_RESOLVER (void *) -1 #define NGX_RESOLVER_MAX_RECURSION 50 typedef struct { ngx_connection_t *connection; struct sockaddr *sockaddr; socklen_t socklen; ngx_str_t server; ngx_log_t log; } ngx_udp_connection_t; typedef struct ngx_resolver_ctx_s ngx_resolver_ctx_t; typedef void (*ngx_resolver_handler_pt)(ngx_resolver_ctx_t *ctx); typedef struct { ngx_rbtree_node_t node; ngx_queue_t queue; /* PTR: resolved name, A: name to resolve */ u_char *name; #if (NGX_HAVE_INET6) /* PTR: IPv6 address to resolve (IPv4 address is in rbtree node key) */ struct in6_addr addr6; #endif u_short nlen; u_short qlen; u_char *query; #if (NGX_HAVE_INET6) u_char *query6; #endif union { in_addr_t addr; in_addr_t *addrs; u_char *cname; } u; u_char code; u_short naddrs; u_short cnlen; #if (NGX_HAVE_INET6) union { struct in6_addr addr6; struct in6_addr *addrs6; } u6; u_short naddrs6; #endif time_t expire; time_t valid; uint32_t ttl; ngx_resolver_ctx_t *waiting; } ngx_resolver_node_t; typedef struct { /* has to be pointer because of "incomplete type" */ ngx_event_t *event; void *dummy; ngx_log_t *log; /* event ident must be after 3 pointers as in ngx_connection_t */ ngx_int_t ident; /* simple round robin DNS peers balancer */ ngx_array_t udp_connections; ngx_uint_t last_connection; ngx_rbtree_t name_rbtree; ngx_rbtree_node_t name_sentinel; ngx_rbtree_t addr_rbtree; ngx_rbtree_node_t addr_sentinel; ngx_queue_t name_resend_queue; ngx_queue_t addr_resend_queue; ngx_queue_t name_expire_queue; ngx_queue_t addr_expire_queue; #if (NGX_HAVE_INET6) ngx_uint_t ipv6; /* unsigned ipv6:1; */ ngx_rbtree_t addr6_rbtree; ngx_rbtree_node_t addr6_sentinel; ngx_queue_t addr6_resend_queue; ngx_queue_t addr6_expire_queue; #endif time_t resend_timeout; time_t expire; time_t valid; ngx_uint_t log_level; } ngx_resolver_t; struct ngx_resolver_ctx_s { ngx_resolver_ctx_t *next; ngx_resolver_t *resolver; ngx_udp_connection_t *udp_connection; /* event ident must be after 3 pointers as in ngx_connection_t */ ngx_int_t ident; ngx_int_t state; ngx_str_t name; ngx_uint_t naddrs; ngx_addr_t *addrs; ngx_addr_t addr; struct sockaddr_in sin; ngx_resolver_handler_pt handler; void *data; ngx_msec_t timeout; ngx_uint_t quick; /* unsigned quick:1; */ ngx_uint_t recursion; ngx_event_t *event; ngx_resolver_node_t *node; }; ngx_resolver_t *ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n); ngx_resolver_ctx_t *ngx_resolve_start(ngx_resolver_t *r, ngx_resolver_ctx_t *temp); ngx_int_t ngx_resolve_name(ngx_resolver_ctx_t *ctx); void ngx_resolve_name_done(ngx_resolver_ctx_t *ctx); ngx_int_t ngx_resolve_addr(ngx_resolver_ctx_t *ctx); void ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx); char *ngx_resolver_strerror(ngx_int_t err); #endif /* _NGX_RESOLVER_H_INCLUDED_ */