NetBSD Problem Report #51751

From www@NetBSD.org  Wed Dec 28 22:12:09 2016
Return-Path: <www@NetBSD.org>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
	(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
	(Client CN "mail.netbsd.org", Issuer "Postmaster NetBSD.org" (verified OK))
	by mollari.NetBSD.org (Postfix) with ESMTPS id 98CBE7A2E1
	for <gnats-bugs@gnats.NetBSD.org>; Wed, 28 Dec 2016 22:12:09 +0000 (UTC)
Message-Id: <20161228221207.C37347A354@mollari.NetBSD.org>
Date: Wed, 28 Dec 2016 22:12:07 +0000 (UTC)
From: khorben@netbsd.org
Reply-To: khorben@netbsd.org
To: gnats-bugs@NetBSD.org
Subject: Local privilege escalation while building math/lp_solve
X-Send-Pr-Version: www-1.0

>Number:         51751
>Category:       pkg
>Synopsis:       Local privilege escalation while building math/lp_solve
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    pkg-manager
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Wed Dec 28 22:15:00 +0000 2016
>Originator:     Pierre Pronchery
>Release:        20161228
>Organization:
The NetBSD Project
>Environment:
NetBSD my.host.name 7.0_STABLE NetBSD 7.0_STABLE (GENERIC) amd64
>Description:
This is copied directly from the e-mail I just sent upstream:

while working on the NetBSD package for lp_solve (in pkgsrc), I figured that the "ccc" tests are vulnerable to local privilege escalation. The path to platform.c is hard-coded, with the file created and filled without error checking, and then compiled and ran directly:

In lp_solve_5.5/lpsolve55/ccc:
>   5 #determine platform (32/64 bit)
>   6 >/tmp/platform.c
>   7 echo '#include <stdlib.h>'>>/tmp/platform.c
>   8 echo '#include <stdio.h>'>>/tmp/platform.c
>   9 echo 'main(){printf("ux%d", (int) (sizeof(void *)*8));}'>>/tmp/platform.c
>  10 $c /tmp/platform.c -o /tmp/platform
>  11 PLATFORM=`/tmp/platform`
>  12 rm /tmp/platform /tmp/platform.c >/dev/null 2>&1

A local attacker can therefore create a /tmp/platform.c file, set its permissions to 0644, and then wait until another user will attempt to build lp_solve.

This issue is mitigated on systems using a separate namespace per-user for /tmp. I would still consider this behaviour generally fragile though.

Also note that there will be no error message while attempting to delete the resulting executable. Error messages are normally showed on lines 6, 7, 8 and 9, but they can be avoided with a race condition:
- setting permissions to e.g. 0666;
- then altering the content before line 10 executes.

Alternatively, /tmp/platform can be created ahead with permissions 0644 by the attacker, and the only error message will then result from line 10 (a similar race condition applies though).

The same issue is also found in:
- lp_solve_5.5/lp_solve/ccc
- lp_solve_5.5/lpsolve55/ccc.aix
- lp_solve_5.5/lpsolve55/ccc.hp-ux
- lp_solve_5.5/lpsolve55/ccc.osx
- lp_solve_5.5/lpsolve55/ccc.solaris
- lp_solve_5.5/lpsolve55/cccLUSOL.osx

The check for the "isnan function" (through /tmp/isnan.c) is vulnerable as well.

I am attaching the patch that I used to mitigate the issue in EdgeBSD's pkgsrc_2016Q1 tree. I admit that it is not very elegant, but as you can see the underlying idea is to leverage `mktemp -d` to create a temporary directory, and run the tests within this directory instead. The temporary directory created is later cleaned up, after every test has completed.

Unfortunately I do not know from the top of my head if `mktemp -d` is effectively available on every platform you want to support. As a nice side-effect, using mktemp will effectively respect the "TMPDIR" variable - which is useful on systems where executing programs in /tmp is denied (a useful hardening situation IMO), or where /tmp does not exist or is otherwise not available or usable for this purpose. 
>How-To-Repeat:
$ cd math/lp_solve
$ make build
>Fix:
As found for the pkgsrc_2016Q1 branch, at https://git.edgebsd.org/gitweb/?p=pkgsrc.git;a=commit;h=9ec8efbbc6c79af820ae781827b580aa6f141b24:

commit 9ec8efbbc6c79af820ae781827b580aa6f141b24
Author: Pierre Pronchery <khorben@EdgeBSD.org>
Date:   Wed Dec 28 22:19:11 2016 +0100

    Fix building math/lp_solve with noexec /tmp

    This commit means to:
    - avoid hard-coding paths while running tests in /tmp;
    - add support for TMPDIR.

    It also effectively fixes a local privilege escalation vulnerability
    while building this package. The real issue is with the upstream
    package and needs to be reported.

diff --git a/math/lp_solve/Makefile b/math/lp_solve/Makefile
index 8520381..320ac47 100644
--- a/math/lp_solve/Makefile
+++ b/math/lp_solve/Makefile
@@ -16,7 +16,16 @@ USE_GCC_RUNTIME=	yes

 WRKSRC=		${WRKDIR}/lp_solve_5.5

-SUBST_CLASSES+=		dl
+SUBST_CLASSES+=		cccdir dl
+SUBST_STAGE.cccdir=	pre-build
+SUBST_SED.cccdir+=	-e s,/tmp/,'$$CCCDIR/',g
+SUBST_FILES.cccdir+=	lp_solve/ccc
+SUBST_FILES.cccdir+=	lpsolve55/ccc
+SUBST_FILES.cccdir+=	lpsolve55/ccc.aix
+SUBST_FILES.cccdir+=	lpsolve55/ccc.hp-ux
+SUBST_FILES.cccdir+=	lpsolve55/ccc.osx
+SUBST_FILES.cccdir+=	lpsolve55/ccc.solaris
+SUBST_FILES.cccdir+=	lpsolve55/cccLUSOL.osx
 SUBST_STAGE.dl=		pre-build
 SUBST_SED.dl+=		-e s,-ldl,${DL_LIBS:Q},g
 SUBST_SED.dl+=		-e s,^opts=.*,opts=\'${CFLAGS:Q}\',g
diff --git a/math/lp_solve/distinfo b/math/lp_solve/distinfo
index 306c847..9000b0b 100644
--- a/math/lp_solve/distinfo
+++ b/math/lp_solve/distinfo
@@ -2,9 +2,15 @@ $NetBSD: distinfo,v 1.4 2015/12/08 17:15:01 joerg Exp $

 SHA1 (lp_solve_5.5.2.0_source.tar.gz) = e2830053cf079839b9ce21662cbc886ac6d31c80
 RMD160 (lp_solve_5.5.2.0_source.tar.gz) = 23a69c71062747ddf4cbc57120cd7db5f9378ac2
+SHA512 (lp_solve_5.5.2.0_source.tar.gz) = 8a22a1c6b7ab8f3ea198f0383f543b697110caa6e43e402490357fd0cefd777443e16b65a5c20965c78b151f11acdb5b9d089c5219b0f262d04fb74311094c7e
 Size (lp_solve_5.5.2.0_source.tar.gz) = 799623 bytes
 SHA1 (patch-aa) = a77ec29e056252b3b82c1a1acdd463b5ff7f6f6b
 SHA1 (patch-demo_ccc) = 6262975fdcc61e94390060425a79e8bbc5f4554b
-SHA1 (patch-lp__solve_ccc) = b70bbaedc56c04e3d2dad14050c0278142f382bd
+SHA1 (patch-lp__solve_ccc) = 7bdb41c8336b234145abbe9c77d6679f795345a7
 SHA1 (patch-lp__utils.c) = b0774bd7b323f12c97c7bc78c26f64a75c841f34
-SHA1 (patch-lpsolve55_ccc) = ce334b85675ca0018cd19bcc828bb8e2cad38829
+SHA1 (patch-lpsolve55_ccc) = da83fe0e76d779334de968b8dbd1a95a728760de
+SHA1 (patch-lpsolve55_ccc.aix) = 1a5c2a76eb96bf8cbaec3f10e9ef4133fa7f1a21
+SHA1 (patch-lpsolve55_ccc.hp-ux) = 0b82aefdcb715945d23e8366e1bca04e4211f45c
+SHA1 (patch-lpsolve55_ccc.osx) = d1e1d39949fab36cc7e0b138c8e542259602167f
+SHA1 (patch-lpsolve55_ccc.solaris) = 12e05ba9ea0161d62d3124f220232b2714f54932
+SHA1 (patch-lpsolve55_cccLUSOL.osx) = eec5fbfb2f3edbe1217f1a7d6d95d1537a13f3f8
diff --git a/math/lp_solve/patches/patch-lp__solve_ccc b/math/lp_solve/patches/patch-lp__solve_ccc
index 1bc64ad..a0b4a06 100644
--- a/math/lp_solve/patches/patch-lp__solve_ccc
+++ b/math/lp_solve/patches/patch-lp__solve_ccc
@@ -1,8 +1,24 @@
 $NetBSD: patch-lp__solve_ccc,v 1.1 2015/12/07 17:40:27 joerg Exp $

---- lp_solve/ccc.orig	2015-12-07 17:17:20.529655116 +0000
+--- lp_solve/ccc.orig	2009-01-25 18:39:03.000000000 +0000
 +++ lp_solve/ccc
-@@ -38,4 +38,4 @@ then opts='-O0'
+@@ -3,6 +3,7 @@ src='../lp_MDO.c ../shared/commonlib.c .
+ c=cc
+ 
+ #determine platform (32/64 bit)
++CCCDIR=`mktemp -d`
+ >/tmp/platform.c
+ echo '#include <stdlib.h>'>>/tmp/platform.c
+ echo '#include <stdio.h>'>>/tmp/platform.c
+@@ -27,6 +28,7 @@ then NOISNAN=
+ else NOISNAN=-DNOISNAN
+ fi
+ rm /tmp/isnan.c /tmp/isnan >/dev/null 2>&1
++rmdir "$CCCDIR"
+ 
+ opts='-O3'
+ 
+@@ -38,4 +40,4 @@ then opts='-O0'
  else dl=-ldl
  fi

diff --git a/math/lp_solve/patches/patch-lpsolve55_ccc b/math/lp_solve/patches/patch-lpsolve55_ccc
index ba053ab..26aa796 100644
--- a/math/lp_solve/patches/patch-lpsolve55_ccc
+++ b/math/lp_solve/patches/patch-lpsolve55_ccc
@@ -2,7 +2,23 @@ $NetBSD: patch-lpsolve55_ccc,v 1.1 2015/12/08 17:15:01 joerg Exp $

 --- lpsolve55/ccc.orig	2009-03-25 00:27:18.000000000 +0000
 +++ lpsolve55/ccc
-@@ -44,7 +44,7 @@ ranlib bin/$PLATFORM/liblpsolve55.a
+@@ -3,6 +3,7 @@ src='../lp_MDO.c ../shared/commonlib.c .
+ c=cc
+ 
+ #determine platform (32/64 bit)
++CCCDIR=`mktemp -d`
+ >/tmp/platform.c
+ echo '#include <stdlib.h>'>>/tmp/platform.c
+ echo '#include <stdio.h>'>>/tmp/platform.c
+@@ -25,6 +26,7 @@ then NOISNAN=
+ else NOISNAN=-DNOISNAN
+ fi
+ rm /tmp/isnan.c /tmp/isnan >/dev/null 2>&1
++rmdir "$CCCDIR"
+ 
+ def=
+ so=
+@@ -44,7 +46,7 @@ ranlib bin/$PLATFORM/liblpsolve55.a
  if [ "$so" != "" ]
  then
    $c -fpic -s -c -I.. -I../shared -I../bfp -I../bfp/bfp_LUSOL -I../bfp/bfp_LUSOL/LUSOL -I../colamd -I. $opts $NOISNAN -DYY_NEVER_INTERACTIVE -DPARSER_LP -DINVERSE_ACTIVE=INVERSE_LUSOL -DRoleIsExternalInvEngine $src
diff --git a/math/lp_solve/patches/patch-lpsolve55_ccc.aix b/math/lp_solve/patches/patch-lpsolve55_ccc.aix
new file mode 100644
index 0000000..694fdcd
--- /dev/null
+++ b/math/lp_solve/patches/patch-lpsolve55_ccc.aix
@@ -0,0 +1,20 @@
+$NetBSD$
+
+--- lpsolve55/ccc.aix.orig	2009-03-03 18:58:07.000000000 +0000
++++ lpsolve55/ccc.aix
+@@ -8,6 +8,7 @@ else c=cc
+ fi
+ 
+ #determine platform (32/64 bit)
++CCCDIR=`mktemp -d`
+ >/tmp/platform.c
+ echo '#include <stdlib.h>'>>/tmp/platform.c
+ echo '#include <stdio.h>'>>/tmp/platform.c
+@@ -30,6 +31,7 @@ then NOISNAN=
+ else NOISNAN=-DNOISNAN
+ fi
+ rm /tmp/isnan.c /tmp/isnan >/dev/null 2>&1
++rmdir "$CCCDIR"
+ 
+ def=
+ dl=-ldl
diff --git a/math/lp_solve/patches/patch-lpsolve55_ccc.hp-ux b/math/lp_solve/patches/patch-lpsolve55_ccc.hp-ux
new file mode 100644
index 0000000..6ad9f8f
--- /dev/null
+++ b/math/lp_solve/patches/patch-lpsolve55_ccc.hp-ux
@@ -0,0 +1,20 @@
+$NetBSD$
+
+--- lpsolve55/ccc.hp-ux.orig	2009-03-03 18:58:21.000000000 +0000
++++ lpsolve55/ccc.hp-ux
+@@ -3,6 +3,7 @@ src='../lp_MDO.c ../shared/commonlib.c .
+ c=cc
+ 
+ #determine platform (32/64 bit)
++CCCDIR=`mktemp -d`
+ >/tmp/platform.c
+ echo '#include <stdlib.h>'>>/tmp/platform.c
+ echo '#include <stdio.h>'>>/tmp/platform.c
+@@ -25,6 +26,7 @@ then NOISNAN=
+ else NOISNAN=-DNOISNAN
+ fi
+ rm /tmp/isnan.c /tmp/isnan >/dev/null 2>&1
++rmdir "$CCCDIR"
+ 
+ def=
+ dl=-ldld
diff --git a/math/lp_solve/patches/patch-lpsolve55_ccc.osx b/math/lp_solve/patches/patch-lpsolve55_ccc.osx
new file mode 100644
index 0000000..e19cda7
--- /dev/null
+++ b/math/lp_solve/patches/patch-lpsolve55_ccc.osx
@@ -0,0 +1,20 @@
+$NetBSD$
+
+--- lpsolve55/ccc.osx.orig	2009-08-09 15:36:19.000000000 +0000
++++ lpsolve55/ccc.osx
+@@ -3,6 +3,7 @@ src='../lp_MDO.c ../shared/commonlib.c .
+ c=cc
+ 
+ #determine platform (32/64 bit)
++CCCDIR=`mktemp -d`
+ >/tmp/platform.c
+ echo '#include <stdlib.h>'>>/tmp/platform.c
+ echo '#include <stdio.h>'>>/tmp/platform.c
+@@ -25,6 +26,7 @@ then NOISNAN=
+ else NOISNAN=-DNOISNAN
+ fi
+ rm /tmp/isnan.c /tmp/isnan >/dev/null 2>&1
++rmdir "$CCCDIR"
+ 
+ def=
+ dl=-ldl
diff --git a/math/lp_solve/patches/patch-lpsolve55_ccc.solaris b/math/lp_solve/patches/patch-lpsolve55_ccc.solaris
new file mode 100644
index 0000000..84a5d6b
--- /dev/null
+++ b/math/lp_solve/patches/patch-lpsolve55_ccc.solaris
@@ -0,0 +1,20 @@
+$NetBSD$
+
+--- lpsolve55/ccc.solaris.orig	2009-03-03 18:58:01.000000000 +0000
++++ lpsolve55/ccc.solaris
+@@ -3,6 +3,7 @@ src='../lp_MDO.c ../shared/commonlib.c .
+ c=cc
+ 
+ #determine platform (32/64 bit)
++CCCDIR=`mktemp -d`
+ >/tmp/platform.c
+ echo '#include <stdlib.h>'>>/tmp/platform.c
+ echo '#include <stdio.h>'>>/tmp/platform.c
+@@ -25,6 +26,7 @@ then NOISNAN=
+ else NOISNAN=-DNOISNAN
+ fi
+ rm /tmp/isnan.c /tmp/isnan >/dev/null 2>&1
++rmdir "$CCCDIR"
+ 
+ def=
+ dl=-ldl
diff --git a/math/lp_solve/patches/patch-lpsolve55_cccLUSOL.osx b/math/lp_solve/patches/patch-lpsolve55_cccLUSOL.osx
new file mode 100644
index 0000000..252e7444
--- /dev/null
+++ b/math/lp_solve/patches/patch-lpsolve55_cccLUSOL.osx
@@ -0,0 +1,20 @@
+$NetBSD$
+
+--- lpsolve55/cccLUSOL.osx.orig	2009-01-25 18:39:54.000000000 +0000
++++ lpsolve55/cccLUSOL.osx
+@@ -2,6 +2,7 @@ src='../lp_MDO.c ../shared/commonlib.c .
+ c=cc
+ 
+ #determine platform (32/64 bit)
++CCCDIR=`mktemp -d`
+ >/tmp/platform.c
+ echo '#include <stdlib.h>'>>/tmp/platform.c
+ echo '#include <stdio.h>'>>/tmp/platform.c
+@@ -24,6 +25,7 @@ then NOISNAN=
+ else NOISNAN=-DNOISNAN
+ fi
+ rm /tmp/isnan.c /tmp/isnan >/dev/null 2>&1
++rmdir "$CCCDIR"
+ 
+ def=
+ so=

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2014 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.