From mboxrd@z Thu Jan 1 00:00:00 1970 From: ludo@gnu.org (Ludovic =?utf-8?Q?Court=C3=A8s?=) Subject: Dealing with CVEs that apply to unspecified package versions Date: Mon, 06 Mar 2017 22:36:48 +0100 Message-ID: <877f4284un.fsf@gnu.org> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Return-path: Received: from eggs.gnu.org ([2001:4830:134:3::10]:34514) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl0JO-00033Y-DJ for guix-devel@gnu.org; Mon, 06 Mar 2017 16:37:00 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cl0JI-0008S1-FT for guix-devel@gnu.org; Mon, 06 Mar 2017 16:36:58 -0500 List-Id: "Development of GNU Guix and the GNU System distribution." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-devel-bounces+gcggd-guix-devel=m.gmane.org@gnu.org Sender: "Guix-devel" To: Leo Famulari Cc: guix-devel --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Hi! A couple of weeks ago you mentioned that CVE-2016-10165 (for lcms) is not reported by =E2=80=98guix lint -c cve=E2=80=99. This is due to the fac= t that the CVE does not specify the lcms version number it applies to, and thus (guix cve) ignores it. The attached patch fixes (guix cve) to honor CVEs with an unspecified version number. Unfortunately, there=E2=80=99s no way to know whether such CVEs are actually fixed at a specific package version or not, and they=E2=80=99re not uncommo= n. Consequently, =E2=80=98guix lint -c cve=E2=80=99 would now report old CVEs = that possibly no longer apply to our package versions. In the patch, I added the ability to specify a =E2=80=98patched-vulnerabili= ties=E2=80=99 property to work around that (with Coreutils as an example). The downside is that we=E2=80=99d have to maintain these lists by ourselves, wh= ich is not great, but might still be better than the status quo. Thoughts? Ludo=E2=80=99. --=-=-= Content-Type: text/x-patch; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable diff --git a/gnu/packages/base.scm b/gnu/packages/base.scm index c75e03828..c84571c21 100644 --- a/gnu/packages/base.scm +++ b/gnu/packages/base.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright =C2=A9 2012, 2013, 2014, 2015, 2016 Ludovic Court=C3=A8s +;;; Copyright =C2=A9 2012, 2013, 2014, 2015, 2016, 2017 Ludovic Court=C3= =A8s ;;; Copyright =C2=A9 2014 Andreas Enge ;;; Copyright =C2=A9 2012 Nikita Karetnikov ;;; Copyright =C2=A9 2014, 2015, 2016 Mark H Weaver @@ -320,6 +320,7 @@ used to apply commands with arbitrarily long arguments.= ") (("#!/bin/sh") (format #f "#!~a/bin/sh" bash))))) %standard-phases))) + (properties '((patched-vulnerabilities "CVE-2016-2781"))) ;really? (synopsis "Core GNU utilities (file, text, shell)") (description "GNU Coreutils includes all of the basic command-line tools that are diff --git a/guix/cve.scm b/guix/cve.scm index 088e39837..771b82d05 100644 --- a/guix/cve.scm +++ b/guix/cve.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright =C2=A9 2015, 2016 Ludovic Court=C3=A8s +;;; Copyright =C2=A9 2015, 2016, 2017 Ludovic Court=C3=A8s ;;; ;;; This file is part of GNU Guix. ;;; @@ -88,9 +88,17 @@ (close-port port))))) =20 (define %cpe-package-rx + ;; The CPE syntax as defined in the CPE 2.2 specs from + ;; . + ;; ;; For applications: "cpe:/a:VENDOR:PACKAGE:VERSION", or sometimes - ;; "cpe/a:VENDOR:PACKAGE:VERSION:PATCH-LEVEL". - (make-regexp "^cpe:/a:([^:]+):([^:]+):([^:]+)((:.+)?)")) + ;; "cpe/a:VENDOR:PACKAGE:VERSION:PATCH-LEVEL"; in some cases, simply + ;; "cpe:/a:VENDOR:PACKAGE", meaning that the affected versions are not + ;; specified. + (make-regexp "^c[pP][eE]:/[aA]:([^:]+):(.*)")) + +(define %not-colon + (char-set-complement (char-set #\:))) =20 (define (cpe->package-name cpe) "Converts the Common Platform Enumeration (CPE) string CPE to a package @@ -99,15 +107,17 @@ version string. Return #f and #f if CPE does not look= like an application CPE string." (cond ((regexp-exec %cpe-package-rx (string-trim-both cpe)) =3D> - (lambda (matches) - (values (match:substring matches 2) - (string-append (match:substring matches 3) - (match (match:substring matches 4) - ("" "") - (patch-level - ;; Drop the colon from things like - ;; "cpe:/a:openbsd:openssh:6.8:p1". - (string-drop patch-level 1))))))) + (lambda (rx-match) + (match (string-tokenize (match:substring rx-match 2) + %not-colon) + ((package) + ;; No version component, as in + ;; "cpe:/a:littlecms:little_cms_color_engine". + (values package 'any)) + ((package version _ ...) + ;; Ignore the "patch level" part if there is one, as in + ;; "cpe:/a:openbsd:openssh:6.8:p1". + (values package version))))) (else (values #f #f)))) =20 @@ -119,6 +129,11 @@ applications listed in PRODUCTS, with names converted = to package names: '(\"cpe:/a:gnu:libtasn1:4.7\" \"cpe:/a:gnu:libtasn1:4.6\" \"cpe:/a:gnu= :cpio:2.11\")) =3D> ((\"libtasn1\" \"4.7\" \"4.6\") (\"cpio\" \"2.11\")) " + (define (version-cons v lst) + (cond ((eq? v 'any) 'any) + ((eq? lst 'any) 'any) + (else (cons v lst)))) + (fold (lambda (product result) (let-values (((name version) (cpe->package-name product))) (if name @@ -126,10 +141,10 @@ applications listed in PRODUCTS, with names converted= to package names: (((previous . versions) . tail) ;; Attempt to coalesce NAME and PREVIOUS. (if (string=3D? name previous) - (alist-cons name (cons version versions) tail) - (alist-cons name (list version) result))) + (alist-cons name (version-cons version versions) ta= il) + (alist-cons name (version-cons version '()) result)= )) (() - (alist-cons name (list version) result))) + (alist-cons name (version-cons version '()) result))) result))) '() (sort products string (package-source package) origin-patches) '()))) + (patched (or (assoc-ref (package-properties package) + 'patched-vulnerabilities) + '())) (unpatched (remove (lambda (vuln) - (find (cute string-contains - <> (vulnerability-id vuln)) - patches)) + (or (member (vulnerability-id vuln) + patched) + (find (cute string-contains + <> (vulnerability-id vuln)) + patches))) vulnerabilities))) (unless (null? unpatched) (emit-warning package diff --git a/tests/cve-sample.xml b/tests/cve-sample.xml index ce158490f..78b2e302b 100644 --- a/tests/cve-sample.xml +++ b/tests/cve-sample.xml @@ -613,4 +613,68 @@ The PCo agent in SAP Plant Connectivity (PCo) allows rem= ote attackers to cause a denial of service (memory corruption and agent cra= sh) via crafted xMII requests, aka SAP Security Note 2238619. + + + + + + + + + + + + + + + + + + cpe:/o:debian:debian_linux:8.0 + cpe:/a:littlecms:little_cms_color_engine + cpe:/o:novell:leap:42.1 + + CVE-2016-10165 + 2017-02-03T14:59:00.177-05:00 + 2017-02-09T10:05:10.670-05:00 + + + 5.8 + NETWORK + MEDIUM + NONE + PARTIAL + NONE + PARTIAL + http://nvd.nist.gov + 2017-02-08T12:23:39.653-05:00 + + + + + SUSE + openSUSE-SU-2017:0336 + + + DEBIAN + DSA-3774 + + + MLIST + [oss-security] 20170125 Re: CVE MLIST:[oss-sec= urity] 20170123 CVE request: lcms2 heap OOB read parsing crafted ICC profil= e + + + MLIST + [oss-security] 20170125 Re: CVE request: lcms= 2 heap OOB read parsing crafted ICC profile + + + BID + 95808 + + + CONFIRM + https://github.com/m= m2/Little-CMS/commit/5ca71a7bc18b6897ab21d815d15e218e204581e2 + + The Type_MLU_Read function in cmstypes.c in Little CMS (= aka lcms2) allows remote attackers to obtain sensitive information or cause= a denial of service via an image with a crafted ICC profile, which trigger= s an out-of-bounds heap read. + diff --git a/tests/cve.scm b/tests/cve.scm index 3fbb22d3c..d4d9ba5f8 100644 --- a/tests/cve.scm +++ b/tests/cve.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright =C2=A9 2015, 2016 Ludovic Court=C3=A8s +;;; Copyright =C2=A9 2015, 2016, 2017 Ludovic Court=C3=A8s ;;; ;;; This file is part of GNU Guix. ;;; @@ -31,12 +31,13 @@ ;; What we should get when reading %SAMPLE. (list ;; CVE-2003-0001 has no "/a" in its product list so it is omitted. - ;; CVE-2004-0230 lists "tcp" as an application, but lacks a version num= ber. + (vulnerability "CVE-2004-0230" '(("tcp" . any))) (vulnerability "CVE-2008-2335" '(("phpvid" "1.2" "1.1"))) (vulnerability "CVE-2008-3522" '(("enterprise_virtualization" "3.5") ("jasper" "1.900.1"))) (vulnerability "CVE-2009-3301" '(("openoffice.org" "2.3.0" "2.2.1" "2.1= .0"))) ;; CVE-2015-8330 has no software list. + (vulnerability "CVE-2016-10165" '(("little_cms_color_engine" . any))) )) =20 @@ -47,17 +48,27 @@ (call-with-input-file %sample xml->vulnerabilities)) =20 (test-equal "vulnerabilities->lookup-proc" - (list (list (first %expected-vulnerabilities)) + (list (list (second %expected-vulnerabilities)) '() '() - (list (second %expected-vulnerabilities)) - (list (third %expected-vulnerabilities))) + (list (third %expected-vulnerabilities)) + (list (fourth %expected-vulnerabilities)) + + (list (fifth %expected-vulnerabilities)) + (list (fifth %expected-vulnerabilities)) + (list (fifth %expected-vulnerabilities))) (let* ((vulns (call-with-input-file %sample xml->vulnerabilities)) (lookup (vulnerabilities->lookup-proc vulns))) (list (lookup "phpvid") (lookup "jasper" "2.0") (lookup "foobar") (lookup "jasper" "1.900.1") - (lookup "openoffice.org" "2.3.0")))) + (lookup "openoffice.org" "2.3.0") + + ;; The 'littlecms' vulnerability has no version specifier so it + ;; should always match. + (lookup "little_cms_color_engine") + (lookup "little_cms_color_engine" "1.2.3") + (lookup "little_cms_color_engine" "42")))) =20 (test-end "cve") diff --git a/tests/lint.scm b/tests/lint.scm index 3a9b89fe9..64bbc18b5 100644 --- a/tests/lint.scm +++ b/tests/lint.scm @@ -1,7 +1,7 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright =C2=A9 2012, 2013 Cyril Roelandt ;;; Copyright =C2=A9 2014, 2015, 2016 Eric Bavier -;;; Copyright =C2=A9 2014, 2015, 2016 Ludovic Court=C3=A8s +;;; Copyright =C2=A9 2014, 2015, 2016, 2017 Ludovic Court=C3=A8s ;;; Copyright =C2=A9 2015, 2016 Mathieu Lirzin ;;; Copyright =C2=A9 2016 Hartmut Goebel ;;; @@ -598,6 +598,21 @@ (patches (list "/a/b/pi-CVE-2015-1234.patch")))))))))) =20 +(test-assert "cve: one patched vulnerability in properties" + (mock ((guix scripts lint) package-vulnerabilities + (lambda (package) + (list (make-struct (@@ (guix cve) ) 0 + "CVE-2015-1234" + (list (cons (package-name package) + (package-version package))))))) + (string-null? + (with-warnings + (check-vulnerabilities + (dummy-package "pi" + (version "3.14") + (properties + '((patched-vulnerabilities "CVE-2015-1234"))))= ))))) + (test-assert "cve: vulnerability fixed in replacement version" (mock ((guix scripts lint) package-vulnerabilities (lambda (package) --=-=-=--