| #!/bin/bash |
| # SPDX-License-Identifier: GPL-2.0 |
| # |
| # Copyright (c) 2024 - Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| # |
| # bippy - creates a json and/or mbox file on standard output in the proper |
| # format to submit a CVE based on a specific git SHA. |
| # |
| # Usage: |
| # bippy [loads of options, see the help text below] |
| # |
| # Right now only works with CVEs, will handle other identifiers as needed. |
| # |
| # Name comes from the phrase "you bet your bippy!" as said by David L. Morse. |
| # |
| # Requires: |
| # A kernel git tree with the SHA to be used in it |
| # jo - the json output tool, found at: https://github.com/jpmens/jo |
| # dyad - tool to find matching pairs of vulnerable:fixed kernel ids for a specific fix |
| |
| # set to 1 to get some debugging logging messages (or use -v/--verbose option) |
| DEBUG=0 |
| |
| KERNEL_TREE=${CVEKERNELTREE} |
| COMMIT_TREE=${CVECOMMITTREE} |
| |
| if [[ ! -d "${KERNEL_TREE}" ]] || [[ ! -d "${COMMIT_TREE}" ]]; then |
| echo "CVEKERNELTREE needs setting to the stable repo directory" |
| echo "CVECOMMITTREE needs setting to the Stable commit tree" |
| echo -e "\nEither manually export them or add them to your .bashrc/.zshrc et al." |
| echo -e "\nSee HOWTO in the root of this repo" |
| exit 1 |
| fi |
| |
| # don't use unset variables |
| set -o nounset |
| |
| # 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##*/} |
| SCRIPT_VERSION=$(cd "${DIR}" && git ls-tree --abbrev=12 HEAD | grep "${SCRIPT}" | awk '{print $3}' | head -n 1) |
| |
| # location of dyad helper script |
| dyad="${DIR}/dyad" |
| |
| help() { |
| echo "Usage: $0 [OPTIONS]" |
| echo "Create a JSON or MBOX file to report a CVE based on a specific Linux kernel" |
| echo "git sha value." |
| echo "" |
| echo "Arguments:" |
| echo " -c, --cve=CVE_NUMBER The full CVE number to assign" |
| echo " -s, --sha=GIT_SHA The kernel git sha1 to assign the CVE to" |
| echo " --vulnerable=GIT_SHA The kernel git sha1 that this issue became vulnerable at. (optional)" |
| echo " -j, --json=JSON_FILENAME Output a JSON report to submit to CVE to the" |
| echo " specified filename" |
| echo " -m, --mbox=MBOX_FILENAME Output a mbox file to submit to the CVE" |
| echo " announce mailing list" |
| echo " --diff=DIFF_FILENAME File containing a diff for the changelog text to be applied. (optional)" |
| echo " --reference=REFERENCE_FILENAME File containing a list of url references to add to the json record. (optional)" |
| echo " -u, --user=EMAIL Email of user creating the record." |
| echo " -n, --name=NAME Name of the user creating the record." |
| echo " -h, --help This information" |
| echo " -v, --verbose Show debugging information to stdout" |
| echo "" |
| echo "Note, CVE_NUMBER and GIT_SHA are required, as well as at least one of" |
| echo "JSON_FILENAME and/or MBOX_FILENAME." |
| echo "If EMAIL or NAME is not specified, they will be taken from 'git config' user settings." |
| exit 1 |
| } |
| |
| dbg() { |
| if [[ ${DEBUG} -ge 1 ]] ; then |
| echo "$1" |
| fi |
| } |
| |
| |
| # Parse the command line |
| short_opts="j:m:c:s:u:n:hv" |
| long_opts="json:,mbox:,cve:,sha:,vulnerable:,user:,name:,diff:,reference:,help,verbose" |
| JSON_FILE="" |
| MBOX_FILE="" |
| DIFF_FILE="" |
| REFERENCE_FILE="" |
| CVE_NUMBER="" |
| GIT_SHA="" |
| GIT_VULNERABLE="" |
| EMAIL="$(git config --get user.email)" |
| NAME="$(git config --get user.name)" |
| |
| TMP=$(getopt -o "${short_opts}" --long "${long_opts}" --name="${SCRIPT}" -- "$@") |
| eval set -- "${TMP}" |
| while :; do |
| dbg "arg=${1}" |
| case "${1}" in |
| -j | --json ) JSON_FILE="${2}"; shift 2 ;; |
| -m | --mbox ) MBOX_FILE="${2}"; shift 2 ;; |
| --diff ) DIFF_FILE="${2}"; shift 2 ;; |
| --reference ) REFERENCE_FILE="${2}"; shift 2 ;; |
| -c | --cve ) CVE_NUMBER="${2}"; shift 2 ;; |
| -s | --sha ) GIT_SHA="${2}"; shift 2 ;; |
| -u | --user ) EMAIL="${2}"; shift 2 ;; |
| -n | --name ) NAME="${2}"; shift 2 ;; |
| --vulnerable ) GIT_VULNERABLE="${2}"; shift 2 ;; |
| -h | --help ) help; shift ;; |
| -v | --verbose ) DEBUG=1; shift ;; |
| -- ) shift; break ;; |
| * ) help ;; |
| esac |
| done |
| |
| dbg "CVE_NUMBER=${CVE_NUMBER}" |
| dbg "GIT_SHA=${GIT_SHA}" |
| dbg "JSON_FILE=${JSON_FILE}" |
| dbg "MBOX_FILE=${MBOX_FILE}" |
| dbg "DIFF_FILE=${DIFF_FILE}" |
| dbg "REFERENCE_FILE=${REFERENCE_FILE}" |
| dbg "GIT_VULNERABLE=${GIT_VULNERABLE}" |
| |
| if [[ "${CVE_NUMBER}" == "" || "${GIT_SHA}" == "" || "${EMAIL}" == "" ]] ; then |
| help |
| fi |
| if [[ "${JSON_FILE}" == "" && "${MBOX_FILE}" == "" ]] ; then |
| help |
| fi |
| |
| if [[ "${CVE_USER}" == "" ]] ; then |
| echo "CVE_USER not set" |
| help |
| fi |
| |
| # Functions for us to use, main flow starts below at ======= point |
| |
| |
| # determine if a kernel version is a "-rc" release or not. |
| # Will return 1 if -rc, 0 if not |
| function version_is_rc |
| { |
| #dbg "version_is_rc($1)" |
| local VERSION=$1 |
| if [[ "${VERSION}" =~ .*"rc" ]] ; then |
| #dbg "version_is_rc: ${VERSION} is -rc" |
| return 1 |
| else |
| #dbg "version_is_rc: ${VERSION} is NOT -rc" |
| return 0 |
| fi |
| } |
| |
| function version_is_queue |
| { |
| local VERSION=$1 |
| |
| if [[ "${VERSION}" =~ .*"queue" ]] ; then |
| return 1 |
| else |
| return 0 |
| fi |
| } |
| |
| # Determine if a kernel version is a "mainline" one, or if it is a stable |
| # kernel release. Will return 1 if mainline, 0 if not |
| function version_is_mainline |
| { |
| #dbg "version_is_mainline($1)" |
| local VERSION=$1 |
| |
| local REL_ARRAY=(${VERSION//./ }) |
| local MAJOR=${REL_ARRAY[0]} |
| #local BASE=${REL_ARRAY[0]}.${REL_ARRAY[1]}.${REL_ARRAY[2]} |
| #local REL=${REL_ARRAY[3]} |
| #local MINOR=${REL_ARRAY[2]} |
| |
| # If this is a 2.6.X release, just return now, we don't care about them |
| # anymore |
| if [[ "${MAJOR}" == "2" ]] ; then |
| return 1 |
| fi |
| |
| version_is_rc "${VERSION}" |
| local rc=$? |
| #echo "rc=$rc" |
| # If this is a -rc release, it's a mainline release |
| #if [[ "${VERSION}" =~ *"-rc"* ]] ; then |
| if [[ "${rc}" == "1" ]] ; then |
| return 1 |
| fi |
| |
| # If this is in a queue, it's not a mainline release |
| version_is_queue "${VERSION}" |
| local queue=$? |
| if [[ "${queue}" == "1" ]] ; then |
| return 0 |
| fi |
| |
| # if the REL_ARRAY only has 2 elements in it, it's a mainline release |
| # (X.Y, not X.Y.Z) |
| if [[ "${#REL_ARRAY[@]}" == "2" ]] ; then |
| return 1 |
| fi |
| |
| # Must be a stable release |
| return 0 |
| } |
| |
| |
| # ======= |
| # Main logic starts here |
| |
| # Get the UUID we are going to use from the linux.uuid file in the directory |
| # where the script is. This allows us to change this if needed in the future |
| # (and it's easier to move between testing and production databases this way, |
| # as those require different uuids.) |
| orig_id=$(cat "${DIR}"/linux.uuid) |
| if [[ "${orig_id}" == "" ]]; then |
| echo "No UUID found to use at ${DIR}/linux.uuid, aborting" |
| exit 1 |
| fi |
| dbg "orig_id=${orig_id}" |
| |
| # go into the kernel tree, we need this to be a valid one |
| #cd ${KERNEL_TREE} || exit 1 |
| |
| # See if the SHA given to us is a valid SHA in the git repo. |
| # This tests if we have a valid kernel tree, AND we need a full/long SHA1 for |
| # many of the searches we do later on. If we stuck with a short one, some of |
| # the searches would give us false-positives as people use short shas in commit |
| # messages. |
| GIT_SHA_FULL=$(cd "${KERNEL_TREE}" && git log -1 --format="%H" "${GIT_SHA}") |
| if [[ "${GIT_SHA_FULL}" == "" ]] ; then |
| echo "error: git id ${GIT_SHA} is not found in the tree at ${KERNEL_TREE}" |
| exit 1 |
| fi |
| |
| # Grab a "real" 12 character short sha to use as well, we "know" this will not fail. |
| GIT_SHA_SHORT=$(cd "${KERNEL_TREE}" && git log -1 --abbrev=12 --format="%h" "${GIT_SHA_FULL}") |
| |
| # Get the subject line of our sha |
| subject=$(cd "${KERNEL_TREE}" && git show --no-patch --pretty=format:"%s" "${GIT_SHA_FULL}" 2> /dev/null) |
| if [[ "${subject}" == "" ]] ; then |
| echo "error: git id ${GIT_SHA_FULL} is not found in the tree at ${KERNEL_TREE}" |
| exit 1 |
| fi |
| dbg "subject=${subject}" |
| |
| # Get the list of files affected in the change |
| files=$(cd "${KERNEL_TREE}" && git diff --name-only "${GIT_SHA_FULL}"^.."${GIT_SHA_FULL}" 2> /dev/null) |
| dbg "${GIT_SHA_FULL} touched the following files:" |
| while IFS= read -r entry; do |
| dbg " ${entry}" |
| done <<< "${files}" |
| |
| # Grab the full commit text, we will use that for many things |
| # We strip off the signed-off-by stuff AFTER we are done with parsing |
| # this text |
| commit_text=$(cd "${KERNEL_TREE}" && git show --no-patch --pretty=format:"%B" "${GIT_SHA_FULL}") |
| |
| #echo "commit_text=${commit_text}" |
| |
| # |
| # Use dyad to find our pairs of vulnerable:fixed entries |
| v="" |
| if [[ "${GIT_VULNERABLE}" != "" ]]; then |
| v="--vulnerable=${GIT_VULNERABLE}" |
| fi |
| |
| # We want to call dyad without quotes for the arguments as we "know" these |
| # arguments are ok, we just set them above explicitly. |
| # shellcheck disable=SC2086 |
| dyad_out=$("${dyad}" ${v} ${GIT_SHA_FULL} | grep -v "^#") |
| dbg "dyad_out=${dyad_out}" |
| dyad_entries=() |
| |
| for dyad_entry in ${dyad_out}; do |
| dyad_entries+=("${dyad_entry}") |
| done |
| dbg "dyad_entries: ${#dyad_entries[@]}" |
| |
| # |
| # Generate the some readable (i.e. text) information, showing where |
| # vulnerabilities showed up, and where they were fixed, and also if they are |
| # not fixed at all. Do this by creating a list of messages that we will later |
| # dump into the mail message itself. |
| vuln_array_mbox=() |
| url_array=() |
| for entry in "${dyad_entries[@]}"; do |
| x=(${entry//:/ }) |
| vuln=${x[0]} |
| vuln_git=${x[1]} |
| fix=${x[2]} |
| fix_git=${x[3]} |
| dbg " mbox: vuln=${vuln} vuln_git=${vuln_git} fix=${fix} fix_git=${fix_git}" |
| |
| if [[ "${fix}" == "0" ]]; then |
| # Issue is not fixed, so say that: |
| vuln_array_mbox+=("Issue introduced in ${vuln} with commit ${vuln_git}") |
| continue |
| fi |
| |
| # if the vulnerability showed up in the same releasae it was |
| # fixed in, then skip it for the mail message |
| if [[ "${vuln}" != "${fix}" ]]; then |
| if [[ "${vuln}" == "0" ]] ; then |
| # We do not know when it showed up, so just say it is fixed |
| vuln_array_mbox+=("Fixed in ${fix} with commit ${fix_git}") |
| else |
| # Report when it was introduced and when it was fixed. |
| vuln_array_mbox+=("Issue introduced in ${vuln} with commit ${vuln_git} and fixed in ${fix} with commit ${fix_git}") |
| fi |
| fi |
| url_array+=("https://git.kernel.org/stable/c/${fix_git}") |
| done |
| |
| # For now, if we do not have ANYTHING to report in the mbox message (i.e. all |
| # fixes were done in the same kernel branch as the issue was vulnerable in) |
| # then just bail out because we can't create the json file very easily at all. |
| if [[ "${#vuln_array_mbox[@]}" == "0" ]]; then |
| echo "Despite having some vulnerable:fixed kernels, none were in an actual release, so aborting and not assigning a CVE to ${GIT_SHA_SHORT}" |
| exit 1 |
| fi |
| |
| # |
| # Iterate over the whole list of kernel pairs to try to determine what the "default status" is. |
| # If there is any "mainline kernel" that is touched by this issue, then the |
| # default status is "affected", otherwise it is "unaffected". |
| default_status="unaffected" |
| for entry in "${dyad_entries[@]}"; do |
| x=(${entry//:/ }) |
| vuln=${x[0]} |
| fix=${x[2]} |
| |
| # if vuln == 0 then the kernel has always been vulnerable |
| if [[ "${vuln}" == "0" ]]; then |
| default_status="affected" |
| continue |
| fi |
| |
| # if the fix is in the same release, skip this entry as it "doesn't count" |
| if [[ "${vuln}" == "${fix}" ]]; then |
| continue |
| fi |
| |
| # if the vuln kernel is mainline, we were vulnerable |
| version_is_mainline "${vuln}" |
| vuln_mainline=$? |
| if [[ "${vuln_mainline}" == "1" ]] ; then |
| default_status="affected" |
| fi |
| done |
| dbg "default_status=${default_status}" |
| |
| vuln_array_json="" |
| url_string_json="" |
| git_array_json="" |
| # |
| # If this is an "affected" kernel, then we need to find the first mainline |
| # kernel where things went wrong, so create an "affected" and "unaffected" json |
| # entry for just this type of thing |
| if [[ "${default_status}" == "affected" ]]; then |
| for entry in "${dyad_entries[@]}"; do |
| x=(${entry//:/ }) |
| vuln=${x[0]} |
| vuln_git=${x[1]} |
| fix=${x[2]} |
| fix_git=${x[3]} |
| dbg " json: vuln=${vuln} vuln_git=${vuln_git} fix=${fix} fix_git=${fix_git}" |
| |
| if [[ "${vuln}" == "0" ]]; then |
| # We do not know when this first was a problem, so we |
| # default to 0 and handle it elsewhere in the logic as |
| # everything is "affected" |
| dbg "vuln=${vuln}" |
| else |
| version_is_mainline "${vuln}" |
| is_mainline=$? |
| if [[ "${is_mainline}" == "1" ]]; then |
| dbg " adding ${vuln} as where everything was affected" |
| vuln_array_json+="versions[]=$(jo -- \ |
| -s version="${vuln}" \ |
| -s status="affected" \ |
| ) " |
| vuln_array_json+="versions[]=$(jo -- \ |
| -s version="0" \ |
| -s lessThan="${vuln}" \ |
| -s status="unaffected" \ |
| -s versionType="semver" \ |
| ) " |
| break |
| fi |
| fi |
| done |
| fi |
| |
| # |
| # Create the normal json entries, based on what is vulnerable and what is fixed |
| for entry in "${dyad_entries[@]}"; do |
| x=(${entry//:/ }) |
| vuln=${x[0]} |
| vuln_git=${x[1]} |
| fix=${x[2]} |
| fix_git=${x[3]} |
| |
| if [[ "${fix}" == "0" ]]; then |
| # FIXME: We are not generating the json pairs for this properly just yet. |
| # Our attempts at this seem to break something, so save this for later.. |
| continue |
| fi |
| |
| # If the vulnerable kernel is 0 then the git id is the first in |
| # history, which we just manually substitute in here. |
| if [[ "${vuln}" == "0" ]]; then |
| vuln_git="1da177e4c3f41524e886b7f1b8a0c1fc7321cac2" # ("Linux-2.6.12-rc2") |
| fi |
| |
| # create the json array for the git ids |
| git_array_json+="versions[]=$(jo -- \ |
| -s version="${vuln_git}" \ |
| -s lessThan="${fix_git}" \ |
| -s status="affected" \ |
| -s versionType="git" \ |
| ) " |
| |
| # Add the git sha of the fix to the "all fix commits" array |
| url_string_json+="references[]=$(jo -- -s url="https://git.kernel.org/stable/c/${fix_git}") " |
| |
| # If the commit was found and fixed in the same release, let's not |
| # create a version number range as that will just confuse everyone |
| if [[ "${vuln}" == "${fix}" ]]; then |
| continue |
| fi |
| |
| # create the json array for the version numbers |
| if [[ "${default_status}" == "unaffected" ]]; then |
| # this is easy, our pairs are the versions that are |
| # affected, no tricky matching needs to happen here |
| vuln_array_json+="versions[]=$(jo -- \ |
| -s version="${vuln}" \ |
| -s lessThan="${fix}" \ |
| -s status="affected" \ |
| -s versionType="semver" \ |
| ) " |
| else |
| # much more tricky, we now need to say what ranges are |
| # both affected, AND unaffected. We handled the |
| # "affected" range above, so now our pairs show where |
| # things are "unaffected". |
| # |
| # By default, everything is affected from the "root" to |
| # the commit in mainline, so we have described that |
| # already above the loop, so this is just going to be |
| # the affected list... |
| # |
| # Note, the "mainline" fix shows where things "stop", |
| # so that gets a "short" record. |
| version_is_mainline "${fix}" |
| is_mainline=$? |
| if [[ "${is_mainline}" == "1" ]]; then |
| vuln_array_json+="versions[]=$(jo -- \ |
| -s version="${fix}" \ |
| -s lessThanOrEqual="*" \ |
| -s status="unaffected" \ |
| -s versionType="original_commit_for_fix" \ |
| ) " |
| else |
| # This is a stable range, so make an unaffected |
| # range with a wildcard |
| REL_ARRAY=(${fix//./ }) |
| MAJOR=${REL_ARRAY[0]} |
| MINOR=${REL_ARRAY[1]} |
| vuln_array_json+="versions[]=$(jo -- \ |
| -s version="${fix}" \ |
| -s lessThanOrEqual="${MAJOR}.${MINOR}.*" \ |
| -s status="unaffected" \ |
| -s versionType="semver" \ |
| ) " |
| fi |
| fi |
| done |
| |
| # If there are url references to be added to the record, read them from the |
| # referenced file and add them to the url and json strings to spit back out |
| # later on. |
| if [[ "${REFERENCE_FILE}" != "" ]]; then |
| dbg "reading references from ${REFERENCE_FILE}" |
| if [[ -f "${REFERENCE_FILE}" ]]; then |
| while read -r ref; do |
| url_array+=("${ref}") |
| url_string_json+="references[]=$(jo -- -s url="${ref}") " |
| done < "${REFERENCE_FILE}" |
| else |
| echo "error: reference file ${REFERENCE_FILE} is not found" |
| exit 1 |
| fi |
| fi |
| |
| dbg "git_array_json=${git_array_json}" |
| dbg "url_string_json=${url_string_json}" |
| dbg "vuln_array_json=${vuln_array_json}" |
| dbg "vuln_array_mbox=" |
| for entry in "${vuln_array_mbox[@]}"; do |
| dbg " ${entry}" |
| done |
| |
| # Strip off all of the signed-off-by stuff out of the commit text. |
| # We have a long list of "tags" to drop in the file, "tags", so compose |
| # the sed regex from the file and run the changelog through sed to strip |
| # things off. |
| # tags consist of one-line-per-tag, and we search the beginning of the |
| # line and a ':' character. This saves us from doing a whole bunch of: |
| # commit_text=$(echo "${commit_text}" | sed -e '/^cc:/Id;/^signed-off-by:/Id') |
| # calls. |
| sed_script="" |
| readarray -t tags < <(cat "${DIR}"/tags) |
| #for tag in $(cat "${DIR}"/tags); do |
| for tag in "${tags[@]}"; do |
| sed_script+="/^${tag}:/Id;" |
| done |
| #dbg "sed_script=${sed_script}" |
| sed_file=$(mktemp -t bippy.XXXX || exit 1) |
| echo "${sed_script}" > "${sed_file}" |
| commit_text=$(echo "${commit_text}" | sed -f "${sed_file}") |
| rm "${sed_file}" |
| |
| # Add a prefix of what this is for, as per the CVE requirements as documented: |
| # https://www.cve.org/ResourcesSupport/AllResources/CNARules#section_8-2_cve_record_prose_description_requirements |
| commit_text=$(printf "In the Linux kernel, the following vulnerability has been resolved:\n\n%s" "${commit_text}") |
| dbg "commit_text length is ${#commit_text}" |
| |
| # Sometimes people want/need to change the changelog text, so if there is a |
| # diff for it, apply it now. |
| if [[ "${DIFF_FILE}" != "" ]]; then |
| dbg "applying diff file ${DIFF_FILE}" |
| patch_file=$(mktemp -t bippy.XXXX || exit 1) |
| echo "${commit_text}" > ${patch_file} |
| patch -p1 ${patch_file} ${DIFF_FILE} |
| commit_text=$(cat ${patch_file}) |
| rm ${patch_file} |
| fi |
| |
| # The json record description can only be 4096 bytes big (because bytes are |
| # expensive) So trim it at 4079, and add "---truncated---" text which brings it |
| # out to 4095, with 1 byte to spare incase people are off-by-one in their |
| # parsing logic |
| #json_commit_text=$(printf "%.4079s" "${commit_text}") |
| json_commit_text=$(printf "%.3982s" "${commit_text}") # really 3982 for now due to CVE backend issues |
| if [[ "${#commit_text}" != "${#json_commit_text}" ]]; then |
| # we truncated the text, so say so |
| json_commit_text=$(printf "%s\n---truncated---\n" "${json_commit_text}") |
| fi |
| dbg "json_commit_text length is ${#json_commit_text}" |
| |
| ######################### |
| # Compose the json knowing what we now know, using the 'jo' tool |
| ######################### |
| if [[ "${JSON_FILE}" != "" ]] ; then |
| # NOTE, be VERY careful about the quoting around the bash |
| # variables when using 'jo', it isn't obvious, for some places |
| # we need the variables to be expanded without the "", and |
| # the shellcheck tool will complain, and test the heck out of |
| # any changes you make here, it seems to work as-is, so watch |
| # out, here lies many dragons. Comments have been added where |
| # needed and able to be used. |
| |
| x_generator=$(jo -- engine="${SCRIPT}-${SCRIPT_VERSION}") |
| |
| cveMetadata=$(jo -- assignerOrgId="${orig_id}" \ |
| cveID="${CVE_NUMBER}" \ |
| requesterUserId="${CVE_USER}" \ |
| -s serial="1" \ |
| state="PUBLISHED") |
| |
| d=$(jo -- \ |
| lang="en" \ |
| -s value="${json_commit_text}" \ |
| ) |
| |
| descriptions=$(jo -a -- "${d}") |
| |
| providerMetadata=$(jo -- \ |
| orgId="${orig_id}" \ |
| ) |
| |
| f="" |
| while IFS= read -r entry; do |
| f+="${entry} " |
| done <<< "${files}" |
| |
| # We want f to be expanded without quotes |
| # shellcheck disable=SC2086 |
| program_files=$(jo -a -- ${f}) |
| |
| # We want vuln_array_json to be expanded without quotes |
| # shellcheck disable=SC2086 |
| a=$(jo -- \ |
| product="Linux" \ |
| vendor="Linux" \ |
| defaultStatus="${default_status}" \ |
| repo="https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git" \ |
| programFiles="${program_files}" \ |
| ${vuln_array_json} \ |
| ) |
| |
| # We want git_array_json to be expanded without quotes |
| # shellcheck disable=SC2086 |
| ag=$(jo -- \ |
| product="Linux" \ |
| vendor="Linux" \ |
| defaultStatus="unaffected" \ |
| repo="https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git" \ |
| programFiles="${program_files}" \ |
| ${git_array_json} \ |
| ) |
| |
| affected=$(jo -a -- "${ag}" "${a}") |
| |
| # We want url_string_json to be expanded without quotes |
| # shellcheck disable=SC2086 |
| cna=$(jo -- \ |
| providerMetadata="${providerMetadata}" \ |
| descriptions="${descriptions}" \ |
| affected="${affected}" \ |
| ${url_string_json} \ |
| title="${subject}" \ |
| x_generator="${x_generator}" \ |
| ) |
| |
| # We might just need the "cna" output, and not the "containers" output below. |
| # Test with the 'cve' tool a bit, I think this might be able to be dropped as |
| # the tool might provide it for us. If not, then just output the above cna |
| # record instead. |
| containers=$(jo -- cna="${cna}") |
| |
| # output the final combination |
| jo -p -- \ |
| containers="${containers}" \ |
| cveMetadata="${cveMetadata}" \ |
| -s dataType="CVE_RECORD" \ |
| -s dataVersion="5.0" > "${JSON_FILE}" |
| |
| dbg "json file written to ${JSON_FILE}" |
| |
| fi # end json creation |
| |
| ######################### |
| # Compose the mbox file |
| ######################### |
| if [[ "${MBOX_FILE}" != "" ]] ; then |
| cat << EOF > "${MBOX_FILE}" |
| From ${SCRIPT}-${SCRIPT_VERSION} Mon Sep 17 00:00:00 2001 |
| From: ${NAME} <${EMAIL}> |
| To: <linux-cve-announce@vger.kernel.org> |
| Reply-to: <cve@kernel.org>, <linux-kernel@vger.kernel.org> |
| Subject: ${CVE_NUMBER}: ${subject} |
| |
| Description |
| =========== |
| |
| ${commit_text} |
| |
| The Linux kernel CVE team has assigned ${CVE_NUMBER} to this issue. |
| |
| |
| Affected and fixed versions |
| =========================== |
| |
| EOF |
| for line in "${vuln_array_mbox[@]}"; do |
| echo " ${line}" >> "${MBOX_FILE}" |
| done |
| |
| cat << EOF >> "${MBOX_FILE}" |
| |
| Please see https://www.kernel.org for a full list of currently supported |
| kernel versions by the kernel community. |
| |
| Unaffected versions might change over time as fixes are backported to |
| older supported kernel versions. The official CVE entry at |
| https://cve.org/CVERecord/?id=${CVE_NUMBER} |
| will be updated if fixes are backported, please check that for the most |
| up to date information about this issue. |
| |
| |
| Affected files |
| ============== |
| |
| The file(s) affected by this issue are: |
| EOF |
| while IFS= read -r entry; do |
| echo " ${entry}" >> "${MBOX_FILE}" |
| done <<< "${files}" |
| |
| cat << EOF >> "${MBOX_FILE}" |
| |
| |
| Mitigation |
| ========== |
| |
| The Linux kernel CVE team recommends that you update to the latest |
| stable kernel version for this, and many other bugfixes. Individual |
| changes are never tested alone, but rather are part of a larger kernel |
| release. Cherry-picking individual commits is not recommended or |
| supported by the Linux kernel community at all. If however, updating to |
| the latest release is impossible, the individual changes to resolve this |
| issue can be found at these commits: |
| EOF |
| for url in "${url_array[@]}"; do |
| echo " ${url}" >> "${MBOX_FILE}" |
| done |
| |
| dbg "mbox file written to ${MBOX_FILE}" |
| |
| fi # end mbox creation |
| |
| # all done! |
| exit 0 |