diff --git a/scripts/check-kernel-fix b/scripts/check-kernel-fix new file mode 100755 index 0000000..8ea73fe --- /dev/null +++ b/scripts/check-kernel-fix @@ -0,0 +1,379 @@ +#!/bin/bash +# vim: sw=4:sts=4:et + +. $(dirname "$0")/common-functions + +usage() +{ + echo "Check state of a kernel fix and eventually suggest needed actions" + echo + echo "Expect upstream kernel tree sha or CVE number as the parameter." + echo "The script checks whether the commit is already in the upstream" + echo "baseline or backported in kernel-source tree." + echo + echo "If backported, checks for CVE/bsc references and recommends adding these" + echo "if they are missing. (Requires VULNS_GIT pointing to" + echo "https://git.kernel.org/pub/scm/linux/security/vulns.git tree." + echo "This will also allow cve number instead of sha and it resolves proer" + echo "upstream commit automatically." + echo + echo "Also the script looks for \"Fixes:\" tag of the given \"sha\"." + echo "When defined, the script informs where the fix has to be backported." + echo + echo "The script also takes into account the hierarchy of branches." + echo "It checks all branches. But the action is proposed only for" + echo "the top level ones. The assumption is that the other branches" + echo "will get the fix via a merge." + echo + echo "If the patch has CVE number with CVSS score associated then limits" + echo "actions only to CVSS affected branches." + echo + echo "Usage: ${0##*/} [options] sha|CVE" + echo + echo "Parameters:" + echo " sha: sha of the upstream commit" + echo " cve: CVE-XXXX-YYYY of the upstream commit (requires VULNS_GIT)" + echo + echo "Options:" + echo " -h: help" + echo " -q: quiet mode (no progress)" + echo " -v: verbose mode: show state of each branch and even NOP actions" + echo " -r: refresh any cached data. Use if cve->sha or cve->cvss fails" + echo " (git pull VULNS_GIT, cve, bsc medata)" +} + +branch= +bprefix= +sha= +references= + +cve= +top_level= + +tmpdir=$(mktemp -d /tmp/${0##*/}.XXXXXX) +trap 'rm -rf "$tmpdir"' EXIT + +branch_state_file="$tmpdir/branch-state" +patch_file="$tmpdir/patches" +actions_file="$tmpdir/actions" + +print_branch_state() +{ + local msg="$@" + + if [ -n "$verbose_mode" ] ; then + echo "$msg" + elif [ -z "$quiet_mode" ] ; then + # show progress + echo -n "." + fi + + echo "$msg" >> "$branch_state_file" +} + +# Check state of the given branch and store +# The states are stored $tmpdir/branch-state are are the following: +# +# + nope: branch not affected +# + ok: branch has the fix and all references +# + missing_references: all or some references were not found +# + missing_patch: patch has to be backported +# + maybe_missing_patch: patch is missing and it is not known which commit +# introduced the bug +# +# When found, the name of the patch is stored into "$patch_file". +check_branch_state() +{ + local branch="$1" + local sha="$2" + shift 2 + local references="$@" + + [ -z "$branch" ] && fail "check_branch_state: No branch provided" + [ -z "$sha" ] && fail "check_branch_state: No sha provided" + + local patch= + local base= + local ref= + local missing_references= + local msg_prefix="$branch:$sha" + + + base=$(branch_base_ver $branch) + + # Already merged upstream? + if sha_merged_in_upstream_tag "$sha" "$base" ; then + print_branch_state "$msg_prefix:nope" + return + fi + + # Does the patch exist? + patch=$(sha_to_patch_in_branch "$sha" "$branch") + + if [ -n "$patch" ] ; then + echo "$branch:$patch" >> "$patch_file" + + # Check references + for ref in $references ; do + if ! patch_has_reference_in_branch "$patch" "$ref" "$branch" ; then + [ -n "$missing_references" ] && missing_references="$missing_references " + missing_references="$missing_references$ref" + fi + done + + if [ -z "$missing_references" ] ; then + print_branch_state "$msg_prefix:ok" + else + print_branch_state "$msg_prefix:missing_references:$missing_references" + fi + + return + fi + + # Sha is not backported + # Do we need to backport it because of the Fixes tag? + local sha_git_fixes=$(sha_get_upstream_git_fixes $sha) + if [ -n "$sha_git_fixes" ] ; then + local affected_by_git_fixes="$(affected_by_git_fixes "$branch" "$base" $sha_git_fixes)" + + if [ -n "$affected_by_git_fixes" ] ; then + print_branch_state "$msg_prefix:missing_patch:$affected_by_git_fixes" + else + print_branch_state "$msg_prefix:nope" + fi + + return + fi + + # missing git fixes + print_branch_state "$msg_prefix:maybe_missing_patch:$ref" +} + +print_action() +{ + local branch="$1" + local sha="$2" + local state="$3" + shift 3 + local references="$@" + + [ -z "$branch" ] && fail "print_action: No branch provided" + [ -z "$sha" ] && fail "print action: No sha provided" + [ -z "$state" ] && fail "print action: No state provided" + + # make sure tha the file exists + touch "$patch_file" + + patch= + action= + case "$state" in + missing_patch) + action="$branch: MANUAL: backport $sha ($references)" + ;; + + maybe_missing_patch) + action="$branch: MANUAL: might need backport of $sha ($references)" + ;; + + missing_references) + patch=$(grep "^$branch:" "$patch_file" | cut -d : -f 2) + if [ -n "$patch" ] ; then + ref_args=$(printf -- '-r %s ' $references) + action="$branch: RUN: scripts/cve_tools/add-missing-reference $ref_args$patch" + else + action="$branch: MANUAL: no patch has the references: $references" + fi + ;; + + nope) + [ -n "$verbose_mode" ] && action="$branch: NOPE: no problema for $sha $references" + ;; + + ok) + [ -n "$verbose_mode" ] && action="$branch: NOPE: up-to-date $sha $references" + ;; + + *) + echo "print_action: Unknown action: $action" >&2 + echo "for $branch:$sha:$state:$references" >&2 + exit 1 + ;; + esac + + if [ -n "$action" ] ; then + if [ ! -e "$actions_file" ] ; then + # first action + echo "ACTION NEEDED!" + touch "$actions_file" + fi + + echo "$action" + fi +} + +cvss_affects_branch() +{ + local branch="$1" + local cvss="$2" + + local ret=1 + if [[ "$branch" =~ .*-EB.* ]] + then + [ $cvss -ge 9 ] && ret=0 + elif [[ "$branch" =~ .*-GA.* ]] + then + [ $cvss -ge 7 ] && ret=0 + elif [[ "$branch" =~ .*-LTSS.* ]] + then + [ $cvss -ge 7 ] && ret=0 + else + ret=0 + fi + return $ret +} + +find_and_print_toplevel_actions() +{ + local branch="$1" + local cvss="${2%%.*}" + local action_parameters= + local merge_branch= + local mb_line= + local line= + local merge_found= + local state= + local mb_state= + + [ -z "$branch" ] && fail "find_and_print_toplevel_actions: No branch provided" + + grep "^$branch:" "$branch_state_file" | \ + while read line ; do + state=$(echo $line | cut -d: -f3) + + # We only want to print branches which really need CVE fix backported + # CVSS 9+ EB branches + # CVSS 7+ LTSS branches + # Any CVSS for regular branch + # If we just need to add a reference then print everything + if [ -n "$cvss" -a "$state" != "missing_references" ] + then + if ! cvss_affects_branch "$branch" "$cvss" + then + continue + fi + fi + + for merge_branch in $(print_merge_branches $branches_conf $branch) ; do + + # Make sure merge_branches are in the same cvss scope + if [ -n "$cvss" -a "$state" != "missing_references" ] + then + if ! cvss_affects_branch "$merge_branch" "$cvss" + then + continue + fi + fi + + # branch name might include '/', e.g. cve/linux-4.12 + mb_line=$(echo -n "$line" | sed -e "s|^$branch:|$merge_branch:|") + + # ignore the state when the same change is needed in a merge branch + if grep -q "^$mb_line$" "$branch_state_file" ; then + merge_found=1 + fi + + mb_state=$(echo $mb_line | cut -d: -f3) + + if [ "$state" == "missing_references" -o \ + "$state" == "missing_patch" -o \ + "$state" == "maybe_missing_patch" ] ; then + + # No action is needed when the patch is backported + # and has all the references in the merge branch + if [ "$mb_state" == "ok" ] ; then + merge_found=1 + fi + fi + + done + + if [ -z "$merge_found" ] ; then + # split line into parameters + print_action ${line//:/ } + fi + done +} + +verbose_mode= +quiet_mode= + +while getopts "hvrq" OPT +do + case $OPT in + h) + usage + exit + ;; + v) + verbose_mode=1 + ;; + r) + refresh=1 + ;; + q) + quiet_mode=1 + ;; + esac +done + +shift "$(($OPTIND-1))" + +[ -n "$verbose_mode" ] && quiet_mode= + +if [ -z "$1" ] ; then + echo "No references provided" + usage + exit 1 +fi + +sha=$1 +if ! sha_in_upstream "$1" ; then + sha=$(cve2sha $1 $refresh) + if [ -z "$sha" ] + then + [ -z "$VULNS_GIT" ] && fail "VULNS_GIT not defined. It has to point https://git.kernel.org/pub/scm/linux/security/vulns.git tree clone." + fail "Can find't sha in upstream: $1." + fi +fi + +print_upstream_sha_summary $sha + +cve=$(sha2cve $sha $refresh) +bsc= +if [ -n "$cve" ] +then + bsc=$(cve2bugzilla $cve $refresh) + cvss=$(cve2cvss $cve $refresh) + echo "Security fix for $cve $bsc with CVSS ${cvss:-unknown}" +else + # emulate no CVE fix as CVSS==0. This will typically happen + # for upstream commit with Fixes: which we want to target to + # less conservative branches only + cvss=0 +fi +references="$cve $bsc" + +branches_conf="$(fetch_branches $refresh)" + +# Check state of each branch +for_each_build_branch "$branches_conf" check_branch_state $sha $references + +# Newline after the dots showing progress +[ -z "$quiet_mode" ] && echo + +for_each_build_branch "$branches_conf" find_and_print_toplevel_actions $cvss + +if [ ! -e "$actions_file" ] ; then + echo "EVERYTHING IS OK!" +fi + diff --git a/scripts/common-functions b/scripts/common-functions new file mode 100644 index 0000000..2cd4a78 --- /dev/null +++ b/scripts/common-functions @@ -0,0 +1,502 @@ +#!/bin/bash +# vim: sw=4:sts=4:et + +fetch_cache() +{ + local CACHE_URL=$1 + local CACHE_FILE=$2 + local EXPIRE=$3 + local REFRESH=$4 + + [ -n "$REFRESH" ] && rm "$CACHE_FILE" + if [[ $(find "$CACHE_FILE" -mtime -${EXPIRE:-7} -print 2>/dev/null) \ + && -s "$CACHE_FILE" ]]; then + echo $CACHE_FILE + return + fi + curl -L "$CACHE_URL" -o "$CACHE_FILE" >/dev/null 2>&1 && echo $CACHE_FILE +} + +fetch_branches() +{ + local CACHED_BRANCHES="/tmp/$USER-branches.conf" + local URL="https://kerncvs.suse.de/branches.conf" + local REFRESH=$1 + branches=$CACHED_BRANCHES + fetch_cache $URL $CACHED_BRANCHES 7 $REFRESH +} + +fetch_cve2bugzilla() +{ + local CACHED_CVE2BSC="/tmp/$USER-cve2bugzilla" + local URL="https://gitlab.suse.de/security/cve-database/-/raw/master/data/cve2bugzilla" + local REFRESH=$1 + fetch_cache $URL $CACHED_CVE2BSC 1 $REFRESH +} + +cve2bugzilla() +{ + local CVE=$1 + local CVE2BUGZILLA=$(fetch_cve2bugzilla $2) + local NR_TO_REPORT=1 + # The first bsc should be the actual report others are product specific (e.g. LP) + for bsc in $(grep $CVE $CVE2BUGZILLA | cut -d: -f2 | head -n $NR_TO_REPORT) + do + echo -n "bsc#$bsc" + done +} + +fetch_cve2cvss() +{ + local CACHED_CVE2CVSS="/tmp/$USER-cve2cvss" + local URL="http://ftp.suse.com/pub/projects/security/yaml/suse-cvss-scores.yaml" + local REFRESH=$1 + fetch_cache $URL $CACHED_CVE2CVSS 1 $REFRESH +} + +cve2cvss() +{ + local CVE=$1 + local REFRESH=$2 + local CVE2CVSS=$(fetch_cve2cvss $REFRESH) + local cvss="$(grep $CVE -A3 $CVE2CVSS | grep score:)" + + echo ${cvss##*:} +} + +cve2sha() +{ + local arg=$1 + local REFRESH=$2 + sha="$(cd $VULNS_GIT; [ -n "$REFRESH" ] && git pull >/dev/null 2>&1; scripts/cve_search $arg 2>/dev/null | cut -d" " -f7)" + + if [ $(echo $sha | wc -c) -eq 41 ] + then + echo $sha + fi +} + +sha2cve() +{ + local arg=$1 + local REFRESH=$2 + cve_sha="$(cd $VULNS_GIT; [ -n "$REFRESH" ] && git pull >/dev/null 2>&1; scripts/cve_search $arg 2>/dev/null | cut -d" " -f1,7)" + + if [ $(echo ${cve_sha##* } | wc -c) -eq 41 ] + then + echo ${cve_sha%% *} + fi +} + +current_branch() +{ + git branch --show-current +} + +print_merge_branches() +{ + local branches_conf="$1" + local branch="$2" + local merge_branch= + + [ -z "$branches_conf" ] && fail "megre_branches: No branches_conf provided" + [ -z "$branch" ] && fail "merge_branches: No branch provided" + + for word in $(grep -w "^$branch:" "$branches_conf") ; do + if [ "${word#merge:}" != "$word" ] ; then + merge_branch="${word#merge:}" + merge_branch="${merge_branch#-}" + [ -z "$merge_branch" ] && fail "print_merge_branges: non supported syntax" + echo "$merge_branch" + fi + done +} + +for_each_build_branch() +{ + local branches_conf="$1" + local fn="$2" + shift 2 + local args="$@" + + grep -w build "$branches_conf" | grep -v -E "^(master|vanilla|linux-next|stable|slowroll)" | \ + while read line ; do + line=${line%%\#*} + branch=${line%%:*} + + # empty line or comment + if [ -z "$branch" ] ; then + continue + fi + + $fn $branch $args || break + done +} + +fail() +{ + echo $* >&2 + exit 1 +} + +branch_base_ver() +{ + local branch="origin/$1" + git show-ref --verify --quiet "refs/remotes/${branch}" || fail "$branch invalid branch" + + local base_ver="v$(git grep SRCVERSION $branch -- rpm/config.sh | sed 's@.*=@@')" + + echo $base_ver +} + +sha_get_upstream_git_fixes() +{ + local sha=$1 + local upstream_git=${2:-$LINUX_GIT} + + [ -z "$sha" ] && fail "No commit provided" + [ -z "$upstream_git" ] && fail "No upstream git tree" + + git --git-dir="$upstream_git/.git" show $sha | grep -i "^[[:space:]]*fixes:" | awk '{print $2}' +} + +print_upstream_sha_info() +{ + local sha=$1 + local upstream_git=${2:-$LINUX_GIT} + + echo -n "$(git --git-dir="$upstream_git/.git" show -s --pretty='format:%h ("%s")' $sha) merged " + git --git-dir="$upstream_git/.git" describe --contains --abbrev=0 --match="v*" $sha +} + +print_upstream_sha_summary() +{ + local sha=$1 + local upstream_git=${2:-$LINUX_GIT} + + print_upstream_sha_info $sha $upstream_git + for fix in $(sha_get_upstream_git_fixes $1 $upstream_git) + do + echo -n "Fixes: " + print_upstream_sha_info $fix $upstream_git + done +} + +sha_merged_in_upstream_tag() +{ + local sha=$1 + local base=$2 + local upstream_git=${3:-$LINUX_GIT} + + [ -z "$sha" ] && fail "sha_merged_in_upstream_tag: No sha provided" + [ -z "$base" ] && fail "sha_merged_in_upstream_tag: No base provided" + [ -z "$upstream_git" ] && fail "sha_merged_in_upstream_tag: No upstream git tree" + + git --git-dir="$LINUX_GIT/.git" merge-base --is-ancestor "$sha" "$base" 2>/dev/null +} + +sha_in_upstream() +{ + local sha=$1 + local upstream_git=${2:-$LINUX_GIT} + + [ -z "$sha" ] && fail "sha_in_upstream: No sha provided" + [ -z "$upstream_git" ] && fail "sha_in_upstream: No upstream git tree" + + sha_merged_in_upstream_tag $sha origin/master $upstream_git +} + + +sha_has_git_fixes() +{ + local sha="$1" + local base="$2" + local upstream_git=${3:-$LINUX_GIT} + + [ -z "$sha" ] && fail "sha_affected_by_git_fixes: No sha provided" + [ -z "$base" ] && fail "sha_affected_by_git_fixes: No tag provided" + [ -z "$upstream_git" ] && fail "sha_affected_by_git_fixes: No upstream_git provided" + + # Check git fixes when the bug was introduced + local git_fixes="$(sha_get_upstream_git_fixes $sha)" + + test -n "$git_fixes" +} + + +affected_by_git_fixes() +{ + local branch="$1" + local base="$2" + shift 2 + local git_fixes="$@" + + [ -z "$branch" ] && fail "affected_by_git_fixes: No branch provided" + [ -z "$base" ] && fail "affected_by_git_fixes: No tag provided" + [ -z "$git_fixes" ] && fail "affected_by_git_fixes: No git fixes provided" + + # Check git fixes when the bug was introduced + local git_fix= + local affected_by= + + for git_fix in $git_fixes ; do + local needs_fix= + + # Is it merged in the upstream base kernel? + if sha_merged_in_upstream_tag "$git_fix" "$base" ; then + needs_fix=1 + fi + + # Do we have it backported? + if sha_merged_in_suse_tree "$git_fix" "$branch" ; then + needs_fix=1 + fi + + if [ -n "$needs_fix" ] ; then + if [ -z "$affected_by" ] ; then + affected_by="$git_fix" + else + affected_by="$affected_by $git_fix" + fi + fi + done + + if [ -n "$affected_by" ] ; then + echo "Fixes: $affected_by" + fi +} + +sha_to_patch_in_branch() +{ + local sha="$1" + local branch="$2" + + [ -z "$sha" ] && fail "sha_to_patch_in_branch: No sha provided" + [ -z "$branch" ] && fail "sha_to_patch_in_branch: No branch provided" + + branch_file=$(git --no-pager grep -l -i "^git-commit[[:space:]]*:[[:space:]]*$sha" "origin/$branch") + + echo "${branch_file#origin/$branch:}" +} + +sha_to_patch() +{ + local sha="$1" + + [ -z "$sha" ] && fail "sha_to_patch: No sha provided" + + git --no-pager grep -l -i "^git-commit[[:space:]]*:[[:space:]]*$sha" +} + +sha_merged_in_suse_tree() +{ + local sha="$1" + local branch="$2" + + [ -z "$sha" ] && fail "sha_merged_in_suse_tree: No sha provided" + [ -z "$branch" ] && fail "sha_merged_in_suse_tree: No branch provided" + + local patch=$(sha_to_patch_in_branch "$sha" "$branch") + + test -n "$patch" +} + +references_to_patches_in_branch() +{ + local branch="$1" + shift + local references="$@" + + [ -z "$branch" ] && fail "references_to_patches_in_branch: No branch provided" + [ -z "$references" ] && fail "references_to_patches_in_branch: No references provided" + + local pattern_prefix="^references[[:space:]]*:[[:space:]]*" + local pattern= + + for ref in $references ; do + [ -n "$pattern" ] && pattern="$pattern|" + pattern="$pattern$pattern_prefix$ref" + done + + branch_files=$(git --no-pager grep -l -E -i "$pattern" "origin/$branch") + + for branch_file in $branch_files ; do + echo "${branch_file#origin/$branch:}" + done +} + +patch_has_reference() +{ + local ref="$1" + local patch="$2" + + [ -z "$patch" ] && fail "No patch provided" + [ -z "$ref" ] && fail "No reference provided" + + grep -q -i "^references:.*$ref" "$patch" +} + +patch_has_reference_in_branch() +{ + local patch="$1" + local ref="$2" + local branch="$3" + + [ -z "$patch" ] && fail "patch_has_reference_in_branch: No patch provided" + [ -z "$ref" ] && fail "patch_has_reference_in_branch: No reference provided" + [ -z "$branch" ] && fail "patch_has_reference_in_branch: No branch provided" + + git --no-pager grep -w -q -i "^references:.*$ref" "origin/$branch" -- "$patch" +} + +sha_has_reference_in_branch() +{ + local sha="$1" + local ref="$2" + local branch="$3" + local patch= + + [ -z "$sha" ] && fail "sha_has_reference_in_branch: No sha provided" + [ -z "$ref" ] && fail "sha_has_reference_in_branch: No reference provided" + [ -z "$branch" ] && fail "sha_has_reference_in_branch: No branch provided" + + patch=$(sha_to_patch_in_branch "$sha" "$branch") + + if [ -n "$patch" ] ; then + patch_has_reference_in_branch "$patch" "$ref" "$branch" + else + # no patch, no refence needed + true + fi +} + +patch_add_reference() +{ + local ref=$1 + local patch=$2 + + [ -z "$patch" ] && fail "No patch provided" + [ -z "$ref" ] && fail "No reference provided" + + if ! patch_has_reference "$ref" "$patch" ; then + local references=$(grep -i "^references:" $patch | sed -e 's/^[Rr]eferences:[[:space:]]//') + + references="$references $ref" + patch-tag --delete "references" "$patch" + patch-tag --add "References=$references" "$patch" + + change_to_commit=1 + fi + + if ! patch_has_reference "$ref" "$patch" ; then + fail "Failed to add reference '$ref' into $patch" + fi +} + +current_branch_state() +{ + local state_line + + status_line=$(git status | grep "Your branch") + + [ -z "$status_line" ] && fail "Can't get status of the current branch" + + if (echo "$status_line" | grep -q "up to date") ; then + echo "up to date" + elif (echo "$status_line" | grep -q "ahead") ; then + echo "ahead" + elif (echo "$status_line" | grep -q "behind.*fast-forwarded") ; then + echo "behind-ff" + elif (echo "$status_line" | grep -q "have diverged") ; then + echo "diverged" + else + echo "unknown" + fi +} + +push_list_name() +{ + local type=$1 + + [ -z "$type" ] && fail "push_list_name: called with no type" + + echo "push-list.$type" +} + +push_list_has_branch() +{ + local type=$1 + local branch=$2 + local file= + + [ -z "$type" ] && fail "push_list_has_branch: called with no type" + [ -z "$branch" ] && fail "push_list_has_branch: called with no branch" + + file=$(push_list_name $type) + + if [ -e "$file" ] ; then + grep -q "^branch\$" "$file" + else + false + fi +} + +push_list_add_branch() +{ + local type="$1" + local branch="$2" + local file= + + [ -z "$type" ] && fail "push_list_update: called with no type" + [ -z "$branch" ] && fail "push_list_has_branch: called with no branch" + + if ! $(push_list_has_branch $type $branch) ; then + file=$(push_list_name $type) + echo "$branch" >> "$file" + fi +} + +queue_push() +{ + local branch_state= + + branch_state=$(current_branch_state) + + case "$branch_state" in + "up to date") + // nope + ;; + ahead) + push_list_add_branch "ready" $(current_branch) + ;; + *) + push_list_add_branch "manual" $(current_branch) + ;; + esac +} + +push_list_msg() +{ + local type="$1" + local msg="$2" + local file= + + [ -z "$type" ] && fail "push_list_msg: called with no type" + [ -z "$msg" ] && fail "push_list_msg: called with no message" + + file=$(push_list_name "$type") + + if ! grep -q "^$msg$" "$file" ; then + echo "$msg" >> "$file" + fi +} + +log_fail() +{ + local msg="$1" + + [ -z "$msg" ] && fail "log_failure: called with no message" + + push_list_msg "failure" "$msg" + fail "$msg" +} diff --git a/scripts/cve_tools/add-missing-reference b/scripts/cve_tools/add-missing-reference new file mode 100755 index 0000000..72af708 --- /dev/null +++ b/scripts/cve_tools/add-missing-reference @@ -0,0 +1,31 @@ +#!/usr/bin/python3 + +import argparse +import sys +import os.path + +scriptsdir = os.path.dirname(__file__) +sys.path.append(os.path.join(scriptsdir, "../git_sort")) +from patch import Patch + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description="Add references to patch file") + parser.add_argument("-r", "--reference", action="append", + help="bsc# or CVE token used to tag the patch file. The option can be used more times.") + parser.add_argument("patches", help="Patch files.", + nargs=argparse.REMAINDER) + args = parser.parse_args() + + + added_refs = list(args.reference) + for f in args.patches: + with Patch(open(f, "r+b")) as patch: + refs = "".join(patch.get("References")) + refs = list(refs.replace(",", " ").split()) + new_refs = refs + [r for r in added_refs if not r in refs] + if new_refs == refs: + continue + patch.change("References", " ".join(new_refs)) + + diff --git a/scripts/cve_tools/cve2metadata.sh b/scripts/cve_tools/cve2metadata.sh new file mode 100755 index 0000000..d0dd51d --- /dev/null +++ b/scripts/cve_tools/cve2metadata.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# +# Usage: +# cve2metadata.sh CVE-NUM[...CVE-NUM] +# +# expects: +# VULNS_GIT to point to vulns DB git tree (clone from https://git.kernel.org/pub/scm/linux/security/vulns.git) + +if [ -z "$VULNS_GIT" -o ! -d "$VULNS_GIT" ] +then + echo "VULNS_GIT should point to vulns git tree" >&2 + echo "clone from https://git.kernel.org/pub/scm/linux/security/vulns.git" >&2 + exit 1 +fi + +. scripts/common-functions + +while [ $# -gt 0 ] +do + arg=$1 + cve_sha="$(cd $VULNS_GIT; scripts/cve_search $arg 2>/dev/null | cut -d" " -f1,7)" + cve=${cve_sha%% *} + sha=${cve_sha##* } + if [ $(echo $sha | wc -c) -eq 41 ] + then + echo -n "$sha" + cvss="$(cve2cvss $cve)" + echo -n " score:${cvss:-unknown}" + bsc="$(cve2bugzilla $cve)" + echo " $cve $bsc" + else + echo $arg cannot be resolved to a CVE >&2 + fi + shift +done