blob: 826530671c187e432ffd92900436cd9357e283a7 [file] [log] [blame]
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# Copyright (c) 2024 - Greg Kroah-Hartman <gregkh@linuxfoundation.org>
#
# cve_update - Update all existing CVE entries based on the latest information
# pulled from the git tree(s).
#
# Will look through the list of all published cve ids and run 'bippy' on them
# to update the mbox and json files. It is recommended that after this
# happens, submit the json files to CVE again, if version numbers have changed.
#
# This is good to do after older stable kernels have been released as often
# CVEs are included in older stable kernels AFTER they show up in newer ones,
# and this keeps the database at CVE more up to date and friendly for others to
# rely on. The mbox files generally shouldn't be resent, as that's just noise
# that no one wants to see.
#
# Usage:
# cve_update
#
# Requires:
# bippy
# Colors are good!
if [[ -t 1 ]]; then
txtred=$(tput setaf 1) # Red
txtgrn=$(tput setaf 2) # Green
txtylw=$(tput setaf 3) # Yellow
txtblu=$(tput setaf 4) # Blue
txtcyn=$(tput setaf 6) # Cyan
txtrst=$(tput sgr0) # Text reset
else
txtred=""
txtgrn=""
txtylw=""
txtblu=""
txtcyn=""
txtrst=""
fi
# set where the tool was run from,
# the name of our script,
# and the git version of it
DIR="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")"
SCRIPT=${0##*/}
help() {
echo "${SCRIPT}"
echo " Note, CVE_USER must be set to your CVE_USER email address"
exit 1
}
CVE=$1
# don't use unset variables
set -o nounset
cd "${DIR}"/../ || exit 1
update_cve()
{
local id=$1
local string=$2
local message=""
local tmp_json
local tmp_mbox
local sha
local cve
local root
local vuln_file
local vulnerable_sha
local vulnerable_option
local diff_file
local reference_file
local reference_option
local result
local updated_file
local diff
local diff_option
tmp_json=$(mktemp -t "${SCRIPT}XXXX.json" || exit 1)
tmp_mbox=$(mktemp -t "${SCRIPT}XXXX.mbox" || exit 1)
sha=$(cat "${id}")
cve=$(echo "${id}" | cut -f 1 -d '.' | cut -f 4 -d '/')
root=$(echo "${id}" | cut -f 1 -d '.')
#echo "id=${id} sha=${sha} cve=${cve}"
message+="Updating ${txtcyn}${cve}${txtrst} ${txtylw}${string}${txtrst}..."
# Look to see if we have a "og_vuln" that is provided to us in a
# published CVE. This is used for when we can't determine it on our
# own, but we have manually looked it up later on and added it to a
# CVE-*.vulnerable file
vuln_file="${root}.vulnerable"
#echo "vuln_file=${vuln_file}"
vulnerable_option=""
vulnerable_sha=""
if [[ -f "${vuln_file}" ]]; then
vulnerable_sha=$(cat "${vuln_file}")
vulnerable_option="--vulnerable=${vulnerable_sha}"
fi
diff_option=""
diff_file="${root}.diff"
if [[ -f "${diff_file}" ]]; then
diff_option="--diff=${diff_file}"
fi
reference_option=""
reference_file="${root}.reference"
if [[ -f "${reference_file}" ]]; then
reference_option="--reference=${reference_file}"
fi
# Create the new json and mbox files
sha_args=()
while IFS= read -r line; do
[ -n "$line" ] && sha_args+=(--sha="$line")
done < "${id}"
"${DIR}"/bippy --cve="${cve}" "${sha_args[@]}" --json="${tmp_json}" --mbox="${tmp_mbox}" --vulnerable="${vulnerable_sha}" "${diff_option}" "${reference_option}"
result=$?
if [[ "${result}" != 0 ]]; then
# bippy failed, so report it and continue on
echo "${txtred}Error:${txtrst} bippy failed to create ${txtcyn}${cve}${txtrst} for commit ${txtgrn}${sha}${txtrst}"
return
fi
# see if the json and/or mbox files actually changed, EXCEPT for the bippy-VERSIONINFO string
updated_file=""
diff=$(diff -u "${root}.json" "${tmp_json}" | grep -v "${tmp_json}" | grep -v "${root}.json" | grep -v "bippy" | grep -v "^@@ " | grep "^[+|-]" | grep -v "@kernel.org" | grep -v "@linuxfoundation.org")
#echo "diff json=${diff}"
if [[ "${diff}" != "" ]] ; then
mv -f "${tmp_json}" "${root}.json"
updated_file+="${root}.json"
else
rm "${tmp_json}"
#echo "diff for json was empty"
fi
diff=$(diff -u "${root}.mbox" "${tmp_mbox}" | grep -v "${tmp_mbox}" | grep -v "${root}.mbox" | grep -v "bippy-" | grep -v "^@@ " | grep "^[+|-]" | grep -v "@kernel.org" | grep -v "@linuxfoundation.org")
#echo "diff mbox=${diff}"
if [[ "${diff}" != "" ]] ; then
mv -f "${tmp_mbox}" "${root}.mbox"
updated_file+=" ${root}.mbox"
else
rm "${tmp_mbox}"
#echo "diff for mbox was empty"
fi
if [[ "${updated_file}" == "" ]] ; then
message+=" ${txtgrn}Nothing changed${txtrst}"
else
message+=" Updated ${txtblu}${updated_file}${txtrst}"
fi
echo "${message}"
}
update_year() {
local year=$1
local threads=$(nproc)
# get a count of ids for this year
total_count=$(ls cve/published/${year}/*.sha1 | wc -l)
count=0
echo "Updating ${txtcyn}${total_count}${txtrst} CVE ids for ${txtgrn}${year}${txtrst} with ${txtcyn}${threads}${txtrst} processes..."
for id in cve/published/${year}/*.sha1 ; do
count=$((count + 1))
count_string=$(printf "[%04d/%04d]" ${count} ${total_count})
while :
do
if [[ $(jobs -p | wc -l) -lt ${threads} ]]; then
#echo "id=${id}"
update_cve "${id}" "${count_string}" &
break
else
sleep 1
fi
done
done
wait
}
if [[ "${CVE}" == "" ]]; then
# Nothing specified on the command line, so just update everything by
# looping through all years
for y in cve/published/* ; do
year=$(echo "${y}" | cut -f 3 -d '/')
update_year ${year}
done
else
# Either the year, or a specific CVE id is specified here.
#
# Test for a specific cve id first
found=$(${DIR}/cve_search ${CVE})
found_result=$?
if [[ "${found_result}" == "0" ]]; then
CVE_ROOT="${DIR}/../cve/"
found=$(find "${CVE_ROOT}" -type f | grep -v testing | grep "${CVE}" | grep "sha1")
#echo "found='${found}"
if [[ "${found}" != "" ]]; then
# strip off the CVE root, as that's what update_cve is expecting:
update_cve "cve/${found/#$CVE_ROOT}" "1"
exit 0
fi
fi
# Not a specific id, let's try to do this for a year
#
if [[ -d cve/published/${CVE} ]]; then
update_year ${CVE}
exit 0
fi
echo "${txtred}ERROR:${txtrst} ${txtcyn}${CVE}${txtrst} is not found or is not a year."
exit 1
fi