From c15b063267c17cba1792c818d6234a0f7c3fe3dc Mon Sep 17 00:00:00 2001 From: cyrus Date: Wed, 20 Aug 2014 09:53:29 +0000 Subject: [PATCH] dnsmasq: fix a race condition possibly leading to lockup git-svn-id: svn://svn.openwrt.org/openwrt/branches/barrier_breaker@42226 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- package/network/services/dnsmasq/Makefile | 2 +- .../002-fix-race-on-interface-flaps.patch | 277 ++++++++++++++++++ 2 files changed, 278 insertions(+), 1 deletion(-) create mode 100644 package/network/services/dnsmasq/patches/002-fix-race-on-interface-flaps.patch diff --git a/package/network/services/dnsmasq/Makefile b/package/network/services/dnsmasq/Makefile index 1d5b201..17af3c5 100644 --- a/package/network/services/dnsmasq/Makefile +++ b/package/network/services/dnsmasq/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=dnsmasq PKG_VERSION:=2.71 -PKG_RELEASE:=3 +PKG_RELEASE:=4 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=http://thekelleys.org.uk/dnsmasq diff --git a/package/network/services/dnsmasq/patches/002-fix-race-on-interface-flaps.patch b/package/network/services/dnsmasq/patches/002-fix-race-on-interface-flaps.patch new file mode 100644 index 0000000..814c876 --- /dev/null +++ b/package/network/services/dnsmasq/patches/002-fix-race-on-interface-flaps.patch @@ -0,0 +1,277 @@ +From a0358e5ddbc1ef3dec791f11f95f5dbe56087a5e Mon Sep 17 00:00:00 2001 +From: Simon Kelley +Date: Sat, 7 Jun 2014 13:38:48 +0100 +Subject: [PATCH] Handle async notification of address changes using the event + system. + +--- + CHANGELOG | 4 ++++ + src/bpf.c | 6 +++--- + src/dhcp6.c | 10 ---------- + src/dnsmasq.c | 13 +++++++++++-- + src/dnsmasq.h | 6 ++++-- + src/netlink.c | 39 ++++++++++----------------------------- + src/network.c | 11 +++-------- + 7 files changed, 35 insertions(+), 54 deletions(-) + +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -15,6 +15,10 @@ version 2.71 + regression introduced in 2.69. Thanks to James Hunt and + the Ubuntu crowd for assistance in fixing this. + ++ Fix race condition which could lock up dnsmasq when an ++ interface goes down and up rapidly. Thanks to Conrad ++ Kostecki for helping to chase this down. ++ + + version 2.70 + Fix crash, introduced in 2.69, on TCP request when dnsmasq +--- a/src/bpf.c ++++ b/src/bpf.c +@@ -376,7 +376,7 @@ void route_init(void) + die(_("cannot create PF_ROUTE socket: %s"), NULL, EC_BADNET); + } + +-void route_sock(time_t now) ++void route_sock(void) + { + struct if_msghdr *msg; + int rc = recv(daemon->routefd, daemon->packet, daemon->packet_buff_sz, 0); +@@ -401,7 +401,7 @@ void route_sock(time_t now) + else if (msg->ifm_type == RTM_NEWADDR) + { + del_family = 0; +- newaddress(now); ++ send_newaddr(); + } + else if (msg->ifm_type == RTM_DELADDR) + { +@@ -439,7 +439,7 @@ void route_sock(time_t now) + of += sizeof(long) - (diff & (sizeof(long) - 1)); + } + +- newaddress(now); ++ send_newaddr(); + } + } + +--- a/src/dnsmasq.c ++++ b/src/dnsmasq.c +@@ -917,10 +917,10 @@ int main (int argc, char **argv) + + #if defined(HAVE_LINUX_NETWORK) + if (FD_ISSET(daemon->netlinkfd, &rset)) +- netlink_multicast(now); ++ netlink_multicast(); + #elif defined(HAVE_BSD_NETWORK) + if (FD_ISSET(daemon->routefd, &rset)) +- route_sock(now); ++ route_sock(); + #endif + + /* Check for changes to resolv files once per second max. */ +@@ -1037,6 +1037,11 @@ void send_alarm(time_t event, time_t now + } + } + ++void send_newaddr(void) ++{ ++ send_event(pipewrite, EVENT_NEWADDR, 0, NULL); ++} ++ + void send_event(int fd, int event, int data, char *msg) + { + struct event_desc ev; +@@ -1230,6 +1235,10 @@ static void async_event(int pipe, time_t + if (daemon->log_file != NULL) + log_reopen(daemon->log_file); + break; ++ ++ case EVENT_NEWADDR: ++ newaddress(now); ++ break; + + case EVENT_TERM: + /* Knock all our children on the head. */ +--- a/src/dnsmasq.h ++++ b/src/dnsmasq.h +@@ -165,6 +165,7 @@ struct event_desc { + #define EVENT_LUA_ERR 19 + #define EVENT_TFTP_ERR 20 + #define EVENT_INIT 21 ++#define EVENT_NEWADDR 22 + + /* Exit codes. */ + #define EC_GOOD 0 +@@ -1289,6 +1290,7 @@ unsigned char *extended_hwaddr(int hwtyp + int make_icmp_sock(void); + int icmp_ping(struct in_addr addr); + #endif ++void send_newaddr(void); + void send_alarm(time_t event, time_t now); + void send_event(int fd, int event, int data, char *msg); + void clear_cache_and_reload(time_t now); +@@ -1297,7 +1299,7 @@ void poll_resolv(int force, int do_reloa + /* netlink.c */ + #ifdef HAVE_LINUX_NETWORK + void netlink_init(void); +-void netlink_multicast(time_t now); ++void netlink_multicast(void); + #endif + + /* bpf.c */ +@@ -1306,7 +1308,7 @@ void init_bpf(void); + void send_via_bpf(struct dhcp_packet *mess, size_t len, + struct in_addr iface_addr, struct ifreq *ifr); + void route_init(void); +-void route_sock(time_t now); ++void route_sock(void); + #endif + + /* bpf.c or netlink.c */ +--- a/src/netlink.c ++++ b/src/netlink.c +@@ -38,7 +38,7 @@ + static struct iovec iov; + static u32 netlink_pid; + +-static int nl_async(struct nlmsghdr *h); ++static void nl_async(struct nlmsghdr *h); + + void netlink_init(void) + { +@@ -142,7 +142,7 @@ int iface_enumerate(int family, void *pa + struct nlmsghdr *h; + ssize_t len; + static unsigned int seq = 0; +- int callback_ok = 1, newaddr = 0; ++ int callback_ok = 1; + + struct { + struct nlmsghdr nlh; +@@ -191,21 +191,10 @@ int iface_enumerate(int family, void *pa + if (h->nlmsg_seq != seq || h->nlmsg_pid != netlink_pid || h->nlmsg_type == NLMSG_ERROR) + { + /* May be multicast arriving async */ +- if (nl_async(h)) +- { +- newaddr = 1; +- enumerate_interfaces(1); /* reset */ +- } ++ nl_async(h); + } + else if (h->nlmsg_type == NLMSG_DONE) +- { +- /* handle async new interface address arrivals, these have to be done +- after we complete as we're not re-entrant */ +- if (newaddr) +- newaddress(dnsmasq_time()); +- +- return callback_ok; +- } ++ return callback_ok; + else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC && family != AF_LOCAL) + { + struct ifaddrmsg *ifa = NLMSG_DATA(h); +@@ -330,11 +319,11 @@ int iface_enumerate(int family, void *pa + } + } + +-void netlink_multicast(time_t now) ++void netlink_multicast(void) + { + ssize_t len; + struct nlmsghdr *h; +- int flags, newaddr = 0; ++ int flags; + + /* don't risk blocking reading netlink messages here. */ + if ((flags = fcntl(daemon->netlinkfd, F_GETFL)) == -1 || +@@ -343,24 +332,19 @@ void netlink_multicast(time_t now) + + if ((len = netlink_recv()) != -1) + for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len)) +- if (nl_async(h)) +- newaddr = 1; ++ nl_async(h); + + /* restore non-blocking status */ + fcntl(daemon->netlinkfd, F_SETFL, flags); +- +- if (newaddr) +- newaddress(now); + } + +-static int nl_async(struct nlmsghdr *h) ++static void nl_async(struct nlmsghdr *h) + { + if (h->nlmsg_type == NLMSG_ERROR) + { + struct nlmsgerr *err = NLMSG_DATA(h); + if (err->error != 0) + my_syslog(LOG_ERR, _("netlink returns error: %s"), strerror(-(err->error))); +- return 0; + } + else if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE) + { +@@ -385,18 +369,15 @@ static int nl_async(struct nlmsghdr *h) + else if (daemon->rfd_save && daemon->rfd_save->refcount != 0) + fd = daemon->rfd_save->fd; + else +- return 0; ++ return; + + while(sendto(fd, daemon->packet, daemon->packet_len, 0, + &daemon->srv_save->addr.sa, sa_len(&daemon->srv_save->addr)) == -1 && retry_send()); + } + } +- return 0; + } + else if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR) +- return 1; /* clever bind mode - rescan */ +- +- return 0; ++ send_newaddr(); + } + #endif + +--- a/src/network.c ++++ b/src/network.c +@@ -551,7 +551,7 @@ static int iface_allowed_v4(struct in_ad + int enumerate_interfaces(int reset) + { + static struct addrlist *spare = NULL; +- static int done = 0, active = 0; ++ static int done = 0; + struct iface_param param; + int errsave, ret = 1; + struct addrlist *addr, *tmp; +@@ -570,14 +570,11 @@ int enumerate_interfaces(int reset) + return 1; + } + +- if (done || active) ++ if (done) + return 1; + + done = 1; + +- /* protect against recusive calls from iface_enumerate(); */ +- active = 1; +- + if ((param.fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) + return 0; + +@@ -677,10 +674,8 @@ int enumerate_interfaces(int reset) + } + + errno = errsave; +- + spare = param.spare; +- active = 0; +- ++ + return ret; + } +