misc/168289: [patch] [pkg_install] fix memory leaks and potential
CPU burning in lib/plist.c:delete_hierarchy
Garrett Cooper
yanegomi at gmail.com
Thu May 24 01:50:02 UTC 2012
>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 at 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 <libgen.h>
#include <stdio.h>
#include <string.h>
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 <miles.ohlrich!AT-SPAMFREE!isilon.com> (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 <err.h>
+#include <libgen.h>
#include <md5.h>
/* 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:
More information about the freebsd-bugs
mailing list