bin/139470: pkg_delete segfaults on '@pkgdep ' in +CONTENTS file

TerryP BigBoss1964 at
Sat Oct 10 04:50:07 UTC 2009

>Number:         139470
>Category:       bin
>Synopsis:       pkg_delete segfaults on '@pkgdep ' in +CONTENTS file
>Confidential:   no
>Severity:       serious
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sat Oct 10 04:50:06 UTC 2009
>Originator:     TerryP
>Release:        7-stable / RELENG_7
FreeBSD 7.2-STABLE FreeBSD 7.2-STABLE #4: Thu Jun 25 22:05:05 UTC 2009     root at  i386

While running make deinstall in /usr/ports/graphics/ImageMagick, pkg_delete crashes with the following output:

pkg_delete: package 'ImageMagick-' is required by these other packages
and may not be deinstalled (but I'll delete it anyway):
Segmentation fault

I've read the source code in /usr/src/usr.sbin/pkg_install and found out what happened. The list that is processed contains a NULL entry, which is later passed onto strcmp() as part of the processing; you can get the exact backtrace through gdb. It looks like the origin of the NULL in question, is found within the function read_plist() from pkg_install/lib/plist.c. In this function, the lines are read from the currently installed /var/db/pkg/pkgname/+CONTENTS file. If the last character in the parsed line, is a space then it is replaced with a \0 terminator, until trailing spaces are blotted out. Within the +CONTENTS file for the installed ImageMagick here, is a line like this: '@pkgdep ', note the trailing space.

Parsing that line results in this code being executed as part of read_plist():

        if (*cp == '\0') {
            cp = NULL;
            goto bottom;

the NULL gets passed on, until it eventually becomes an argument to strcmp(), which obviously is a cork poping event!

I am not familiar with the syntax of directives used in the +CONTENTS files, but I know that pkg_delete should never crash ;). There is probably a problem with the ImageMagick port or the code that generates the packing list in +CONTENTS.
I believe all you would have to do, is run pkg_delete -f pkgname, where pkgname has a /var/db/pkg/pkgname/+CONTENTS file with a bad directive comparable to this one: '@pkgdep ', again note the trailing space and lack of an argument to the pkgdep command.

This was found while trying to deinstall ImageMagick-
0.) Decide how read_plist() should deal with parsing errors
1.) Generate warning about +CONTENTS having a bad line.
2.) Do anything except pass on a NULL pointer further down the chain.

My advice is that the bad directive should generate a warning and be ignored, or the whole thing should just exit with an error message.

Attached is a unified diff/patch file that makes it exit with an error message instead of segfault. Someone who works on FreeBSD is a much better judge of what behaviour is actually desired here, so I will leave the wisdom department to y'all.

cd /usr/src/usr.sbin/pkg_install
patch < /path/to/patchfile

Patch attached with submission follows:

--- lib/plist.c	2009-10-10 04:20:46.000000000 +0000
+++ lib/plist.c.changed	2009-10-10 04:28:50.000000000 +0000
@@ -284,8 +284,8 @@
 	    goto bottom;
 	if (*cp == '\0') {
-	    cp = NULL;
-	    goto bottom;
+	    errx(2, "%s: error in line '%s', the +CONTENTS file for %s is probably bad",
+	          __func__, pline, pkg->name);
 	if (cmd == PLIST_COMMENT && sscanf(cp, "PKG_FORMAT_REVISION:%d.%d\n",
 					   &major, &minor) == 2) {


More information about the freebsd-bugs mailing list