From patchwork Fri Jul 29 08:51:59 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sinan X-Patchwork-Id: 56426 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 35F743858429 for ; Fri, 29 Jul 2022 08:54:28 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 35F743858429 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1659084868; bh=bd2A0JdQNaobmB/VQxxSVzAqi+ydrWTzXOSbzVfXCcI=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:Cc:From; b=to8TXj2znkwT24ayaezJmdJtxIS3s+XqbwbIKgNptMvs4JJ8KToCZJBiaBaoIqvlt 6o93sDLP/6OUQPzZhWgTyZDmNHYNFdVPJZHgMIARnUW5Ak45a34g3y1ETLjyxK/zhY MdxQlHUOqUY1G41/EQG7P2PuJp4mPNX8ysNFLvDk= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from out30-43.freemail.mail.aliyun.com (out30-43.freemail.mail.aliyun.com [115.124.30.43]) by sourceware.org (Postfix) with ESMTPS id BD0F73858D39 for ; Fri, 29 Jul 2022 08:54:05 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org BD0F73858D39 X-Alimail-AntiSpam: AC=PASS; BC=-1|-1; BR=01201311R211e4; CH=green; DM=||false|; DS=||; FP=0|-1|-1|-1|0|-1|-1|-1; HT=ay29a033018045168; MF=sinan.lin@linux.alibaba.com; NM=1; PH=DS; RN=2; SR=0; TI=SMTPD_---0VKkqMA._1659084821; Received: from localhost(mailfrom:sinan.lin@linux.alibaba.com fp:SMTPD_---0VKkqMA._1659084821) by smtp.aliyun-inc.com; Fri, 29 Jul 2022 16:53:58 +0800 To: libc-alpha@sourceware.org Subject: [PATCH] resolv: Set a timeout for TCP-based query read (bug 19643) Date: Fri, 29 Jul 2022 16:51:59 +0800 Message-Id: <20220729085159.68458-1-sinan.lin@linux.alibaba.com> X-Mailer: git-send-email 2.36.0 MIME-Version: 1.0 X-Spam-Status: No, score=-19.4 required=5.0 tests=BAYES_00, ENV_AND_HDR_SPF_MATCH, GIT_PATCH_0, KAM_DMARC_STATUS, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_PASS, TXREP, UNPARSEABLE_RELAY, USER_IN_DEF_SPF_WL autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Sinan Lin via Libc-alpha From: Sinan Reply-To: Sinan Lin Cc: Sinan Lin Errors-To: libc-alpha-bounces+patchwork=sourceware.org@sourceware.org Sender: "Libc-alpha" There was no timeout set to tcp socket read during name resolution, and this might lead to a hang on read when DNS response is too large. This patch proposes a default 10 seconds timeout for TCP-based query read, and it currently does not include the connection and write part. Signed-off-by: Sinan Lin --- inet/deadline.c | 15 +++++++++++++ inet/net-internal.h | 5 +++++ resolv/res_send.c | 55 ++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 70 insertions(+), 5 deletions(-) diff --git a/inet/deadline.c b/inet/deadline.c index 7deb39b0ec..138e7a3351 100644 --- a/inet/deadline.c +++ b/inet/deadline.c @@ -73,6 +73,21 @@ __deadline_from_timeval (struct deadline_current_time current, return (struct deadline) { { sec, nsec } }; } +struct deadline +__deadline_from_sec (struct deadline_current_time current, int sec) +{ + assert (sec >= 0); + + /* Compute second-based deadline. Perform the addition in + uintmax_t, which is unsigned, to simply overflow detection. */ + uintmax_t deadline_sec = current.current.tv_sec; + deadline_sec += sec; + if (deadline_sec < (uintmax_t) sec) + return infinite_deadline (); + + return (struct deadline) { { deadline_sec, 0 } }; +} + int __deadline_to_ms (struct deadline_current_time current, struct deadline deadline) diff --git a/inet/net-internal.h b/inet/net-internal.h index cdccdd3976..638a3dbd53 100644 --- a/inet/net-internal.h +++ b/inet/net-internal.h @@ -139,6 +139,11 @@ DIAG_POP_NEEDS_COMMENT; struct deadline __deadline_from_timeval (struct deadline_current_time, struct timeval tv) attribute_hidden; +/* Add time in second to the current time and return it. Returns a special + infinite absolute deadline on overflow. */ +struct deadline __deadline_from_sec (struct deadline_current_time, + int sec) attribute_hidden; + /* Compute the number of milliseconds until the specified deadline, from the current time in the argument. The result is mainly for use with poll. If the deadline has already passed, return 0. If diff --git a/resolv/res_send.c b/resolv/res_send.c index 6a08e729a4..fee32451aa 100644 --- a/resolv/res_send.c +++ b/resolv/res_send.c @@ -110,6 +110,7 @@ #include #include #include +#include #if PACKETSZ > 65536 #define MAXPACKET PACKETSZ @@ -190,6 +191,30 @@ static int send_dg(res_state, const u_char *, int, int *, int *, u_char **, u_char **, int *, int *, int *); static int sock_eq(struct sockaddr_in6 *, struct sockaddr_in6 *); +static int wait_on_socket(struct pollfd *, struct deadline); + +static int +wait_on_socket (struct pollfd *pfd, struct deadline wait_deadline) +{ + do + { + int timeout = __deadline_to_ms (__deadline_current_time(), + wait_deadline); + switch (__poll (pfd, 1, timeout)) + { + case -1: + if (errno == EINTR) + continue; + /* FALLTHROUGH */ + case 0: + return -1; + default: + break; + } + } while ((pfd->revents & POLLIN) == 0); + + return 1; +} /* Returns a shift value for the name server index. Used to implement RES_ROTATE. */ @@ -570,6 +595,8 @@ send_vc(res_state statp, UHEADER *anhp = (UHEADER *) *ansp; struct sockaddr *nsap = __res_get_nsaddr (statp, ns); int truncating, connreset, n; + struct pollfd pfd[1] = { [0] = { .events = POLLIN } }; + struct deadline read_deadline; /* On some architectures compiler might emit a warning indicating 'resplen' may be used uninitialized. However if buf2 == NULL then this code won't be executed; if buf2 != NULL, then first @@ -589,6 +616,16 @@ send_vc(res_state statp, u_char *cp; connreset = 0; + + /* Compute and set timeout for each socket read. The timeout is + currently twice the lengh of send_dg routine. */ + int seconds = (statp->retrans << (ns+1)); + if (ns > 0) + seconds /= statp->nscount; + if (seconds <= 0) + seconds = 1; + read_deadline = + __deadline_from_sec (__deadline_current_time(), seconds); same_ns: truncating = 0; @@ -657,10 +694,13 @@ send_vc(res_state statp, int recvresp2 = buf2 == NULL; uint16_t rlen16; read_len: + pfd[0].fd = statp->_vcsock; cp = (u_char *)&rlen16; len = sizeof(rlen16); - while ((n = TEMP_FAILURE_RETRY (read(statp->_vcsock, cp, - (int)len))) > 0) { + + while ((n = wait_on_socket (pfd, read_deadline)) > 0 + && (n = TEMP_FAILURE_RETRY (read(statp->_vcsock, cp, + (int)len))) > 0) { cp += n; if ((len -= n) <= 0) break; @@ -744,10 +784,14 @@ send_vc(res_state statp, } cp = *thisansp; - while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (int)len)) > 0){ + + while (len != 0 + && (n = wait_on_socket (pfd, read_deadline)) > 0 + && (n = read(statp->_vcsock, (char *)cp, (int)len)) > 0) { cp += n; len -= n; } + if (__glibc_unlikely (n <= 0)) { *terrno = errno; return close_and_return_error (statp, resplen2); @@ -758,9 +802,10 @@ send_vc(res_state statp, */ anhp->tc = 1; len = rlen - *thisanssizp; - while (len != 0) { - char junk[PACKETSZ]; + while (len != 0 + && (n = wait_on_socket (pfd, read_deadline)) > 0) { + char junk[PACKETSZ]; n = read(statp->_vcsock, junk, (len > sizeof junk) ? sizeof junk : len); if (n > 0)