From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp2 ([2001:41d0:2:bcc0::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms11 with LMTPS id eJcbFrfZUGAqdQAA0tVLHw (envelope-from ) for ; Tue, 16 Mar 2021 16:15:51 +0000 Received: from aspmx1.migadu.com ([2001:41d0:2:bcc0::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp2 with LMTPS id CDHYEbfZUGBtNAAAB5/wlQ (envelope-from ) for ; Tue, 16 Mar 2021 16:15:51 +0000 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id 9707812DCD for ; Tue, 16 Mar 2021 17:15:50 +0100 (CET) Received: from localhost ([::1]:38322 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lMCMH-0006Mr-3W for larch@yhetil.org; Tue, 16 Mar 2021 12:15:49 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:38556) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lMCEl-0006Xh-Ah for guix-patches@gnu.org; Tue, 16 Mar 2021 12:08:04 -0400 Received: from debbugs.gnu.org ([209.51.188.43]:57531) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1lMCEl-00044W-2s for guix-patches@gnu.org; Tue, 16 Mar 2021 12:08:03 -0400 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1lMCEk-0002ig-UN for guix-patches@gnu.org; Tue, 16 Mar 2021 12:08:02 -0400 X-Loop: help-debbugs@gnu.org Subject: [bug#47193] [PATCH 2/2] lint: Indicate CVE severity. Resent-From: Tobias Geerinckx-Rice Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Tue, 16 Mar 2021 16:08:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 47193 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: To: 47193@debbugs.gnu.org Received: via spool by 47193-submit@debbugs.gnu.org id=B47193.161591082710381 (code B ref 47193); Tue, 16 Mar 2021 16:08:02 +0000 Received: (at 47193) by debbugs.gnu.org; 16 Mar 2021 16:07:07 +0000 Received: from localhost ([127.0.0.1]:40843 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1lMCDq-0002hN-Lr for submit@debbugs.gnu.org; Tue, 16 Mar 2021 12:07:07 -0400 Received: from tobias.gr ([80.241.217.52]:40566) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1lMCDn-0002gi-Ih for 47193@debbugs.gnu.org; Tue, 16 Mar 2021 12:07:04 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tobias.gr; s=2018; bh=PboByRz5iej9DIUZpuu/uFXHUQtJFQo+QgdshhvDfa4=; h=references: in-reply-to:date:subject:to:from; b=Fa6JCu9jodoT5U21DwFSAeOuwTq3aAsdaj 1M2Lb7XA2u5IndoMmDIcHtGtZ/qZf8s6OvbI8pw+2mbEJeI5R7h92C37gWgiq4oYYqr1KB Asbxgsqz5CcDmWnmmE+biLZwxZAdkSKu0R0YCbZ9eJnvVUxxsiPBd5i6M8xsUpeCDcZ0py r2r8nb7RZQcw0TlY6qbxhs2jbwB01oopKAVEgSRoWhZrHWcWA3OA8846e2Bh/cXqmEpi9g xdpW9FhYSDp8FIfBM5diJvy52zvMh/uhOy6SVkEb2vLIB96z/bcuLrRUuFSj77kfgUMgw5 SyVCcpFeXRwIOYR1BxiGrqnJhriQ== Received: by submission.tobias.gr (OpenSMTPD) with ESMTPSA id ae76bf27 (TLSv1.2:ECDHE-ECDSA-AES256-GCM-SHA384:256:NO) for <47193@debbugs.gnu.org>; Tue, 16 Mar 2021 16:08:02 +0000 (UTC) Date: Tue, 16 Mar 2021 17:06:53 +0100 Message-Id: <20210316160653.9891-2-me@tobias.gr> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210316160653.9891-1-me@tobias.gr> References: <20210316160653.9891-1-me@tobias.gr> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+larch=yhetil.org@gnu.org Sender: "Guix-patches" Reply-to: Tobias Geerinckx-Rice X-ACL-Warn: , Tobias Geerinckx-Rice via Guix-patches From: Tobias Geerinckx-Rice via Guix-patches via X-Migadu-Flow: FLOW_IN ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=yhetil.org; s=key1; t=1615911350; h=from:from:sender:sender:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding:resent-cc: resent-from:resent-sender:resent-message-id:in-reply-to:in-reply-to: references:references:list-id:list-help:list-unsubscribe: list-subscribe:list-post:dkim-signature; bh=PboByRz5iej9DIUZpuu/uFXHUQtJFQo+QgdshhvDfa4=; b=JpkC3Pci2immO+0tCYXl5xfOvTwcwOQz8Ijm6iSkZXPqx/nYdEIq3pcaLPndBNrscCdwMV 5DnQjDu+Kespz1XnuG7GYo8+CjrQfmRY2rUAz4dzx37dhcTgRBRHHprgwi4Ml7M+mRMSmX 3Sh0ICCfiYARRFwxE0TOCCIBNPJXdxMBHNdq0HhC+mx2Zoq7j9u9YVae47YaUha/CamcPM FZT6XFmm4pb/gxoepC9kNLrwn6zUbjJIHzxUmE4hpABMBIOM9l3YAoM5kUbms8K3XES4pd bxuBjrf0fMxbGKvx4Fr/j7lUP8Gi1gLWPHke9PCEmpgEvVkzG+DJVjvt6a5wUw== ARC-Seal: i=1; s=key1; d=yhetil.org; t=1615911350; a=rsa-sha256; cv=none; b=gOftlwnrgPd5ViWxJuDxIX0ZocXs88tDu9FRsCN+clf2CWgWNMpfkzudqk7ExaBi6PtI4C YsUdlN1JE6PQ8Nw1yfiagCM7hudgqyBdtbnixY7zVQZG79u+cPzRN/hJTXH87wlMXNiVVF xxYiKSCnUoJyTja3JeoFJ+iNVAjrFpqiE5Qa1QC+FAW+U3VQ+YUZmgOePjX00i4X411CKU 2aRzC5Ka/4G7JEPaMqLANLWL02n2Ast7xLGF4clhDZqWHI9ZVhFlQ5vZvDeT1FwlYEcR33 bi9BklTWsA2wSPRRGu/LDlntsWVghTgXovlT3OJWhaXJdzQIUUMBc7idw1zUrg== ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=fail ("headers rsa verify failed") header.d=tobias.gr header.s=2018 header.b=Fa6JCu9j; spf=pass (aspmx1.migadu.com: domain of guix-patches-bounces@gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=guix-patches-bounces@gnu.org X-Migadu-Spam-Score: -1.40 Authentication-Results: aspmx1.migadu.com; dkim=fail ("headers rsa verify failed") header.d=tobias.gr header.s=2018 header.b=Fa6JCu9j; dmarc=pass (policy=none) header.from=gnu.org; spf=pass (aspmx1.migadu.com: domain of guix-patches-bounces@gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=guix-patches-bounces@gnu.org X-Migadu-Queue-Id: 9707812DCD X-Spam-Score: -1.40 X-Migadu-Scanner: scn0.migadu.com X-TUID: aBVzFIG4FFYT * guix/cve.scm [cvss3-base-severity]: New field. (impact-data->cve-cvss3-base-severity): New procedure. [severity]: New field. (vulnerability->sexp, sexp->vulnerability, cve-item->vulnerability) (write-cache): Bump the format version to 2. (vulnerabilities->lookup-proc): Adjust accordingly. * guix/lint.scm (check-vulnerabilities): Indicate CVE severity according to the output port's terminal capabilities. --- guix/cve.scm | 48 ++++++++++++++++++++++++++++++++---------------- guix/lint.scm | 32 +++++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 17 deletions(-) diff --git a/guix/cve.scm b/guix/cve.scm index b3a8b13a06..3809e4493f 100644 --- a/guix/cve.scm +++ b/guix/cve.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2015, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès +;;; Copyright © 2021 Tobias Geerinckx-Rice ;;; ;;; This file is part of GNU Guix. ;;; @@ -38,6 +39,7 @@ cve-item? cve-item-cve cve-item-configurations + cve-item-cvssv3-base-severity cve-item-published-date cve-item-last-modified-date @@ -53,6 +55,7 @@ vulnerability? vulnerability-id + vulnerability-severity vulnerability-packages json->vulnerabilities @@ -72,13 +75,15 @@ (define-json-mapping cve-item cve-item? json->cve-item - (cve cve-item-cve "cve" json->cve) ; - (configurations cve-item-configurations ;list of sexps - "configurations" configuration-data->cve-configurations) - (published-date cve-item-published-date - "publishedDate" string->date*) - (last-modified-date cve-item-last-modified-date - "lastModifiedDate" string->date*)) + (cve cve-item-cve "cve" json->cve) ; + (configurations cve-item-configurations ;list of sexps + "configurations" configuration-data->cve-configurations) + (cvssv3-base-severity cve-item-cvssv3-base-severity ;string + "impact" impact-data->cve-cvssv3-base-severity) + (published-date cve-item-published-date + "publishedDate" string->date*) + (last-modified-date cve-item-last-modified-date + "lastModifiedDate" string->date*)) (define-json-mapping cve cve? json->cve @@ -183,6 +188,15 @@ element found in CVEs, return an sexp such as (\"binutils\" (< (let ((nodes (vector->list (assoc-ref alist "nodes")))) (filter-map node->configuration nodes))) +(define (impact-data->cve-cvssv3-base-severity alist) + "Given ALIST, a JSON dictionary for the \"impact\" element found in +CVEs, return a string indicating its CVSSv3 severity. This should be +one of \"NONE\", \"LOW\", \"MEDIUM\", \"HIGH\", or \"CRITICAL\", but we +return whatever we find, or #F if the severity cannot be determined." + (let* ((base-metric-v3 (assoc-ref alist "baseMetricV3")) + (cvss-v3 (assoc-ref base-metric-v3 "cvssV3"))) + (assoc-ref cvss-v3 "baseSeverity"))) + (define (json->cve-items json) "Parse JSON, an input port or a string, and return a list of records." @@ -251,20 +265,21 @@ records." (* 3600 24 (date-month %now))) (define-record-type - (vulnerability id packages) + (vulnerability id severity packages) vulnerability? (id vulnerability-id) ;string + (severity vulnerability-severity) ;string (packages vulnerability-packages)) ;((p1 sexp1) (p2 sexp2) ...) (define vulnerability->sexp (match-lambda - (($ id packages) - `(v ,id ,packages)))) + (($ id severity packages) + `(v ,id ,severity ,packages)))) (define sexp->vulnerability (match-lambda - (('v id (packages ...)) - (vulnerability id packages)))) + (('v id severity (packages ...)) + (vulnerability id severity packages)))) (define (cve-configuration->package-list config) "Parse CONFIG, a config sexp, and return a list of the form (P SEXP) @@ -309,12 +324,13 @@ versions." "Return a corresponding to ITEM, a record; return #f if ITEM does not list any configuration or if it does not list any \"a\" (application) configuration." - (let ((id (cve-id (cve-item-cve item)))) + (let ((id (cve-id (cve-item-cve item))) + (severity (cve-item-base-severity item))) (match (cve-item-configurations item) (() ;no configurations #f) ((configs ...) - (vulnerability id + (vulnerability id severity (merge-package-lists (map cve-configuration->package-list configs))))))) @@ -332,7 +348,7 @@ sexp to CACHE." (json->vulnerabilities input)) (write `(vulnerabilities - 1 ;format version + 2 ;format version ,(map vulnerability->sexp vulns)) cache)))) @@ -396,7 +412,7 @@ vulnerabilities affecting the given package version." ;; Map package names to lists of version/vulnerability pairs. (fold (lambda (vuln table) (match vuln - (($ id packages) + (($ id severity packages) (fold (lambda (package table) (match package ((name . versions) diff --git a/guix/lint.scm b/guix/lint.scm index ed57e19fe2..f3c4e13052 100644 --- a/guix/lint.scm +++ b/guix/lint.scm @@ -48,6 +48,7 @@ #:use-module (guix monads) #:use-module (guix scripts) #:use-module ((guix ui) #:select (texi->plain-text fill-paragraph)) + #:use-module (guix colors) #:use-module (guix gnu-maintenance) #:use-module (guix cve) #:use-module ((guix swh) #:hide (origin?)) @@ -1165,6 +1166,35 @@ the NIST server non-fatal." "Check for known vulnerabilities for PACKAGE. Obtain the list of vulnerability records for PACKAGE by calling PACKAGE-VULNERABILITIES." + (define severity->color + ;; A standard CVE colour gradient is red > orange > yellow > green > none. + ;; However, ANSI non-bold YELLOW is actually orange whilst BOLD YELLOW + ;; is actual yellow, so BOLD would confusingly be less serious. Skip it. + (match-lambda + ("CRITICAL" (color BOLD RED)) + ("HIGH" (color RED)) + ("MEDIUM" (color YELLOW)) + ("LOW" (color GREEN)) + (_ (color)))) + + (define (colorize-vulnerability vulnerability) + ;; If the terminal supports ANSI colours, use them to indicate severity. + (colorize-string (vulnerability-id vulnerability) + (severity->color (vulnerability-severity + vulnerability)))) + + (define (simple-format-vulnerability vulnerability) + ;; Otherwise, omit colour coding and explicitly append the severity string. + (simple-format #f "~a (~a)" + (vulnerability-id vulnerability) + (string-downcase (vulnerability-severity vulnerability)))) + + (define format-vulnerability + ;; Check once which of the above to use for all PACKAGE vulnerabilities. + (if (color-output? (current-output-port)) + colorize-vulnerability + simple-format-vulnerability)) + (define (vulnerability< v1 v2) (define (string-list< list1 list2) (match list1 @@ -1201,7 +1231,7 @@ vulnerability records for PACKAGE by calling PACKAGE-VULNERABILITIES." (make-warning package (G_ "probably vulnerable to ~a") - (list (string-join (map vulnerability-id + (list (string-join (map format-vulnerability (sort unpatched vulnerability<)) ", ")))))))))) -- 2.30.1