From owner-freebsd-bugs@FreeBSD.ORG Thu May 24 01:50:02 2012 Return-Path: Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id A42A4106566B for ; Thu, 24 May 2012 01:50:02 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id 419C58FC14 for ; Thu, 24 May 2012 01:50:02 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.5/8.14.5) with ESMTP id q4O1o2l4082162 for ; Thu, 24 May 2012 01:50:02 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.5/8.14.5/Submit) id q4O1o2ib082161; Thu, 24 May 2012 01:50:02 GMT (envelope-from gnats) Resent-Date: Thu, 24 May 2012 01:50:02 GMT Resent-Message-Id: <201205240150.q4O1o2ib082161@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Garrett Cooper Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 5998B106566B for ; Thu, 24 May 2012 01:48:07 +0000 (UTC) (envelope-from nobody@FreeBSD.org) Received: from red.freebsd.org (red.freebsd.org [IPv6:2001:4f8:fff6::22]) by mx1.freebsd.org (Postfix) with ESMTP id 449368FC0A for ; Thu, 24 May 2012 01:48:07 +0000 (UTC) Received: from red.freebsd.org (localhost [127.0.0.1]) by red.freebsd.org (8.14.4/8.14.4) with ESMTP id q4O1m7O8047095 for ; Thu, 24 May 2012 01:48:07 GMT (envelope-from nobody@red.freebsd.org) Received: (from nobody@localhost) by red.freebsd.org (8.14.4/8.14.4/Submit) id q4O1m6c8047094; Thu, 24 May 2012 01:48:06 GMT (envelope-from nobody) Message-Id: <201205240148.q4O1m6c8047094@red.freebsd.org> Date: Thu, 24 May 2012 01:48:06 GMT From: Garrett Cooper To: freebsd-gnats-submit@FreeBSD.org X-Send-Pr-Version: www-3.1 Cc: Subject: misc/168289: [patch] [pkg_install] fix memory leaks and potential CPU burning in lib/plist.c:delete_hierarchy X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 24 May 2012 01:50:02 -0000 >Number: 168289 >Category: misc >Synopsis: [patch] [pkg_install] fix memory leaks and potential CPU burning in lib/plist.c:delete_hierarchy >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Thu May 24 01:50:01 UTC 2012 >Closed-Date: >Last-Modified: >Originator: Garrett Cooper >Release: 9-STABLE >Organization: EMC Isilon >Environment: FreeBSD forza.west.isilon.com 9.0-STABLE FreeBSD 9.0-STABLE #4 r235133: Mon May 7 10:31:22 PDT 2012 root@forza.isilon.com:/usr/obj/usr/src/sys/FORZA amd64 >Description: A case was noted internally where input in delete_hierarchy could leak memory and burn CPU cycles when trying to delete a directory hierarchy with two or more contiguous slashes next to them. Example of the CPU burning is as follows: $ cat ~/infinite_plist.c #include #include #include int main(void) { char *paths[] = { "foo//bar", "/root/foo.bar", "///root/foo.bar/baz", "a.b.c.d", }; char *cp1, *cp2; int i; #ifdef STUCK for (i = 0; i < sizeof(paths)/sizeof(paths[0]); i++) { cp1 = cp2 = strdup(paths[i]); printf("%s... ", cp2); fflush(stdout); while (cp2) { if ((cp2 = strrchr(cp1, '/')) != NULL) *cp2 = '\0'; if (cp2) cp1 = strdup(paths[0]); } } #else for (i = 0; i < sizeof(paths)/sizeof(paths[0]); i++) { cp1 = paths[i]; for (;;) { if ((cp2 = dirname(cp2)) == NULL || strcmp("/", cp2) == 0 || strcmp(".", cp2) == 0) break; } printf("%s: %s\n", paths[i], cp2); } #endif return (0); } $ gcc -DSTUCK -o ~/infinite_plist ~/infinite_plist.c $ ~/infinite_plist foo//bar... ^C $ gcc -o ~/infinite_plist ~/infinite_plist.c $ ~/infinite_plist foo//bar: . /root/foo.bar: . ///root/foo.bar/baz: . a.b.c.d: . $ Reported by Miles Ohlrich (replace !AT-SPAMFREE! with '@'). >How-To-Repeat: Call delete_hierarchy with dir == "/usr/local//foo-1.0", or trigger any of the error conditions with the file hierarchy tests. >Fix: Patch attached with submission follows: Index: usr.sbin/pkg_install/lib/plist.c =================================================================== --- usr.sbin/pkg_install/lib/plist.c (revision 235484) +++ usr.sbin/pkg_install/lib/plist.c (working copy) @@ -23,6 +23,7 @@ #include "lib.h" #include +#include #include /* Add an item to a packing list */ @@ -548,9 +549,8 @@ int delete_hierarchy(const char *dir, Boolean ign_err, Boolean nukedirs) { - char *cp1, *cp2; + char *cp; - cp1 = cp2 = strdup(dir); if (!fexists(dir) && !issymlink(dir)) { if (!ign_err) warnx("%s '%s' doesn't exist", @@ -572,21 +572,21 @@ if (!nukedirs) return 0; - while (cp2) { - if ((cp2 = strrchr(cp1, '/')) != NULL) - *cp2 = '\0'; - if (!isemptydir(dir)) - return 0; - if (RMDIR(dir) && !ign_err) { - if (!fexists(dir)) - warnx("directory '%s' doesn't exist", dir); - else - return 1; + + cp = (char*)dir; + for (;;) { + if ((cp = dirname(cp)) == NULL) + return 1; + if (strcmp("/", cp) == 0 || strcmp(".", cp) == 0) + break; + if (!isemptydir(cp)) + break; + if (RMDIR(cp) && !ign_err) { + if (!fexists(cp)) + warnx("directory '%s' doesn't exist", cp); + return 1; } - /* back up the pathname one component */ - if (cp2) { - cp1 = strdup(dir); - } } + return 0; } >Release-Note: >Audit-Trail: >Unformatted: