#!/bin/bash

# Copyright (c) 2019  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 3 of the License, or
# (at your option) any later version.

VERSION="1.1"

# Warning! Be sure to download the latest version of this script from its primary source:

ARTICLE="https://access.redhat.com/security/vulnerabilities/kernel-vhost"

# DO NOT blindly trust any internet sources and NEVER do `curl something | bash`!

# This script is meant for simple detection of the vulnerability. Feel free to modify it for your
# environment or needs. For more advanced detection, consider Red Hat Insights:
# https://access.redhat.com/products/red-hat-insights#getstarted

# Checking against the list of vulnerable packages is necessary because of the way how features
# are back-ported to older versions of packages in various channels.


VULNERABLE_KERNELS=(
    # Example: '2.6.18-8.1.1.el5'
    "3.10.0-229.ael7b"
    "3.10.0-229.1.2.ael7b"
    "3.10.0-229.4.2.ael7b"
    "3.10.0-229.7.2.ael7b"
    "3.10.0-229.11.1.ael7b"
    "3.10.0-229.14.1.ael7b"
    "3.10.0-229.20.1.ael7b"
    "3.10.0-229.24.2.ael7b"
    "3.10.0-229.26.2.ael7b"
    "3.10.0-229.28.1.ael7b"
    "3.10.0-229.30.1.ael7b"
    "3.10.0-229.34.1.ael7b"
    "3.10.0-229.38.1.ael7b"
    "3.10.0-229.40.1.ael7b"
    "3.10.0-229.42.1.ael7b"
    "3.10.0-229.42.2.ael7b"
    "3.10.0-229.44.1.ael7b"
    "3.10.0-229.46.1.ael7b"
    "3.10.0-229.48.1.ael7b"
    "3.10.0-229.49.1.ael7b"
    "2.6.32-71.el6"
    "2.6.32-71.7.1.el6"
    "2.6.32-71.14.1.el6"
    "2.6.32-71.18.1.el6"
    "2.6.32-71.18.2.el6"
    "2.6.32-71.24.1.el6"
    "2.6.32-71.29.1.el6"
    "2.6.32-71.31.1.el6"
    "2.6.32-71.34.1.el6"
    "2.6.32-71.35.1.el6"
    "2.6.32-71.36.1.el6"
    "2.6.32-71.37.1.el6"
    "2.6.32-71.38.1.el6"
    "2.6.32-71.39.1.el6"
    "2.6.32-71.40.1.el6"
    "2.6.32-131.0.15.el6"
    "2.6.32-131.2.1.el6"
    "2.6.32-131.4.1.el6"
    "2.6.32-131.6.1.el6"
    "2.6.32-131.12.1.el6"
    "2.6.32-131.17.1.el6"
    "2.6.32-131.21.1.el6"
    "2.6.32-131.22.1.el6"
    "2.6.32-131.25.1.el6"
    "2.6.32-131.26.1.el6"
    "2.6.32-131.28.1.el6"
    "2.6.32-131.29.1.el6"
    "2.6.32-131.30.1.el6"
    "2.6.32-131.30.2.el6"
    "2.6.32-131.33.1.el6"
    "2.6.32-131.35.1.el6"
    "2.6.32-131.36.1.el6"
    "2.6.32-131.37.1.el6"
    "2.6.32-131.38.1.el6"
    "2.6.32-131.39.1.el6"
    "2.6.32-220.el6"
    "2.6.32-220.2.1.el6"
    "2.6.32-220.4.1.el6"
    "2.6.32-220.4.2.el6"
    "2.6.32-220.4.4.bgq.el6"
    "2.6.32-220.4.7.bgq.el6"
    "2.6.32-220.7.1.el6"
    "2.6.32-220.7.2.p7ih.el6"
    "2.6.32-220.7.3.p7ih.el6"
    "2.6.32-220.7.4.p7ih.el6"
    "2.6.32-220.7.6.p7ih.el6"
    "2.6.32-220.7.7.p7ih.el6"
    "2.6.32-220.13.1.el6"
    "2.6.32-220.17.1.el6"
    "2.6.32-220.23.1.el6"
    "2.6.32-220.24.1.el6"
    "2.6.32-220.25.1.el6"
    "2.6.32-220.26.1.el6"
    "2.6.32-220.28.1.el6"
    "2.6.32-220.30.1.el6"
    "2.6.32-220.31.1.el6"
    "2.6.32-220.32.1.el6"
    "2.6.32-220.34.1.el6"
    "2.6.32-220.34.2.el6"
    "2.6.32-220.38.1.el6"
    "2.6.32-220.39.1.el6"
    "2.6.32-220.41.1.el6"
    "2.6.32-220.42.1.el6"
    "2.6.32-220.45.1.el6"
    "2.6.32-220.46.1.el6"
    "2.6.32-220.48.1.el6"
    "2.6.32-220.51.1.el6"
    "2.6.32-220.52.1.el6"
    "2.6.32-220.53.1.el6"
    "2.6.32-220.54.1.el6"
    "2.6.32-220.55.1.el6"
    "2.6.32-220.56.1.el6"
    "2.6.32-220.57.1.el6"
    "2.6.32-220.58.1.el6"
    "2.6.32-220.60.2.el6"
    "2.6.32-220.62.1.el6"
    "2.6.32-220.63.2.el6"
    "2.6.32-220.64.1.el6"
    "2.6.32-220.65.1.el6"
    "2.6.32-220.66.1.el6"
    "2.6.32-220.67.1.el6"
    "2.6.32-220.68.1.el6"
    "2.6.32-220.69.1.el6"
    "2.6.32-220.70.1.el6"
    "2.6.32-220.71.1.el6"
    "2.6.32-220.72.2.el6"
    "2.6.32-220.73.1.el6"
    "2.6.32-220.75.1.el6"
    "2.6.32-220.76.1.el6"
    "2.6.32-220.76.2.el6"
    "2.6.32-220.77.1.el6"
    "2.6.32-279.el6"
    "2.6.32-279.1.1.el6"
    "2.6.32-279.2.1.el6"
    "2.6.32-279.5.1.el6"
    "2.6.32-279.5.2.el6"
    "2.6.32-279.9.1.el6"
    "2.6.32-279.11.1.el6"
    "2.6.32-279.14.1.bgq.el6"
    "2.6.32-279.14.1.el6"
    "2.6.32-279.19.1.el6"
    "2.6.32-279.22.1.el6"
    "2.6.32-279.23.1.el6"
    "2.6.32-279.25.1.el6"
    "2.6.32-279.25.2.el6"
    "2.6.32-279.31.1.el6"
    "2.6.32-279.33.1.el6"
    "2.6.32-279.34.1.el6"
    "2.6.32-279.37.2.el6"
    "2.6.32-279.39.1.el6"
    "2.6.32-279.41.1.el6"
    "2.6.32-279.42.1.el6"
    "2.6.32-279.43.1.el6"
    "2.6.32-279.43.2.el6"
    "2.6.32-279.46.1.el6"
    "2.6.32-358.el6"
    "2.6.32-358.0.1.el6"
    "2.6.32-358.2.1.el6"
    "2.6.32-358.6.1.el6"
    "2.6.32-358.6.2.el6"
    "2.6.32-358.6.3.p7ih.el6"
    "2.6.32-358.11.1.bgq.el6"
    "2.6.32-358.11.1.el6"
    "2.6.32-358.14.1.el6"
    "2.6.32-358.18.1.el6"
    "2.6.32-358.23.2.el6"
    "2.6.32-358.28.1.el6"
    "2.6.32-358.32.3.el6"
    "2.6.32-358.37.1.el6"
    "2.6.32-358.41.1.el6"
    "2.6.32-358.44.1.el6"
    "2.6.32-358.46.1.el6"
    "2.6.32-358.46.2.el6"
    "2.6.32-358.48.1.el6"
    "2.6.32-358.49.1.el6"
    "2.6.32-358.51.1.el6"
    "2.6.32-358.51.2.el6"
    "2.6.32-358.55.1.el6"
    "2.6.32-358.56.1.el6"
    "2.6.32-358.59.1.el6"
    "2.6.32-358.61.1.el6"
    "2.6.32-358.62.1.el6"
    "2.6.32-358.65.1.el6"
    "2.6.32-358.67.1.el6"
    "2.6.32-358.68.1.el6"
    "2.6.32-358.69.1.el6"
    "2.6.32-358.70.1.el6"
    "2.6.32-358.71.1.el6"
    "2.6.32-358.72.1.el6"
    "2.6.32-358.73.1.el6"
    "2.6.32-358.75.1.el6"
    "2.6.32-358.76.1.el6"
    "2.6.32-358.77.1.el6"
    "2.6.32-358.78.1.el6"
    "2.6.32-358.79.1.el6"
    "2.6.32-358.79.2.el6"
    "2.6.32-358.81.1.el6"
    "2.6.32-358.82.1.el6"
    "2.6.32-358.83.1.el6"
    "2.6.32-358.84.1.el6"
    "2.6.32-358.84.2.el6"
    "2.6.32-358.85.1.el6"
    "2.6.32-358.87.1.el6"
    "2.6.32-358.88.2.el6"
    "2.6.32-358.88.4.el6"
    "2.6.32-358.90.1.el6"
    "2.6.32-358.91.4.el6"
    "2.6.32-358.93.1.el6"
    "2.6.32-358.94.1.el6"
    "2.6.32-358.95.1.el6"
    "2.6.32-358.111.1.openstack.el6"
    "2.6.32-358.114.1.openstack.el6"
    "2.6.32-358.118.1.openstack.el6"
    "2.6.32-358.123.4.openstack.el6"
    "2.6.32-431.el6"
    "2.6.32-431.1.1.bgq.el6"
    "2.6.32-431.1.2.el6"
    "2.6.32-431.3.1.el6"
    "2.6.32-431.5.1.el6"
    "2.6.32-431.11.2.el6"
    "2.6.32-431.17.1.el6"
    "2.6.32-431.20.3.el6"
    "2.6.32-431.20.5.el6"
    "2.6.32-431.23.3.el6"
    "2.6.32-431.29.2.el6"
    "2.6.32-431.37.1.el6"
    "2.6.32-431.40.1.el6"
    "2.6.32-431.40.2.el6"
    "2.6.32-431.46.2.el6"
    "2.6.32-431.50.1.el6"
    "2.6.32-431.53.2.el6"
    "2.6.32-431.56.1.el6"
    "2.6.32-431.59.1.el6"
    "2.6.32-431.61.2.el6"
    "2.6.32-431.64.1.el6"
    "2.6.32-431.66.1.el6"
    "2.6.32-431.68.1.el6"
    "2.6.32-431.69.1.el6"
    "2.6.32-431.70.1.el6"
    "2.6.32-431.71.1.el6"
    "2.6.32-431.72.1.el6"
    "2.6.32-431.73.2.el6"
    "2.6.32-431.74.1.el6"
    "2.6.32-431.75.1.el6"
    "2.6.32-431.75.1.el6"
    "2.6.32-431.76.1.el6"
    "2.6.32-431.77.1.el6"
    "2.6.32-431.77.1.el6"
    "2.6.32-431.78.1.el6"
    "2.6.32-431.78.1.el6"
    "2.6.32-431.79.1.el6"
    "2.6.32-431.79.1.el6"
    "2.6.32-431.80.1.el6"
    "2.6.32-431.80.1.el6"
    "2.6.32-431.80.2.el6"
    "2.6.32-431.80.2.el6"
    "2.6.32-431.81.2.el6"
    "2.6.32-431.81.2.el6"
    "2.6.32-431.81.3.el6"
    "2.6.32-431.81.3.el6"
    "2.6.32-431.82.1.el6"
    "2.6.32-431.82.1.el6"
    "2.6.32-431.84.1.el6"
    "2.6.32-431.84.1.el6"
    "2.6.32-431.85.1.el6"
    "2.6.32-431.85.1.el6"
    "2.6.32-431.85.2.el6"
    "2.6.32-431.86.1.el6"
    "2.6.32-431.87.1.el6"
    "2.6.32-431.89.2.el6"
    "2.6.32-431.89.4.el6"
    "2.6.32-431.90.1.el6"
    "2.6.32-431.91.3.el6"
    "2.6.32-431.93.2.el6"
    "2.6.32-431.94.1.el6"
    "2.6.32-431.94.2.el6"
    "2.6.32-431.95.3.el6"
    "2.6.32-431.96.1.el6"
    "2.6.32-504.el6"
    "2.6.32-504.1.3.el6"
    "2.6.32-504.3.3.el6"
    "2.6.32-504.8.1.el6"
    "2.6.32-504.8.2.bgq.el6"
    "2.6.32-504.12.2.el6"
    "2.6.32-504.16.2.el6"
    "2.6.32-504.23.4.el6"
    "2.6.32-504.30.3.el6"
    "2.6.32-504.30.5.p7ih.el6"
    "2.6.32-504.30.6.p7ih.el6"
    "2.6.32-504.33.2.el6"
    "2.6.32-504.36.1.el6"
    "2.6.32-504.38.1.el6"
    "2.6.32-504.40.1.el6"
    "2.6.32-504.43.1.el6"
    "2.6.32-504.46.1.el6"
    "2.6.32-504.49.1.el6"
    "2.6.32-504.50.1.el6"
    "2.6.32-504.51.1.el6"
    "2.6.32-504.52.1.el6"
    "2.6.32-504.54.1.el6"
    "2.6.32-504.55.1.el6"
    "2.6.32-504.56.1.el6"
    "2.6.32-504.56.1.el6"
    "2.6.32-504.57.1.el6"
    "2.6.32-504.57.1.el6"
    "2.6.32-504.58.1.el6"
    "2.6.32-504.58.1.el6"
    "2.6.32-504.60.2.el6"
    "2.6.32-504.60.2.el6"
    "2.6.32-504.60.3.el6"
    "2.6.32-504.60.3.el6"
    "2.6.32-504.62.1.el6"
    "2.6.32-504.62.1.el6"
    "2.6.32-504.63.2.el6"
    "2.6.32-504.63.2.el6"
    "2.6.32-504.63.3.el6"
    "2.6.32-504.63.3.el6"
    "2.6.32-504.64.1.el6"
    "2.6.32-504.64.1.el6"
    "2.6.32-504.64.4.el6"
    "2.6.32-504.64.4.el6"
    "2.6.32-504.65.1.el6"
    "2.6.32-504.65.1.el6"
    "2.6.32-504.66.1.el6"
    "2.6.32-504.66.1.el6"
    "2.6.32-504.68.2.el6"
    "2.6.32-504.68.2.el6"
    "2.6.32-504.69.3.el6"
    "2.6.32-504.69.3.el6"
    "2.6.32-504.71.1.el6"
    "2.6.32-504.71.1.el6"
    "2.6.32-504.72.1.el6"
    "2.6.32-504.72.1.el6"
    "2.6.32-504.72.4.el6"
    "2.6.32-504.72.4.el6"
    "2.6.32-504.76.2.el6"
    "2.6.32-504.76.2.el6"
    "2.6.32-504.78.1.el6"
    "2.6.32-504.78.2.el6"
    "2.6.32-504.79.3.el6"
    "2.6.32-504.80.2.el6"
    "2.6.32-572.el6"
    "2.6.32-573.el6"
    "2.6.32-573.1.1.el6"
    "2.6.32-573.3.1.el6"
    "2.6.32-573.4.2.bgq.el6"
    "2.6.32-573.7.1.el6"
    "2.6.32-573.8.1.el6"
    "2.6.32-573.12.1.el6"
    "2.6.32-573.18.1.el6"
    "2.6.32-573.22.1.el6"
    "2.6.32-573.26.1.el6"
    "2.6.32-573.30.1.el6"
    "2.6.32-573.32.1.el6"
    "2.6.32-573.34.1.el6"
    "2.6.32-573.35.1.el6"
    "2.6.32-573.35.2.el6"
    "2.6.32-573.37.1.el6"
    "2.6.32-573.38.1.el6"
    "2.6.32-573.40.1.el6"
    "2.6.32-573.41.1.el6"
    "2.6.32-573.42.1.el6"
    "2.6.32-573.42.2.el6"
    "2.6.32-573.43.2.el6"
    "2.6.32-573.43.3.el6"
    "2.6.32-573.45.1.el6"
    "2.6.32-573.45.2.el6"
    "2.6.32-573.47.1.el6"
    "2.6.32-573.48.1.el6"
    "2.6.32-573.49.1.el6"
    "2.6.32-573.49.3.el6"
    "2.6.32-573.51.1.el6"
    "2.6.32-573.53.1.el6"
    "2.6.32-573.55.2.el6"
    "2.6.32-573.55.4.el6"
    "2.6.32-573.59.1.el6"
    "2.6.32-573.60.1.el6"
    "2.6.32-573.60.4.el6"
    "2.6.32-573.62.1.el6"
    "2.6.32-573.65.2.el6"
    "2.6.32-642.el6"
    "2.6.32-642.1.1.el6"
    "2.6.32-642.3.1.el6"
    "2.6.32-642.4.2.el6"
    "2.6.32-642.6.1.el6"
    "2.6.32-642.6.2.el6"
    "2.6.32-642.11.1.el6"
    "2.6.32-642.13.1.el6"
    "2.6.32-642.13.2.el6"
    "2.6.32-642.15.1.el6"
    "2.6.32-682.el6"
    "2.6.32-683.el6"
    "2.6.32-696.el6"
    "2.6.32-696.1.1.bgq.el6"
    "2.6.32-696.1.1.el6"
    "2.6.32-696.3.1.el6"
    "2.6.32-696.3.2.el6"
    "2.6.32-696.6.3.el6"
    "2.6.32-696.10.1.el6"
    "2.6.32-696.10.2.el6"
    "2.6.32-696.10.3.el6"
    "2.6.32-696.13.2.el6"
    "2.6.32-696.16.1.el6"
    "2.6.32-696.18.7.el6"
    "2.6.32-696.20.1.el6"
    "2.6.32-696.23.1.el6"
    "2.6.32-696.28.1.el6"
    "2.6.32-696.30.1.el6"
    "2.6.32-749.el6"
    "2.6.32-751.el6"
    "2.6.32-752.el6"
    "2.6.32-754.el6"
    "2.6.32-754.2.1.el6"
    "2.6.32-754.3.5.el6"
    "2.6.32-754.6.3.el6"
    "2.6.32-754.9.1.el6"
    "2.6.32-754.10.1.el6"
    "2.6.32-754.11.1.el6"
    "2.6.32-754.12.1.el6"
    "2.6.32-754.14.2.el6"
    "2.6.32-754.15.3.el6"
    "2.6.32-754.17.1.el6"
    "2.6.32-754.18.2.el6"
    "3.10.0-121.el7"
    "3.10.0-123.el7"
    "3.10.0-123.1.2.el7"
    "3.10.0-123.4.2.el7"
    "3.10.0-123.4.4.el7"
    "3.10.0-123.6.3.el7"
    "3.10.0-123.8.1.el7"
    "3.10.0-123.9.2.el7"
    "3.10.0-123.9.3.el7"
    "3.10.0-123.13.1.el7"
    "3.10.0-123.13.2.el7"
    "3.10.0-123.20.1.el7"
    "3.10.0-229.el7"
    "3.10.0-229.1.2.el7"
    "3.10.0-229.4.2.el7"
    "3.10.0-229.7.2.el7"
    "3.10.0-229.11.1.el7"
    "3.10.0-229.14.1.el7"
    "3.10.0-229.20.1.el7"
    "3.10.0-229.24.2.el7"
    "3.10.0-229.26.2.el7"
    "3.10.0-229.28.1.el7"
    "3.10.0-229.30.1.el7"
    "3.10.0-229.34.1.el7"
    "3.10.0-229.38.1.el7"
    "3.10.0-229.40.1.el7"
    "3.10.0-229.42.1.el7"
    "3.10.0-229.42.2.el7"
    "3.10.0-229.44.1.el7"
    "3.10.0-229.46.1.el7"
    "3.10.0-229.48.1.el7"
    "3.10.0-229.49.1.el7"
    "3.10.0-327.el7"
    "3.10.0-327.3.1.el7"
    "3.10.0-327.4.4.el7"
    "3.10.0-327.4.5.el7"
    "3.10.0-327.10.1.el7"
    "3.10.0-327.13.1.el7"
    "3.10.0-327.18.2.el7"
    "3.10.0-327.22.2.el7"
    "3.10.0-327.28.2.el7"
    "3.10.0-327.28.3.el7"
    "3.10.0-327.36.1.el7"
    "3.10.0-327.36.2.el7"
    "3.10.0-327.36.3.el7"
    "3.10.0-327.41.3.el7"
    "3.10.0-327.41.4.el7"
    "3.10.0-327.44.2.el7"
    "3.10.0-327.46.1.el7"
    "3.10.0-327.49.2.el7"
    "3.10.0-327.53.1.el7"
    "3.10.0-327.55.1.el7"
    "3.10.0-327.55.2.el7"
    "3.10.0-327.55.3.el7"
    "3.10.0-327.58.1.el7"
    "3.10.0-327.59.1.el7"
    "3.10.0-327.59.2.el7"
    "3.10.0-327.59.3.el7"
    "3.10.0-327.61.3.el7"
    "3.10.0-327.62.1.el7"
    "3.10.0-327.62.4.el7"
    "3.10.0-327.62.4.el7"
    "3.10.0-327.62.4.el7"
    "3.10.0-327.64.1.el7"
    "3.10.0-327.64.1.el7"
    "3.10.0-327.64.1.el7"
    "3.10.0-327.66.1.el7"
    "3.10.0-327.66.1.el7"
    "3.10.0-327.66.1.el7"
    "3.10.0-327.66.3.el7"
    "3.10.0-327.66.3.el7"
    "3.10.0-327.66.3.el7"
    "3.10.0-327.66.5.el7"
    "3.10.0-327.66.5.el7"
    "3.10.0-327.66.5.el7"
    "3.10.0-327.70.1.el7"
    "3.10.0-327.70.1.el7"
    "3.10.0-327.70.1.el7"
    "3.10.0-327.71.1.el7"
    "3.10.0-327.71.1.el7"
    "3.10.0-327.71.1.el7"
    "3.10.0-327.71.4.el7"
    "3.10.0-327.71.4.el7"
    "3.10.0-327.71.4.el7"
    "3.10.0-327.73.1.el7"
    "3.10.0-327.73.1.el7"
    "3.10.0-327.73.1.el7"
    "3.10.0-327.76.1.el7"
    "3.10.0-327.76.1.el7"
    "3.10.0-327.76.1.el7"
    "3.10.0-327.77.1.el7"
    "3.10.0-327.77.1.el7"
    "3.10.0-327.77.1.el7"
    "3.10.0-327.78.2.el7"
    "3.10.0-327.78.2.el7"
    "3.10.0-327.78.2.el7"
    "3.10.0-327.79.2.el7"
    "3.10.0-327.79.2.el7"
    "3.10.0-327.79.2.el7"
    "3.10.0-327.80.1.el7"
    "3.10.0-327.80.1.el7"
    "3.10.0-327.80.1.el7"
    "3.10.0-514.el7"
    "3.10.0-514.2.2.el7"
    "3.10.0-514.6.1.el7"
    "3.10.0-514.6.2.el7"
    "3.10.0-514.10.2.el7"
    "3.10.0-514.16.1.el7"
    "3.10.0-514.16.2.p7ih.el7"
    "3.10.0-514.21.1.el7"
    "3.10.0-514.21.2.el7"
    "3.10.0-514.26.1.el7"
    "3.10.0-514.26.2.el7"
    "3.10.0-514.28.1.el7"
    "3.10.0-514.28.2.el7"
    "3.10.0-514.32.2.el7"
    "3.10.0-514.32.3.el7"
    "3.10.0-514.35.1.el7"
    "3.10.0-514.36.1.el7"
    "3.10.0-514.36.5.el7"
    "3.10.0-514.41.1.el7"
    "3.10.0-514.44.1.el7"
    "3.10.0-514.48.1.el7"
    "3.10.0-514.48.3.el7"
    "3.10.0-514.48.5.el7"
    "3.10.0-514.51.1.el7"
    "3.10.0-514.53.1.el7"
    "3.10.0-514.55.4.el7"
    "3.10.0-514.58.1.el7"
    "3.10.0-514.61.1.el7"
    "3.10.0-514.62.1.el7"
    "3.10.0-514.62.1.el7"
    "3.10.0-514.62.1.el7"
    "3.10.0-514.63.1.el7"
    "3.10.0-514.63.1.el7"
    "3.10.0-514.63.1.el7"
    "3.10.0-514.64.2.el7"
    "3.10.0-514.64.2.el7"
    "3.10.0-514.64.2.el7"
    "3.10.0-514.66.2.el7"
    "3.10.0-514.66.2.el7"
    "3.10.0-514.66.2.el7"
    "3.10.0-693.el7"
    "3.10.0-693.1.1.el7"
    "3.10.0-693.2.1.el7"
    "3.10.0-693.2.2.el7"
    "3.10.0-693.5.2.el7"
    "3.10.0-693.5.2.p7ih.el7"
    "3.10.0-693.11.1.el7"
    "3.10.0-693.11.6.el7"
    "3.10.0-693.17.1.el7"
    "3.10.0-693.21.1.el7"
    "3.10.0-693.25.2.el7"
    "3.10.0-693.25.4.el7"
    "3.10.0-693.25.7.el7"
    "3.10.0-693.33.1.el7"
    "3.10.0-693.35.1.el7"
    "3.10.0-693.37.4.el7"
    "3.10.0-693.39.1.el7"
    "3.10.0-693.43.1.el7"
    "3.10.0-693.44.1.el7"
    "3.10.0-693.46.1.el7"
    "3.10.0-693.47.2.el7"
    "3.10.0-693.50.3.el7"
    "3.10.0-693.55.1.el7"
    "3.10.0-693.58.1.el7"
    "3.10.0-861.el7"
    "3.10.0-862.el7"
    "3.10.0-862.2.3.el7"
    "3.10.0-862.3.2.el7"
    "3.10.0-862.3.3.el7"
    "3.10.0-862.6.3.el7"
    "3.10.0-862.9.1.el7"
    "3.10.0-862.11.6.el7"
    "3.10.0-862.14.4.el7"
    "3.10.0-862.20.2.el7"
    "3.10.0-862.25.3.el7"
    "3.10.0-862.27.1.el7"
    "3.10.0-862.29.1.el7"
    "3.10.0-862.32.1.el7"
    "3.10.0-862.32.2.el7"
    "3.10.0-862.34.1.el7"
    "3.10.0-862.34.2.el7"
    "3.10.0-862.37.1.el7"
    "3.10.0-862.41.1.el7"
    "3.10.0-957.el7"
    "3.10.0-957.1.3.el7"
    "3.10.0-957.5.1.el7"
    "3.10.0-957.10.1.el7"
    "3.10.0-957.12.1.el7"
    "3.10.0-957.12.1.el7"
    "3.10.0-957.12.2.el7"
    "3.10.0-957.21.2.el7"
    "3.10.0-957.21.3.el7"
    "3.10.0-957.27.2.el7"
    "3.10.0-957.27.4.el7"
    "3.10.0-1062.el7"
    "3.10.0-1062.1.1.el7"
    "4.18.0-80.el8"
    "4.18.0-80.1.2.el8_0"
    "4.18.0-80.4.2.el8_0"
    "4.18.0-80.7.1.el8_0"
    "4.18.0-80.7.2.el8_0"
    "4.18.0-80.11.1.el8_0"
    "4.18.0-107.el8"
    "4.18.0-128.el8"
    "rt-3.10.0-229.rt56.141.el7"
    "rt-3.10.0-229.1.2.rt56.141.2.el7_1"
    "rt-3.10.0-229.4.2.rt56.141.6.el7_1"
    "rt-3.10.0-229.7.2.rt56.141.6.el7_1"
    "rt-3.10.0-229.11.1.rt56.141.11.el7_1"
    "rt-3.10.0-229.14.1.rt56.141.13.el7_1"
    "rt-3.10.0-229.20.1.rt56.141.14.el7_1"
    "rt-3.10.0-327.rt56.204.el7"
    "rt-3.10.0-327.4.5.rt56.206.el7_2"
    "rt-3.10.0-327.10.1.rt56.211.el7_2"
    "rt-3.10.0-327.13.1.rt56.216.el7_2"
    "rt-3.10.0-327.18.2.rt56.223.el7_2"
    "rt-3.10.0-327.22.2.rt56.230.el7_2"
    "rt-3.10.0-327.28.2.rt56.234.el7_2"
    "rt-3.10.0-327.28.3.rt56.235.el7"
    "rt-3.10.0-327.36.1.rt56.237.el7"
    "rt-3.10.0-327.36.3.rt56.238.el7"
    "rt-3.10.0-514.rt56.420.el7"
    "rt-3.10.0-514.2.2.rt56.424.el7"
    "rt-3.10.0-514.6.1.rt56.429.el7"
    "rt-3.10.0-514.6.1.rt56.430.el7"
    "rt-3.10.0-514.10.2.rt56.435.el7"
    "rt-3.10.0-514.16.1.rt56.437.el7"
    "rt-3.10.0-514.21.1.rt56.438.el7"
    "rt-3.10.0-514.26.1.rt56.442.el7"
    "rt-3.10.0-693.rt56.617.el7"
    "rt-3.10.0-693.2.1.rt56.620.el7"
    "rt-3.10.0-693.2.2.rt56.623.el7"
    "rt-3.10.0-693.5.2.rt56.626.el7"
    "rt-3.10.0-693.11.1.rt56.632.el7"
    "rt-3.10.0-693.11.1.rt56.639.el7"
    "rt-3.10.0-693.17.1.rt56.636.el7"
    "rt-3.10.0-693.21.1.rt56.639.el7"
    "rt-3.10.0-861.rt56.803.el7"
    "rt-3.10.0-862.rt56.804.el7"
    "rt-3.10.0-862.2.3.rt56.806.el7"
    "rt-3.10.0-862.3.2.rt56.808.el7"
    "rt-3.10.0-862.3.3.rt56.809.el7"
    "rt-3.10.0-862.6.3.rt56.811.el7"
    "rt-3.10.0-862.11.6.rt56.819.el7"
    "rt-3.10.0-862.14.4.rt56.821.el7"
    "rt-3.10.0-957.rt56.910.el7"
    "rt-3.10.0-957.1.3.rt56.913.el7"
    "rt-3.10.0-957.5.1.rt56.916.el7"
    "rt-3.10.0-957.10.1.rt56.921.el7"
    "rt-3.10.0-957.12.1.rt56.927.el7"
    "rt-3.10.0-957.12.2.rt56.929.el7"
    "rt-3.10.0-957.21.2.rt56.934.el7"
    "rt-3.10.0-957.21.3.rt56.935.el7"
    "rt-3.10.0-957.27.2.rt56.940.el7"
    "rt-3.10.0-1062.rt56.1022.el7"
    "rt-3.10.0-1062.1.1.rt56.1024.el7"
    "rt-4.18.0-80.rt9.138.el8"
    "rt-4.18.0-80.1.2.rt9.145.el8_0"
    "rt-4.18.0-80.4.2.rt9.152.el8_0"
    "rt-4.18.0-80.7.1.rt9.153.el8_0"
    "rt-4.18.0-80.7.2.rt9.154.el8_0"
    "rt-4.18.0-107.rt20.48.el8"
    "rt-4.18.0-128.rt24.73.el8"
    "rt-4.18.0-135.rt24.80.el8"
    "4.11.0-44.el7a"
    "4.11.0-44.2.1.el7a"
    "4.11.0-44.4.1.el7a"
    "4.11.0-44.6.1.el7a"
    "4.11.0-44.7.1.el7a"
    "4.14.0-49.el7a"
    "4.14.0-49.2.2.el7a"
    "4.14.0-49.8.1.el7a"
    "4.14.0-49.10.1.el7a"
    "4.14.0-49.13.1.el7a"
    "4.14.0-104.el7a"
    "4.14.0-115.el7a"
    "4.14.0-115.2.2.el7a"
    "4.14.0-115.5.1.el7a"
    "4.14.0-115.6.1.el7a"
    "4.14.0-115.7.1.el7a"
    "4.14.0-115.8.1.el7a"
    "4.14.0-115.8.2.el7a"
    "4.14.0-115.10.1.el7a"
)

KPATCH_MODULE_NAMES=(
    "kpatch_3_10_0_957_35_1_1_1"
    "kpatch_3_10_0_1062_1_1"
    "kpatch_3_10_0_1062_1_1_1_1"
)

VULNERABLE_KERNEL_MODULE_NAMES=( "vhost_net" )


basic_args() {
    # Parses basic commandline arguments and sets basic environment.
    #
    # Args:
    #     parameters - an array of commandline arguments
    #
    # Side effects:
    #     Exits if --help parameters is used
    #     Sets COLOR constants and debug variable

    local parameters=( "$@" )

    RED="\\033[1;31m"
    YELLOW="\\033[1;33m"
    GREEN="\\033[1;32m"
    BOLD="\\033[1m"
    RESET="\\033[0m"
    for parameter in "${parameters[@]}"; do
        if [[ "$parameter" == "-h" || "$parameter" == "--help" ]]; then
            echo "Usage: $( basename "$0" ) [-n | --no-colors] [-d | --debug]"
            exit 1
        elif [[ "$parameter" == "-n" || "$parameter" == "--no-colors" ]]; then
            RED=""
            YELLOW=""
            GREEN=""
            BOLD=""
            RESET=""
        elif [[ "$parameter" == "-d" || "$parameter" == "--debug" ]]; then
            debug=true
        fi
    done
}


basic_reqs() {
    # Prints common disclaimer and checks basic requirements.
    #
    # Args:
    #     CVE - string printed in the disclaimer
    #
    # Side effects:
    #     Exits when 'rpm' command is not available

    local CVE="$1"

    # Disclaimer
    echo
    echo -e "${BOLD}This script (v$VERSION) is primarily designed to detect $CVE on supported"
    echo -e "Red Hat Enterprise Linux systems and kernel packages."
    echo -e "Result may be inaccurate for other RPM based systems.${RESET}"
    echo

    # RPM is required
    if ! command -v rpm &> /dev/null; then
        echo "'rpm' command is required, but not installed. Exiting."
        exit 1
    fi
}


check_supported_kernel() {
    # Checks if running kernel is supported.
    #
    # Args:
    #     running_kernel - kernel string as returned by 'uname -r'
    #
    # Side effects:
    #     Exits when running kernel is obviously not supported

    local running_kernel="$1"

    # Check supported platform
    if [[ "$running_kernel" != *".el"[5-8]* ]]; then
        echo -e "${RED}This script is meant to be used only on RHEL 5-8.${RESET}"
        exit 1
    fi
}


get_rhel() {
    # Gets RHEL number.
    #
    # Args:
    #     running_kernel - kernel string as returned by 'uname -r'
    #
    # Prints:
    #     RHEL number, e.g. '5', '6', '7', or '8'

    local running_kernel="$1"

    local rhel
    rhel=$( sed -r -n 's/^.*el([[:digit:]]).*$/\1/p' <<< "$running_kernel" )
    echo "$rhel"
}


check_kernel() {
    # Checks kernel if it is in list of vulnerable kernels.
    #
    # Args:
    #     running_kernel - kernel string as returned by 'uname -r'
    #     vulnerable_versions - an array of vulnerable versions
    #
    # Prints:
    #     Vulnerable kernel string as returned by 'uname -r', or nothing

    local running_kernel="$1"
    shift
    local vulnerable_versions=( "$@" )

    for tested_kernel in "${vulnerable_versions[@]}"; do
        if [[ "$running_kernel" == *"$tested_kernel"* ]]; then
            echo "$running_kernel"
            break
        fi
    done
}


check_kpatch() {
    # Checks if specific kpatch listed in a kpatch list is applied.
    #
    # Args:
    #     kpatch_module_names - an array of kpatches
    #
    # Prints:
    #     Found kpatch, or nothing

    local kpatch_module_names=( "$@" )
    local modules

    # Get loaded kernel modules
    modules=$( lsmod )

    # Check if kpatch is installed
    for tested_kpatch in "${kpatch_module_names[@]}"; do
        if [[ "$modules" == *"$tested_kpatch"* ]]; then
            echo "$tested_kpatch"
            break
        fi
    done
}


check_kernel_modules() {
    # Checks if modules listed in a list are loaded.
    #
    # Args:
    #     kernel_module_names - an array of kernel module names
    #
    # Prints:
    #     Found kernel module names as one string, or an empty string

    local kernel_module_names=( "$@" )
    local modules
    local matching_modules=()

    # Get loaded kernel modules
    modules=$( lsmod )

    for tested_module in "${kernel_module_names[@]}"; do
        if [[ "$modules" == *"$tested_module"* ]]; then
            matching_modules+=( "$tested_module" )
        fi
    done

    echo "${matching_modules[*]}"
}


get_installed_packages() {
    # Checks for installed packages of a 'package_name'. Compatible with RHEL5.
    #
    # Args:
    #     package_name - package name string
    #
    # Prints:
    #     Lines with N-V-R.A strings of all installed packages.

    local package_name="$1"

    rpm -qa --queryformat="%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n" "$package_name"
}


check_all_modules_blacklisted() {
    # Checks if all specified kernel modules are blacklisted.
    #
    # Args:
    #     module_names - an array of kernel modules to be checked
    #
    # Returns:
    #     0 if all modules were blacklisted, 1 otherwise
    #
    # Notes:
    #     MOCK_MODPROBE_PATH can be used to mock /etc/modprobe.d directory

    local modprobe_dir=${MOCK_MODPROBE_PATH:-/etc/modprobe.d}

    local module_names=( "$@" )
    local mitigation_patterns=()
    local current_pattern_found

    # Prepare regular expressions
    for module_name in "${module_names[@]}"; do
        mitigation_patterns+=( "^[[:space:]]*install[[:space:]]+${module_name}[[:space:]]+/bin/(true|false)" )
    done

    # Check if all patterns are found at least once
    for pattern in "${mitigation_patterns[@]}"; do
        current_pattern_found=0
        # Check recommended mitigation
        for file in "$modprobe_dir/"*; do
            if grep -E --quiet "$pattern" "$file"; then
                current_pattern_found=1
                break
            fi
        done
        if (( ! current_pattern_found )); then
            return 1  # No need to search for the rest of the patterns, already have the answer
        fi
    done

    return 0
}


set_default_values() {
    result=2
    vulnerable=0
    mitigation_kpatch=0
    mitigation_blacklisting=0
    virtualization=0
}


parse_facts() {
    # Gathers all available information and stores it in global variables. Only store facts and
    # do not draw conclusion in this function for better maintainability.
    #
    # Side effects:
    #     Sets many global boolean flags and content variables

    vulnerable_kernel=$( check_kernel "$running_kernel" "${VULNERABLE_KERNELS[@]}" )
    applied_kpatch=$( check_kpatch "${KPATCH_MODULE_NAMES[@]}" )
    vulnerable_loaded_kernel_modules=$( check_kernel_modules "${VULNERABLE_KERNEL_MODULE_NAMES[@]}" )
    libvirtd_running=$( pgrep libvirtd )
    installed_libvirt=$( get_installed_packages "libvirt-*" )

    check_all_modules_blacklisted "${VULNERABLE_KERNEL_MODULE_NAMES[@]}"
    # Store result as a flag, 1 as True, 0 as False
    # shellcheck disable=SC2181
    all_vulnerable_modules_loading_disabled=$(( !$? ))
}

draw_conclusions() {
    # Draws conclusions based on available system data.
    #
    # Side effects:
    #     Sets many global boolean flags and content variables

    if [[ "$vulnerable_kernel" ]]; then
        vulnerable=1
    fi

    if [[ "$applied_kpatch" ]]; then
        mitigation_kpatch=1
    fi

    if [[ ! "$vulnerable_loaded_kernel_modules" && "$all_vulnerable_modules_loading_disabled" == 1 ]]; then
        mitigation_blacklisting=1
    fi

    if [[ "$installed_libvirt" || "$libvirtd_running" || "$vulnerable_loaded_kernel_modules" ]]; then
        virtualization=1
    fi

    if (( ! vulnerable || mitigation_kpatch || mitigation_blacklisting || ! virtualization )); then
        result=0
    fi
}


debug_print() {
    # Prints selected variables when debugging is enabled.

    variables=( running_kernel rhel vulnerable_kernel applied_kpatch vulnerable_loaded_kernel_modules
        libvirtd_running installed_libvirt all_vulnerable_modules_loading_disabled
        vulnerable mitigation_kpatch mitigation_blacklisting virtualization )
    for variable in "${variables[@]}"; do
        echo "$variable = *${!variable}*"
    done
    echo
}


if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
    basic_args "$@"
    basic_reqs "CVE-2019-14835"
    running_kernel=$( uname -r )
    check_supported_kernel "$running_kernel"

    rhel=$( get_rhel "$running_kernel" )
    if (( rhel == 5 )); then
        export PATH="/sbin:/usr/sbin:$PATH"
    fi

    set_default_values
    parse_facts
    draw_conclusions

    # Debug prints
    if [[ "$debug" ]]; then
        debug_print
    fi

    # Results
    echo -e "This system is running kernel ${BOLD}${running_kernel}${RESET}"
    echo

    if (( vulnerable )); then
        if (( mitigation_kpatch )); then
            echo -e "${YELLOW}This kernel version is vulnerable.${RESET}"
            echo -e "${GREEN}The correct kpatch is applied${RESET} so"
            echo -e "the vulnerability is not exploitable."
        elif (( mitigation_blacklisting )); then
            echo -e "${YELLOW}This kernel version is vulnerable.${RESET}"
            echo -e "${GREEN}The vhost_net kernel module is blacklisted${RESET} so"
            echo -e "the vulnerability is not exploitable."
        elif (( ! virtualization )); then
            echo -e "${YELLOW}This kernel version is vulnerable.${RESET}"
            echo -e "${GREEN}This system does not seem to be a virtualization host.${RESET}"
            echo -e "vhost_net kernel module is not loaded and libvirtd does not seem to be used."
            echo -e "This vulnerability is only exploitable by untrusted virtualization guests."
        else
            echo -e "${RED}This kernel version is vulnerable.${RESET}"
            echo -e "This system seems to be a virtualization host."
        fi
    else
        echo -e "${GREEN}This kernel version is not affected.${RESET}"
    fi
    echo
    echo -e "For more information about this vulnerability, see:"
    echo -e "${ARTICLE}"

    exit "$result"
fi
