Signed-off-by: Daniel P. Berrangé <berra...@redhat.com> --- _config.yml | 4 + _includes/nav.html | 3 +- _layouts/secnotice.html | 22 ++ assets/css/style.css | 47 +++ secnotice/Makefile | 40 +++ secnotice/README-template.md | 78 +++++ secnotice/README.md | 20 ++ secnotice/_scripts/index-html.xsl | 72 +++++ secnotice/_scripts/index-xml | 28 ++ secnotice/_scripts/notice-html.xsl | 286 +++++++++++++++++++ secnotice/_scripts/notice-txt.xsl | 277 ++++++++++++++++++ secnotice/_scripts/report-vulnerable-tags.pl | 135 +++++++++ secnotice/template.xml | 50 ++++ 13 files changed, 1061 insertions(+), 1 deletion(-) create mode 100644 _layouts/secnotice.html create mode 100644 secnotice/Makefile create mode 100644 secnotice/README-template.md create mode 100644 secnotice/README.md create mode 100644 secnotice/_scripts/index-html.xsl create mode 100755 secnotice/_scripts/index-xml create mode 100644 secnotice/_scripts/notice-html.xsl create mode 100644 secnotice/_scripts/notice-txt.xsl create mode 100644 secnotice/_scripts/report-vulnerable-tags.pl create mode 100644 secnotice/template.xml
diff --git a/_config.yml b/_config.yml index 0a0201c..6fddace 100644 --- a/_config.yml +++ b/_config.yml @@ -37,3 +37,7 @@ gems: exclude: - Gemfile - Gemfile.lock + - Makefile + - secalert/README.md + - secalert/README-template.md + - secalert/template.xml diff --git a/_includes/nav.html b/_includes/nav.html index 241d83e..350de6d 100644 --- a/_includes/nav.html +++ b/_includes/nav.html @@ -6,7 +6,8 @@ </li><li {% if current[1] == 'download' %}class='current'{% endif %}><a href="/download">Download</a> </li><li {% if current[1] == 'contribute' %}class='current'{% endif %}><a href="/contribute">Contribute</a> </li><li {% if current[1] == 'documentation' %}class='current'{% endif %}><a href="/documentation">Documentation</a> - </li><li {% if current[1] == 'blog' %}class='current'{% endif %}><a href="/blog">Blog</a></li> + </li><li {% if current[1] == 'blog' %}class='current'{% endif %}><a href="/blog">Blog</a> + </li><li {% if current[1] == 'secnotice' %}class='current'{% endif %}><a href="/secnotice">Security Notices</a></li> </ul> </nav> diff --git a/_layouts/secnotice.html b/_layouts/secnotice.html new file mode 100644 index 0000000..b30c036 --- /dev/null +++ b/_layouts/secnotice.html @@ -0,0 +1,22 @@ +<!DOCTYPE HTML> +<!-- +Linear by TEMPLATED +templated.co @templatedco +Released for free under the Creative Commons Attribution 3.0 license (templated.co/license) +--> +<html> +<head> + <title>{{ page.title }} - {{ site.title }}</title> + {% include assets.html %} +</head> +<body class="secnotice"> + + {% include nav.html %} + + {{ content }} + + {% include footer.html %} + {% include copyright.html %} + +</body> +</html> diff --git a/assets/css/style.css b/assets/css/style.css index b828887..dccffb0 100644 --- a/assets/css/style.css +++ b/assets/css/style.css @@ -590,3 +590,50 @@ { margin-top: 1.5em; } + +/*********************************************************************************/ +/* Security notices */ +/*********************************************************************************/ + + body.secnotice #main + { + width: 50%; + } + + body.secnotice #sidebar + { + margin-top: 10em; + width: 30%; + } + + body.secnotice p.altformat + { + font-size: smaller; + color: inherit; + text-align: right; + } + + body.secnotice table.repository { + border-spacing: 0px; + } + + body.secnotice table.repository tbody th { + text-align: right; + } + + body.secnotice table.repository tbody th, + body.secnotice table.repository tbody td { + padding: 2px; + } + + body.secnotice table.repository tbody td.fixedtag, + body.secnotice table.repository tbody td.mergedcommit { + background: rgb(240,255,240); + } + body.secnotice table.repository tbody td.fixedcommit { + background: rgb(240,240,255); + } + + body.secnotice table.repository thead { + background: rgb(240,240,240); + } diff --git a/secnotice/Makefile b/secnotice/Makefile new file mode 100644 index 0000000..fef2e8c --- /dev/null +++ b/secnotice/Makefile @@ -0,0 +1,40 @@ + +YEARS = $(wildcard 2???) + +INDEX_XML = index.xml $(YEARS:%=%/index.xml) +INDEX_HTML = $(INDEX_XML:%.xml=%.html) + +NOTICE_XML = $(wildcard */???.xml) +NOTICE_TXT = $(NOTICE_XML:%.xml=%.txt) +NOTICE_HTML = $(NOTICE_XML:%.xml=%.html) + +all: $(INDEX_XML) $(INDEX_HTML) $(NOTICE_TXT) $(NOTICE_HTML) + +index.xml: $(NOTICE_XML) _scripts/index-xml Makefile + mkdir -p `dirname $@` + _scripts/index-xml $(sort $(NOTICE_XML)) > $@ + +index.html: index.xml _scripts/index-html.xsl Makefile + xsltproc _scripts/index-html.xsl $< > $@ + +%/index.xml: $(NOTICE_XML) _scripts/index-xml Makefile + mkdir -p `dirname $@` + DIR=`echo $@ | sed -e 's,/index.xml,,'` + rm -f $@ + _scripts/index-xml $(sort $(wildcard $(@:%/index.xml=%/)???.xml)) > $@ + +%/index.html: %/index.xml _scripts/index-html.xsl Makefile + xsltproc --stringparam permalink $(@:%/index.html=/secnotice/%/) _scripts/index-html.xsl $< > $@ + +%.txt: %.xml _scripts/notice-txt.xsl Makefile + mkdir -p `dirname $@` + xsltproc _scripts/notice-txt.xsl $< > $@ + +%.html: %.xml _scripts/notice-html.xsl Makefile + mkdir -p `dirname $@` + xsltproc _scripts/notice-html.xsl $< > $@ + +clean: + rm -rf index.{xml,html} + rm -rf */index.{xml,html} + rm -rf */*.{txt,html} diff --git a/secnotice/README-template.md b/secnotice/README-template.md new file mode 100644 index 0000000..2b80dca --- /dev/null +++ b/secnotice/README-template.md @@ -0,0 +1,78 @@ +QEMU Security Notice Schema +=========================== + +The top level element of a QEMU security notice has a name of +``security-notice`` and is in an XML namespace of +``http://qemu.org/xmlns/security-notice/1.0`` + +Basic metadata +-------------- + +The ``id`` element content is a pair of 4 digit numbers uniquely identifying +the security issue. By convention the first 4 digit number is the year in which +it was reported and the second number is an integer value that is unique within +the year, monotonically incrementing from 1. eg the 137th issue reported in +2013 would have an id of ``2013-0137`` + +The ``summary`` element is a short, single line description of the flaw, +ideally 80 characters or less to make it suitable for use in email subject +lines or git commit messages. + +The ``credits`` element provides information on persons involved with the flaw. +It permits the child elements ``reporter`` or ``patcher`` each of which can be +repeated zero or more times. Both elements contain two further child elements +``email`` and ``name`` with the former providing the email address and the +latter providing the full name. At least one of ``email`` and ``name`` must +be provided. + +The ``lifecycle`` element provides date on key milestones in handling of the +issue. It contains between one and three child elements, ``reported``, +``published`` and ``fixed``. The ``reported`` element says the date on which +the QEMU security received notification of the issue. The ``published`` element +says the date on which the issue was revealed to the public. The ``fixed`` +element says the date on which the issue was patched in the primary code branch +(typically GIT master). + +The ``reference`` element provides details of related resources. It will have +one or more child elements which can be either ``advisory`` or ``bug``. An +``advisory`` element includes a ``type`` and ``id`` attribute where ``type`` is +currently allowed to be ``CVE`` and ``id`` is the identifier of the report. A +``bug`` element includes ``tracker`` and ``id`` attributes where ``tracker`` is +allowed to be ``redhat``, ``debian`` or a short name for another vendors' bug +tracker. + +Descriptive data +---------------- + +There are three free form text elements providing descriptive data about the +issue. The data will usually be inside a CDATA block. + +The ``description`` element content is an expanded version of the ``summary`` +element content, describing what the flaw is. + +The ``impact`` element content describes the implications of the security +issue. ie what can a malicious user do with the flaw. + +The ``workaround`` element content describes any steps that an administrator +can take to eliminate or at least mitigate the impact of the flaw. + + +Product data +------------ + +The ``product`` element provides information about the codebase of the affected +products. The ``name`` attribute is the name of a QEMU product, typically based +on the tar.gz archive name with the suffix stripped. This contains a child +``repository`` element which is a URL to the master GIT repository. There is +then one or more ``branch`` elements which details the state of affected +branches. + +The first child of the ``branch`` element is a ``name`` giving the branch name, +eg ``master``, ``v1.0.1-maint``, etc. There are then zero or more ``tag`` or +``change`` child elements with a ``state`` attribute of ``vulnerable`` or +``fixed``. The ``tag`` element content details the name of the GIT tag(s) on +that branch are vulnerable and which tags are fixed. The ``change`` element +content details the GIT hash of the change(s) which both introduce and fix the +flaw. The same vulnerable change hash may appear under multiple ``branch`` +elements since branches will share large portions of their history. The fix +hash will however usually be different. diff --git a/secnotice/README.md b/secnotice/README.md new file mode 100644 index 0000000..643076d --- /dev/null +++ b/secnotice/README.md @@ -0,0 +1,20 @@ +QEMU Security Notices +===================== + +This directory records all QEMU Security Notices that are issued. + +Notices must only added to this directory once any embargo is lifted, since the +GIT repository is fully public. + +Notices are written in XML in a file ``$YEAR/$NUM.xml`` eg ``2014/0001.xml``. +Assign numbers incrementally as new issues are reported. More details on the +XML format can be found in `README-schema.rst``. + +When a new notice is published for the first time, send the text rendering of +the notice to the ``qemu-devel@nongnu.org`` + +When backporting security fixes to ``stable-X.Y`` branches, update the notice +with details of the backported changeset hash. + +When doing a formal stable release, update the notices included with the release +tag name. diff --git a/secnotice/_scripts/index-html.xsl b/secnotice/_scripts/index-html.xsl new file mode 100644 index 0000000..71ae716 --- /dev/null +++ b/secnotice/_scripts/index-html.xsl @@ -0,0 +1,72 @@ +<!-- + - This program is free software; you can redistribute it and/or modify + - it under the terms of the GNU General Public License as published by + - the Free Software Foundation; either version 2 of the License, or + - (at your option) any later version. + - + - This program is distributed in the hope that it will be useful, + - but WITHOUT ANY WARRANTY; without even the implied warranty of + - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + - GNU General Public License for more details. + - + - You should have received a copy of the GNU General Public License + - along with this program. If not, see + - <http://www.gnu.org/licenses/>. + --> +<xsl:stylesheet + xmlns="http://www.w3.org/1999/xhtml" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:qsn="http://qemu.org/xmlns/security-notice/1.0" + xmlns:qsnl="http://qemu.org/xmlns/security-notice-list/1.0" + exclude-result-prefixes="xsl qsn qsnl" + version="1.0"> + + <xsl:output omit-xml-declaration="yes" method="xml" indent="yes" /> + + <xsl:param name="permalink" select="'/secnotice/'"/> + + <xsl:template match="/qsnl:security-notice-list">--- +title: QEMU Security Notices +permalink: <xsl:value-of select="$permalink"/> +--- + + <p> + If you believe you have identified a new security issue in QEMU, please + follow the <a href="https://wiki.qemu.org/SecurityProcess">security process</a> + to report it in a non-public way. Do <strong>NOT</strong> use the bug tracker, + mailing lists, or IRC to report non-public security issues. + </p> + + <ul> + <xsl:apply-templates select="qsnl:security-notice"> + <xsl:sort select="@name" order="descending" /> + </xsl:apply-templates> + </ul> + + <p class="alt"> + Alternative formats: <a href="index.xml">[xml]</a> + </p> + </xsl:template> + + <xsl:template name="qsnhref"> + <xsl:param name="id"/> + + <xsl:variable name="dir" select="substring-before($id, '-')"/> + <xsl:variable name="file" select="substring-after($id, '-')"/> + + <xsl:value-of select="concat($dir, '/', $file)"/> + </xsl:template> + + <xsl:template match="qsnl:security-notice"> + <xsl:variable name="notice" select="document(concat('../../', @name))"/> + <xsl:variable name="id" select="$notice/qsn:security-notice/qsn:id"/> + <xsl:variable name="summary" select="$notice/qsn:security-notice/qsn:summary"/> + <xsl:variable name="href"> + <xsl:call-template name="qsnhref"> + <xsl:with-param name="id" select="$id"/> + </xsl:call-template> + </xsl:variable> + + <li><a href="{$href}">QSN-<xsl:value-of select="$id"/>: <xsl:value-of select="$summary"/></a></li> + </xsl:template> +</xsl:stylesheet> diff --git a/secnotice/_scripts/index-xml b/secnotice/_scripts/index-xml new file mode 100755 index 0000000..67de29f --- /dev/null +++ b/secnotice/_scripts/index-xml @@ -0,0 +1,28 @@ +#!/bin/bash +# +# Copyright (C) 2013-2014 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see +# <http://www.gnu.org/licenses/>. + +set -e + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +echo '<security-notice-list xmlns="http://qemu.org/xmlns/security-notice-list/1.0">' +for n in $@ +do + echo " <security-notice name='/secnotice/$n'/>" +done +echo '</security-notice-list>' diff --git a/secnotice/_scripts/notice-html.xsl b/secnotice/_scripts/notice-html.xsl new file mode 100644 index 0000000..50ba802 --- /dev/null +++ b/secnotice/_scripts/notice-html.xsl @@ -0,0 +1,286 @@ +<!-- + - This program is free software; you can redistribute it and/or modify + - it under the terms of the GNU General Public License as published by + - the Free Software Foundation; either version 2 of the License, or + - (at your option) any later version. + - + - This program is distributed in the hope that it will be useful, + - but WITHOUT ANY WARRANTY; without even the implied warranty of + - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + - GNU General Public License for more details. + - + - You should have received a copy of the GNU General Public License + - along with this program. If not, see + - <http://www.gnu.org/licenses/>. + --> +<xsl:stylesheet + xmlns="http://www.w3.org/1999/xhtml" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:qsn="http://qemu.org/xmlns/security-notice/1.0" + exclude-result-prefixes="xsl qsn" + version="1.0"> + + <xsl:output omit-xml-declaration="yes" method="xml" indent="yes" /> + + <xsl:template name="selfhref"> + <xsl:param name="id"/> + <xsl:param name="ext"/> + + <xsl:variable name="dir" select="substring-before($id, '-')"/> + <xsl:variable name="file" select="substring-after($id, '-')"/> + + <xsl:value-of select="concat('/secnotice/', $dir, '/', $file, $ext)"/> + </xsl:template> + + <xsl:template match="/qsn:security-notice">--- +title: 'QSN-<xsl:value-of select="qsn:id"/>: <xsl:value-of select="qsn:summary"/>' +layout: secnotice +permalink: <xsl:call-template name="selfhref"> + <xsl:with-param name="id" select="qsn:id"/> +</xsl:call-template> +--- + + <div id="main"> + <div class="container"> + + <h2> + <xsl:value-of select="qsn:summary"/> + </h2> + + <xsl:apply-templates select="qsn:lifecycle"/> + <xsl:apply-templates select="qsn:credits"/> + + <xsl:apply-templates select="qsn:reference"/> + <xsl:apply-templates select="qsn:description"/> + <xsl:apply-templates select="qsn:impact"/> + <xsl:apply-templates select="qsn:mitigation"/> + + <xsl:call-template name="selflink"/> + </div> + </div> + + <div id="sidebar"> + <div class="container"> + <section> + <header> + <h2>Related commits</h2> + </header> + <xsl:apply-templates select="qsn:repository"/> + </section> + </div> + </div> + </xsl:template> + + <xsl:template name="selflink"> + <p class="altformat"> + Alternative formats: + <a> + <xsl:attribute name="href"> + <xsl:call-template name="selfhref"> + <xsl:with-param name="id" select="qsn:id"/> + <xsl:with-param name="ext" select="'.xml'"/> + </xsl:call-template> + </xsl:attribute> + <xsl:text>[xml]</xsl:text> + </a> + <xsl:text> </xsl:text> + <a> + <xsl:attribute name="href"> + <xsl:call-template name="selfhref"> + <xsl:with-param name="id" select="qsn:id"/> + <xsl:with-param name="ext" select="'.txt'"/> + </xsl:call-template> + </xsl:attribute> + <xsl:text>[text]</xsl:text> + </a> + </p> + </xsl:template> + + <xsl:template match="qsn:lifecycle"> + <h3>Lifecycle</h3> + <table> + <tr> + <th>Reported on:</th> + <td><xsl:value-of select="qsn:reported"/></td> + </tr> + <tr> + <th>Published on:</th> + <td><xsl:value-of select="qsn:published"/></td> + </tr> + <tr> + <th>Fixed on:</th> + <td><xsl:value-of select="qsn:fixed"/></td> + </tr> + </table> + </xsl:template> + + <xsl:template match="qsn:credits"> + <h3>Credits</h3> + <table> + <xsl:for-each select="qsn:reporter"> + <tr> + <xsl:if test="position() = 1"> + <th>Reported by:</th> + </xsl:if> + <xsl:if test="position() > 1"> + <th></th> + </xsl:if> + <td> + <a href="mailto:{qsn:email}"><xsl:value-of select="qsn:name"/></a> + </td> + </tr> + </xsl:for-each> + <xsl:for-each select="qsn:patcher"> + <tr> + <xsl:if test="position() = 1"> + <th>Patched by:</th> + </xsl:if> + <xsl:if test="position() > 1"> + <th></th> + </xsl:if> + <td> + <a href="mailto:{qsn:email}"><xsl:value-of select="qsn:name"/></a> + </td> + </tr> + </xsl:for-each> + </table> + </xsl:template> + + <xsl:template match="qsn:advisory"> + <xsl:choose> + <xsl:when test="@type='CVE'"> + <a href="https://nvd.nist.gov/vuln/detail/CVE-{@id}"> + <xsl:text>CVE-</xsl:text> + <xsl:value-of select="@id"/> + </a> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="@type"/> + <xsl:text>-</xsl:text> + <xsl:value-of select="@id"/> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <xsl:template match="qsn:bug"> + <xsl:value-of select="@tracker"/> + <xsl:text> bug #</xsl:text> + <xsl:value-of select="@id"/> + </xsl:template> + + <xsl:template match="qsn:reference"> + <h3>See also</h3> + <ul> + <xsl:for-each select="qsn:advisory|qsn:bug"> + <li><xsl:apply-templates select="."/></li> + </xsl:for-each> + </ul> + </xsl:template> + + <xsl:template match="qsn:description"> + <h3>Description</h3> + <p> + <xsl:value-of select="."/> + </p> + </xsl:template> + + <xsl:template match="qsn:impact"> + <h3>Impact</h3> + <p> + <xsl:value-of select="."/> + </p> + </xsl:template> + + <xsl:template match="qsn:mitigation"> + <h3>Mitigation</h3> + <p> + <xsl:value-of select="."/> + </p> + </xsl:template> + + <xsl:template name="gitbranch"> + <xsl:param name="branch"/> + + <a href="http://git.qemu.org/?p=qemu.git;a=shortlog;h=refs/heads/{$branch}"><xsl:value-of select="$branch"/></a> + </xsl:template> + + <xsl:template name="gittag"> + <xsl:param name="tag"/> + + <a href="http://git.qemu.org/?p=qemu.git;a=tag;h={$tag}"><xsl:value-of select="$tag"/></a> + </xsl:template> + + <xsl:template name="gitchange"> + <xsl:param name="change"/> + + <a href="http://git.qemu.org/?p=qemu.git;a=commit;h={$change}"><xsl:value-of select="$change"/></a> + </xsl:template> + + <xsl:template match="qsn:repository"> + <xsl:for-each select="qsn:branch"> + <table class="repository"> + <thead> + <tr> + <th colspan="2">Branch: + <xsl:call-template name="gitbranch"> + <xsl:with-param name="branch" select="qsn:name"/> + </xsl:call-template> + </th> + </tr> + </thead> + <tbody> + <xsl:for-each select="qsn:tag[@state='fixed']"> + <tr> + <th>Fixed in:</th> + <td class="fixedtag"> + <xsl:call-template name="gittag"> + <xsl:with-param name="tag" select="."/> + </xsl:call-template> + </td> + </tr> + </xsl:for-each> + <xsl:for-each select="qsn:change[@state='fixed']"> + <tr> + <th>Fixed by:</th> + <td class="fixedcommit"> + <xsl:call-template name="gitchange"> + <xsl:with-param name="change" select="."/> + </xsl:call-template> + </td> + </tr> + </xsl:for-each> + <xsl:for-each select="qsn:change[@state='merged']"> + <tr> + <th>Merged by:</th> + <td class="mergedcommit"> + <xsl:call-template name="gitchange"> + <xsl:with-param name="change" select="."/> + </xsl:call-template> + </td> + </tr> + </xsl:for-each> + <xsl:for-each select="qsn:tag[@state='vulnerable']"> + <tr> + <th>Broken in:</th> + <td class="brokentag"> + <xsl:call-template name="gittag"> + <xsl:with-param name="tag" select="."/> + </xsl:call-template> + </td> + </tr> + </xsl:for-each> + <xsl:for-each select="qsn:change[@state='vulnerable']"> + <tr> + <th>Broken by:</th> + <td class="brokencommit"> + <xsl:call-template name="gitchange"> + <xsl:with-param name="change" select="."/> + </xsl:call-template> + </td> + </tr> + </xsl:for-each> + </tbody> + </table> + </xsl:for-each> + </xsl:template> +</xsl:stylesheet> diff --git a/secnotice/_scripts/notice-txt.xsl b/secnotice/_scripts/notice-txt.xsl new file mode 100644 index 0000000..dc4c125 --- /dev/null +++ b/secnotice/_scripts/notice-txt.xsl @@ -0,0 +1,277 @@ +<!-- + - This program is free software; you can redistribute it and/or modify + - it under the terms of the GNU General Public License as published by + - the Free Software Foundation; either version 2 of the License, or + - (at your option) any later version. + - + - This program is distributed in the hope that it will be useful, + - but WITHOUT ANY WARRANTY; without even the implied warranty of + - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + - GNU General Public License for more details. + - + - You should have received a copy of the GNU General Public License + - along with this program. If not, see + - <http://www.gnu.org/licenses/>. + --> +<xsl:stylesheet + xmlns="http://www.w3.org/1999/xhtml" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:qsn="http://qemu.org/xmlns/security-notice/1.0" + exclude-result-prefixes="xsl qsn" + version="1.0"> + + <xsl:output method="text"/> + + <xsl:variable name="nl"> + <xsl:text> +</xsl:text> + </xsl:variable> + + <!-- based on http://plasmasturm.org/log/xslwordwrap/ --> + <!-- Copyright 2010 Aristotle Pagaltzis; under the MIT licence --> + <!-- http://www.opensource.org/licenses/mit-license.php --> + <xsl:template name="wrap-string"> + <xsl:param name="str" /> + <xsl:param name="wrap-col" /> + <xsl:param name="break-mark" /> + <xsl:param name="pos" select="0" /> + <xsl:choose> + <xsl:when test="contains( $str, ' ' )"> + <xsl:variable name="first-word" select="substring-before( $str, ' ' )" /> + <xsl:variable name="pos-now" select="$pos + 1 + string-length( $first-word )" /> + <xsl:choose> + <xsl:when test="$pos > 0 and $pos-now >= $wrap-col"> + <xsl:copy-of select="$break-mark" /> + <xsl:call-template name="wrap-string"> + <xsl:with-param name="str" select="$str" /> + <xsl:with-param name="wrap-col" select="$wrap-col" /> + <xsl:with-param name="break-mark" select="$break-mark" /> + <xsl:with-param name="pos" select="0" /> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:if test="$pos > 0"> + <xsl:text> </xsl:text> + </xsl:if> + <xsl:value-of select="$first-word" /> + <xsl:call-template name="wrap-string"> + <xsl:with-param name="str" select="substring-after( $str, ' ' )" /> + <xsl:with-param name="wrap-col" select="$wrap-col" /> + <xsl:with-param name="break-mark" select="$break-mark" /> + <xsl:with-param name="pos" select="$pos-now" /> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise> + <xsl:choose> + <xsl:when test="$pos + string-length( $str ) >= $wrap-col"> + <xsl:copy-of select="$break-mark" /> + </xsl:when> + <xsl:otherwise> + <xsl:if test="$pos > 0"> + <xsl:text> </xsl:text> + </xsl:if> + </xsl:otherwise> + </xsl:choose> + <xsl:value-of select="$str" /> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <xsl:template match="/qsn:security-notice"> + <xsl:text> QEMU Security Notice: QSN-</xsl:text> + <xsl:value-of select="qsn:id"/> + <xsl:value-of select="$nl"/> + <xsl:text> ==================================</xsl:text> + <xsl:value-of select="$nl"/> + + <xsl:value-of select="$nl"/> + + + <xsl:apply-templates select="qsn:summary"/> + <xsl:apply-templates select="qsn:lifecycle"/> + <xsl:apply-templates select="qsn:credits"/> + <xsl:apply-templates select="qsn:reference"/> + <xsl:apply-templates select="qsn:description"/> + <xsl:apply-templates select="qsn:impact"/> + <xsl:apply-templates select="qsn:mitigation"/> + <xsl:apply-templates select="qsn:repository"/> + </xsl:template> + + <xsl:template match="qsn:summary"> + <xsl:text> Summary: </xsl:text> + <xsl:call-template name="wrap-string"> + <xsl:with-param name="str" select="normalize-space(.)"/> + <xsl:with-param name="wrap-col" select="52"/> + <xsl:with-param name="break-mark" select="concat($nl, ' ')"/> + </xsl:call-template> + <xsl:value-of select="$nl"/> + </xsl:template> + + <xsl:template match="qsn:lifecycle"> + <xsl:text> Reported on: </xsl:text> + <xsl:value-of select="qsn:reported"/> + <xsl:value-of select="$nl"/> + + <xsl:text> Published on: </xsl:text> + <xsl:value-of select="qsn:published"/> + <xsl:value-of select="$nl"/> + + <xsl:text> Fixed on: </xsl:text> + <xsl:value-of select="qsn:fixed"/> + <xsl:value-of select="$nl"/> + </xsl:template> + + <xsl:template match="qsn:credits"> + <xsl:text> Reported by: </xsl:text> + <xsl:for-each select="qsn:reporter"> + <xsl:if test="position() > 1"> + <xsl:text> </xsl:text> + </xsl:if> + <xsl:value-of select="qsn:name"/> + <xsl:text> <</xsl:text> + <xsl:value-of select="qsn:email"/> + <xsl:text>></xsl:text> + <xsl:if test="position() != last()"> + <xsl:value-of select="$nl"/> + </xsl:if> + </xsl:for-each> + <xsl:value-of select="$nl"/> + <xsl:text> Patched by: </xsl:text> + <xsl:for-each select="qsn:patcher"> + <xsl:if test="position() > 1"> + <xsl:text> </xsl:text> + </xsl:if> + <xsl:value-of select="qsn:name"/> + <xsl:text> <</xsl:text> + <xsl:value-of select="qsn:email"/> + <xsl:text>></xsl:text> + <xsl:if test="position() != last()"> + <xsl:value-of select="concat(',',$nl)"/> + </xsl:if> + </xsl:for-each> + <xsl:value-of select="$nl"/> + </xsl:template> + + <xsl:template match="qsn:advisory"> + <xsl:value-of select="@type"/> + <xsl:text>-</xsl:text> + <xsl:value-of select="@id"/> + </xsl:template> + + <xsl:template match="qsn:bug"> + <xsl:value-of select="@tracker"/> + <xsl:text> bug #</xsl:text> + <xsl:value-of select="@id"/> + </xsl:template> + + <xsl:template match="qsn:reference"> + <xsl:text> See also: </xsl:text> + <xsl:variable name="refs"> + <xsl:for-each select="qsn:advisory|qsn:bug"> + <xsl:apply-templates select="."/> + <xsl:if test="position() != last()"> + <xsl:text>, </xsl:text> + </xsl:if> + </xsl:for-each> + </xsl:variable> + <xsl:call-template name="wrap-string"> + <xsl:with-param name="str" select="$refs"/> + <xsl:with-param name="wrap-col" select="52"/> + <xsl:with-param name="break-mark" select="concat($nl, ' ')"/> + </xsl:call-template> + <xsl:value-of select="$nl"/> + <xsl:value-of select="$nl"/> + </xsl:template> + + <xsl:template match="qsn:description"> + <xsl:text>Description</xsl:text> + <xsl:value-of select="$nl"/> + <xsl:text>-----------</xsl:text> + <xsl:value-of select="$nl"/> + <xsl:value-of select="$nl"/> + <xsl:call-template name="wrap-string"> + <xsl:with-param name="str" select="normalize-space(.)"/> + <xsl:with-param name="wrap-col" select="70"/> + <xsl:with-param name="break-mark" select="$nl"/> + </xsl:call-template> + <xsl:value-of select="$nl"/> + <xsl:value-of select="$nl"/> + </xsl:template> + + <xsl:template match="qsn:impact"> + <xsl:text>Impact</xsl:text> + <xsl:value-of select="$nl"/> + <xsl:text>------</xsl:text> + <xsl:value-of select="$nl"/> + <xsl:value-of select="$nl"/> + <xsl:call-template name="wrap-string"> + <xsl:with-param name="str" select="normalize-space(.)"/> + <xsl:with-param name="wrap-col" select="70"/> + <xsl:with-param name="break-mark" select="$nl"/> + </xsl:call-template> + <xsl:value-of select="$nl"/> + <xsl:value-of select="$nl"/> + </xsl:template> + + <xsl:template match="qsn:mitigation"> + <xsl:text>Mitigation</xsl:text> + <xsl:value-of select="$nl"/> + <xsl:text>----------</xsl:text> + <xsl:value-of select="$nl"/> + <xsl:value-of select="$nl"/> + <xsl:call-template name="wrap-string"> + <xsl:with-param name="str" select="normalize-space(.)"/> + <xsl:with-param name="wrap-col" select="70"/> + <xsl:with-param name="break-mark" select="$nl"/> + </xsl:call-template> + <xsl:value-of select="$nl"/> + <xsl:value-of select="$nl"/> + </xsl:template> + + + <xsl:template match="qsn:repository"> + <xsl:text>Related commits</xsl:text> + <xsl:value-of select="$nl"/> + <xsl:text>----------------</xsl:text> + <xsl:value-of select="$nl"/> + <xsl:value-of select="$nl"/> + <xsl:text> git://git.qemu.org/qemu.git</xsl:text> + <xsl:value-of select="$nl"/> + <xsl:text> https://git.qemu.org/?p=qemu.git</xsl:text> + <xsl:value-of select="$nl"/> + <xsl:value-of select="$nl"/> + + <xsl:for-each select="qsn:branch"> + <xsl:text> Branch: </xsl:text> + <xsl:value-of select="qsn:name"/> + <xsl:value-of select="$nl"/> + <xsl:if test="count(qsn:tag)"> + <xsl:for-each select="qsn:tag[@state='vulnerable']"> + <xsl:text> Broken in: </xsl:text> + <xsl:value-of select="."/> + <xsl:value-of select="$nl"/> + </xsl:for-each> + <xsl:for-each select="qsn:tag[@state='fixed']"> + <xsl:text> Fixed in: </xsl:text> + <xsl:value-of select="."/> + <xsl:value-of select="$nl"/> + </xsl:for-each> + </xsl:if> + <xsl:if test="count(qsn:change)"> + <xsl:for-each select="qsn:change[@state='vulnerable']"> + <xsl:text> Broken by: </xsl:text> + <xsl:value-of select="."/> + <xsl:value-of select="$nl"/> + </xsl:for-each> + <xsl:for-each select="qsn:change[@state='fixed']"> + <xsl:text> Fixed by: </xsl:text> + <xsl:value-of select="."/> + <xsl:value-of select="$nl"/> + </xsl:for-each> + </xsl:if> + <xsl:value-of select="$nl"/> + </xsl:for-each> + </xsl:template> +</xsl:stylesheet> diff --git a/secnotice/_scripts/report-vulnerable-tags.pl b/secnotice/_scripts/report-vulnerable-tags.pl new file mode 100644 index 0000000..3b89efd --- /dev/null +++ b/secnotice/_scripts/report-vulnerable-tags.pl @@ -0,0 +1,135 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use Sort::Versions; + +if (int(@ARGV) != 1 && int (@ARGV) != 2) { + die "syntax: $0 BROKEN-COMMIT [MERGED-COMMIT]\n"; +} + +my $broken = shift @ARGV; +my $merged = shift @ARGV; + +sub get_tags { + my @args = @_; + + my @tags; + open GIT, "-|", "git", "tag", @args or + die "cannot query 'git tags @args': $!\n"; + + while (<GIT>) { + chomp; + + # Drop anything except vN.N.N style tags + # where 'N' is only digits. + if (/^v(\d+)(\.\d+)+$/) { + push @tags, $_; + } + } + + close GIT; + + return @tags; +} + +sub get_branch { + my $tag = shift; + + my @branches; + open GIT, "-|", "git", "branch", "--all", "--contains", $tag or + die "cannot query 'git branch --all --contains $tag': $!\n"; + + while (<GIT>) { + chomp; + + if (m,^\s*remotes/origin/(stable-.*)$,) { + push @branches, $1; + } + } + + close GIT; + + return @branches; +} + +my @branches; +my %tags; +my %branches; + +my %merged; +my $mergedtag; + +if (defined $merged) { + for my $tag (get_tags("--contains", $merged)) { + $merged{$tag} = 1; + $mergedtag = $tag unless defined $mergedtag; + } +} + +$branches{"master"} = []; +# Most tags live on master so lets get them first +for my $tag (get_tags("--contains", $broken, "--merged", "master")) { + next if exists $merged{$tag}; + push @{$branches{"master"}}, $tag; + $tags{$tag} = 1; +} +push @branches, "master"; + +# Now we need slower work to find branches for +# few remaining tags +for my $tag (get_tags("--contains", $broken)) { + + next if exists $tags{$tag}; + next if exists $merged{$tag}; + next if $tag =~ /v\d+\.\d+\.9\d/; + + my @tagbranches = get_branch($tag); + if (int(@tagbranches) == 0) { + if ($tag =~ "^v0.10") { + @tagbranches = ("stable-0.10") + } elsif ($tag =~ "^v0") { + @tagbranches = ("master") + } else { + print "Tag $tag doesn't appear in any branch\n"; + next; + } + } + + if (int(@tagbranches) > 1) { + print "Tag $tag appears in multiple branches\n"; + } + + unless (exists($branches{$tagbranches[0]})) { + $branches{$tagbranches[0]} = []; + push @branches, $tagbranches[0]; + } + push @{$branches{$tagbranches[0]}}, $tag; +} + + +foreach my $branch (sort versioncmp @branches) { + print " <branch>\n"; + print " <name>$branch</name>\n"; + if ($branch eq "master") { + print " <change state=\"fixed\"></change>\n"; + if (defined $merged) { + print " <change state=\"merged\">$merged</change>\n"; + } else { + print " <change state=\"merged\"></change>\n"; + } + if (defined $mergedtag) { + print " <tag state=\"fixed\">$mergedtag</tag>\n"; + } else { + print " <tag state=\"fixed\"></tag>\n"; + } + } + + foreach my $tag (sort versioncmp @{$branches{$branch}}) { + print " <tag state=\"vulnerable\">$tag</tag>\n"; + } + print " <change state=\"vulnerable\">$broken</change>\n"; + + print " </branch>\n"; +} diff --git a/secnotice/template.xml b/secnotice/template.xml new file mode 100644 index 0000000..8f8a0d4 --- /dev/null +++ b/secnotice/template.xml @@ -0,0 +1,50 @@ +<security-notice xmlns="http://qemu.org/xmlns/security-notice/1.0"> + <id>XXXX-XXX</id> + + <summary></summary> + + <description> +<![CDATA[]]> + </description> + + <impact> +<![CDATA[]]> + </impact> + + <workaround> +<![CDATA[]]> + </workaround> + + <credits> + <reporter> + <name></name> + <email></email> + </reporter> + <patcher> + <name></name> + <email></email> + </patcher> + </credits> + + <lifecycle> + <reported></reported> + <published></published> + <fixed></fixed> + </lifecycle> + + <reference> + <advisory type="CVE" id="XXXX-XXXX"/> + </reference> + + <repository> + <branch> + <name>master</name> + <tag state="fixed"></tag> + <change state="fixed"></change> + <change state="merged"></change> + <change state="vulnerable"></change> + <tag state="vulnerable"></tag> + </branch> + </repository> + +</security-notice> -- 2.17.2