Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Leap:15.1:PowerPC
spectre-meltdown-checker
spectre-meltdown-checker-0.40.obscpio
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File spectre-meltdown-checker-0.40.obscpio of Package spectre-meltdown-checker
07070101CC3DAD000081A40000294E00000032000000015B0EA6ED0000894B000000080000000700000000000000000000002600000000spectre-meltdown-checker-0.40/LICENSE GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the program's name and a brief idea of what it does.> Copyright (C) <year> <name of author> 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. 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/>. Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: <program> Copyright (C) <year> <name of author> This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see <http://www.gnu.org/licenses/>. The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read <http://www.gnu.org/philosophy/why-not-lgpl.html>. 07070101CC677C000081A40000294E00000032000000015C8B3EB9000000BD000000080000000700000000000000000000002900000000spectre-meltdown-checker-0.40/DockerfileFROM alpine:3.7 RUN apk --update --no-cache add kmod binutils grep perl COPY . /check ENTRYPOINT ["/check/spectre-meltdown-checker.sh"] VOLUME /boot VOLUME /dev/cpu VOLUME /lib/modules 07070101CC7345000081ED0000294E00000032000000015C8B3EB900026C56000000080000000700000000000000000000003A00000000spectre-meltdown-checker-0.40/spectre-meltdown-checker.sh#! /bin/sh # SPDX-License-Identifier: GPL-3.0-only # # Spectre & Meltdown checker # # Check for the latest version at: # https://github.com/speed47/spectre-meltdown-checker # git clone https://github.com/speed47/spectre-meltdown-checker.git # or wget https://meltdown.ovh -O spectre-meltdown-checker.sh # or curl -L https://meltdown.ovh -o spectre-meltdown-checker.sh # # Stephane Lesimple # VERSION='0.40' trap 'exit_cleanup' EXIT trap '_warn "interrupted, cleaning up..."; exit_cleanup; exit 1' INT exit_cleanup() { # cleanup the temp decompressed config & kernel image [ -n "$dumped_config" ] && [ -f "$dumped_config" ] && rm -f "$dumped_config" [ -n "$kerneltmp" ] && [ -f "$kerneltmp" ] && rm -f "$kerneltmp" [ -n "$kerneltmp2" ] && [ -f "$kerneltmp2" ] && rm -f "$kerneltmp2" [ -n "$mcedb_tmp" ] && [ -f "$mcedb_tmp" ] && rm -f "$mcedb_tmp" [ "$mounted_debugfs" = 1 ] && umount /sys/kernel/debug 2>/dev/null [ "$mounted_procfs" = 1 ] && umount "$procfs" 2>/dev/null [ "$insmod_cpuid" = 1 ] && rmmod cpuid 2>/dev/null [ "$insmod_msr" = 1 ] && rmmod msr 2>/dev/null [ "$kldload_cpuctl" = 1 ] && kldunload cpuctl 2>/dev/null } # if we were git clone'd, adjust VERSION if [ -d "$(dirname "$0")/.git" ] && which git >/dev/null 2>&1; then describe=$(git -C "$(dirname "$0")" describe --tags --dirty 2>/dev/null) [ -n "$describe" ] && VERSION=$(echo "$describe" | sed -e s/^v//) fi show_usage() { # shellcheck disable=SC2086 cat <<EOF Usage: Live mode: $(basename $0) [options] [--live] Offline mode: $(basename $0) [options] [--kernel <kernel_file>] [--config <kernel_config>] [--map <kernel_map_file>] Modes: Two modes are available. First mode is the "live" mode (default), it does its best to find information about the currently running kernel. To run under this mode, just start the script without any option (you can also use --live explicitly) Second mode is the "offline" mode, where you can inspect a non-running kernel. You'll need to specify the location of the kernel file, config and System.map files: --kernel kernel_file specify a (possibly compressed) Linux or BSD kernel file --config kernel_config specify a kernel config file (Linux only) --map kernel_map_file specify a kernel System.map file (Linux only) Options: --no-color don't use color codes --verbose, -v increase verbosity level, possibly several times --explain produce an additional human-readable explanation of actions to take to mitigate a vulnerability --paranoid require IBPB to deem Variant 2 as mitigated also require SMT disabled + unconditional L1D flush to deem Foreshadow-NG VMM as mitigated --no-sysfs don't use the /sys interface even if present [Linux] --sysfs-only only use the /sys interface, don't run our own checks [Linux] --coreos special mode for CoreOS (use an ephemeral toolbox to inspect kernel) [Linux] --arch-prefix PREFIX specify a prefix for cross-inspecting a kernel of a different arch, for example "aarch64-linux-gnu-", so that invoked tools will be prefixed with this (i.e. aarch64-linux-gnu-objdump) --batch text produce machine readable output, this is the default if --batch is specified alone --batch short produce only one line with the vulnerabilities separated by spaces --batch json produce JSON output formatted for Puppet, Ansible, Chef... --batch nrpe produce machine readable output formatted for NRPE --batch prometheus produce output for consumption by prometheus-node-exporter --variant [1,2,3,3a,4,l1tf] specify which variant you'd like to check, by default all variants are checked --cve [cve1,cve2,...] specify which CVE you'd like to check, by default all supported CVEs are checked can be specified multiple times (e.g. --variant 2 --variant 3) --hw-only only check for CPU information, don't check for any variant --no-hw skip CPU information and checks, if you're inspecting a kernel not to be run on this host --vmm [auto,yes,no] override the detection of the presence of an hypervisor (for CVE-2018-3646), default: auto --update-mcedb update our local copy of the CPU microcodes versions database (from the awesome MCExtractor project) --update-builtin-mcedb same as --update-mcedb but update builtin DB inside the script itself Return codes: 0 (not vulnerable), 2 (vulnerable), 3 (unknown), 255 (error) IMPORTANT: A false sense of security is worse than no security at all. Please use the --disclaimer option to understand exactly what this script does. EOF } show_disclaimer() { cat <<EOF Disclaimer: This tool does its best to determine whether your system is immune (or has proper mitigations in place) for the collectively named "speculative execution" vulnerabilities. It doesn't attempt to run any kind of exploit, and can't guarantee that your system is secure, but rather helps you verifying whether your system has the known correct mitigations in place. However, some mitigations could also exist in your kernel that this script doesn't know (yet) how to detect, or it might falsely detect mitigations that in the end don't work as expected (for example, on backported or modified kernels). Your system exposure also depends on your CPU. As of now, AMD and ARM processors are marked as immune to some or all of these vulnerabilities (except some specific ARM models). All Intel processors manufactured since circa 1995 are thought to be vulnerable, except some specific/old models, such as some early Atoms. Whatever processor one uses, one might seek more information from the manufacturer of that processor and/or of the device in which it runs. The nature of the discovered vulnerabilities being quite new, the landscape of vulnerable processors can be expected to change over time, which is why this script makes the assumption that all CPUs are vulnerable, except if the manufacturer explicitly stated otherwise in a verifiable public announcement. Please also note that for Spectre vulnerabilities, all software can possibly be exploited, this tool only verifies that the kernel (which is the core of the system) you're using has the proper protections in place. Verifying all the other software is out of the scope of this tool. As a general measure, ensure you always have the most up to date stable versions of all the software you use, especially for those who are exposed to the world, such as network daemons and browsers. This tool has been released in the hope that it'll be useful, but don't use it to jump to conclusions about your security. EOF } os=$(uname -s) # parse options opt_kernel='' opt_config='' opt_map='' opt_live_explicit=0 opt_live=1 opt_no_color=0 opt_batch=0 opt_batch_format="text" opt_verbose=1 opt_cve_list='' opt_cve_all=1 opt_no_sysfs=0 opt_sysfs_only=0 opt_coreos=0 opt_arch_prefix='' opt_hw_only=0 opt_no_hw=0 opt_vmm=-1 opt_explain=0 opt_paranoid=0 global_critical=0 global_unknown=0 nrpe_vuln="" supported_cve_list='CVE-2017-5753 CVE-2017-5715 CVE-2017-5754 CVE-2018-3640 CVE-2018-3639 CVE-2018-3615 CVE-2018-3620 CVE-2018-3646' # find a sane command to print colored messages, we prefer `printf` over `echo` # because `printf` behavior is more standard across Linux/BSD # we'll try to avoid using shell builtins that might not take options echo_cmd_type=echo if which printf >/dev/null 2>&1; then echo_cmd=$(which printf) echo_cmd_type=printf elif which echo >/dev/null 2>&1; then echo_cmd=$(which echo) else # maybe the `which` command is broken? [ -x /bin/echo ] && echo_cmd=/bin/echo # for Android [ -x /system/bin/echo ] && echo_cmd=/system/bin/echo fi # still empty? fallback to builtin [ -z "$echo_cmd" ] && echo_cmd=echo __echo() { opt="$1" shift _msg="$*" if [ "$opt_no_color" = 1 ] ; then # strip ANSI color codes # some sed versions (i.e. toybox) can't seem to handle # \033 aka \x1B correctly, so do it for them. if [ "$echo_cmd_type" = printf ]; then _interpret_chars='' else _interpret_chars='-e' fi _ctrlchar=$($echo_cmd $_interpret_chars "\033") _msg=$($echo_cmd $_interpret_chars "$_msg" | sed -r "s/$_ctrlchar\[([0-9][0-9]?(;[0-9][0-9]?)?)?m//g") fi if [ "$echo_cmd_type" = printf ]; then if [ "$opt" = "-n" ]; then $echo_cmd "$_msg" else $echo_cmd "$_msg\n" fi else # shellcheck disable=SC2086 $echo_cmd $opt -e "$_msg" fi } _echo() { if [ "$opt_verbose" -ge "$1" ]; then shift __echo '' "$*" fi } _echo_nol() { if [ "$opt_verbose" -ge "$1" ]; then shift __echo -n "$*" fi } _warn() { _echo 0 "\033[31m$*\033[0m" >&2 } _info() { _echo 1 "$*" } _info_nol() { _echo_nol 1 "$*" } _verbose() { _echo 2 "$*" } _verbose_nol() { _echo_nol 2 "$*" } _debug() { _echo 3 "\033[34m(debug) $*\033[0m" } explain() { if [ "$opt_explain" = 1 ] ; then _info '' _info "> \033[41m\033[30mHow to fix:\033[0m $*" fi } cve2name() { case "$1" in CVE-2017-5753) echo "Spectre Variant 1, bounds check bypass";; CVE-2017-5715) echo "Spectre Variant 2, branch target injection";; CVE-2017-5754) echo "Variant 3, Meltdown, rogue data cache load";; CVE-2018-3640) echo "Variant 3a, rogue system register read";; CVE-2018-3639) echo "Variant 4, speculative store bypass";; CVE-2018-3615) echo "Foreshadow (SGX), L1 terminal fault";; CVE-2018-3620) echo "Foreshadow-NG (OS), L1 terminal fault";; CVE-2018-3646) echo "Foreshadow-NG (VMM), L1 terminal fault";; esac } is_cpu_vulnerable_cached=0 _is_cpu_vulnerable_cached() { # shellcheck disable=SC2086 case "$1" in CVE-2017-5753) return $variant1;; CVE-2017-5715) return $variant2;; CVE-2017-5754) return $variant3;; CVE-2018-3640) return $variant3a;; CVE-2018-3639) return $variant4;; CVE-2018-3615) return $variantl1tf_sgx;; CVE-2018-3620) return $variantl1tf;; CVE-2018-3646) return $variantl1tf;; esac echo "$0: error: invalid variant '$1' passed to is_cpu_vulnerable()" >&2 exit 255 } is_cpu_vulnerable() { # param: one of the $supported_cve_list items # returns 0 if vulnerable, 1 if not vulnerable # (note that in shell, a return of 0 is success) # by default, everything is vulnerable, we work in a "whitelist" logic here. # usage: is_cpu_vulnerable CVE-xxxx-yyyy && do something if vulnerable if [ "$is_cpu_vulnerable_cached" = 1 ]; then _is_cpu_vulnerable_cached "$1" return $? fi variant1='' variant2='' variant3='' variant3a='' variant4='' variantl1tf='' if is_cpu_specex_free; then variant1=immune variant2=immune variant3=immune variant3a=immune variant4=immune variantl1tf=immune elif is_intel; then # Intel # https://github.com/crozone/SpectrePoC/issues/1 ^F E5200 => spectre 2 not vulnerable # https://github.com/paboldin/meltdown-exploit/issues/19 ^F E5200 => meltdown vulnerable # model name : Pentium(R) Dual-Core CPU E5200 @ 2.50GHz if grep -qE '^model name.+ Pentium\(R\) Dual-Core[[:space:]]+CPU[[:space:]]+E[0-9]{4}K? ' "$procfs/cpuinfo"; then variant1=vuln [ -z "$variant2" ] && variant2=immune variant3=vuln fi if [ "$capabilities_rdcl_no" = 1 ]; then # capability bit for future Intel processor that will explicitly state # that they're not vulnerable to Meltdown # this var is set in check_cpu() [ -z "$variant3" ] && variant3=immune [ -z "$variantl1tf" ] && variantl1tf=immune _debug "is_cpu_vulnerable: RDCL_NO is set so not vuln to meltdown nor l1tf" fi if [ "$capabilities_ssb_no" = 1 ]; then # capability bit for future Intel processor that will explicitly state # that they're not vulnerable to Variant 4 # this var is set in check_cpu() [ -z "$variant4" ] && variant4=immune _debug "is_cpu_vulnerable: SSB_NO is set so not vuln to variant4" fi if is_cpu_ssb_free; then [ -z "$variant4" ] && variant4=immune _debug "is_cpu_vulnerable: cpu not affected by speculative store bypass so not vuln to variant4" fi # variant 4a for xeon phi if [ "$cpu_family" = 6 ]; then if [ "$cpu_model" = "$INTEL_FAM6_XEON_PHI_KNL" ] || [ "$cpu_model" = "$INTEL_FAM6_XEON_PHI_KNM" ]; then _debug "is_cpu_vulnerable: xeon phi immune to variant 3a" [ -z "$variant3a" ] && variant3a=immune fi fi # L1TF (RDCL_NO already checked above) if [ "$cpu_family" = 6 ]; then if [ "$cpu_model" = "$INTEL_FAM6_ATOM_CEDARVIEW" ] || \ [ "$cpu_model" = "$INTEL_FAM6_ATOM_CLOVERVIEW" ] || \ [ "$cpu_model" = "$INTEL_FAM6_ATOM_LINCROFT" ] || \ [ "$cpu_model" = "$INTEL_FAM6_ATOM_PENWELL" ] || \ [ "$cpu_model" = "$INTEL_FAM6_ATOM_PINEVIEW" ] || \ [ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT1" ] || \ [ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT2" ] || \ [ "$cpu_model" = "$INTEL_FAM6_ATOM_AIRMONT" ] || \ [ "$cpu_model" = "$INTEL_FAM6_ATOM_MERRIFIELD" ] || \ [ "$cpu_model" = "$INTEL_FAM6_XEON_PHI_KNL" ] || \ [ "$cpu_model" = "$INTEL_FAM6_XEON_PHI_KNM" ]; then _debug "is_cpu_vulnerable: intel family 6 but model known to be immune" [ -z "$variantl1tf" ] && variantl1tf=immune else _debug "is_cpu_vulnerable: intel family 6 is vuln" variantl1tf=vuln fi elif [ "$cpu_family" -lt 6 ]; then _debug "is_cpu_vulnerable: intel family < 6 is immune" [ -z "$variantl1tf" ] && variantl1tf=immune fi elif is_amd; then # AMD revised their statement about variant2 => vulnerable # https://www.amd.com/en/corporate/speculative-execution variant1=vuln variant2=vuln [ -z "$variant3" ] && variant3=immune # https://www.amd.com/en/corporate/security-updates # "We have not identified any AMD x86 products susceptible to the Variant 3a vulnerability in our analysis to-date." [ -z "$variant3a" ] && variant3a=immune if is_cpu_ssb_free; then [ -z "$variant4" ] && variant4=immune _debug "is_cpu_vulnerable: cpu not affected by speculative store bypass so not vuln to variant4" fi variantl1tf=immune elif [ "$cpu_vendor" = CAVIUM ]; then variant3=immune variant3a=immune variantl1tf=immune elif [ "$cpu_vendor" = ARM ]; then # ARM # reference: https://developer.arm.com/support/security-update # some devices (phones or other) have several ARMs and as such different part numbers, # an example is "bigLITTLE". we shouldn't rely on the first CPU only, so we check the whole list i=0 for cpupart in $cpu_part_list do i=$(( i + 1 )) # do NOT quote $cpu_arch_list below # shellcheck disable=SC2086 cpuarch=$(echo $cpu_arch_list | awk '{ print $'$i' }') _debug "checking cpu$i: <$cpupart> <$cpuarch>" # some kernels report AArch64 instead of 8 [ "$cpuarch" = "AArch64" ] && cpuarch=8 if [ -n "$cpupart" ] && [ -n "$cpuarch" ]; then # Cortex-R7 and Cortex-R8 are real-time and only used in medical devices or such # I can't find their CPU part number, but it's probably not that useful anyway # model R7 R8 A8 A9 A12 A15 A17 A57 A72 A73 A75 A76 # part ? ? c08 c09 c0d c0f c0e d07 d08 d09 d0a d0b? # arch 7? 7? 7 7 7 7 7 8 8 8 8 8 # # Whitelist identified non-vulnerable processors, use vulnerability information from # https://developer.arm.com/support/arm-security-updates/speculative-processor-vulnerability # # Maintain cumulative check of vulnerabilities - # if at least one of the cpu is vulnerable, then the system is vulnerable if [ "$cpuarch" = 7 ] && echo "$cpupart" | grep -q -w -e 0xc08 -e 0xc09 -e 0xc0d -e 0xc0e; then variant1=vuln variant2=vuln [ -z "$variant3" ] && variant3=immune [ -z "$variant3a" ] && variant3a=immune [ -z "$variant4" ] && variant4=immune _debug "checking cpu$i: armv7 A8/A9/A12/A17 non vulnerable to variants 3, 3a & 4" elif [ "$cpuarch" = 7 ] && echo "$cpupart" | grep -q -w -e 0xc0f; then variant1=vuln variant2=vuln [ -z "$variant3" ] && variant3=immune variant3a=vuln [ -z "$variant4" ] && variant4=immune _debug "checking cpu$i: armv7 A15 non vulnerable to variants 3 & 4" elif [ "$cpuarch" = 8 ] && echo "$cpupart" | grep -q -w -e 0xd07 -e 0xd08; then variant1=vuln variant2=vuln [ -z "$variant3" ] && variant3=immune variant3a=vuln variant4=vuln _debug "checking cpu$i: armv8 A57/A72 non vulnerable to variants 3" elif [ "$cpuarch" = 8 ] && echo "$cpupart" | grep -q -w -e 0xd09; then variant1=vuln variant2=vuln [ -z "$variant3" ] && variant3=immune [ -z "$variant3a" ] && variant3a=immune variant4=vuln _debug "checking cpu$i: armv8 A73 non vulnerable to variants 3 & 3a" elif [ "$cpuarch" = 8 ] && echo "$cpupart" | grep -q -w -e 0xd0a; then variant1=vuln variant2=vuln variant3=vuln [ -z "$variant3a" ] && variant3a=immune variant4=vuln _debug "checking cpu$i: armv8 A75 non vulnerable to variant 3a" elif [ "$cpuarch" = 8 ] && echo "$cpupart" | grep -q -w -e 0xd0b; then variant1=vuln [ -z "$variant2" ] && variant2=immune [ -z "$variant3" ] && variant3=immune [ -z "$variant3a" ] && variant3a=immune variant4=vuln _debug "checking cpu$i: armv8 A76 non vulnerable to variant 2, 3 & 3a" elif [ "$cpuarch" -le 7 ] || ( [ "$cpuarch" = 8 ] && [ $(( cpupart )) -lt $(( 0xd07 )) ] ) ; then [ -z "$variant1" ] && variant1=immune [ -z "$variant2" ] && variant2=immune [ -z "$variant3" ] && variant3=immune [ -z "$variant3a" ] && variant3a=immune [ -z "$variant4" ] && variant4=immune _debug "checking cpu$i: arm arch$cpuarch, all immune (v7 or v8 and model < 0xd07)" else variant1=vuln variant2=vuln variant3=vuln variant3a=vuln variant4=vuln _debug "checking cpu$i: arm unknown arch$cpuarch part$cpupart, considering vuln" fi fi _debug "is_cpu_vulnerable: for cpu$i and so far, we have <$variant1> <$variant2> <$variant3> <$variant3a> <$variant4>" done variantl1tf=immune fi _debug "is_cpu_vulnerable: temp results are <$variant1> <$variant2> <$variant3> <$variant3a> <$variant4> <$variantl1tf>" [ "$variant1" = "immune" ] && variant1=1 || variant1=0 [ "$variant2" = "immune" ] && variant2=1 || variant2=0 [ "$variant3" = "immune" ] && variant3=1 || variant3=0 [ "$variant3a" = "immune" ] && variant3a=1 || variant3a=0 [ "$variant4" = "immune" ] && variant4=1 || variant4=0 [ "$variantl1tf" = "immune" ] && variantl1tf=1 || variantl1tf=0 variantl1tf_sgx="$variantl1tf" # even if we are vulnerable to L1TF, if there's no SGX, we're safe for the original foreshadow [ "$cpuid_sgx" = 0 ] && variantl1tf_sgx=1 _debug "is_cpu_vulnerable: final results are <$variant1> <$variant2> <$variant3> <$variant3a> <$variant4> <$variantl1tf> <$variantl1tf_sgx>" is_cpu_vulnerable_cached=1 _is_cpu_vulnerable_cached "$1" return $? } is_cpu_specex_free() { # return true (0) if the CPU doesn't do speculative execution, false (1) if it does. # if it's not in the list we know, return false (1). # source: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/kernel/cpu/common.c#n882 # { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_CEDARVIEW, X86_FEATURE_ANY }, # { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_CLOVERVIEW, X86_FEATURE_ANY }, # { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_LINCROFT, X86_FEATURE_ANY }, # { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_PENWELL, X86_FEATURE_ANY }, # { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_PINEVIEW, X86_FEATURE_ANY }, # { X86_VENDOR_CENTAUR, 5 }, # { X86_VENDOR_INTEL, 5 }, # { X86_VENDOR_NSC, 5 }, # { X86_VENDOR_ANY, 4 }, parse_cpu_details if is_intel; then if [ "$cpu_family" = 6 ]; then if [ "$cpu_model" = "$INTEL_FAM6_ATOM_CEDARVIEW" ] || \ [ "$cpu_model" = "$INTEL_FAM6_ATOM_CLOVERVIEW" ] || \ [ "$cpu_model" = "$INTEL_FAM6_ATOM_LINCROFT" ] || \ [ "$cpu_model" = "$INTEL_FAM6_ATOM_PENWELL" ] || \ [ "$cpu_model" = "$INTEL_FAM6_ATOM_PINEVIEW" ]; then return 0 fi elif [ "$cpu_family" = 5 ]; then return 0 fi fi [ "$cpu_family" = 4 ] && return 0 return 1 } is_cpu_ssb_free() { # return true (0) if the CPU isn't affected by speculative store bypass, false (1) if it does. # if it's not in the list we know, return false (1). # source1: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/kernel/cpu/common.c#n945 # source2: https://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git/tree/arch/x86/kernel/cpu/common.c # Only list CPUs that speculate but are immune, to avoid duplication of cpus listed in is_cpu_specex_free() #{ X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT1 }, #{ X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_AIRMONT }, #{ X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT2 }, #{ X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_MERRIFIELD }, #{ X86_VENDOR_INTEL, 6, INTEL_FAM6_CORE_YONAH }, #{ X86_VENDOR_INTEL, 6, INTEL_FAM6_XEON_PHI_KNL }, #{ X86_VENDOR_INTEL, 6, INTEL_FAM6_XEON_PHI_KNM }, #{ X86_VENDOR_AMD, 0x12, }, #{ X86_VENDOR_AMD, 0x11, }, #{ X86_VENDOR_AMD, 0x10, }, #{ X86_VENDOR_AMD, 0xf, }, parse_cpu_details if is_intel; then if [ "$cpu_family" = 6 ]; then if [ "$cpu_model" = "$INTEL_FAM6_ATOM_AIRMONT" ] || \ [ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT1" ] || \ [ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT2" ] || \ [ "$cpu_model" = "$INTEL_FAM6_ATOM_MERRIFIELD" ]; then return 0 elif [ "$cpu_model" = "$INTEL_FAM6_CORE_YONAH" ] || \ [ "$cpu_model" = "$INTEL_FAM6_XEON_PHI_KNL" ] || \ [ "$cpu_model" = "$INTEL_FAM6_XEON_PHI_KNM" ]; then return 0 fi fi fi if is_amd; then if [ "$cpu_family" = "18" ] || \ [ "$cpu_family" = "17" ] || \ [ "$cpu_family" = "16" ] || \ [ "$cpu_family" = "15" ]; then return 0 fi fi [ "$cpu_family" = 4 ] && return 0 return 1 } show_header() { _info "Spectre and Meltdown mitigation detection tool v$VERSION" _info } [ -z "$HOME" ] && HOME="$(getent passwd "$(whoami)" | cut -d: -f6)" mcedb_cache="$HOME/.mcedb" update_mcedb() { # We're using MCE.db from the excellent platomav's MCExtractor project show_header if [ -r "$mcedb_cache" ]; then previous_mcedb_revision=$(awk '/^# %%% MCEDB / { print $4 }' "$mcedb_cache") fi # first download the database mcedb_tmp="$(mktemp /tmp/mcedb-XXXXXX)" mcedb_url='https://github.com/platomav/MCExtractor/raw/master/MCE.db' _info_nol "Fetching MCE.db from the MCExtractor project... " if which wget >/dev/null 2>&1; then wget -q "$mcedb_url" -O "$mcedb_tmp"; ret=$? elif which curl >/dev/null 2>&1; then curl -sL "$mcedb_url" -o "$mcedb_tmp"; ret=$? elif which fetch >/dev/null 2>&1; then fetch -q "$mcedb_url" -o "$mcedb_tmp"; ret=$? else echo ERROR "please install one of \`wget\`, \`curl\` of \`fetch\` programs" return 1 fi if [ "$ret" != 0 ]; then echo ERROR "error $ret while downloading MCE.db" return $ret fi echo DONE # now extract contents using sqlite _info_nol "Extracting data... " if ! which sqlite3 >/dev/null 2>&1; then echo ERROR "please install the \`sqlite3\` program" return 1 fi mcedb_revision=$(sqlite3 "$mcedb_tmp" "select revision from MCE") mcedb_date=$(sqlite3 "$mcedb_tmp" "select strftime('%Y/%m/%d', date, 'unixepoch') from MCE") if [ -z "$mcedb_revision" ]; then echo ERROR "downloaded file seems invalid" return 1 fi echo OK "MCExtractor database revision $mcedb_revision dated $mcedb_date" if [ -n "$previous_mcedb_revision" ]; then if [ "$previous_mcedb_revision" = "v$mcedb_revision" ]; then echo "We already have this version locally, no update needed" [ "$1" != builtin ] && return 0 fi fi echo "# Spectre & Meltdown Checker" > "$mcedb_cache" echo "# %%% MCEDB v$mcedb_revision - $mcedb_date" >> "$mcedb_cache" sqlite3 "$mcedb_tmp" "select '# I,0x'||cpuid||',0x'||version||','||max(yyyymmdd) from Intel group by cpuid order by cpuid asc; select '# A,0x'||cpuid||',0x'||version||','||max(yyyymmdd) from AMD group by cpuid order by cpuid asc" | grep -v '^# .,0x00000000,' >> "$mcedb_cache" echo OK "local version updated" if [ "$1" = builtin ]; then newfile=$(mktemp /tmp/smc-XXXXXX) awk '/^# %%% MCEDB / { exit }; { print }' "$0" > "$newfile" awk '{ if (NR>1) { print } }' "$mcedb_cache" >> "$newfile" cat "$newfile" > "$0" rm -f "$newfile" fi } parse_opt_file() { # parse_opt_file option_name option_value option_name="$1" option_value="$2" if [ -z "$option_value" ]; then show_header show_usage echo "$0: error: --$option_name expects one parameter (a file)" >&2 exit 1 elif [ ! -e "$option_value" ]; then show_header echo "$0: error: couldn't find file $option_value" >&2 exit 1 elif [ ! -f "$option_value" ]; then show_header echo "$0: error: $option_value is not a file" >&2 exit 1 elif [ ! -r "$option_value" ]; then show_header echo "$0: error: couldn't read $option_value (are you root?)" >&2 exit 1 fi echo "$option_value" exit 0 } while [ -n "$1" ]; do if [ "$1" = "--kernel" ]; then opt_kernel=$(parse_opt_file kernel "$2"); ret=$? [ $ret -ne 0 ] && exit 255 shift 2 opt_live=0 elif [ "$1" = "--config" ]; then opt_config=$(parse_opt_file config "$2"); ret=$? [ $ret -ne 0 ] && exit 255 shift 2 opt_live=0 elif [ "$1" = "--map" ]; then opt_map=$(parse_opt_file map "$2"); ret=$? [ $ret -ne 0 ] && exit 255 shift 2 opt_live=0 elif [ "$1" = "--arch-prefix" ]; then opt_arch_prefix="$2" shift 2 elif [ "$1" = "--live" ]; then opt_live_explicit=1 shift elif [ "$1" = "--no-color" ]; then opt_no_color=1 shift elif [ "$1" = "--no-sysfs" ]; then opt_no_sysfs=1 shift elif [ "$1" = "--sysfs-only" ]; then opt_sysfs_only=1 shift elif [ "$1" = "--coreos" ]; then opt_coreos=1 shift elif [ "$1" = "--coreos-within-toolbox" ]; then # don't use directly: used internally by --coreos opt_coreos=0 shift elif [ "$1" = "--paranoid" ]; then opt_paranoid=1 shift elif [ "$1" = "--hw-only" ]; then opt_hw_only=1 shift elif [ "$1" = "--no-hw" ]; then opt_no_hw=1 shift elif [ "$1" = "--no-explain" ]; then # deprecated, kept for compatibility opt_explain=0 shift elif [ "$1" = "--update-mcedb" ]; then update_mcedb exit $? elif [ "$1" = "--update-builtin-mcedb" ]; then update_mcedb builtin exit $? elif [ "$1" = "--explain" ]; then opt_explain=1 shift elif [ "$1" = "--batch" ]; then opt_batch=1 opt_verbose=0 opt_no_color=1 shift case "$1" in text|short|nrpe|json|prometheus) opt_batch_format="$1"; shift;; --*) ;; # allow subsequent flags '') ;; # allow nothing at all *) echo "$0: error: unknown batch format '$1'" >&2 echo "$0: error: --batch expects a format from: text, nrpe, json" >&2 exit 255 ;; esac elif [ "$1" = "-v" ] || [ "$1" = "--verbose" ]; then opt_verbose=$(( opt_verbose + 1 )) shift elif [ "$1" = "--cve" ]; then if [ -z "$2" ]; then echo "$0: error: option --cve expects a parameter, supported CVEs are: $supported_cve_list" >&2 exit 255 fi selected_cve=$(echo "$supported_cve_list" | grep -iwo "$2") if [ -n "$selected_cve" ]; then opt_cve_list="$opt_cve_list $selected_cve" opt_cve_all=0 else echo "$0: error: unsupported CVE specified ('$2'), supported CVEs are: $supported_cve_list" >&2 exit 255 fi shift 2 elif [ "$1" = "--vmm" ]; then if [ -z "$2" ]; then echo "$0: error: option --vmm (auto, yes, no)" >&2 exit 255 fi case "$2" in auto) opt_vmm=-1;; yes) opt_vmm=1;; no) opt_vmm=0;; esac shift 2 elif [ "$1" = "--variant" ]; then if [ -z "$2" ]; then echo "$0: error: option --variant expects a parameter (1, 2, 3, 3a, 4 or l1tf)" >&2 exit 255 fi case "$2" in 1) opt_cve_list="$opt_cve_list CVE-2017-5753"; opt_cve_all=0;; 2) opt_cve_list="$opt_cve_list CVE-2017-5715"; opt_cve_all=0;; 3) opt_cve_list="$opt_cve_list CVE-2017-5754"; opt_cve_all=0;; 3a) opt_cve_list="$opt_cve_list CVE-2018-3640"; opt_cve_all=0;; 4) opt_cve_list="$opt_cve_list CVE-2018-3639"; opt_cve_all=0;; l1tf) opt_cve_list="$opt_cve_list CVE-2018-3615 CVE-2018-3620 CVE-2018-3646"; opt_cve_all=0;; *) echo "$0: error: invalid parameter '$2' for --variant, expected either 1, 2, 3, 3a, 4 or l1tf" >&2; exit 255 ;; esac shift 2 elif [ "$1" = "-h" ] || [ "$1" = "--help" ]; then show_header show_usage exit 0 elif [ "$1" = "--version" ]; then opt_no_color=1 show_header exit 0 elif [ "$1" = "--disclaimer" ]; then show_header show_disclaimer exit 0 else show_header show_usage echo "$0: error: unknown option '$1'" exit 255 fi done show_header if [ "$opt_no_sysfs" = 1 ] && [ "$opt_sysfs_only" = 1 ]; then _warn "Incompatible options specified (--no-sysfs and --sysfs-only), aborting" exit 255 fi if [ "$opt_no_hw" = 1 ] && [ "$opt_hw_only" = 1 ]; then _warn "Incompatible options specified (--no-hw and --hw-only), aborting" exit 255 fi # print status function pstatus() { if [ "$opt_no_color" = 1 ]; then _info_nol "$2" else case "$1" in red) col="\033[41m\033[30m";; green) col="\033[42m\033[30m";; yellow) col="\033[43m\033[30m";; blue) col="\033[44m\033[30m";; *) col="";; esac _info_nol "$col $2 \033[0m" fi [ -n "$3" ] && _info_nol " ($3)" _info unset col } # Print the final status of a vulnerability (incl. batch mode) # Arguments are: CVE UNK/OK/VULN description pvulnstatus() { pvulnstatus_last_cve="$1" if [ "$opt_batch" = 1 ]; then case "$1" in CVE-2017-5753) aka="SPECTRE VARIANT 1";; CVE-2017-5715) aka="SPECTRE VARIANT 2";; CVE-2017-5754) aka="MELTDOWN";; CVE-2018-3640) aka="VARIANT 3A";; CVE-2018-3639) aka="VARIANT 4";; CVE-2018-3615/3620/3646) aka="L1TF";; esac case "$opt_batch_format" in text) _echo 0 "$1: $2 ($3)";; short) short_output="${short_output}$1 ";; json) case "$2" in UNK) is_vuln="null";; VULN) is_vuln="true";; OK) is_vuln="false";; esac json_output="${json_output:-[}{\"NAME\":\"$aka\",\"CVE\":\"$1\",\"VULNERABLE\":$is_vuln,\"INFOS\":\"$3\"}," ;; nrpe) [ "$2" = VULN ] && nrpe_vuln="$nrpe_vuln $1";; prometheus) prometheus_output="${prometheus_output:+$prometheus_output\n}specex_vuln_status{name=\"$aka\",cve=\"$1\",status=\"$2\",info=\"$3\"} 1" ;; esac fi # always fill global_* vars because we use that do decide the program exit code case "$2" in UNK) global_unknown="1";; VULN) global_critical="1";; esac # display info if we're not in quiet/batch mode vulnstatus="$2" shift 2 _info_nol "> \033[46m\033[30mSTATUS:\033[0m " case "$vulnstatus" in UNK) pstatus yellow 'UNKNOWN' "$@"; final_summary="$final_summary \033[43m\033[30m$pvulnstatus_last_cve:??\033[0m";; VULN) pstatus red 'VULNERABLE' "$@"; final_summary="$final_summary \033[41m\033[30m$pvulnstatus_last_cve:KO\033[0m";; OK) pstatus green 'NOT VULNERABLE' "$@"; final_summary="$final_summary \033[42m\033[30m$pvulnstatus_last_cve:OK\033[0m";; esac } # The 3 below functions are taken from the extract-linux script, available here: # https://github.com/torvalds/linux/blob/master/scripts/extract-vmlinux # The functions have been modified for better integration to this script # The original header of the file has been retained below # ---------------------------------------------------------------------- # extract-vmlinux - Extract uncompressed vmlinux from a kernel image # # Inspired from extract-ikconfig # (c) 2009,2010 Dick Streefland <dick@streefland.net> # # (c) 2011 Corentin Chary <corentin.chary@gmail.com> # # Licensed under the GNU General Public License, version 2 (GPLv2). # ---------------------------------------------------------------------- kernel='' kernel_err='' check_kernel() { _file="$1" _desperate_mode="$2" # checking the return code of readelf -h is not enough, we could get # a damaged ELF file and validate it, check for stderr warnings too _readelf_warnings=$("${opt_arch_prefix}readelf" -S "$_file" 2>&1 >/dev/null | tr "\n" "/"); ret=$? _readelf_sections=$("${opt_arch_prefix}readelf" -S "$_file" 2>/dev/null | grep -c -e data -e text -e init) _kernel_size=$(stat -c %s "$_file" 2>/dev/null || stat -f %z "$_file" 2>/dev/null || echo 10000) _debug "check_kernel: ret=$? size=$_kernel_size sections=$_readelf_sections warnings=$_readelf_warnings" if [ -n "$_desperate_mode" ]; then if "${opt_arch_prefix}strings" "$_file" | grep -Eq '^Linux version '; then _debug "check_kernel (desperate): ... matched!" return 0 else _debug "check_kernel (desperate): ... invalid" fi else if [ $ret -eq 0 ] && [ -z "$_readelf_warnings" ] && [ "$_readelf_sections" -gt 0 ]; then if [ "$_kernel_size" -ge 100000 ]; then _debug "check_kernel: ... file is valid" return 0 else _debug "check_kernel: ... file seems valid but is too small, ignoring" fi else _debug "check_kernel: ... file is invalid" fi fi return 1 } try_decompress() { # The obscure use of the "tr" filter is to work around older versions of # "grep" that report the byte offset of the line instead of the pattern. # Try to find the header ($1) and decompress from here _debug "try_decompress: looking for $3 magic in $6" for pos in $(tr "$1\n$2" "\n$2=" < "$6" | grep -abo "^$2") do _debug "try_decompress: magic for $3 found at offset $pos" if ! which "$3" >/dev/null 2>&1; then kernel_err="missing '$3' tool, please install it, usually it's in the '$5' package" return 0 fi pos=${pos%%:*} # shellcheck disable=SC2086 tail -c+$pos "$6" 2>/dev/null | $3 $4 > "$kerneltmp" 2>/dev/null; ret=$? if [ ! -s "$kerneltmp" ]; then # don't rely on $ret, sometimes it's != 0 but worked # (e.g. gunzip ret=2 just means there was trailing garbage) _debug "try_decompress: decompression with $3 failed (err=$ret)" elif check_kernel "$kerneltmp" "$7"; then kernel="$kerneltmp" _debug "try_decompress: decompressed with $3 successfully!" return 0 elif [ "$3" != "cat" ]; then _debug "try_decompress: decompression with $3 worked but result is not a kernel, trying with an offset" [ -z "$kerneltmp2" ] && kerneltmp2=$(mktemp /tmp/kernel-XXXXXX) cat "$kerneltmp" > "$kerneltmp2" try_decompress '\177ELF' xxy 'cat' '' cat "$kerneltmp2" && return 0 else _debug "try_decompress: decompression with $3 worked but result is not a kernel" fi done return 1 } extract_kernel() { [ -n "$1" ] || return 1 # Prepare temp files: kerneltmp="$(mktemp /tmp/kernel-XXXXXX)" # Initial attempt for uncompressed images or objects: if check_kernel "$1"; then cat "$1" > "$kerneltmp" kernel=$kerneltmp return 0 fi # That didn't work, so retry after decompression. for mode in '' 'desperate'; do try_decompress '\037\213\010' xy gunzip '' gunzip "$1" "$mode" && return 0 try_decompress '\3757zXZ\000' abcde unxz '' xz-utils "$1" "$mode" && return 0 try_decompress 'BZh' xy bunzip2 '' bzip2 "$1" "$mode" && return 0 try_decompress '\135\0\0\0' xxx unlzma '' xz-utils "$1" "$mode" && return 0 try_decompress '\211\114\132' xy 'lzop' '-d' lzop "$1" "$mode" && return 0 try_decompress '\002\041\114\030' xyy 'lz4' '-d -l' liblz4-tool "$1" "$mode" && return 0 try_decompress '\177ELF' xxy 'cat' '' cat "$1" "$mode" && return 0 done _verbose "Couldn't extract the kernel image, accuracy might be reduced" return 1 } # end of extract-vmlinux functions mount_debugfs() { if [ ! -e /sys/kernel/debug/sched_features ]; then # try to mount the debugfs hierarchy ourselves and remember it to umount afterwards mount -t debugfs debugfs /sys/kernel/debug 2>/dev/null && mounted_debugfs=1 fi } load_msr() { if [ "$os" = Linux ]; then if ! grep -e msr "$procfs/modules" 2>/dev/null; then modprobe msr 2>/dev/null && insmod_msr=1 _debug "attempted to load module msr, insmod_msr=$insmod_msr" else _debug "msr module already loaded" fi else if ! kldstat -q -m cpuctl; then kldload cpuctl 2>/dev/null && kldload_cpuctl=1 _debug "attempted to load module cpuctl, kldload_cpuctl=$kldload_cpuctl" else _debug "cpuctl module already loaded" fi fi } load_cpuid() { if [ "$os" = Linux ]; then if ! grep -e cpuid "$procfs/modules" 2>/dev/null; then modprobe cpuid 2>/dev/null && insmod_cpuid=1 _debug "attempted to load module cpuid, insmod_cpuid=$insmod_cpuid" else _debug "cpuid module already loaded" fi else if ! kldstat -q -m cpuctl; then kldload cpuctl 2>/dev/null && kldload_cpuctl=1 _debug "attempted to load module cpuctl, kldload_cpuctl=$kldload_cpuctl" else _debug "cpuctl module already loaded" fi fi } # shellcheck disable=SC2034 EAX=1; EBX=2; ECX=3; EDX=4; read_cpuid() { # leaf is the value of the eax register when calling the cpuid instruction: _leaf="$1" # eax=1 ebx=2 ecx=3 edx=4: _register="$2" # number of bits to shift the register right to: _shift="$3" # mask to apply as an AND operand to the shifted register value _mask="$4" # wanted value (optional), if present we return 0(true) if the obtained value is equal, 1 otherwise: _wanted="$5" # in any case, the read value is globally available in $read_cpuid_value read_cpuid_value='' if [ ! -e /dev/cpu/0/cpuid ] && [ ! -e /dev/cpuctl0 ]; then # try to load the module ourselves (and remember it so we can rmmod it afterwards) load_cpuid fi if [ -e /dev/cpu/0/cpuid ]; then # Linux if [ ! -r /dev/cpu/0/cpuid ]; then return 2 fi # on some kernel versions, /dev/cpu/0/cpuid doesn't imply that the cpuid module is loaded, in that case dd returns an error dd if=/dev/cpu/0/cpuid bs=16 count=1 >/dev/null 2>&1 || load_cpuid # we need _leaf to be converted to decimal for dd _leaf=$(( _leaf )) # to avoid using iflag=skip_bytes, which doesn't exist on old versions of dd, seek to the closer multiple-of-16 _ddskip=$(( _leaf / 16 )) _odskip=$(( _leaf - _ddskip * 16 )) # now read the value _cpuid=$(dd if=/dev/cpu/0/cpuid bs=16 skip=$_ddskip count=$((_odskip + 1)) 2>/dev/null | od -j $((_odskip * 16)) -A n -t u4) elif [ -e /dev/cpuctl0 ]; then # BSD if [ ! -r /dev/cpuctl0 ]; then return 2 fi _cpuid=$(cpucontrol -i "$_leaf" /dev/cpuctl0 2>/dev/null | awk '{print $4,$5,$6,$7}') # cpuid level 0x1: 0x000306d4 0x00100800 0x4dfaebbf 0xbfebfbff else return 2 fi _debug "cpuid: leaf$_leaf on cpu0, eax-ebx-ecx-edx: $_cpuid" [ -z "$_cpuid" ] && return 2 # get the value of the register we want _reg=$(echo "$_cpuid" | awk '{print $'"$_register"'}') # Linux returns it as decimal, BSD as hex, normalize to decimal _reg=$(( _reg )) # shellcheck disable=SC2046 _debug "cpuid: wanted register ($_register) has value $_reg aka "$(printf "%08x" "$_reg") _reg_shifted=$(( _reg >> _shift )) # shellcheck disable=SC2046 _debug "cpuid: shifted value by $_shift is $_reg_shifted aka "$(printf "%x" "$_reg_shifted") read_cpuid_value=$(( _reg_shifted & _mask )) # shellcheck disable=SC2046 _debug "cpuid: after AND $_mask, final value is $read_cpuid_value aka "$(printf "%x" "$read_cpuid_value") if [ -n "$_wanted" ]; then _debug "cpuid: wanted $_wanted and got $read_cpuid_value" if [ "$read_cpuid_value" = "$_wanted" ]; then return 0 else return 1 fi fi return 0 } dmesg_grep() { # grep for something in dmesg, ensuring that the dmesg buffer # has not been truncated dmesg_grepped='' if ! dmesg | grep -qE -e '(^|\] )Linux version [0-9]' -e '^FreeBSD is a registered' ; then # dmesg truncated return 2 fi dmesg_grepped=$(dmesg | grep -E "$1" | head -1) # not found: [ -z "$dmesg_grepped" ] && return 1 # found, output is in $dmesg_grepped return 0 } is_coreos() { which coreos-install >/dev/null 2>&1 && which toolbox >/dev/null 2>&1 && return 0 return 1 } parse_cpu_details() { [ "$parse_cpu_details_done" = 1 ] && return 0 if [ -e "$procfs/cpuinfo" ]; then cpu_vendor=$( grep '^vendor_id' "$procfs/cpuinfo" | awk '{print $3}' | head -1) cpu_friendly_name=$(grep '^model name' "$procfs/cpuinfo" | cut -d: -f2- | head -1 | sed -e 's/^ *//') # special case for ARM follows if grep -qi 'CPU implementer[[:space:]]*:[[:space:]]*0x41' "$procfs/cpuinfo"; then cpu_vendor='ARM' # some devices (phones or other) have several ARMs and as such different part numbers, # an example is "bigLITTLE", so we need to store the whole list, this is needed for is_cpu_vulnerable cpu_part_list=$(awk '/CPU part/ {print $4}' "$procfs/cpuinfo") cpu_arch_list=$(awk '/CPU architecture/ {print $3}' "$procfs/cpuinfo") # take the first one to fill the friendly name, do NOT quote the vars below # shellcheck disable=SC2086 cpu_arch=$(echo $cpu_arch_list | awk '{ print $1 }') # shellcheck disable=SC2086 cpu_part=$(echo $cpu_part_list | awk '{ print $1 }') [ "$cpu_arch" = "AArch64" ] && cpu_arch=8 cpu_friendly_name="ARM" [ -n "$cpu_arch" ] && cpu_friendly_name="$cpu_friendly_name v$cpu_arch" [ -n "$cpu_part" ] && cpu_friendly_name="$cpu_friendly_name model $cpu_part" elif grep -qi 'CPU implementer[[:space:]]*:[[:space:]]*0x43' "$procfs/cpuinfo"; then cpu_vendor='CAVIUM' fi cpu_family=$( grep '^cpu family' "$procfs/cpuinfo" | awk '{print $4}' | grep -E '^[0-9]+$' | head -1) cpu_model=$( grep '^model' "$procfs/cpuinfo" | awk '{print $3}' | grep -E '^[0-9]+$' | head -1) cpu_stepping=$(grep '^stepping' "$procfs/cpuinfo" | awk '{print $3}' | grep -E '^[0-9]+$' | head -1) cpu_ucode=$( grep '^microcode' "$procfs/cpuinfo" | awk '{print $3}' | head -1) else cpu_friendly_name=$(sysctl -n hw.model) fi # get raw cpuid, it's always useful (referenced in the Intel doc for firmware updates for example) if read_cpuid 0x1 $EAX 0 0xFFFFFFFF; then cpu_cpuid="$read_cpuid_value" else cpu_cpuid=0 fi # under BSD, linprocfs often doesn't export ucode information, so fetch it ourselves the good old way if [ -z "$cpu_ucode" ] && [ "$os" != Linux ]; then load_cpuid if [ -e /dev/cpuctl0 ]; then # init MSR with NULLs cpucontrol -m 0x8b=0 /dev/cpuctl0 # call CPUID cpucontrol -i 1 /dev/cpuctl0 >/dev/null # read MSR cpu_ucode=$(cpucontrol -m 0x8b /dev/cpuctl0 | awk '{print $3}') # convert to decimal cpu_ucode=$(( cpu_ucode )) # convert back to hex cpu_ucode=$(printf "0x%x" "$cpu_ucode") fi fi # if we got no cpu_ucode (e.g. we're in a vm), fall back to 0x0 [ -z "$cpu_ucode" ] && cpu_ucode=0x0 echo "$cpu_ucode" | grep -q ^0x && cpu_ucode=$(( cpu_ucode )) ucode_found=$(printf "model 0x%x family 0x%x stepping 0x%x ucode 0x%x cpuid 0x%x" "$cpu_model" "$cpu_family" "$cpu_stepping" "$cpu_ucode" "$cpu_cpuid") # also define those that we will need in other funcs # taken from ttps://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/include/asm/intel-family.h # shellcheck disable=SC2034 { INTEL_FAM6_CORE_YONAH=$(( 0x0E )) INTEL_FAM6_CORE2_MEROM=$(( 0x0F )) INTEL_FAM6_CORE2_MEROM_L=$(( 0x16 )) INTEL_FAM6_CORE2_PENRYN=$(( 0x17 )) INTEL_FAM6_CORE2_DUNNINGTON=$(( 0x1D )) INTEL_FAM6_NEHALEM=$(( 0x1E )) INTEL_FAM6_NEHALEM_G=$(( 0x1F )) INTEL_FAM6_NEHALEM_EP=$(( 0x1A )) INTEL_FAM6_NEHALEM_EX=$(( 0x2E )) INTEL_FAM6_WESTMERE=$(( 0x25 )) INTEL_FAM6_WESTMERE_EP=$(( 0x2C )) INTEL_FAM6_WESTMERE_EX=$(( 0x2F )) INTEL_FAM6_SANDYBRIDGE=$(( 0x2A )) INTEL_FAM6_SANDYBRIDGE_X=$(( 0x2D )) INTEL_FAM6_IVYBRIDGE=$(( 0x3A )) INTEL_FAM6_IVYBRIDGE_X=$(( 0x3E )) INTEL_FAM6_HASWELL_CORE=$(( 0x3C )) INTEL_FAM6_HASWELL_X=$(( 0x3F )) INTEL_FAM6_HASWELL_ULT=$(( 0x45 )) INTEL_FAM6_HASWELL_GT3E=$(( 0x46 )) INTEL_FAM6_BROADWELL_CORE=$(( 0x3D )) INTEL_FAM6_BROADWELL_GT3E=$(( 0x47 )) INTEL_FAM6_BROADWELL_X=$(( 0x4F )) INTEL_FAM6_BROADWELL_XEON_D=$(( 0x56 )) INTEL_FAM6_SKYLAKE_MOBILE=$(( 0x4E )) INTEL_FAM6_SKYLAKE_DESKTOP=$(( 0x5E )) INTEL_FAM6_SKYLAKE_X=$(( 0x55 )) INTEL_FAM6_KABYLAKE_MOBILE=$(( 0x8E )) INTEL_FAM6_KABYLAKE_DESKTOP=$(( 0x9E )) # /* "Small Core" Processors (Atom) */ INTEL_FAM6_ATOM_PINEVIEW=$(( 0x1C )) INTEL_FAM6_ATOM_LINCROFT=$(( 0x26 )) INTEL_FAM6_ATOM_PENWELL=$(( 0x27 )) INTEL_FAM6_ATOM_CLOVERVIEW=$(( 0x35 )) INTEL_FAM6_ATOM_CEDARVIEW=$(( 0x36 )) INTEL_FAM6_ATOM_SILVERMONT1=$(( 0x37 )) INTEL_FAM6_ATOM_SILVERMONT2=$(( 0x4D )) INTEL_FAM6_ATOM_AIRMONT=$(( 0x4C )) INTEL_FAM6_ATOM_MERRIFIELD=$(( 0x4A )) INTEL_FAM6_ATOM_MOOREFIELD=$(( 0x5A )) INTEL_FAM6_ATOM_GOLDMONT=$(( 0x5C )) INTEL_FAM6_ATOM_DENVERTON=$(( 0x5F )) INTEL_FAM6_ATOM_GEMINI_LAKE=$(( 0x7A )) # /* Xeon Phi */ INTEL_FAM6_XEON_PHI_KNL=$(( 0x57 )) INTEL_FAM6_XEON_PHI_KNM=$(( 0x85 )) } parse_cpu_details_done=1 } is_amd() { [ "$cpu_vendor" = AuthenticAMD ] && return 0 return 1 } is_intel() { [ "$cpu_vendor" = GenuineIntel ] && return 0 return 1 } is_cpu_smt_enabled() { # SMT / HyperThreading is enabled if siblings != cpucores if [ -e "$procfs/cpuinfo" ]; then _siblings=$(awk '/^siblings/ {print $3;exit}' "$procfs/cpuinfo") _cpucores=$(awk '/^cpu cores/ {print $4;exit}' "$procfs/cpuinfo") if [ -n "$_siblings" ] && [ -n "$_cpucores" ]; then if [ "$_siblings" = "$_cpucores" ]; then return 1 else return 0 fi fi fi # we can't tell return 2 } is_ucode_blacklisted() { parse_cpu_details # if it's not an Intel, don't bother: it's not blacklisted is_intel || return 1 # it also needs to be family=6 [ "$cpu_family" = 6 ] || return 1 # now, check each known bad microcode # source: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/kernel/cpu/intel.c#n105 # 2018-02-08 update: https://newsroom.intel.com/wp-content/uploads/sites/11/2018/02/microcode-update-guidance.pdf # model,stepping,microcode for tuple in \ $INTEL_FAM6_KABYLAKE_DESKTOP,0x0B,0x80 \ $INTEL_FAM6_KABYLAKE_DESKTOP,0x0A,0x80 \ $INTEL_FAM6_KABYLAKE_DESKTOP,0x09,0x80 \ $INTEL_FAM6_KABYLAKE_MOBILE,0x0A,0x80 \ $INTEL_FAM6_KABYLAKE_MOBILE,0x09,0x80 \ $INTEL_FAM6_SKYLAKE_X,0x03,0x0100013e \ $INTEL_FAM6_SKYLAKE_X,0x04,0x02000036 \ $INTEL_FAM6_SKYLAKE_X,0x04,0x0200003a \ $INTEL_FAM6_SKYLAKE_X,0x04,0x0200003c \ $INTEL_FAM6_BROADWELL_CORE,0x04,0x28 \ $INTEL_FAM6_BROADWELL_GT3E,0x01,0x1b \ $INTEL_FAM6_BROADWELL_XEON_D,0x02,0x14 \ $INTEL_FAM6_BROADWELL_XEON_D,0x03,0x07000011 \ $INTEL_FAM6_BROADWELL_X,0x01,0x0b000023 \ $INTEL_FAM6_BROADWELL_X,0x01,0x0b000025 \ $INTEL_FAM6_HASWELL_ULT,0x01,0x21 \ $INTEL_FAM6_HASWELL_GT3E,0x01,0x18 \ $INTEL_FAM6_HASWELL_CORE,0x03,0x23 \ $INTEL_FAM6_HASWELL_X,0x02,0x3b \ $INTEL_FAM6_HASWELL_X,0x04,0x10 \ $INTEL_FAM6_IVYBRIDGE_X,0x04,0x42a \ $INTEL_FAM6_SANDYBRIDGE_X,0x06,0x61b \ $INTEL_FAM6_SANDYBRIDGE_X,0x07,0x712 do model=$(echo $tuple | cut -d, -f1) stepping=$(( $(echo $tuple | cut -d, -f2) )) if [ "$cpu_model" = "$model" ] && [ "$cpu_stepping" = "$stepping" ]; then ucode=$(( $(echo $tuple | cut -d, -f3) )) if [ "$cpu_ucode" = "$ucode" ]; then _debug "is_ucode_blacklisted: we have a match! ($cpu_model/$cpu_stepping/$cpu_ucode)" return 0 fi fi done _debug "is_ucode_blacklisted: no ($cpu_model/$cpu_stepping/$cpu_ucode)" return 1 } is_skylake_cpu() { # is this a skylake cpu? # return 0 if yes, 1 otherwise #if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && # boot_cpu_data.x86 == 6) { # switch (boot_cpu_data.x86_model) { # case INTEL_FAM6_SKYLAKE_MOBILE: # case INTEL_FAM6_SKYLAKE_DESKTOP: # case INTEL_FAM6_SKYLAKE_X: # case INTEL_FAM6_KABYLAKE_MOBILE: # case INTEL_FAM6_KABYLAKE_DESKTOP: # return true; parse_cpu_details is_intel || return 1 [ "$cpu_family" = 6 ] || return 1 if [ "$cpu_model" = $INTEL_FAM6_SKYLAKE_MOBILE ] || \ [ "$cpu_model" = $INTEL_FAM6_SKYLAKE_DESKTOP ] || \ [ "$cpu_model" = $INTEL_FAM6_SKYLAKE_X ] || \ [ "$cpu_model" = $INTEL_FAM6_KABYLAKE_MOBILE ] || \ [ "$cpu_model" = $INTEL_FAM6_KABYLAKE_DESKTOP ]; then return 0 fi return 1 } is_vulnerable_to_empty_rsb() { if is_intel && [ -z "$capabilities_rsba" ]; then _warn "is_vulnerable_to_empty_rsb() called before ARCH CAPABILITIES MSR was read" fi if is_skylake_cpu || [ "$capabilities_rsba" = 1 ]; then return 0 fi return 1 } is_zen_cpu() { # is this CPU from the AMD ZEN family ? (ryzen, epyc, ...) parse_cpu_details is_amd || return 1 [ "$cpu_family" = 23 ] && return 0 return 1 } if [ -r "$mcedb_cache" ]; then mcedb_source="$mcedb_cache" mcedb_info="local MCExtractor DB "$(grep -E '^# %%% MCEDB ' "$mcedb_source" | cut -c13-) else mcedb_source="$0" mcedb_info="builtin MCExtractor DB "$(grep -E '^# %%% MCEDB ' "$mcedb_source" | cut -c13-) fi read_mcedb() { awk '{ if (DELIM==1) { print $2 } } /^# %%% MCEDB / { DELIM=1 }' "$mcedb_source" } is_latest_known_ucode() { # 0: yes, 1: no, 2: unknown parse_cpu_details if [ "$cpu_cpuid" = 0 ]; then ucode_latest="couldn't get your cpuid" return 2 fi ucode_latest="latest microcode version for your CPU model is unknown" if is_intel; then cpu_brand_prefix=I elif is_amd; then cpu_brand_prefix=A else return 2 fi for tuple in $(read_mcedb | grep "$(printf "^$cpu_brand_prefix,0x%08X," "$cpu_cpuid")") do ucode=$(( $(echo "$tuple" | cut -d, -f3) )) ucode_date=$(echo "$tuple" | cut -d, -f4 | sed -r 's=(....)(..)(..)=\1/\2/\3=') _debug "is_latest_known_ucode: with cpuid $cpu_cpuid has ucode $cpu_ucode, last known is $ucode from $ucode_date" ucode_latest=$(printf "latest version is 0x%x dated $ucode_date according to $mcedb_info" "$ucode") if [ "$cpu_ucode" -ge "$ucode" ]; then return 0 else return 1 fi done _debug "is_latest_known_ucode: this cpuid is not referenced ($cpu_cpuid)" return 2 } # ENTRYPOINT # we can't do anything useful under WSL if uname -a | grep -qE -- '-Microsoft #[0-9]+-Microsoft '; then _warn "This script doesn't work under Windows Subsystem for Linux" _warn "You should use the official Microsoft tool instead." _warn "It can be found under https://aka.ms/SpeculationControlPS" exit 1 fi # check for mode selection inconsistency if [ "$opt_live_explicit" = 1 ]; then if [ -n "$opt_kernel" ] || [ -n "$opt_config" ] || [ -n "$opt_map" ]; then show_usage echo "$0: error: incompatible modes specified, use either --live or --kernel/--config/--map" >&2 exit 255 fi fi if [ "$opt_hw_only" = 1 ]; then if [ "$opt_cve_all" = 0 ]; then show_usage echo "$0: error: incompatible modes specified, --hw-only vs --variant" >&2 exit 255 else opt_cve_all=0 opt_cve_list='' fi fi # coreos mode if [ "$opt_coreos" = 1 ]; then if ! is_coreos; then _warn "CoreOS mode asked, but we're not under CoreOS!" exit 255 fi _warn "CoreOS mode, starting an ephemeral toolbox to launch the script" load_msr load_cpuid mount_debugfs toolbox --ephemeral --bind-ro /dev/cpu:/dev/cpu -- sh -c "dnf install -y binutils which && /media/root$PWD/$0 $* --coreos-within-toolbox" exitcode=$? exit $exitcode else if is_coreos; then _warn "You seem to be running CoreOS, you might want to use the --coreos option for better results" _warn fi fi # if we're under a BSD, try to mount linprocfs for "$procfs/cpuinfo" procfs=/proc if echo "$os" | grep -q BSD; then _debug "We're under BSD, check if we have procfs" procfs=$(mount | awk '/^linprocfs/ { print $3; exit; }') if [ -z "$procfs" ]; then _debug "we don't, try to mount it" procfs=/proc [ -d /compat/linux/proc ] && procfs=/compat/linux/proc test -d $procfs || mkdir $procfs if mount -t linprocfs linprocfs $procfs 2>/dev/null; then mounted_procfs=1 _debug "procfs just mounted at $procfs" else procfs='' fi else _debug "We do: $procfs" fi fi parse_cpu_details if [ "$opt_live" = 1 ]; then # root check (only for live mode, for offline mode, we already checked if we could read the files) if [ "$(id -u)" -ne 0 ]; then _warn "Note that you should launch this script with root privileges to get accurate information." _warn "We'll proceed but you might see permission denied errors." _warn "To run it as root, you can try the following command: sudo $0" _warn fi _info "Checking for vulnerabilities on current system" _info "Kernel is \033[35m$(uname -s) $(uname -r) $(uname -v) $(uname -m)\033[0m" _info "CPU is \033[35m$cpu_friendly_name\033[0m" # try to find the image of the current running kernel # first, look for the BOOT_IMAGE hint in the kernel cmdline if [ -r "$procfs/cmdline" ] && grep -q 'BOOT_IMAGE=' "$procfs/cmdline"; then opt_kernel=$(grep -Eo 'BOOT_IMAGE=[^ ]+' "$procfs/cmdline" | cut -d= -f2) _debug "found opt_kernel=$opt_kernel in $procfs/cmdline" # if the boot partition is within a btrfs subvolume, strip the subvolume name # if /boot is a separate subvolume, the remainder of the code in this section should handle it if echo "$opt_kernel" | grep -q "^/@"; then opt_kernel=$(echo "$opt_kernel" | sed "s:/@[^/]*::"); fi # if we have a dedicated /boot partition, our bootloader might have just called it / # so try to prepend /boot and see if we find anything [ -e "/boot/$opt_kernel" ] && opt_kernel="/boot/$opt_kernel" # special case for CoreOS if we're inside the toolbox [ -e "/media/root/boot/$opt_kernel" ] && opt_kernel="/media/root/boot/$opt_kernel" _debug "opt_kernel is now $opt_kernel" # else, the full path is already there (most probably /boot/something) fi # if we didn't find a kernel, default to guessing if [ ! -e "$opt_kernel" ]; then # Fedora: [ -e "/lib/modules/$(uname -r)/vmlinuz" ] && opt_kernel="/lib/modules/$(uname -r)/vmlinuz" # Slackare: [ -e "/boot/vmlinuz" ] && opt_kernel="/boot/vmlinuz" # Arch: [ -e "/boot/vmlinuz-linux" ] && opt_kernel="/boot/vmlinuz-linux" # Arch aarch64: [ -e "/boot/Image" ] && opt_kernel="/boot/Image" # Arch armv5/armv7: [ -e "/boot/zImage" ] && opt_kernel="/boot/zImage" # Arch arm7: [ -e "/boot/kernel7.img" ] && opt_kernel="/boot/kernel7.img" # Linux-Libre: [ -e "/boot/vmlinuz-linux-libre" ] && opt_kernel="/boot/vmlinuz-linux-libre" # pine64 [ -e "/boot/pine64/Image" ] && opt_kernel="/boot/pine64/Image" # generic: [ -e "/boot/vmlinuz-$(uname -r)" ] && opt_kernel="/boot/vmlinuz-$(uname -r)" [ -e "/boot/kernel-$( uname -r)" ] && opt_kernel="/boot/kernel-$( uname -r)" [ -e "/boot/bzImage-$(uname -r)" ] && opt_kernel="/boot/bzImage-$(uname -r)" # Gentoo: [ -e "/boot/kernel-genkernel-$(uname -m)-$(uname -r)" ] && opt_kernel="/boot/kernel-genkernel-$(uname -m)-$(uname -r)" # NixOS: [ -e "/run/booted-system/kernel" ] && opt_kernel="/run/booted-system/kernel" # systemd kernel-install: [ -e "/etc/machine-id" ] && [ -e "/boot/$(cat /etc/machine-id)/$(uname -r)/linux" ] && opt_kernel="/boot/$(cat /etc/machine-id)/$(uname -r)/linux" # Clear Linux: str_uname=$(uname -r) clear_linux_kernel="/lib/kernel/org.clearlinux.${str_uname##*.}.${str_uname%.*}" [ -e "$clear_linux_kernel" ] && opt_kernel=$clear_linux_kernel fi # system.map if [ -e "$procfs/kallsyms" ] ; then opt_map="$procfs/kallsyms" elif [ -e "/lib/modules/$(uname -r)/System.map" ] ; then opt_map="/lib/modules/$(uname -r)/System.map" elif [ -e "/boot/System.map-$(uname -r)" ] ; then opt_map="/boot/System.map-$(uname -r)" elif [ -e "/lib/kernel/config-$(uname -r)" ]; then opt_config="/lib/kernel/config-$(uname -r)" fi # config if [ -e "$procfs/config.gz" ] ; then dumped_config="$(mktemp /tmp/config-XXXXXX)" gunzip -c "$procfs/config.gz" > "$dumped_config" # dumped_config will be deleted at the end of the script opt_config="$dumped_config" elif [ -e "/lib/modules/$(uname -r)/config" ]; then opt_config="/lib/modules/$(uname -r)/config" elif [ -e "/boot/config-$(uname -r)" ]; then opt_config="/boot/config-$(uname -r)" elif [ -e "/etc/kernels/kernel-config-$(uname -m)-$(uname -r)" ]; then opt_config="/etc/kernels/kernel-config-$(uname -m)-$(uname -r)" fi else _info "Checking for vulnerabilities against specified kernel" _info "CPU is \033[35m$cpu_friendly_name\033[0m" fi if [ -n "$opt_kernel" ]; then _verbose "Will use kernel image \033[35m$opt_kernel\033[0m" else _verbose "Will use no kernel image (accuracy might be reduced)" bad_accuracy=1 fi if [ "$os" = Linux ]; then if [ -n "$opt_config" ] && ! grep -q '^CONFIG_' "$opt_config"; then # given file is invalid! _warn "The kernel config file seems invalid, was expecting a plain-text file, ignoring it!" opt_config='' fi if [ -n "$dumped_config" ] && [ -n "$opt_config" ]; then _verbose "Will use kconfig \033[35m$procfs/config.gz (decompressed)\033[0m" elif [ -n "$opt_config" ]; then _verbose "Will use kconfig \033[35m$opt_config\033[0m" else _verbose "Will use no kconfig (accuracy might be reduced)" bad_accuracy=1 fi if [ -n "$opt_map" ]; then _verbose "Will use System.map file \033[35m$opt_map\033[0m" else _verbose "Will use no System.map file (accuracy might be reduced)" bad_accuracy=1 fi if [ "$bad_accuracy" = 1 ]; then _info "We're missing some kernel info (see -v), accuracy might be reduced" fi fi if [ -e "$opt_kernel" ]; then if ! which "${opt_arch_prefix}readelf" >/dev/null 2>&1; then _debug "readelf not found" kernel_err="missing '${opt_arch_prefix}readelf' tool, please install it, usually it's in the 'binutils' package" elif [ "$opt_sysfs_only" = 1 ] || [ "$opt_hw_only" = 1 ]; then kernel_err='kernel image decompression skipped' else extract_kernel "$opt_kernel" fi else _debug "no opt_kernel defined" kernel_err="couldn't find your kernel image in /boot, if you used netboot, this is normal" fi if [ -z "$kernel" ] || [ ! -r "$kernel" ]; then [ -z "$kernel_err" ] && kernel_err="couldn't extract your kernel from $opt_kernel" else # vanilla kernels have with ^Linux version # also try harder with some kernels (such as Red Hat) that don't have ^Linux version before their version string # and check for FreeBSD kernel_version=$("${opt_arch_prefix}strings" "$kernel" 2>/dev/null | grep -E \ -e '^Linux version ' \ -e '^[[:alnum:]][^[:space:]]+ \([^[:space:]]+\) #[0-9]+ .+ (19|20)[0-9][0-9]$' \ -e '^FreeBSD [0-9]' | head -1) if [ -z "$kernel_version" ]; then # try even harder with some kernels (such as ARM) that split the release (uname -r) and version (uname -v) in 2 adjacent strings kernel_version=$("${opt_arch_prefix}strings" "$kernel" 2>/dev/null | grep -E -B1 '^#[0-9]+ .+ (19|20)[0-9][0-9]$' | tr "\n" " ") fi if [ -n "$kernel_version" ]; then # in live mode, check if the img we found is the correct one if [ "$opt_live" = 1 ]; then _verbose "Kernel image is \033[35m$kernel_version" if ! echo "$kernel_version" | grep -qF "$(uname -r)"; then _warn "Possible disrepancy between your running kernel '$(uname -r)' and the image '$kernel_version' we found ($opt_kernel), results might be incorrect" fi else _info "Kernel image is \033[35m$kernel_version" fi else _verbose "Kernel image version is unknown" fi fi _info # end of header stuff # now we define some util functions and the check_*() funcs, as # the user can choose to execute only some of those sys_interface_check() { file="$1" regex="$2" mode="$3" [ "$opt_live" = 1 ] && [ "$opt_no_sysfs" = 0 ] && [ -r "$file" ] || return 1 [ -n "$regex" ] || regex='.*' msg=$(grep -Eo "$regex" "$file") if [ "$mode" = silent ]; then _info "* Information from the /sys interface: $msg" return 0 fi _info_nol "* Mitigated according to the /sys interface: " if echo "$msg" | grep -qi '^not affected'; then # Not affected status=OK pstatus green YES "$msg" elif echo "$msg" | grep -qi '^mitigation'; then # Mitigation: PTI status=OK pstatus green YES "$msg" elif echo "$msg" | grep -qi '^vulnerable'; then # Vulnerable status=VULN pstatus yellow NO "$msg" else status=UNK pstatus yellow UNKNOWN "$msg" fi _debug "sys_interface_check: $file=$msg (re=$regex)" return 0 } number_of_cpus() { if echo "$os" | grep -q BSD; then n=$(sysctl -n hw.ncpu 2>/dev/null || echo 1) elif [ -e "$procfs/cpuinfo" ]; then n=$(grep -c ^processor "$procfs/cpuinfo" 2>/dev/null || echo 1) else # if we don't know, default to 1 CPU n=1 fi return "$n" } # $1 - msr number # $2 - cpu index write_msr() { # _msr must be in hex, in the form 0x1234: _msr="$1" # cpu index, starting from 0: _cpu="$2" if [ "$os" != Linux ]; then cpucontrol -m "$_msr=0" "/dev/cpuctl$_cpu" >/dev/null 2>&1; ret=$? else # for Linux # convert to decimal _msr=$(( _msr )) if [ ! -w /dev/cpu/"$_cpu"/msr ]; then ret=200 # permission error # if wrmsr is available, use it elif which wrmsr >/dev/null 2>&1 && [ "$SMC_NO_WRMSR" != 1 ]; then _debug "write_msr: using wrmsr" wrmsr $_msr 0 2>/dev/null; ret=$? # or if we have perl, use it, any 5.x version will work elif which perl >/dev/null 2>&1 && [ "$SMC_NO_PERL" != 1 ]; then _debug "write_msr: using perl" ret=1 perl -e "open(M,'>','/dev/cpu/$_cpu/msr') and seek(M,$_msr,0) and exit(syswrite(M,pack('H16',0)))"; [ $? -eq 8 ] && ret=0 # fallback to dd if it supports seek_bytes elif dd if=/dev/null of=/dev/null bs=8 count=1 seek="$_msr" oflag=seek_bytes 2>/dev/null; then _debug "write_msr: using dd" dd if=/dev/zero of=/dev/cpu/"$_cpu"/msr bs=8 count=1 seek="$_msr" oflag=seek_bytes 2>/dev/null; ret=$? else _debug "write_msr: got no wrmsr, perl or recent enough dd!" return 201 # missing tool error fi fi # normalize ret [ "$ret" != 0 ] && ret=1 _debug "write_msr: for cpu $_cpu on msr $_msr, ret=$ret" return $ret } read_msr() { # _msr must be in hex, in the form 0x1234: _msr="$1" # cpu index, starting from 0: _cpu="$2" read_msr_value='' if [ "$os" != Linux ]; then _msr=$(cpucontrol -m "$_msr" "/dev/cpuctl$_cpu" 2>/dev/null); ret=$? [ $ret -ne 0 ] && return 1 # MSR 0x10: 0x000003e1 0xb106dded _msr_h=$(echo "$_msr" | awk '{print $3}'); _msr_h="$(( _msr_h >> 24 & 0xFF )) $(( _msr_h >> 16 & 0xFF )) $(( _msr_h >> 8 & 0xFF )) $(( _msr_h & 0xFF ))" _msr_l=$(echo "$_msr" | awk '{print $4}'); _msr_l="$(( _msr_l >> 24 & 0xFF )) $(( _msr_l >> 16 & 0xFF )) $(( _msr_l >> 8 & 0xFF )) $(( _msr_l & 0xFF ))" read_msr_value="$_msr_h $_msr_l" else # for Linux # convert to decimal _msr=$(( _msr )) if [ ! -r /dev/cpu/"$_cpu"/msr ]; then return 200 # permission error # if rdmsr is available, use it elif which rdmsr >/dev/null 2>&1 && [ "$SMC_NO_RDMSR" != 1 ]; then _debug "read_msr: using rdmsr" read_msr_value=$(rdmsr -r $_msr 2>/dev/null | od -t u8 -A n) # or if we have perl, use it, any 5.x version will work elif which perl >/dev/null 2>&1 && [ "$SMC_NO_PERL" != 1 ]; then _debug "read_msr: using perl" read_msr_value=$(perl -e "open(M,'<','/dev/cpu/$_cpu/msr') and seek(M,$_msr,0) and read(M,\$_,8) and print" | od -t u8 -A n) # fallback to dd if it supports skip_bytes elif dd if=/dev/null of=/dev/null bs=8 count=1 skip="$_msr" iflag=skip_bytes 2>/dev/null; then _debug "read_msr: using dd" read_msr_value=$(dd if=/dev/cpu/"$_cpu"/msr bs=8 count=1 skip="$_msr" iflag=skip_bytes 2>/dev/null | od -t u8 -A n) else _debug "read_msr: got no rdmsr, perl or recent enough dd!" return 201 # missing tool error fi if [ -z "$read_msr_value" ]; then # MSR doesn't exist, don't check for $? because some versions of dd still return 0! return 1 fi fi _debug "read_msr: MSR=$1 value is $read_msr_value" return 0 } check_cpu() { _info "\033[1;34mHardware check\033[0m" if ! uname -m | grep -qwE 'x86_64|i[3-6]86|amd64'; then return fi _info "* Hardware support (CPU microcode) for mitigation techniques" _info " * Indirect Branch Restricted Speculation (IBRS)" _info_nol " * SPEC_CTRL MSR is available: " number_of_cpus ncpus=$? idx_max_cpu=$((ncpus-1)) if [ ! -e /dev/cpu/0/msr ] && [ ! -e /dev/cpuctl0 ]; then # try to load the module ourselves (and remember it so we can rmmod it afterwards) load_msr fi if [ ! -e /dev/cpu/0/msr ] && [ ! -e /dev/cpuctl0 ]; then spec_ctrl_msr=-1 pstatus yellow UNKNOWN "is msr kernel module available?" else # the new MSR 'SPEC_CTRL' is at offset 0x48 # we check if we have it for all cpus val=0 cpu_mismatch=0 for i in $(seq 0 "$idx_max_cpu") do read_msr 0x48 "$i"; ret=$? if [ "$i" -eq 0 ]; then val=$ret else if [ "$ret" -eq $val ]; then continue else cpu_mismatch=1 fi fi done if [ $val -eq 0 ]; then if [ $cpu_mismatch -eq 0 ]; then spec_ctrl_msr=1 pstatus green YES else spec_ctrl_msr=1 pstatus green YES "But not in all CPUs" fi elif [ $val -eq 200 ]; then pstatus yellow UNKNOWN "is msr kernel module available?" spec_ctrl_msr=-1 elif [ $val -eq 201 ]; then pstatus yellow UNKNOWN "missing tool, install either msr-tools or perl" spec_ctrl_msr=-1 else spec_ctrl_msr=0 pstatus yellow NO fi fi _info_nol " * CPU indicates IBRS capability: " # from kernel src: { X86_FEATURE_SPEC_CTRL, CPUID_EDX,26, 0x00000007, 0 }, # amd: https://developer.amd.com/wp-content/resources/Architecture_Guidelines_Update_Indirect_Branch_Control.pdf # amd: 8000_0008 EBX[14]=1 if is_intel; then read_cpuid 0x7 $EDX 26 1 1; ret=$? if [ $ret -eq 0 ]; then pstatus green YES "SPEC_CTRL feature bit" cpuid_spec_ctrl=1 cpuid_ibrs='SPEC_CTRL' fi elif is_amd; then read_cpuid 0x80000008 $EBX 14 1 1; ret=$? if [ $ret -eq 0 ]; then pstatus green YES "IBRS_SUPPORT feature bit" cpuid_ibrs='IBRS_SUPPORT' fi else ret=-1 pstatus yellow UNKNOWN "unknown CPU" fi if [ $ret -eq 1 ]; then pstatus yellow NO elif [ $ret -eq 2 ]; then pstatus yellow UNKNOWN "is cpuid kernel module available?" cpuid_spec_ctrl=-1 fi if is_amd; then _info_nol " * CPU indicates preferring IBRS always-on: " # amd read_cpuid 0x80000008 $EBX 16 1 1; ret=$? if [ $ret -eq 0 ]; then pstatus green YES else pstatus yellow NO fi _info_nol " * CPU indicates preferring IBRS over retpoline: " # amd read_cpuid 0x80000008 $EBX 18 1 1; ret=$? if [ $ret -eq 0 ]; then pstatus green YES else pstatus yellow NO fi fi # IBPB _info " * Indirect Branch Prediction Barrier (IBPB)" _info_nol " * PRED_CMD MSR is available: " if [ ! -e /dev/cpu/0/msr ] && [ ! -e /dev/cpuctl0 ]; then pstatus yellow UNKNOWN "is msr kernel module available?" elif [ ! -r /dev/cpu/0/msr ] && [ ! -w /dev/cpuctl0 ]; then pstatus yellow UNKNOWN "are you root?" else # the new MSR 'PRED_CTRL' is at offset 0x49, write-only # we test if of all cpus val=0 cpu_mismatch=0 for i in $(seq 0 "$idx_max_cpu") do write_msr 0x49 "$i"; ret=$? if [ "$i" -eq 0 ]; then val=$ret else if [ "$ret" -eq $val ]; then continue else cpu_mismatch=1 fi fi done if [ $val -eq 0 ]; then if [ $cpu_mismatch -eq 0 ]; then pstatus green YES else pstatus green YES "But not in all CPUs" fi elif [ $val -eq 200 ]; then pstatus yellow UNKNOWN "is msr kernel module available?" else pstatus yellow NO fi fi _info_nol " * CPU indicates IBPB capability: " # CPUID EAX=0x80000008, ECX=0x00 return EBX[12] indicates support for just IBPB. if [ "$cpuid_spec_ctrl" = 1 ]; then # spec_ctrl implies ibpb cpuid_ibpb='SPEC_CTRL' pstatus green YES "SPEC_CTRL feature bit" elif is_intel; then if [ "$cpuid_spec_ctrl" = -1 ]; then pstatus yellow UNKNOWN "is cpuid kernel module available?" else pstatus yellow NO fi elif is_amd; then read_cpuid 0x80000008 $EBX 12 1 1; ret=$? if [ $ret -eq 0 ]; then cpuid_ibpb='IBPB_SUPPORT' pstatus green YES "IBPB_SUPPORT feature bit" elif [ $ret -eq 1 ]; then pstatus yellow NO else pstatus yellow UNKNOWN "is cpuid kernel module available?" fi fi # STIBP _info " * Single Thread Indirect Branch Predictors (STIBP)" _info_nol " * SPEC_CTRL MSR is available: " if [ "$spec_ctrl_msr" = 1 ]; then pstatus green YES elif [ "$spec_ctrl_msr" = 0 ]; then pstatus yellow NO else pstatus yellow UNKNOWN "is msr kernel module available?" fi _info_nol " * CPU indicates STIBP capability: " # intel: A processor supports STIBP if it enumerates CPUID (EAX=7H,ECX=0):EDX[27] as 1 # amd: 8000_0008 EBX[15]=1 if is_intel; then read_cpuid 0x7 $EDX 27 1 1; ret=$? if [ $ret -eq 0 ]; then pstatus green YES "Intel STIBP feature bit" #cpuid_stibp='Intel STIBP' fi elif is_amd; then read_cpuid 0x80000008 $EBX 15 1 1; ret=$? if [ $ret -eq 0 ]; then pstatus green YES "AMD STIBP feature bit" #cpuid_stibp='AMD STIBP' fi else ret=-1 pstatus yellow UNKNOWN "unknown CPU" fi if [ $ret -eq 1 ]; then pstatus yellow NO elif [ $ret -eq 2 ]; then pstatus yellow UNKNOWN "is cpuid kernel module available?" fi if is_amd; then _info_nol " * CPU indicates preferring STIBP always-on: " read_cpuid 0x80000008 $EBX 17 1 1; ret=$? if [ $ret -eq 0 ]; then pstatus green YES else pstatus yellow NO fi fi # variant 4 if is_intel; then _info " * Speculative Store Bypass Disable (SSBD)" _info_nol " * CPU indicates SSBD capability: " read_cpuid 0x7 $EDX 31 1 1; ret24=$?; ret25=$ret24 if [ $ret24 -eq 0 ]; then cpuid_ssbd='Intel SSBD' fi elif is_amd; then _info " * Speculative Store Bypass Disable (SSBD)" _info_nol " * CPU indicates SSBD capability: " read_cpuid 0x80000008 $EBX 24 1 1; ret24=$? read_cpuid 0x80000008 $EBX 25 1 1; ret25=$? if [ $ret24 -eq 0 ]; then cpuid_ssbd='AMD SSBD in SPEC_CTRL' #cpuid_ssbd_spec_ctrl=1 elif [ $ret25 -eq 0 ]; then cpuid_ssbd='AMD SSBD in VIRT_SPEC_CTRL' #cpuid_ssbd_virt_spec_ctrl=1 elif [ "$cpu_family" -ge 21 ] && [ "$cpu_family" -le 23 ]; then cpuid_ssbd='AMD non-architectural MSR' fi fi if [ -n "$cpuid_ssbd" ]; then pstatus green YES "$cpuid_ssbd" elif [ "$ret24" = 2 ] && [ "$ret25" = 2 ]; then pstatus yellow UNKNOWN "is cpuid kernel module available?" else pstatus yellow NO fi if is_amd; then # similar to SSB_NO for intel read_cpuid 0x80000008 $EBX 26 1 1; ret=$? if [ $ret -eq 0 ]; then amd_ssb_no=1 fi fi _info " * L1 data cache invalidation" _info_nol " * FLUSH_CMD MSR is available: " if [ ! -e /dev/cpu/0/msr ] && [ ! -e /dev/cpuctl0 ]; then pstatus yellow UNKNOWN "is msr kernel module available?" elif [ ! -r /dev/cpu/0/msr ] && [ ! -w /dev/cpuctl0 ]; then pstatus yellow UNKNOWN "are you root?" else # the new MSR 'FLUSH_CMD' is at offset 0x10b, write-only # we test if of all cpus val=0 cpu_mismatch=0 for i in $(seq 0 "$idx_max_cpu") do write_msr 0x10b "$i"; ret=$? if [ "$i" -eq 0 ]; then val=$ret else if [ "$ret" -eq $val ]; then continue else cpu_mismatch=1 fi fi done if [ $val -eq 0 ]; then if [ $cpu_mismatch -eq 0 ]; then pstatus green YES cpu_flush_cmd=1 else pstatus green YES "But not in all CPUs" fi elif [ $val -eq 200 ]; then pstatus yellow UNKNOWN "is msr kernel module available?" else pstatus yellow NO fi fi # CPUID of L1D _info_nol " * CPU indicates L1D flush capability: " read_cpuid 0x7 $EDX 28 1 1; ret=$? if [ $ret -eq 0 ]; then pstatus green YES "L1D flush feature bit" elif [ $ret -eq 1 ]; then pstatus yellow NO elif [ $ret -eq 2 ]; then pstatus yellow UNKNOWN "is cpuid kernel module available?" fi if is_intel; then _info " * Enhanced IBRS (IBRS_ALL)" _info_nol " * CPU indicates ARCH_CAPABILITIES MSR availability: " cpuid_arch_capabilities=-1 # A processor supports the ARCH_CAPABILITIES MSR if it enumerates CPUID (EAX=7H,ECX=0):EDX[29] as 1 read_cpuid 0x7 $EDX 29 1 1; ret=$? if [ $ret -eq 0 ]; then pstatus green YES cpuid_arch_capabilities=1 elif [ $ret -eq 2 ]; then pstatus yellow UNKNOWN "is cpuid kernel module available?" else pstatus yellow NO cpuid_arch_capabilities=0 fi _info_nol " * ARCH_CAPABILITIES MSR advertises IBRS_ALL capability: " capabilities_rdcl_no=-1 capabilities_ibrs_all=-1 capabilities_rsba=-1 capabilities_l1dflush_no=-1 capabilities_ssb_no=-1 if [ "$cpuid_arch_capabilities" = -1 ]; then pstatus yellow UNKNOWN elif [ "$cpuid_arch_capabilities" != 1 ]; then capabilities_rdcl_no=0 capabilities_ibrs_all=0 capabilities_rsba=0 capabilities_l1dflush_no=0 capabilities_ssb_no=0 pstatus yellow NO elif [ ! -e /dev/cpu/0/msr ] && [ ! -e /dev/cpuctl0 ]; then spec_ctrl_msr=-1 pstatus yellow UNKNOWN "is msr kernel module available?" else # the new MSR 'ARCH_CAPABILITIES' is at offset 0x10a # we check if we have it for all cpus val=0 val_cap_msr=0 cpu_mismatch=0 for i in $(seq 0 "$idx_max_cpu") do read_msr 0x10a "$i"; ret=$? capabilities=$read_msr_value if [ "$i" -eq 0 ]; then val=$ret val_cap_msr=$capabilities else if [ "$ret" -eq "$val" ] && [ "$capabilities" -eq "$val_cap_msr" ]; then continue else cpu_mismatch=1 fi fi done capabilities=$val_cap_msr capabilities_rdcl_no=0 capabilities_ibrs_all=0 capabilities_rsba=0 capabilities_l1dflush_no=0 capabilities_ssb_no=0 if [ $val -eq 0 ]; then _debug "capabilities MSR is $capabilities (decimal)" [ $(( capabilities >> 0 & 1 )) -eq 1 ] && capabilities_rdcl_no=1 [ $(( capabilities >> 1 & 1 )) -eq 1 ] && capabilities_ibrs_all=1 [ $(( capabilities >> 2 & 1 )) -eq 1 ] && capabilities_rsba=1 [ $(( capabilities >> 3 & 1 )) -eq 1 ] && capabilities_l1dflush_no=1 [ $(( capabilities >> 4 & 1 )) -eq 1 ] && capabilities_ssb_no=1 _debug "capabilities says rdcl_no=$capabilities_rdcl_no ibrs_all=$capabilities_ibrs_all rsba=$capabilities_rsba l1dflush_no=$capabilities_l1dflush_no ssb_no=$capabilities_ssb_no" if [ "$capabilities_ibrs_all" = 1 ]; then if [ $cpu_mismatch -eq 0 ]; then pstatus green YES else pstatus green YES "But not in all CPUs" fi else pstatus yellow NO fi elif [ $val -eq 200 ]; then pstatus yellow UNKNOWN "is msr kernel module available?" elif [ $val -eq 201 ]; then pstatus yellow UNKNOWN "missing tool, install either msr-tools or perl" else pstatus yellow NO fi fi _info_nol " * CPU explicitly indicates not being vulnerable to Meltdown (RDCL_NO): " if [ "$capabilities_rdcl_no" = -1 ]; then pstatus yellow UNKNOWN elif [ "$capabilities_rdcl_no" = 1 ]; then pstatus green YES else pstatus yellow NO fi _info_nol " * CPU explicitly indicates not being vulnerable to Variant 4 (SSB_NO): " if [ "$capabilities_ssb_no" = -1 ]; then pstatus yellow UNKNOWN elif [ "$capabilities_ssb_no" = 1 ] || [ "$amd_ssb_no" = 1 ]; then pstatus green YES else pstatus yellow NO fi _info_nol " * CPU/Hypervisor indicates L1D flushing is not necessary on this system: " if [ "$capabilities_l1dflush_no" = -1 ]; then pstatus yellow UNKNOWN elif [ "$capabilities_l1dflush_no" = 1 ]; then pstatus green YES else pstatus yellow NO fi _info_nol " * Hypervisor indicates host CPU might be vulnerable to RSB underflow (RSBA): " if [ "$capabilities_rsba" = -1 ]; then pstatus yellow UNKNOWN elif [ "$capabilities_rsba" = 1 ]; then pstatus yellow YES else pstatus blue NO fi fi _info_nol " * CPU supports Software Guard Extensions (SGX): " ret=1 cpuid_sgx=0 if is_intel; then read_cpuid 0x7 $EBX 2 1 1; ret=$? fi if [ $ret -eq 0 ]; then pstatus blue YES cpuid_sgx=1 elif [ $ret -eq 2 ]; then pstatus yellow UNKNOWN "is cpuid kernel module available?" cpuid_sgx=-1 else pstatus green NO fi _info_nol " * CPU microcode is known to cause stability problems: " if is_ucode_blacklisted; then pstatus red YES "$ucode_found" _warn _warn "The microcode your CPU is running on is known to cause instability problems," _warn "such as intempestive reboots or random crashes." _warn "You are advised to either revert to a previous microcode version (that might not have" _warn "the mitigations for Spectre), or upgrade to a newer one if available." _warn else pstatus blue NO "$ucode_found" fi _info_nol " * CPU microcode is the latest known available version: " is_latest_known_ucode; ret=$? if [ $ret -eq 0 ]; then pstatus green YES "$ucode_latest" elif [ $ret -eq 1 ]; then pstatus red NO "$ucode_latest" else pstatus blue UNKNOWN "$ucode_latest" fi } check_cpu_vulnerabilities() { _info "* CPU vulnerability to the speculative execution attack variants" for cve in $supported_cve_list; do _info_nol " * Vulnerable to $cve ($(cve2name "$cve")): " if is_cpu_vulnerable "$cve"; then pstatus yellow YES else pstatus green NO fi done } check_redhat_canonical_spectre() { # if we were already called, don't do it again [ -n "$redhat_canonical_spectre" ] && return if ! which "${opt_arch_prefix}strings" >/dev/null 2>&1; then redhat_canonical_spectre=-1 elif [ -n "$kernel_err" ]; then redhat_canonical_spectre=-2 else # Red Hat / Ubuntu specific variant1 patch is difficult to detect, # let's use the two same tricks than the official Red Hat detection script uses: if "${opt_arch_prefix}strings" "$kernel" | grep -qw noibrs && "${opt_arch_prefix}strings" "$kernel" | grep -qw noibpb; then # 1) detect their specific variant2 patch. If it's present, it means # that the variant1 patch is also present (both were merged at the same time) _debug "found redhat/canonical version of the variant2 patch (implies variant1)" redhat_canonical_spectre=1 elif "${opt_arch_prefix}strings" "$kernel" | grep -q 'x86/pti:'; then # 2) detect their specific variant3 patch. If it's present, but the variant2 # is not, it means that only variant1 is present in addition to variant3 _debug "found redhat/canonical version of the variant3 patch (implies variant1 but not variant2)" redhat_canonical_spectre=2 else redhat_canonical_spectre=0 fi fi } ################### # SPECTRE 1 SECTION # bounds check bypass aka 'Spectre Variant 1' check_CVE_2017_5753() { cve='CVE-2017-5753' _info "\033[1;34m$cve aka '$(cve2name "$cve")'\033[0m" if [ "$os" = Linux ]; then check_CVE_2017_5753_linux elif echo "$os" | grep -q BSD; then check_CVE_2017_5753_bsd else _warn "Unsupported OS ($os)" fi } check_CVE_2017_5753_linux() { status=UNK sys_interface_available=0 msg='' if sys_interface_check "/sys/devices/system/cpu/vulnerabilities/spectre_v1"; then # this kernel has the /sys interface, trust it over everything # v0.33+: don't. some kernels have backported the array_index_mask_nospec() workaround without # modifying the vulnerabilities/spectre_v1 file. that's bad. we can't trust it when it says Vulnerable :( # see "silent backport" detection at the bottom of this func sys_interface_available=1 fi if [ "$opt_sysfs_only" != 1 ]; then # no /sys interface (or offline mode), fallback to our own ways _info_nol "* Kernel has array_index_mask_nospec: " # vanilla: look for the Linus' mask aka array_index_mask_nospec() # that is inlined at least in raw_copy_from_user (__get_user_X symbols) #mov PER_CPU_VAR(current_task), %_ASM_DX #cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX #jae bad_get_user # /* array_index_mask_nospec() are the 2 opcodes that follow */ #+sbb %_ASM_DX, %_ASM_DX #+and %_ASM_DX, %_ASM_AX #ASM_STAC # x86 64bits: jae(0x0f 0x83 0x?? 0x?? 0x?? 0x??) sbb(0x48 0x19 0xd2) and(0x48 0x21 0xd0) # x86 32bits: cmp(0x3b 0x82 0x?? 0x?? 0x00 0x00) jae(0x73 0x??) sbb(0x19 0xd2) and(0x21 0xd0) # # arm32 ##ifdef CONFIG_THUMB2_KERNEL ##define CSDB ".inst.w 0xf3af8014" ##else ##define CSDB ".inst 0xe320f014" e320f014 ##endif #asm volatile( # "cmp %1, %2\n" e1500003 #" sbc %0, %1, %1\n" e0c03000 #CSDB #: "=r" (mask) #: "r" (idx), "Ir" (sz) #: "cc"); # # http://git.arm.linux.org.uk/cgit/linux-arm.git/commit/?h=spectre&id=a78d156587931a2c3b354534aa772febf6c9e855 if [ -n "$kernel_err" ]; then pstatus yellow UNKNOWN "couldn't check ($kernel_err)" elif ! which perl >/dev/null 2>&1; then pstatus yellow UNKNOWN "missing 'perl' binary, please install it" else perl -ne '/\x0f\x83....\x48\x19\xd2\x48\x21\xd0/ and $found++; END { exit($found) }' "$kernel"; ret=$? if [ $ret -gt 0 ]; then pstatus green YES "$ret occurrence(s) found of x86 64 bits array_index_mask_nospec()" v1_mask_nospec="x86 64 bits array_index_mask_nospec" else perl -ne '/\x3b\x82..\x00\x00\x73.\x19\xd2\x21\xd0/ and $found++; END { exit($found) }' "$kernel"; ret=$? if [ $ret -gt 0 ]; then pstatus green YES "$ret occurrence(s) found of x86 32 bits array_index_mask_nospec()" v1_mask_nospec="x86 32 bits array_index_mask_nospec" else ret=$("${opt_arch_prefix}objdump" -d "$kernel" | grep -w -e f3af8014 -e e320f014 -B2 | grep -B1 -w sbc | grep -w -c cmp) if [ "$ret" -gt 0 ]; then pstatus green YES "$ret occurrence(s) found of arm 32 bits array_index_mask_nospec()" v1_mask_nospec="arm 32 bits array_index_mask_nospec" else pstatus yellow NO fi fi fi fi _info_nol "* Kernel has the Red Hat/Ubuntu patch: " check_redhat_canonical_spectre if [ "$redhat_canonical_spectre" = -1 ]; then pstatus yellow UNKNOWN "missing '${opt_arch_prefix}strings' tool, please install it, usually it's in the binutils package" elif [ "$redhat_canonical_spectre" = -2 ]; then pstatus yellow UNKNOWN "couldn't check ($kernel_err)" elif [ "$redhat_canonical_spectre" = 1 ]; then pstatus green YES elif [ "$redhat_canonical_spectre" = 2 ]; then pstatus green YES "but without IBRS" else pstatus yellow NO fi _info_nol "* Kernel has mask_nospec64 (arm64): " #.macro mask_nospec64, idx, limit, tmp #sub \tmp, \idx, \limit #bic \tmp, \tmp, \idx #and \idx, \idx, \tmp, asr #63 #csdb #.endm #$ aarch64-linux-gnu-objdump -d vmlinux | grep -w bic -A1 -B1 | grep -w sub -A2 | grep -w and -B2 #ffffff8008082e44: cb190353 sub x19, x26, x25 #ffffff8008082e48: 8a3a0273 bic x19, x19, x26 #ffffff8008082e4c: 8a93ff5a and x26, x26, x19, asr #63 #ffffff8008082e50: d503229f hint #0x14 # /!\ can also just be "csdb" instead of "hint #0x14" for native objdump # # if we have v1_mask_nospec or redhat_canonical_spectre>0, don't bother disassembling the kernel, the answer is no. if [ -n "$v1_mask_nospec" ] || [ "$redhat_canonical_spectre" -gt 0 ]; then pstatus yellow NO elif [ -n "$kernel_err" ]; then pstatus yellow UNKNOWN "couldn't check ($kernel_err)" elif ! which perl >/dev/null 2>&1; then pstatus yellow UNKNOWN "missing 'perl' binary, please install it" elif ! which "${opt_arch_prefix}objdump" >/dev/null 2>&1; then pstatus yellow UNKNOWN "missing '${opt_arch_prefix}objdump' tool, please install it, usually it's in the binutils package" else "${opt_arch_prefix}objdump" -d "$kernel" | perl -ne 'push @r, $_; /\s(hint|csdb)\s/ && $r[0]=~/\ssub\s+(x\d+)/ && $r[1]=~/\sbic\s+$1,\s+$1,/ && $r[2]=~/\sand\s/ && exit(9); shift @r if @r>3'; ret=$? if [ "$ret" -eq 9 ]; then pstatus green YES "mask_nospec64 macro is present and used" v1_mask_nospec="arm64 mask_nospec64" else pstatus yellow NO fi fi if [ "$opt_verbose" -ge 2 ] || ( [ -z "$v1_mask_nospec" ] && [ "$redhat_canonical_spectre" != 1 ] && [ "$redhat_canonical_spectre" != 2 ] ); then # this is a slow heuristic and we don't need it if we already know the kernel is patched # but still show it in verbose mode _info_nol "* Checking count of LFENCE instructions following a jump in kernel... " if [ -n "$kernel_err" ]; then pstatus yellow UNKNOWN "couldn't check ($kernel_err)" else if ! which "${opt_arch_prefix}objdump" >/dev/null 2>&1; then pstatus yellow UNKNOWN "missing '${opt_arch_prefix}objdump' tool, please install it, usually it's in the binutils package" else # here we disassemble the kernel and count the number of occurrences of the LFENCE opcode # in non-patched kernels, this has been empirically determined as being around 40-50 # in patched kernels, this is more around 70-80, sometimes way higher (100+) # v0.13: 68 found in a 3.10.23-xxxx-std-ipv6-64 (with lots of modules compiled-in directly), which doesn't have the LFENCE patches, # so let's push the threshold to 70. # v0.33+: now only count lfence opcodes after a jump, way less error-prone # non patched kernel have between 0 and 20 matches, patched ones have at least 40-45 nb_lfence=$("${opt_arch_prefix}objdump" -d "$kernel" 2>/dev/null | grep -w -B1 lfence | grep -Ewc 'jmp|jne|je') if [ "$nb_lfence" -lt 30 ]; then pstatus yellow NO "only $nb_lfence jump-then-lfence instructions found, should be >= 30 (heuristic)" else v1_lfence=1 pstatus green YES "$nb_lfence jump-then-lfence instructions found, which is >= 30 (heuristic)" fi fi fi fi else # we have no sysfs but were asked to use it only! msg="/sys vulnerability interface use forced, but it's not available!" status=UNK fi # report status if ! is_cpu_vulnerable "$cve"; then # override status & msg in case CPU is not vulnerable after all pvulnstatus $cve OK "your CPU vendor reported your CPU model as not vulnerable" elif [ -z "$msg" ]; then # if msg is empty, sysfs check didn't fill it, rely on our own test if [ -n "$v1_mask_nospec" ]; then pvulnstatus $cve OK "Kernel source has been patched to mitigate the vulnerability ($v1_mask_nospec)" elif [ "$redhat_canonical_spectre" = 1 ] || [ "$redhat_canonical_spectre" = 2 ]; then pvulnstatus $cve OK "Kernel source has been patched to mitigate the vulnerability (Red Hat/Ubuntu patch)" elif [ "$v1_lfence" = 1 ]; then pvulnstatus $cve OK "Kernel source has PROBABLY been patched to mitigate the vulnerability (jump-then-lfence instructions heuristic)" elif [ "$kernel_err" ]; then pvulnstatus $cve UNK "Couldn't find kernel image or tools missing to execute the checks" explain "Re-run this script with root privileges, after installing the missing tools indicated above" else pvulnstatus $cve VULN "Kernel source needs to be patched to mitigate the vulnerability" explain "Your kernel is too old to have the mitigation for Variant 1, you should upgrade to a newer kernel. If you're using a Linux distro and didn't compile the kernel yourself, you should upgrade your distro to get a newer kernel." fi else if [ "$msg" = "Vulnerable" ] && [ -n "$v1_mask_nospec" ]; then pvulnstatus $cve OK "Kernel source has been patched to mitigate the vulnerability (silent backport of array_index_mask_nospec)" else if [ "$msg" = "Vulnerable" ]; then msg="Kernel source needs to be patched to mitigate the vulnerability" _explain="Your kernel is too old to have the mitigation for Variant 1, you should upgrade to a newer kernel. If you're using a Linux distro and didn't compile the kernel yourself, you should upgrade your distro to get a newer kernel." fi pvulnstatus $cve "$status" "$msg" [ -n "$_explain" ] && explain "$_explain" unset _explain fi fi } check_CVE_2017_5753_bsd() { if ! is_cpu_vulnerable "$cve"; then # override status & msg in case CPU is not vulnerable after all pvulnstatus $cve OK "your CPU vendor reported your CPU model as not vulnerable" else pvulnstatus $cve VULN "no mitigation for BSD yet" fi } ################### # SPECTRE 2 SECTION # branch target injection aka 'Spectre Variant 2' check_CVE_2017_5715() { cve='CVE-2017-5715' _info "\033[1;34m$cve aka '$(cve2name "$cve")'\033[0m" if [ "$os" = Linux ]; then check_CVE_2017_5715_linux elif echo "$os" | grep -q BSD; then check_CVE_2017_5715_bsd else _warn "Unsupported OS ($os)" fi } check_CVE_2017_5715_linux() { status=UNK sys_interface_available=0 msg='' if sys_interface_check "/sys/devices/system/cpu/vulnerabilities/spectre_v2"; then # this kernel has the /sys interface, trust it over everything sys_interface_available=1 fi if [ "$opt_sysfs_only" != 1 ]; then _info "* Mitigation 1" ibrs_can_tell=0 ibrs_supported='' ibrs_enabled='' ibpb_can_tell=0 ibpb_supported='' ibpb_enabled='' if [ "$opt_live" = 1 ]; then # in live mode, we can check for the ibrs_enabled file in debugfs # all versions of the patches have it (NOT the case of IBPB or KPTI) ibrs_can_tell=1 mount_debugfs for dir in \ /sys/kernel/debug \ /sys/kernel/debug/x86 \ "$procfs/sys/kernel"; do if [ -e "$dir/ibrs_enabled" ]; then # if the file is there, we have IBRS compiled-in # /sys/kernel/debug/ibrs_enabled: vanilla # /sys/kernel/debug/x86/ibrs_enabled: Red Hat (see https://access.redhat.com/articles/3311301) # /proc/sys/kernel/ibrs_enabled: OpenSUSE tumbleweed specex_knob_dir=$dir ibrs_supported="$dir/ibrs_enabled exists" ibrs_enabled=$(cat "$dir/ibrs_enabled" 2>/dev/null) _debug "ibrs: found $dir/ibrs_enabled=$ibrs_enabled" # if ibrs_enabled is there, ibpb_enabled will be in the same dir if [ -e "$dir/ibpb_enabled" ]; then # if the file is there, we have IBPB compiled-in (see note above for IBRS) ibpb_supported="$dir/ibpb_enabled exists" ibpb_enabled=$(cat "$dir/ibpb_enabled" 2>/dev/null) _debug "ibpb: found $dir/ibpb_enabled=$ibpb_enabled" else _debug "ibpb: $dir/ibpb_enabled file doesn't exist" fi break else _debug "ibrs: $dir/ibrs_enabled file doesn't exist" fi done # on some newer kernels, the spec_ctrl_ibrs flag in "$procfs/cpuinfo" # is set when ibrs has been administratively enabled (usually from cmdline) # which in that case means ibrs is supported *and* enabled for kernel & user # as per the ibrs patch series v3 if [ -z "$ibrs_supported" ]; then if grep ^flags "$procfs/cpuinfo" | grep -qw spec_ctrl_ibrs; then _debug "ibrs: found spec_ctrl_ibrs flag in $procfs/cpuinfo" ibrs_supported="spec_ctrl_ibrs flag in $procfs/cpuinfo" # enabled=2 -> kernel & user ibrs_enabled=2 # XXX and what about ibpb ? fi fi if [ -e "/sys/devices/system/cpu/vulnerabilities/spectre_v2" ]; then # when IBPB is enabled on 4.15+, we can see it in sysfs if grep -q 'IBPB' "/sys/devices/system/cpu/vulnerabilities/spectre_v2"; then _debug "ibpb: found enabled in sysfs" [ -z "$ibpb_supported" ] && ibpb_supported='IBPB found enabled in sysfs' [ -z "$ibpb_enabled" ] && ibpb_enabled=1 fi # when IBRS_FW is enabled on 4.15+, we can see it in sysfs if grep -q ', IBRS_FW' "/sys/devices/system/cpu/vulnerabilities/spectre_v2"; then _debug "ibrs: found IBRS_FW in sysfs" [ -z "$ibrs_supported" ] && ibrs_supported='found IBRS_FW in sysfs' ibrs_fw_enabled=1 fi # when IBRS is enabled on 4.15+, we can see it in sysfs if grep -q -e 'IBRS' -e 'Indirect Branch Restricted Speculation' "/sys/devices/system/cpu/vulnerabilities/spectre_v2"; then _debug "ibrs: found IBRS in sysfs" [ -z "$ibrs_supported" ] && ibrs_supported='found IBRS in sysfs' [ -z "$ibrs_enabled" ] && ibrs_enabled=3 fi fi # in live mode, if ibrs or ibpb is supported and we didn't find these are enabled, then they are not [ -n "$ibrs_supported" ] && [ -z "$ibrs_enabled" ] && ibrs_enabled=0 [ -n "$ibpb_supported" ] && [ -z "$ibpb_enabled" ] && ibpb_enabled=0 fi if [ -z "$ibrs_supported" ]; then check_redhat_canonical_spectre if [ "$redhat_canonical_spectre" = 1 ]; then ibrs_supported="Red Hat/Ubuntu variant" ibpb_supported="Red Hat/Ubuntu variant" fi fi if [ -z "$ibrs_supported" ] && [ -n "$kernel" ]; then if ! which "${opt_arch_prefix}strings" >/dev/null 2>&1; then : else ibrs_can_tell=1 ibrs_supported=$("${opt_arch_prefix}strings" "$kernel" | grep -Fw -e ', IBRS_FW' | head -1) if [ -n "$ibrs_supported" ]; then _debug "ibrs: found ibrs evidence in kernel image ($ibrs_supported)" ibrs_supported="found '$ibrs_supported' in kernel image" fi fi fi if [ -z "$ibrs_supported" ] && [ -n "$opt_map" ]; then ibrs_can_tell=1 if grep -q spec_ctrl "$opt_map"; then ibrs_supported="found spec_ctrl in symbols file" _debug "ibrs: found '*spec_ctrl*' symbol in $opt_map" fi fi # recent (4.15) vanilla kernels have IBPB but not IBRS, and without the debugfs tunables of Red Hat # we can detect it directly in the image if [ -z "$ibpb_supported" ] && [ -n "$kernel" ]; then if ! which "${opt_arch_prefix}strings" >/dev/null 2>&1; then : else ibpb_can_tell=1 ibpb_supported=$("${opt_arch_prefix}strings" "$kernel" | grep -Fw -e 'ibpb' -e ', IBPB' | head -1) if [ -n "$ibpb_supported" ]; then _debug "ibpb: found ibpb evidence in kernel image ($ibpb_supported)" ibpb_supported="found '$ibpb_supported' in kernel image" fi fi fi _info_nol " * Kernel is compiled with IBRS support: " if [ -z "$ibrs_supported" ]; then if [ "$ibrs_can_tell" = 1 ]; then pstatus yellow NO else # if we're in offline mode without System.map, we can't really know pstatus yellow UNKNOWN "in offline mode, we need the kernel image and System.map to be able to tell" fi else if [ "$opt_verbose" -ge 2 ]; then pstatus green YES "$ibrs_supported" else pstatus green YES fi fi _info_nol " * IBRS enabled and active: " if [ "$opt_live" = 1 ]; then if [ "$ibpb_enabled" = 2 ]; then # if ibpb=2, ibrs is forcefully=0 pstatus blue NO "IBPB used instead of IBRS in all kernel entrypoints" else # 0 means disabled # 1 is enabled only for kernel space # 2 is enabled for kernel and user space # 3 is enabled case "$ibrs_enabled" in 0) if [ "$ibrs_fw_enabled" = 1 ]; then pstatus blue YES "for firmware code only" else pstatus yellow NO fi ;; 1) if [ "$ibrs_fw_enabled" = 1 ]; then pstatus green YES "for kernel space and firmware code"; else pstatus green YES "for kernel space"; fi;; 2) if [ "$ibrs_fw_enabled" = 1 ]; then pstatus green YES "for kernel, user space, and firmware code" ; else pstatus green YES "for both kernel and user space"; fi;; 3) if [ "$ibrs_fw_enabled" = 1 ]; then pstatus green YES "for kernel and firmware code"; else pstatus green YES; fi;; *) if [ "$cpuid_ibrs" != 'SPEC_CTRL' ] && [ "$cpuid_ibrs" != 'IBRS_SUPPORT' ] && [ "$cpuid_spec_ctrl" != -1 ]; then pstatus yellow NO; _debug "ibrs: known cpu not supporting SPEC-CTRL or IBRS"; else pstatus yellow UNKNOWN; fi;; esac fi else pstatus blue N/A "not testable in offline mode" fi _info_nol " * Kernel is compiled with IBPB support: " if [ -z "$ibpb_supported" ]; then if [ "$ibpb_can_tell" = 1 ]; then pstatus yellow NO else # if we're in offline mode without System.map, we can't really know pstatus yellow UNKNOWN "in offline mode, we need the kernel image to be able to tell" fi else if [ "$opt_verbose" -ge 2 ]; then pstatus green YES "$ibpb_supported" else pstatus green YES fi fi _info_nol " * IBPB enabled and active: " if [ "$opt_live" = 1 ]; then case "$ibpb_enabled" in "") if [ "$ibrs_supported" = 1 ]; then pstatus yellow UNKNOWN else pstatus yellow NO fi ;; 0) pstatus yellow NO ;; 1) pstatus green YES;; 2) pstatus green YES "IBPB used instead of IBRS in all kernel entrypoints";; *) pstatus yellow UNKNOWN;; esac else pstatus blue N/A "not testable in offline mode" fi _info "* Mitigation 2" _info_nol " * Kernel has branch predictor hardening (arm): " if [ -r "$opt_config" ]; then bp_harden_can_tell=1 bp_harden=$(grep -w 'CONFIG_HARDEN_BRANCH_PREDICTOR=y' "$opt_config") if [ -n "$bp_harden" ]; then pstatus green YES _debug "bp_harden: found '$bp_harden' in $opt_config" fi fi if [ -z "$bp_harden" ] && [ -n "$opt_map" ]; then bp_harden_can_tell=1 bp_harden=$(grep -w bp_hardening_data "$opt_map") if [ -n "$bp_harden" ]; then pstatus green YES _debug "bp_harden: found '$bp_harden' in $opt_map" fi fi if [ -z "$bp_harden" ]; then if [ "$bp_harden_can_tell" = 1 ]; then pstatus yellow NO else pstatus yellow UNKNOWN fi fi _info_nol " * Kernel compiled with retpoline option: " # We check the RETPOLINE kernel options if [ -r "$opt_config" ]; then if grep -q '^CONFIG_RETPOLINE=y' "$opt_config"; then pstatus green YES retpoline=1 # shellcheck disable=SC2046 _debug 'retpoline: found '$(grep '^CONFIG_RETPOLINE' "$opt_config")" in $opt_config" else pstatus yellow NO fi else pstatus yellow UNKNOWN "couldn't read your kernel configuration" fi if [ "$retpoline" = 1 ]; then # Now check if the compiler used to compile the kernel knows how to insert retpolines in generated asm # For gcc, this is -mindirect-branch=thunk-extern (detected by the kernel makefiles) # See gcc commit https://github.com/hjl-tools/gcc/commit/23b517d4a67c02d3ef80b6109218f2aadad7bd79 # In latest retpoline LKML patches, the noretpoline_setup symbol exists only if CONFIG_RETPOLINE is set # *AND* if the compiler is retpoline-compliant, so look for that symbol # # if there is "retpoline" in the file and NOT "minimal", then it's full retpoline # (works for vanilla and Red Hat variants) if [ "$opt_live" = 1 ] && [ -e "/sys/devices/system/cpu/vulnerabilities/spectre_v2" ]; then if grep -qwi retpoline /sys/devices/system/cpu/vulnerabilities/spectre_v2; then if grep -qwi minimal /sys/devices/system/cpu/vulnerabilities/spectre_v2; then retpoline_compiler=0 retpoline_compiler_reason="kernel reports minimal retpoline compilation" else retpoline_compiler=1 retpoline_compiler_reason="kernel reports full retpoline compilation" fi fi elif [ -n "$opt_map" ]; then # look for the symbol if grep -qw noretpoline_setup "$opt_map"; then retpoline_compiler=1 retpoline_compiler_reason="noretpoline_setup symbol found in System.map" fi elif [ -n "$kernel" ]; then # look for the symbol if which "${opt_arch_prefix}nm" >/dev/null 2>&1; then # the proper way: use nm and look for the symbol if "${opt_arch_prefix}nm" "$kernel" 2>/dev/null | grep -qw 'noretpoline_setup'; then retpoline_compiler=1 retpoline_compiler_reason="noretpoline_setup found in kernel symbols" fi elif grep -q noretpoline_setup "$kernel"; then # if we don't have nm, nevermind, the symbol name is long enough to not have # any false positive using good old grep directly on the binary retpoline_compiler=1 retpoline_compiler_reason="noretpoline_setup found in kernel" fi fi if [ -n "$retpoline_compiler" ]; then _info_nol " * Kernel compiled with a retpoline-aware compiler: " if [ "$retpoline_compiler" = 1 ]; then if [ -n "$retpoline_compiler_reason" ]; then pstatus green YES "$retpoline_compiler_reason" else pstatus green YES fi else if [ -n "$retpoline_compiler_reason" ]; then pstatus red NO "$retpoline_compiler_reason" else pstatus red NO fi fi fi fi # only Red Hat has a tunable to disable it on runtime if [ "$opt_live" = 1 ]; then if [ -e "$specex_knob_dir/retp_enabled" ]; then retp_enabled=$(cat "$specex_knob_dir/retp_enabled" 2>/dev/null) _debug "retpoline: found $specex_knob_dir/retp_enabled=$retp_enabled" _info_nol " * Retpoline is enabled: " if [ "$retp_enabled" = 1 ]; then pstatus green YES else pstatus yellow NO fi fi fi # only for information, in verbose mode if [ "$opt_verbose" -ge 2 ]; then _info_nol " * Local gcc is retpoline-aware: " if which gcc >/dev/null 2>&1; then if [ -n "$(gcc -mindirect-branch=thunk-extern --version 2>&1 >/dev/null)" ]; then pstatus blue NO else pstatus green YES fi else pstatus blue NO "gcc is not installed" fi fi if is_vulnerable_to_empty_rsb || [ "$opt_verbose" -ge 2 ]; then _info_nol " * Kernel supports RSB filling: " if ! which "${opt_arch_prefix}strings" >/dev/null 2>&1; then pstatus yellow UNKNOWN "missing '${opt_arch_prefix}strings' tool, please install it, usually it's in the binutils package" elif [ -z "$kernel" ]; then pstatus yellow UNKNOWN "kernel image missing" else rsb_filling=$("${opt_arch_prefix}strings" "$kernel" | grep -w 'Filling RSB on context switch') if [ -n "$rsb_filling" ]; then pstatus green YES else pstatus yellow NO fi fi fi elif [ "$sys_interface_available" = 0 ]; then # we have no sysfs but were asked to use it only! msg="/sys vulnerability interface use forced, but it's not available!" status=UNK fi if ! is_cpu_vulnerable "$cve"; then # override status & msg in case CPU is not vulnerable after all pvulnstatus $cve OK "your CPU vendor reported your CPU model as not vulnerable" else if [ "$retpoline" = 1 ] && [ "$retpoline_compiler" = 1 ] && [ "$retp_enabled" != 0 ] && [ -n "$ibpb_enabled" ] && [ "$ibpb_enabled" -ge 1 ] && ( ! is_vulnerable_to_empty_rsb || [ -n "$rsb_filling" ] ); then pvulnstatus $cve OK "Full retpoline + IBPB are mitigating the vulnerability" elif [ "$retpoline" = 1 ] && [ "$retpoline_compiler" = 1 ] && [ "$retp_enabled" != 0 ] && [ "$opt_paranoid" = 0 ] && ( ! is_vulnerable_to_empty_rsb || [ -n "$rsb_filling" ] ); then pvulnstatus $cve OK "Full retpoline is mitigating the vulnerability" if [ -n "$cpuid_ibpb" ]; then _warn "You should enable IBPB to complete retpoline as a Variant 2 mitigation" else _warn "IBPB is considered as a good addition to retpoline for Variant 2 mitigation, but your CPU microcode doesn't support it" fi elif [ -n "$ibrs_enabled" ] && [ -n "$ibpb_enabled" ] && [ "$ibrs_enabled" -ge 1 ] && [ "$ibpb_enabled" -ge 1 ]; then pvulnstatus $cve OK "IBRS + IBPB are mitigating the vulnerability" elif [ "$ibpb_enabled" = 2 ] && ! is_cpu_smt_enabled; then pvulnstatus $cve OK "Full IBPB is mitigating the vulnerability" elif [ -n "$bp_harden" ]; then pvulnstatus $cve OK "Branch predictor hardening mitigates the vulnerability" elif [ -z "$bp_harden" ] && [ "$cpu_vendor" = ARM ]; then pvulnstatus $cve VULN "Branch predictor hardening is needed to mitigate the vulnerability" explain "Your kernel has not been compiled with the CONFIG_UNMAP_KERNEL_AT_EL0 option, recompile it with this option enabled." elif [ "$opt_live" != 1 ]; then if [ "$retpoline" = 1 ] && [ -n "$ibpb_supported" ]; then pvulnstatus $cve OK "offline mode: kernel supports retpoline + IBPB to mitigate the vulnerability" elif [ -n "$ibrs_supported" ] && [ -n "$ibpb_supported" ]; then pvulnstatus $cve OK "offline mode: kernel supports IBRS + IBPB to mitigate the vulnerability" elif [ "$ibrs_can_tell" != 1 ]; then pvulnstatus $cve UNK "offline mode: not enough information" explain "Re-run this script with root privileges, and give it the kernel image (--kernel), the kernel configuration (--config) and the System.map file (--map) corresponding to the kernel you would like to inspect." fi fi # if we arrive here and didn't already call pvulnstatus, then it's VULN, let's explain why if [ "$pvulnstatus_last_cve" != "$cve" ]; then # explain what's needed for this CPU if is_vulnerable_to_empty_rsb; then pvulnstatus $cve VULN "IBRS+IBPB or retpoline+IBPB+RSB filling, is needed to mitigate the vulnerability" explain "To mitigate this vulnerability, you need either IBRS + IBPB, both requiring hardware support from your CPU microcode in addition to kernel support, or a kernel compiled with retpoline and IBPB, with retpoline requiring a retpoline-aware compiler (re-run this script with -v to know if your version of gcc is retpoline-aware) and IBPB requiring hardware support from your CPU microcode. You also need a recent-enough kernel that supports RSB filling if you plan to use retpoline. For Skylake+ CPUs, the IBRS + IBPB approach is generally preferred as it guarantees complete protection, and the performance impact is not as high as with older CPUs in comparison with retpoline. More information about how to enable the missing bits for those two possible mitigations on your system follow. You only need to take one of the two approaches." elif is_zen_cpu; then pvulnstatus $cve VULN "retpoline+IBPB is needed to mitigate the vulnerability" explain "To mitigate this vulnerability, You need a kernel compiled with retpoline + IBPB support, with retpoline requiring a retpoline-aware compiler (re-run this script with -v to know if your version of gcc is retpoline-aware) and IBPB requiring hardware support from your CPU microcode." elif is_intel || is_amd; then pvulnstatus $cve VULN "IBRS+IBPB or retpoline+IBPB is needed to mitigate the vulnerability" explain "To mitigate this vulnerability, you need either IBRS + IBPB, both requiring hardware support from your CPU microcode in addition to kernel support, or a kernel compiled with retpoline and IBPB, with retpoline requiring a retpoline-aware compiler (re-run this script with -v to know if your version of gcc is retpoline-aware) and IBPB requiring hardware support from your CPU microcode. The retpoline + IBPB approach is generally preferred as the performance impact is lower. More information about how to enable the missing bits for those two possible mitigations on your system follow. You only need to take one of the two approaches." else # in that case, we might want to trust sysfs if it's there if [ -n "$msg" ]; then [ "$msg" = Vulnerable ] && msg="no known mitigation exists for your CPU vendor ($cpu_vendor)" pvulnstatus $cve $status "$msg" else pvulnstatus $cve VULN "no known mitigation exists for your CPU vendor ($cpu_vendor)" fi fi fi # if we are in live mode, we can check for a lot more stuff and explain further if [ "$opt_live" = 1 ] && [ "$vulnstatus" != "OK" ]; then _explain_hypervisor="An updated CPU microcode will have IBRS/IBPB capabilities indicated in the Hardware Check section above. If you're running under an hypervisor (KVM, Xen, VirtualBox, VMware, ...), the hypervisor needs to be up to date to be able to export the new host CPU flags to the guest. You can run this script on the host to check if the host CPU is IBRS/IBPB. If it is, and it doesn't show up in the guest, upgrade the hypervisor. You may need to reconfigure your VM to use a CPU model that has IBRS capability; in Libvirt, such CPUs are listed with an IBRS suffix." # IBPB (amd & intel) if ( [ -z "$ibpb_enabled" ] || [ "$ibpb_enabled" = 0 ] ) && ( is_intel || is_amd ); then if [ -z "$cpuid_ibpb" ]; then explain "The microcode of your CPU needs to be upgraded to be able to use IBPB. This is usually done at boot time by your kernel (the upgrade is not persistent across reboots which is why it's done at each boot). If you're using a distro, make sure you are up to date, as microcode updates are usually shipped alongside with the distro kernel. Availability of a microcode update for you CPU model depends on your CPU vendor. You can usually find out online if a microcode update is available for your CPU by searching for your CPUID (indicated in the Hardware Check section). $_explain_hypervisor" fi if [ -z "$ibpb_supported" ]; then explain "Your kernel doesn't have IBPB support, so you need to either upgrade your kernel (if you're using a distro) or recompiling a more recent kernel." fi if [ -n "$cpuid_ibpb" ] && [ -n "$ibpb_supported" ]; then if [ -e "$specex_knob_dir/ibpb_enabled" ]; then # newer (April 2018) Red Hat kernels have ibpb_enabled as ro, and automatically enables it with retpoline if [ ! -w "$specex_knob_dir/ibpb_enabled" ] && [ -e "$specex_knob_dir/retp_enabled" ]; then explain "Both your CPU and your kernel have IBPB support, but it is currently disabled. You kernel should enable IBPB automatically if you enable retpoline. You may enable it with \`echo 1 > $specex_knob_dir/retp_enabled\`." else explain "Both your CPU and your kernel have IBPB support, but it is currently disabled. You may enable it with \`echo 1 > $specex_knob_dir/ibpb_enabled\`." fi else explain "Both your CPU and your kernel have IBPB support, but it is currently disabled. You may enable it. Check in your distro's documentation on how to do this." fi fi elif [ "$ibpb_enabled" = 2 ] && is_cpu_smt_enabled; then explain "You have ibpb_enabled set to 2, but it only offers sufficient protection when simultaneous multi-threading (aka SMT or HyperThreading) is disabled. You should reboot your system with the kernel parameter \`nosmt\`." fi # /IBPB # IBRS (amd & intel) if ( [ -z "$ibrs_enabled" ] || [ "$ibrs_enabled" = 0 ] ) && ( is_intel || is_amd ); then if [ -z "$cpuid_ibrs" ]; then explain "The microcode of your CPU needs to be upgraded to be able to use IBRS. This is usually done at boot time by your kernel (the upgrade is not persistent across reboots which is why it's done at each boot). If you're using a distro, make sure you are up to date, as microcode updates are usually shipped alongside with the distro kernel. Availability of a microcode update for you CPU model depends on your CPU vendor. You can usually find out online if a microcode update is available for your CPU by searching for your CPUID (indicated in the Hardware Check section). $_explain_hypervisor" fi if [ -z "$ibrs_supported" ]; then explain "Your kernel doesn't have IBRS support, so you need to either upgrade your kernel (if you're using a distro) or recompiling a more recent kernel." fi if [ -n "$cpuid_ibrs" ] && [ -n "$ibrs_supported" ]; then if [ -e "$specex_knob_dir/ibrs_enabled" ]; then explain "Both your CPU and your kernel have IBRS support, but it is currently disabled. You may enable it with \`echo 1 > $specex_knob_dir/ibrs_enabled\`." else explain "Both your CPU and your kernel have IBRS support, but it is currently disabled. You may enable it. Check in your distro's documentation on how to do this." fi fi fi # /IBRS unset _explain_hypervisor # RETPOLINE (amd & intel) if is_amd || is_intel; then if [ "$retpoline" = 0 ]; then explain "Your kernel is not compiled with retpoline support, so you need to either upgrade your kernel (if you're using a distro) or recompile your kernel with the CONFIG_RETPOLINE option enabled. You also need to compile your kernel with a retpoline-aware compiler (re-run this script with -v to know if your version of gcc is retpoline-aware)." elif [ "$retpoline" = 1 ] && [ "$retpoline_compiler" = 0 ]; then explain "Your kernel is compiled with retpoline, but without a retpoline-aware compiler (re-run this script with -v to know if your version of gcc is retpoline-aware)." elif [ "$retpoline" = 1 ] && [ "$retpoline_compiler" = 1 ] && [ "$retp_enabled" = 0 ]; then explain "Your kernel has retpoline support and has been compiled with a retpoline-aware compiler, but retpoline is disabled. You should enable it with \`echo 1 > $specex_knob_dir/retp_enabled\`." fi fi # /RETPOLINE fi fi # sysfs msgs: #1 "Vulnerable" #2 "Vulnerable: Minimal generic ASM retpoline" #2 "Vulnerable: Minimal AMD ASM retpoline" # "Mitigation: Full generic retpoline" # "Mitigation: Full AMD retpoline" # $MITIGATION + ", IBPB" # $MITIGATION + ", IBRS_FW" #5 $MITIGATION + " - vulnerable module loaded" # Red Hat only: #2 "Vulnerable: Minimal ASM retpoline", #3 "Vulnerable: Retpoline without IBPB", #4 "Vulnerable: Retpoline on Skylake+", #5 "Vulnerable: Retpoline with unsafe module(s)", # "Mitigation: Full retpoline", # "Mitigation: Full retpoline and IBRS (user space)", # "Mitigation: IBRS (kernel)", # "Mitigation: IBRS (kernel and user space)", # "Mitigation: IBP disabled", } check_CVE_2017_5715_bsd() { _info "* Mitigation 1" _info_nol " * Kernel supports IBRS: " ibrs_disabled=$(sysctl -n hw.ibrs_disable 2>/dev/null) if [ -z "$ibrs_disabled" ]; then pstatus yellow NO else pstatus green YES fi _info_nol " * IBRS enabled and active: " ibrs_active=$(sysctl -n hw.ibrs_active 2>/dev/null) if [ "$ibrs_active" = 1 ]; then pstatus green YES else pstatus yellow NO fi _info "* Mitigation 2" _info_nol " * Kernel compiled with RETPOLINE: " if [ -n "$kernel_err" ]; then pstatus yellow UNKNOWN "couldn't check ($kernel_err)" else if ! which "${opt_arch_prefix}readelf" >/dev/null 2>&1; then pstatus yellow UNKNOWN "missing '${opt_arch_prefix}readelf' tool, please install it, usually it's in the binutils package" else nb_thunks=$("${opt_arch_prefix}readelf" -s "$kernel" | grep -c -e __llvm_retpoline_ -e __llvm_external_retpoline_ -e __x86_indirect_thunk_) if [ "$nb_thunks" -gt 0 ]; then retpoline=1 pstatus green YES "found $nb_thunks thunk(s)" else pstatus yellow NO fi fi fi if ! is_cpu_vulnerable "$cve"; then # override status & msg in case CPU is not vulnerable after all pvulnstatus $cve OK "your CPU vendor reported your CPU model as not vulnerable" elif [ "$retpoline" = 1 ]; then pvulnstatus $cve OK "Retpoline mitigates the vulnerability" elif [ "$ibrs_active" = 1 ]; then pvulnstatus $cve OK "IBRS mitigates the vulnerability" elif [ "$ibrs_disabled" = 0 ]; then pvulnstatus $cve VULN "IBRS is supported by your kernel but your CPU microcode lacks support" explain "The microcode of your CPU needs to be upgraded to be able to use IBRS. Availability of a microcode update for you CPU model depends on your CPU vendor. You can usually find out online if a microcode update is available for your CPU by searching for your CPUID (indicated in the Hardware Check section). To do a microcode update, you can search the ports for the \`cpupdate\` tool. Microcode updates done this way are not reboot-proof, so be sure to do it every time the system boots up." elif [ "$ibrs_disabled" = 1 ]; then pvulnstatus $cve VULN "IBRS is supported but administratively disabled on your system" explain "To enable IBRS, use \`sysctl hw.ibrs_disable=0\`" else pvulnstatus $cve VULN "IBRS is needed to mitigate the vulnerability but your kernel is missing support" explain "You need to either upgrade your kernel or recompile yourself a more recent version having IBRS support" fi } ################## # MELTDOWN SECTION # no security impact but give a hint to the user in verbose mode # about PCID/INVPCID cpuid features that must be present to avoid # too big a performance impact with PTI # refs: # https://marc.info/?t=151532047900001&r=1&w=2 # https://groups.google.com/forum/m/#!topic/mechanical-sympathy/L9mHTbeQLNU pti_performance_check() { _info_nol " * Reduced performance impact of PTI: " if [ -e "$procfs/cpuinfo" ] && grep ^flags "$procfs/cpuinfo" | grep -qw pcid; then cpu_pcid=1 else read_cpuid 0x1 $ECX 17 1 1; ret=$? [ $ret -eq 0 ] && cpu_pcid=1 fi if [ -e "$procfs/cpuinfo" ] && grep ^flags "$procfs/cpuinfo" | grep -qw invpcid; then cpu_invpcid=1 else read_cpuid 0x7 $EBX 10 1 1; ret=$? [ $ret -eq 0 ] && cpu_invpcid=1 fi if [ "$cpu_invpcid" = 1 ]; then pstatus green YES 'CPU supports INVPCID, performance impact of PTI will be greatly reduced' elif [ "$cpu_pcid" = 1 ]; then pstatus green YES 'CPU supports PCID, performance impact of PTI will be reduced' else pstatus blue NO 'PCID/INVPCID not supported, performance impact of PTI will be significant' fi } # rogue data cache load aka 'Meltdown' aka 'Variant 3' check_CVE_2017_5754() { cve='CVE-2017-5754' _info "\033[1;34m$cve aka '$(cve2name "$cve")'\033[0m" if [ "$os" = Linux ]; then check_CVE_2017_5754_linux elif echo "$os" | grep -q BSD; then check_CVE_2017_5754_bsd else _warn "Unsupported OS ($os)" fi } check_CVE_2017_5754_linux() { status=UNK sys_interface_available=0 msg='' if sys_interface_check "/sys/devices/system/cpu/vulnerabilities/meltdown"; then # this kernel has the /sys interface, trust it over everything sys_interface_available=1 fi if [ "$opt_sysfs_only" != 1 ]; then _info_nol "* Kernel supports Page Table Isolation (PTI): " kpti_support='' kpti_can_tell=0 if [ -n "$opt_config" ]; then kpti_can_tell=1 kpti_support=$(grep -w -e CONFIG_PAGE_TABLE_ISOLATION=y -e CONFIG_KAISER=y -e CONFIG_UNMAP_KERNEL_AT_EL0=y "$opt_config") if [ -n "$kpti_support" ]; then _debug "kpti_support: found option '$kpti_support' in $opt_config" fi fi if [ -z "$kpti_support" ] && [ -n "$opt_map" ]; then # it's not an elif: some backports don't have the PTI config but still include the patch # so we try to find an exported symbol that is part of the PTI patch in System.map # parse_kpti: arm kpti_can_tell=1 kpti_support=$(grep -w -e kpti_force_enabled -e parse_kpti "$opt_map") if [ -n "$kpti_support" ]; then _debug "kpti_support: found '$kpti_support' in $opt_map" fi fi if [ -z "$kpti_support" ] && [ -n "$kernel" ]; then # same as above but in case we don't have System.map and only kernel, look for the # nopti option that is part of the patch (kernel command line option) # 'kpti=': arm kpti_can_tell=1 if ! which "${opt_arch_prefix}strings" >/dev/null 2>&1; then pstatus yellow UNKNOWN "missing '${opt_arch_prefix}strings' tool, please install it, usually it's in the binutils package" else kpti_support=$("${opt_arch_prefix}strings" "$kernel" | grep -w -e nopti -e kpti=) if [ -n "$kpti_support" ]; then _debug "kpti_support: found '$kpti_support' in $kernel" fi fi fi if [ -n "$kpti_support" ]; then if [ "$opt_verbose" -ge 2 ]; then pstatus green YES "found '$kpti_support'" else pstatus green YES fi elif [ "$kpti_can_tell" = 1 ]; then pstatus yellow NO else pstatus yellow UNKNOWN "couldn't read your kernel configuration nor System.map file" fi mount_debugfs _info_nol " * PTI enabled and active: " if [ "$opt_live" = 1 ]; then dmesg_grep="Kernel/User page tables isolation: enabled" dmesg_grep="$dmesg_grep|Kernel page table isolation enabled" dmesg_grep="$dmesg_grep|x86/pti: Unmapping kernel while in userspace" # aarch64 dmesg_grep="$dmesg_grep|CPU features: detected( feature)?: Kernel page table isolation \(KPTI\)" if grep ^flags "$procfs/cpuinfo" | grep -qw pti; then # vanilla PTI patch sets the 'pti' flag in cpuinfo _debug "kpti_enabled: found 'pti' flag in $procfs/cpuinfo" kpti_enabled=1 elif grep ^flags "$procfs/cpuinfo" | grep -qw kaiser; then # kernel line 4.9 sets the 'kaiser' flag in cpuinfo _debug "kpti_enabled: found 'kaiser' flag in $procfs/cpuinfo" kpti_enabled=1 elif [ -e /sys/kernel/debug/x86/pti_enabled ]; then # Red Hat Backport creates a dedicated file, see https://access.redhat.com/articles/3311301 kpti_enabled=$(cat /sys/kernel/debug/x86/pti_enabled 2>/dev/null) _debug "kpti_enabled: file /sys/kernel/debug/x86/pti_enabled exists and says: $kpti_enabled" fi if [ -z "$kpti_enabled" ]; then dmesg_grep "$dmesg_grep"; ret=$? if [ $ret -eq 0 ]; then _debug "kpti_enabled: found hint in dmesg: $dmesg_grepped" kpti_enabled=1 elif [ $ret -eq 2 ]; then _debug "kpti_enabled: dmesg truncated" kpti_enabled=-1 fi fi if [ -z "$kpti_enabled" ]; then _debug "kpti_enabled: couldn't find any hint that PTI is enabled" kpti_enabled=0 fi if [ "$kpti_enabled" = 1 ]; then pstatus green YES elif [ "$kpti_enabled" = -1 ]; then pstatus yellow UNKNOWN "dmesg truncated, please reboot and relaunch this script" else pstatus yellow NO fi else pstatus blue N/A "not testable in offline mode" fi pti_performance_check elif [ "$sys_interface_available" = 0 ]; then # we have no sysfs but were asked to use it only! msg="/sys vulnerability interface use forced, but it's not available!" status=UNK fi # Test if the current host is a Xen PV Dom0 / DomU if [ -d "$procfs/xen" ]; then # XXX do we have a better way that relying on dmesg? dmesg_grep 'Booting paravirtualized kernel on Xen$'; ret=$? if [ $ret -eq 2 ]; then _warn "dmesg truncated, Xen detection will be unreliable. Please reboot and relaunch this script" elif [ $ret -eq 0 ]; then if [ -e "$procfs/xen/capabilities" ] && grep -q "control_d" "$procfs/xen/capabilities"; then xen_pv_domo=1 else xen_pv_domu=1 fi # PVHVM guests also print 'Booting paravirtualized kernel', so we need this check. dmesg_grep 'Xen HVM callback vector for event delivery is enabled$'; ret=$? if [ $ret -eq 0 ]; then xen_pv_domu=0 fi fi fi if [ "$opt_live" = 1 ]; then # checking whether we're running under Xen PV 64 bits. If yes, we are affected by variant3 # (unless we are a Dom0) _info_nol "* Running as a Xen PV DomU: " if [ "$xen_pv_domu" = 1 ]; then pstatus yellow YES else pstatus blue NO fi fi if ! is_cpu_vulnerable "$cve"; then # override status & msg in case CPU is not vulnerable after all pvulnstatus $cve OK "your CPU vendor reported your CPU model as not vulnerable" elif [ -z "$msg" ]; then # if msg is empty, sysfs check didn't fill it, rely on our own test if [ "$opt_live" = 1 ]; then if [ "$kpti_enabled" = 1 ]; then pvulnstatus $cve OK "PTI mitigates the vulnerability" elif [ "$xen_pv_domo" = 1 ]; then pvulnstatus $cve OK "Xen Dom0s are safe and do not require PTI" elif [ "$xen_pv_domu" = 1 ]; then pvulnstatus $cve VULN "Xen PV DomUs are vulnerable and need to be run in HVM, PVHVM, PVH mode, or the Xen hypervisor must have the Xen's own PTI patch" explain "Go to https://blog.xenproject.org/2018/01/22/xen-project-spectre-meltdown-faq-jan-22-update/ for more information" elif [ "$kpti_enabled" = -1 ]; then pvulnstatus $cve UNK "couldn't find any clue of PTI activation due to a truncated dmesg, please reboot and relaunch this script" else pvulnstatus $cve VULN "PTI is needed to mitigate the vulnerability" if [ -n "$kpti_support" ]; then if [ -e "/sys/kernel/debug/x86/pti_enabled" ]; then explain "Your kernel supports PTI but it's disabled, you can enable it with \`echo 1 > /sys/kernel/debug/x86/pti_enabled\`" elif grep -q -w -e nopti -e pti=off "$procfs/cmdline"; then explain "Your kernel supports PTI but it has been disabled on command-line, remove the nopti or pti=off option from your bootloader configuration" else explain "Your kernel supports PTI but it has been disabled, check \`dmesg\` right after boot to find clues why the system disabled it" fi else explain "If you're using a distro kernel, upgrade your distro to get the latest kernel available. Otherwise, recompile the kernel with the CONFIG_PAGE_TABLE_ISOLATION option (named CONFIG_KAISER for some kernels), or the CONFIG_UNMAP_KERNEL_AT_EL0 option (for ARM64)" fi fi else if [ -n "$kpti_support" ]; then pvulnstatus $cve OK "offline mode: PTI will mitigate the vulnerability if enabled at runtime" elif [ "$kpti_can_tell" = 1 ]; then pvulnstatus $cve VULN "PTI is needed to mitigate the vulnerability" explain "If you're using a distro kernel, upgrade your distro to get the latest kernel available. Otherwise, recompile the kernel with the CONFIG_PAGE_TABLE_ISOLATION option (named CONFIG_KAISER for some kernels), or the CONFIG_UNMAP_KERNEL_AT_EL0 option (for ARM64)" else pvulnstatus $cve UNK "offline mode: not enough information" explain "Re-run this script with root privileges, and give it the kernel image (--kernel), the kernel configuration (--config) and the System.map file (--map) corresponding to the kernel you would like to inspect." fi fi else if [ "$xen_pv_domo" = 1 ]; then msg="Xen Dom0s are safe and do not require PTI" status="OK" elif [ "$xen_pv_domu" = 1 ]; then msg="Xen PV DomUs are vulnerable and need to be run in HVM, PVHVM, PVH mode, or the Xen hypervisor must have the Xen's own PTI patch" status="VULN" _explain="Go to https://blog.xenproject.org/2018/01/22/xen-project-spectre-meltdown-faq-jan-22-update/ for more information" elif [ "$msg" = "Vulnerable" ]; then msg="PTI is needed to mitigate the vulnerability" _explain="If you're using a distro kernel, upgrade your distro to get the latest kernel available. Otherwise, recompile the kernel with the CONFIG_PAGE_TABLE_ISOLATION option (named CONFIG_KAISER for some kernels), or the CONFIG_UNMAP_KERNEL_AT_EL0 option (for ARM64)" fi pvulnstatus $cve "$status" "$msg" [ -z "$_explain" ] && [ "$msg" = "Vulnerable" ] && _explain="If you're using a distro kernel, upgrade your distro to get the latest kernel available. Otherwise, recompile the kernel with the CONFIG_PAGE_TABLE_ISOLATION option (named CONFIG_KAISER for some kernels), or the CONFIG_UNMAP_KERNEL_AT_EL0 option (for ARM64)" [ -n "$_explain" ] && explain "$_explain" unset _explain fi # Warn the user about XSA-254 recommended mitigations if [ "$xen_pv_domo" = 1 ]; then _warn _warn "This host is a Xen Dom0. Please make sure that you are running your DomUs" _warn "in HVM, PVHVM or PVH mode to prevent any guest-to-host / host-to-guest attacks." _warn _warn "See https://blog.xenproject.org/2018/01/22/xen-project-spectre-meltdown-faq-jan-22-update/ and XSA-254 for details." fi } check_CVE_2017_5754_bsd() { _info_nol "* Kernel supports Page Table Isolation (PTI): " kpti_enabled=$(sysctl -n vm.pmap.pti 2>/dev/null) if [ -z "$kpti_enabled" ]; then pstatus yellow NO else pstatus green YES fi _info_nol " * PTI enabled and active: " if [ "$kpti_enabled" = 1 ]; then pstatus green YES else pstatus yellow NO fi pti_performance_check if ! is_cpu_vulnerable "$cve"; then # override status & msg in case CPU is not vulnerable after all pvulnstatus $cve OK "your CPU vendor reported your CPU model as not vulnerable" elif [ "$kpti_enabled" = 1 ]; then pvulnstatus $cve OK "PTI mitigates the vulnerability" elif [ -n "$kpti_enabled" ]; then pvulnstatus $cve VULN "PTI is supported but disabled on your system" else pvulnstatus $cve VULN "PTI is needed to mitigate the vulnerability" fi } #################### # VARIANT 3A SECTION # rogue system register read aka 'Variant 3a' check_CVE_2018_3640() { cve='CVE-2018-3640' _info "\033[1;34m$cve aka '$(cve2name "$cve")'\033[0m" status=UNK sys_interface_available=0 msg='' _info_nol "* CPU microcode mitigates the vulnerability: " if [ -n "$cpuid_ssbd" ]; then # microcodes that ship with SSBD are known to also fix variant3a # there is no specific cpuid bit as far as we know pstatus green YES else pstatus yellow NO fi if ! is_cpu_vulnerable "$cve"; then # override status & msg in case CPU is not vulnerable after all pvulnstatus $cve OK "your CPU vendor reported your CPU model as not vulnerable" elif [ -n "$cpuid_ssbd" ]; then pvulnstatus $cve OK "your CPU microcode mitigates the vulnerability" else pvulnstatus $cve VULN "an up-to-date CPU microcode is needed to mitigate this vulnerability" explain "The microcode of your CPU needs to be upgraded to mitigate this vulnerability. This is usually done at boot time by your kernel (the upgrade is not persistent across reboots which is why it's done at each boot). If you're using a distro, make sure you are up to date, as microcode updates are usually shipped alongside with the distro kernel. Availability of a microcode update for you CPU model depends on your CPU vendor. You can usually find out online if a microcode update is available for your CPU by searching for your CPUID (indicated in the Hardware Check section). The microcode update is enough, there is no additional OS, kernel or software change needed." fi } ################### # VARIANT 4 SECTION # speculative store bypass aka 'Variant 4' check_CVE_2018_3639() { cve='CVE-2018-3639' _info "\033[1;34m$cve aka '$(cve2name "$cve")'\033[0m" if [ "$os" = Linux ]; then check_CVE_2018_3639_linux elif echo "$os" | grep -q BSD; then check_CVE_2018_3639_bsd else _warn "Unsupported OS ($os)" fi } check_CVE_2018_3639_linux() { status=UNK sys_interface_available=0 msg='' if sys_interface_check "/sys/devices/system/cpu/vulnerabilities/spec_store_bypass"; then # this kernel has the /sys interface, trust it over everything sys_interface_available=1 fi if [ "$opt_sysfs_only" != 1 ]; then _info_nol "* Kernel supports speculation store bypass: " if [ "$opt_live" = 1 ]; then if grep -Eq 'Speculation.?Store.?Bypass:' "$procfs/self/status" 2>/dev/null; then kernel_ssb="found in $procfs/self/status" _debug "found Speculation.Store.Bypass: in $procfs/self/status" fi fi if [ -z "$kernel_ssb" ] && [ -n "$kernel" ]; then kernel_ssb=$("${opt_arch_prefix}strings" "$kernel" | grep spec_store_bypass | head -n1); [ -n "$kernel_ssb" ] && _debug "found $kernel_ssb in kernel" fi if [ -z "$kernel_ssb" ] && [ -n "$opt_map" ]; then kernel_ssb=$(grep spec_store_bypass "$opt_map" | head -n1) [ -n "$kernel_ssb" ] && _debug "found $kernel_ssb in System.map" fi if [ -n "$kernel_ssb" ]; then pstatus green YES "$kernel_ssb" else pstatus yellow NO fi elif [ "$sys_interface_available" = 0 ]; then # we have no sysfs but were asked to use it only! msg="/sys vulnerability interface use forced, but it's not available!" status=UNK fi if ! is_cpu_vulnerable "$cve"; then # override status & msg in case CPU is not vulnerable after all pvulnstatus $cve OK "your CPU vendor reported your CPU model as not vulnerable" elif [ -z "$msg" ] || [ "$msg" = "Vulnerable" ]; then # if msg is empty, sysfs check didn't fill it, rely on our own test if [ -n "$cpuid_ssbd" ]; then if [ -n "$kernel_ssb" ]; then pvulnstatus $cve OK "your system provides the necessary tools for software mitigation" else pvulnstatus $cve VULN "your kernel needs to be updated" explain "You have a recent-enough CPU microcode but your kernel is too old to use the new features exported by your CPU's microcode. If you're using a distro kernel, upgrade your distro to get the latest kernel available. Otherwise, recompile the kernel from recent-enough sources." fi else if [ -n "$kernel_ssb" ]; then pvulnstatus $cve VULN "Your CPU doesn't support SSBD" explain "Your kernel is recent enough to use the CPU microcode features for mitigation, but your CPU microcode doesn't actually provide the necessary features for the kernel to use. The microcode of your CPU hence needs to be upgraded. This is usually done at boot time by your kernel (the upgrade is not persistent across reboots which is why it's done at each boot). If you're using a distro, make sure you are up to date, as microcode updates are usually shipped alongside with the distro kernel. Availability of a microcode update for you CPU model depends on your CPU vendor. You can usually find out online if a microcode update is available for your CPU by searching for your CPUID (indicated in the Hardware Check section)." else pvulnstatus $cve VULN "Neither your CPU nor your kernel support SSBD" explain "Both your CPU microcode and your kernel are lacking support for mitigation. If you're using a distro kernel, upgrade your distro to get the latest kernel available. Otherwise, recompile the kernel from recent-enough sources. The microcode of your CPU also needs to be upgraded. This is usually done at boot time by your kernel (the upgrade is not persistent across reboots which is why it's done at each boot). If you're using a distro, make sure you are up to date, as microcode updates are usually shipped alongside with the distro kernel. Availability of a microcode update for you CPU model depends on your CPU vendor. You can usually find out online if a microcode update is available for your CPU by searching for your CPUID (indicated in the Hardware Check section)." fi fi else pvulnstatus $cve "$status" "$msg" fi } check_CVE_2018_3639_bsd() { _info_nol "* Kernel supports speculation store bypass: " if sysctl hw.spec_store_bypass_disable >/dev/null 2>&1; then kernel_ssb=1 pstatus green YES else kernel_ssb=0 pstatus yellow NO fi _info_nol "* Speculation store bypass is administratively enabled: " ssb_enabled=$(sysctl -n hw.spec_store_bypass_disable 2>/dev/null) _debug "hw.spec_store_bypass_disable=$ssb_enabled" case "$ssb_enabled" in 0) pstatus yellow NO "disabled";; 1) pstatus green YES "enabled";; 2) pstatus green YES "auto mode";; *) pstatus yellow NO "unavailable";; esac _info_nol "* Speculation store bypass is currently active: " ssb_active=$(sysctl -n hw.spec_store_bypass_disable_active 2>/dev/null) _debug "hw.spec_store_bypass_disable_active=$ssb_active" case "$ssb_active" in 1) pstatus green YES;; *) pstatus yellow NO;; esac if ! is_cpu_vulnerable "$cve"; then pvulnstatus $cve OK "your CPU vendor reported your CPU model as not vulnerable" else if [ "$ssb_active" = 1 ]; then pvulnstatus $cve OK "SSBD mitigates the vulnerability" elif [ -n "$cpuid_ssbd" ]; then if [ "$kernel_ssb" = 1 ]; then pvulnstatus $cve VULN "you need to enable ssbd through sysctl to mitigate the vulnerability" else pvulnstatus $cve VULN "your kernel needs to be updated" fi else if [ "$kernel_ssb" = 1 ]; then pvulnstatus $cve VULN "Your CPU doesn't support SSBD" else pvulnstatus $cve VULN "Neither your CPU nor your kernel support SSBD" fi fi fi } ########################### # L1TF / FORESHADOW SECTION # L1 terminal fault (SGX) aka 'Foreshadow' check_CVE_2018_3615() { cve='CVE-2018-3615' _info "\033[1;34m$cve aka '$(cve2name "$cve")'\033[0m" _info_nol "* CPU microcode mitigates the vulnerability: " if [ "$cpu_flush_cmd" = 1 ] && [ "$cpuid_sgx" = 1 ]; then # no easy way to detect a fixed SGX but we know that # microcodes that have the FLUSH_CMD MSR also have the # fixed SGX (for CPUs that support it) pstatus green YES elif [ "$cpuid_sgx" = 1 ]; then pstatus red NO else pstatus blue N/A fi if ! is_cpu_vulnerable "$cve"; then # override status & msg in case CPU is not vulnerable after all pvulnstatus $cve OK "your CPU vendor reported your CPU model as not vulnerable" elif [ "$cpu_flush_cmd" = 1 ]; then pvulnstatus $cve OK "your CPU microcode mitigates the vulnerability" else pvulnstatus $cve VULN "your CPU supports SGX and the microcode is not up to date" fi } # L1 terminal fault (OS) aka 'Foreshadow-NG (OS)' check_CVE_2018_3620() { cve='CVE-2018-3620' _info "\033[1;34m$cve aka '$(cve2name "$cve")'\033[0m" if [ "$os" = Linux ]; then check_CVE_2018_3620_linux elif echo "$os" | grep -q BSD; then check_CVE_2018_3620_bsd else _warn "Unsupported OS ($os)" fi } check_CVE_2018_3620_linux() { status=UNK sys_interface_available=0 msg='' if sys_interface_check "/sys/devices/system/cpu/vulnerabilities/l1tf" '^[^;]+'; then # this kernel has the /sys interface, trust it over everything sys_interface_available=1 fi if [ "$opt_sysfs_only" != 1 ]; then _info_nol "* Kernel supports PTE inversion: " if ! which "${opt_arch_prefix}strings" >/dev/null 2>&1; then pteinv_supported=-1 else if "${opt_arch_prefix}strings" "$kernel" | grep -Fq 'PTE Inversion'; then pstatus green YES "found in kernel image" _debug "pteinv: found pte inversion evidence in kernel image" pteinv_supported=1 else pstatus yellow NO pteinv_supported=0 fi fi _info_nol "* PTE inversion enabled and active: " if [ "$opt_live" = 1 ]; then if [ "$sys_interface_available" = 1 ]; then if grep -q 'Mitigation: PTE Inversion' /sys/devices/system/cpu/vulnerabilities/l1tf; then pstatus green YES pteinv_active=1 else pstatus yellow NO pteinv_active=0 fi else pstatus yellow UNKNOWN "sysfs interface not available" pteinv_active=-1 fi else pstatus blue N/A "not testable in offline mode" fi elif [ "$sys_interface_available" = 0 ]; then # we have no sysfs but were asked to use it only! msg="/sys vulnerability interface use forced, but it's not available!" status=UNK fi if ! is_cpu_vulnerable "$cve"; then # override status & msg in case CPU is not vulnerable after all pvulnstatus $cve OK "your CPU vendor reported your CPU model as not vulnerable" elif [ -z "$msg" ]; then # if msg is empty, sysfs check didn't fill it, rely on our own test if [ "$pteinv_supported" = 1 ]; then if [ "$pteinv_active" = 1 ] || [ "$opt_live" != 1 ]; then pvulnstatus $cve OK "PTE inversion mitigates the vunerability" else pvulnstatus $cve VULN "Your kernel supports PTE inversion but it doesn't seem to be enabled" fi else pvulnstatus $cve VULN "Your kernel doesn't support PTE inversion, update it" fi else pvulnstatus $cve "$status" "$msg" fi } check_CVE_2018_3620_bsd() { _info_nol "* Kernel reserved the memory page at physical address 0x0: " if sysctl hw.vmm.vmx.l1d_flush >/dev/null 2>&1; then # https://security.FreeBSD.org/patches/SA-18:09/l1tf-11.2.patch # this is very difficult to detect that the kernel reserved the 0 page, but this fix # is part of the exact same patch than the other L1TF CVE, so we detect it # and deem it as OK if the other patch is there pstatus green YES bsd_zero_reserved=1 else pstatus yellow NO bsd_zero_reserved=0 fi if ! is_cpu_vulnerable "$cve"; then pvulnstatus $cve OK "your CPU vendor reported your CPU model as not vulnerable" else if [ "$bsd_zero_reserved" = 1 ]; then pvulnstatus $cve OK "kernel mitigates the vulnerability" else pvulnstatus $cve VULN "your kernel needs to be updated" fi fi } # L1TF VMM check_CVE_2018_3646() { cve='CVE-2018-3646' _info "\033[1;34m$cve aka '$(cve2name "$cve")'\033[0m" if [ "$os" = Linux ]; then check_CVE_2018_3646_linux elif echo "$os" | grep -q BSD; then check_CVE_2018_3646_bsd else _warn "Unsupported OS ($os)" fi } check_CVE_2018_3646_linux() { status=UNK sys_interface_available=0 msg='' if sys_interface_check "/sys/devices/system/cpu/vulnerabilities/l1tf" 'VMX:.*' silent; then # this kernel has the /sys interface, trust it over everything sys_interface_available=1 fi if [ "$opt_sysfs_only" != 1 ]; then _info_nol "* This system is a host running an hypervisor: " has_vmm=$opt_vmm if [ "$has_vmm" = -1 ]; then # FIXME enhance detection, this one is pretty basic/stupid has_vmm=0 # shellcheck disable=SC2009 ps ax | grep -v -e grep -e '\[kvm' | grep -q -e qemu -e kvm && has_vmm=1 fi if [ "$has_vmm" = 0 ]; then if [ "$opt_vmm" != -1 ]; then pstatus green NO "forced from command line" else pstatus green NO fi else if [ "$opt_vmm" != -1 ]; then pstatus blue YES "forced from command line" else pstatus blue YES fi fi _info "* Mitigation 1 (KVM)" _info_nol " * EPT is disabled: " if [ "$opt_live" = 1 ]; then if ! [ -r /sys/module/kvm_intel/parameters/ept ]; then pstatus blue N/A "the kvm_intel module is not loaded" elif [ "$(cat /sys/module/kvm_intel/parameters/ept)" = N ]; then pstatus green YES ept_disabled=1 else pstatus yellow NO fi else pstatus blue N/A "not testable in offline mode" fi _info "* Mitigation 2" _info_nol " * L1D flush is supported by kernel: " if [ "$opt_live" = 1 ] && grep -qw flush_l1d "$procfs/cpuinfo"; then l1d_kernel="found flush_l1d in $procfs/cpuinfo" fi if [ -z "$l1d_kernel" ]; then if ! which "${opt_arch_prefix}strings" >/dev/null 2>&1; then l1d_kernel_err="missing '${opt_arch_prefix}strings' tool, please install it, usually it's in the binutils package" elif [ -n "$kernel_err" ]; then l1d_kernel_err="$kernel_err" elif "${opt_arch_prefix}strings" "$kernel" | grep -qw flush_l1d; then l1d_kernel='found flush_l1d in kernel image' fi fi if [ -n "$l1d_kernel" ]; then pstatus green YES "$l1d_kernel" elif [ -n "$l1d_kernel_err" ]; then pstatus yellow UNKNOWN "$l1d_kernel_err" else pstatus yellow NO fi _info_nol " * L1D flush enabled: " if [ "$opt_live" = 1 ]; then if [ -r "/sys/devices/system/cpu/vulnerabilities/l1tf" ]; then # vanilla: VMX: $l1dstatus, SMT $smtstatus # Red Hat: VMX: SMT $smtstatus, L1D $l1dstatus # $l1dstatus is one of (auto|vulnerable|conditional cache flushes|cache flushes|EPT disabled|flush not necessary) # $smtstatus is one of (vulnerable|disabled) if grep -Eq '(VMX:|L1D) (EPT disabled|vulnerable|flush not necessary)' "/sys/devices/system/cpu/vulnerabilities/l1tf"; then l1d_mode=0 pstatus yellow NO elif grep -Eq '(VMX:|L1D) conditional cache flushes' "/sys/devices/system/cpu/vulnerabilities/l1tf"; then l1d_mode=1 pstatus green YES "conditional flushes" elif grep -Eq '(VMX:|L1D) cache flushes' "/sys/devices/system/cpu/vulnerabilities/l1tf"; then l1d_mode=2 pstatus green YES "unconditional flushes" else l1d_mode=-1 pstatus yellow UNKNOWN "unrecognized mode" fi else pstatus yellow UNKNOWN "can't find or read /sys/devices/system/cpu/vulnerabilities/l1tf" fi else pstatus blue N/A "not testable in offline mode" fi _info_nol " * Hardware-backed L1D flush supported: " if [ "$opt_live" = 1 ]; then if grep -qw flush_l1d "$procfs/cpuinfo"; then pstatus green YES "performance impact of the mitigation will be greatly reduced" else pstatus blue NO "flush will be done in software, this is slower" fi else pstatus blue N/A "not testable in offline mode" fi _info_nol " * Hyper-Threading (SMT) is enabled: " is_cpu_smt_enabled; smt_enabled=$? if [ "$smt_enabled" = 0 ]; then pstatus yellow YES elif [ "$smt_enabled" = 1 ]; then pstatus green NO else pstatus yellow UNKNOWN fi elif [ "$sys_interface_available" = 0 ]; then # we have no sysfs but were asked to use it only! msg="/sys vulnerability interface use forced, but it's not available!" status=UNK fi if ! is_cpu_vulnerable "$cve"; then # override status & msg in case CPU is not vulnerable after all pvulnstatus $cve OK "your CPU vendor reported your CPU model as not vulnerable" elif [ "$has_vmm" = 0 ]; then pvulnstatus $cve OK "this system is not running an hypervisor" else if [ "$ept_disabled" = 1 ]; then pvulnstatus $cve OK "EPT is disabled which mitigates the vulnerability" elif [ "$opt_paranoid" = 0 ]; then if [ "$l1d_mode" -ge 1 ]; then pvulnstatus $cve OK "L1D flushing is enabled and mitigates the vulnerability" else pvulnstatus $cve VULN "disable EPT or enabled L1D flushing to mitigate the vulnerability" fi else if [ "$l1d_mode" -ge 2 ]; then if [ "$smt_enabled" = 1 ]; then pvulnstatus $cve OK "L1D unconditional flushing and Hyper-Threading disabled are mitigating the vulnerability" else pvulnstatus $cve VULN "Hyper-Threading must be disabled to fully mitigate the vulnerability" fi else if [ "$smt_enabled" = 1 ]; then pvulnstatus $cve VULN "L1D unconditional flushing should be enabled to fully mitigate the vulnerability" else pvulnstatus $cve VULN "enable L1D unconditional flushing and disable Hyper-Threading to fully mitigate the vulnerability" fi fi fi fi } check_CVE_2018_3646_bsd() { _info_nol "* Kernel supports L1D flushing: " if sysctl hw.vmm.vmx.l1d_flush >/dev/null 2>&1; then pstatus green YES kernel_l1d_supported=1 else pstatus yellow NO kernel_l1d_supported=0 fi _info_nol "* L1D flushing is enabled: " kernel_l1d_enabled=$(sysctl -n hw.vmm.vmx.l1d_flush 2>/dev/null) case "$kernel_l1d_enabled" in 0) pstatus yellow NO;; 1) pstatus green YES;; "") pstatus yellow NO;; *) pstatus yellow UNKNOWN;; esac if ! is_cpu_vulnerable "$cve"; then pvulnstatus $cve OK "your CPU vendor reported your CPU model as not vulnerable" else if [ "$kernel_l1d_enabled" = 1 ]; then pvulnstatus $cve OK "L1D flushing mitigates the vulnerability" elif [ "$kernel_l1d_supported" = 1 ]; then pvulnstatus $cve VULN "L1D flushing is supported by your kernel but is disabled" else pvulnstatus $cve VULN "your kernel needs to be updated" fi fi } if [ "$opt_no_hw" = 0 ] && [ -z "$opt_arch_prefix" ]; then check_cpu check_cpu_vulnerabilities _info fi # now run the checks the user asked for for cve in $supported_cve_list do if [ "$opt_cve_all" = 1 ] || echo "$opt_cve_list" | grep -qw "$cve"; then check_"$(echo "$cve" | tr - _)" _info fi done if [ -n "$final_summary" ]; then _info "> \033[46m\033[30mSUMMARY:\033[0m$final_summary" _info "" fi _vars=$(set | grep -Ev '^[A-Z_[:space:]]' | sort | tr "\n" '|') _debug "variables at end of script: $_vars" if [ "$opt_explain" = 0 ]; then _info "Need more detailed information about mitigation options? Use --explain" fi _info "A false sense of security is worse than no security at all, see --disclaimer" if [ "$opt_batch" = 1 ] && [ "$opt_batch_format" = "nrpe" ]; then if [ ! -z "$nrpe_vuln" ]; then echo "Vulnerable:$nrpe_vuln" else echo "OK" fi fi if [ "$opt_batch" = 1 ] && [ "$opt_batch_format" = "short" ]; then _echo 0 "${short_output% }" fi if [ "$opt_batch" = 1 ] && [ "$opt_batch_format" = "json" ]; then _echo 0 "${json_output%?}]" fi if [ "$opt_batch" = 1 ] && [ "$opt_batch_format" = "prometheus" ]; then echo "# TYPE specex_vuln_status untyped" echo "# HELP specex_vuln_status Exposure of system to speculative execution vulnerabilities" printf "%b\n" "$prometheus_output" fi # exit with the proper exit code [ "$global_critical" = 1 ] && exit 2 # critical [ "$global_unknown" = 1 ] && exit 3 # unknown exit 0 # ok # We're using MCE.db from the excellent platomav's MCExtractor project # The builtin version follows, the user can update it with --update-mcedb # wget https://github.com/platomav/MCExtractor/raw/master/MCE.db # sqlite3 MCE.db "select '%%% MCEDB v'||revision||' - '||strftime('%Y/%m/%d', date, 'unixepoch') from MCE; select '# I,0x'||cpuid||',0x'||version||','||max(yyyymmdd) from Intel group by cpuid order by cpuid asc; select '# A,0x'||cpuid||',0x'||version||','||max(yyyymmdd) from AMD group by cpuid order by cpuid asc" # %%% MCEDB v84 - 2018/09/27 # I,0x00000611,0x00000B27,19961218 # I,0x00000612,0x000000C6,19961210 # I,0x00000616,0x000000C6,19961210 # I,0x00000617,0x000000C6,19961210 # I,0x00000619,0x000000D2,19980218 # I,0x00000630,0x00000013,19960827 # I,0x00000632,0x00000020,19960903 # I,0x00000633,0x00000036,19980923 # I,0x00000634,0x00000037,19980923 # I,0x00000650,0x00000040,19990525 # I,0x00000651,0x00000040,19990525 # I,0x00000652,0x0000002D,19990518 # I,0x00000653,0x00000010,19990628 # I,0x00000660,0x0000000A,19990505 # I,0x00000665,0x00000003,19990505 # I,0x0000066A,0x0000000C,19990505 # I,0x0000066D,0x00000007,19990505 # I,0x00000670,0x00000007,19980602 # I,0x00000671,0x00000003,19980811 # I,0x00000672,0x00000010,19990922 # I,0x00000673,0x0000000E,19990910 # I,0x00000680,0x00000014,19990610 # I,0x00000681,0x00000014,19991209 # I,0x00000683,0x00000013,20010206 # I,0x00000686,0x00000007,20000505 # I,0x0000068A,0x00000004,20001207 # I,0x00000690,0x00000004,20000206 # I,0x00000691,0x00000001,20020527 # I,0x00000692,0x00000001,20020620 # I,0x00000694,0x00000002,20020926 # I,0x00000695,0x00000007,20041109 # I,0x00000696,0x00000001,20000707 # I,0x000006A0,0x00000003,20000110 # I,0x000006A1,0x00000001,20000306 # I,0x000006A4,0x00000001,20000616 # I,0x000006B0,0x0000001A,20010129 # I,0x000006B1,0x0000001D,20010220 # I,0x000006B4,0x00000002,20020111 # I,0x000006D0,0x00000006,20030522 # I,0x000006D1,0x00000009,20030709 # I,0x000006D2,0x00000010,20030814 # I,0x000006D6,0x00000018,20041017 # I,0x000006D8,0x00000021,20060831 # I,0x000006E0,0x00000008,20050215 # I,0x000006E1,0x0000000C,20050413 # I,0x000006E4,0x00000026,20050816 # I,0x000006E8,0x0000003C,20060208 # I,0x000006EC,0x0000005B,20070208 # I,0x000006F0,0x00000005,20050818 # I,0x000006F1,0x00000012,20051129 # I,0x000006F2,0x0000005D,20101002 # I,0x000006F4,0x00000028,20060417 # I,0x000006F5,0x00000039,20060727 # I,0x000006F6,0x000000D2,20101001 # I,0x000006F7,0x0000006A,20101002 # I,0x000006F9,0x00000084,20061012 # I,0x000006FA,0x00000095,20101002 # I,0x000006FB,0x000000C1,20111004 # I,0x000006FD,0x000000A4,20101002 # I,0x00000F00,0xFFFF0001,20000130 # I,0x00000F01,0xFFFF0007,20000404 # I,0x00000F02,0xFFFF000B,20000518 # I,0x00000F03,0xFFFF0001,20000518 # I,0x00000F04,0xFFFF0010,20000803 # I,0x00000F05,0x0000000B,20000824 # I,0x00000F06,0x00000004,20000911 # I,0x00000F07,0x00000012,20020716 # I,0x00000F08,0x00000008,20001101 # I,0x00000F09,0x00000008,20010104 # I,0x00000F0A,0x00000015,20020821 # I,0x00000F11,0x0000000A,20030729 # I,0x00000F12,0x0000002D,20030502 # I,0x00000F13,0x00000005,20030508 # I,0x00000F20,0x00000001,20010423 # I,0x00000F21,0x00000002,20010529 # I,0x00000F22,0x00000005,20030729 # I,0x00000F23,0x0000000D,20010817 # I,0x00000F24,0x00000021,20030610 # I,0x00000F25,0x0000002C,20040826 # I,0x00000F26,0x00000010,20040805 # I,0x00000F27,0x00000038,20030604 # I,0x00000F29,0x0000002D,20040811 # I,0x00000F30,0x00000013,20030815 # I,0x00000F31,0x0000000B,20031021 # I,0x00000F32,0x0000000A,20040511 # I,0x00000F33,0x0000000C,20050421 # I,0x00000F34,0x00000017,20050421 # I,0x00000F36,0x00000007,20040309 # I,0x00000F37,0x00000003,20031218 # I,0x00000F40,0x00000006,20040318 # I,0x00000F41,0x00000017,20050422 # I,0x00000F42,0x00000003,20050421 # I,0x00000F43,0x00000005,20050421 # I,0x00000F44,0x00000006,20050421 # I,0x00000F46,0x00000004,20050411 # I,0x00000F47,0x00000003,20050421 # I,0x00000F48,0x0000000E,20080115 # I,0x00000F49,0x00000003,20050421 # I,0x00000F4A,0x00000004,20051214 # I,0x00000F60,0x00000005,20050124 # I,0x00000F61,0x00000008,20050610 # I,0x00000F62,0x0000000F,20051215 # I,0x00000F63,0x00000005,20051010 # I,0x00000F64,0x00000004,20051223 # I,0x00000F65,0x0000000B,20070510 # I,0x00000F66,0x0000001B,20060310 # I,0x00000F68,0x00000009,20060714 # I,0x00001632,0x00000002,19980610 # I,0x00010650,0x00000002,20060513 # I,0x00010660,0x00000004,20060612 # I,0x00010661,0x00000043,20101004 # I,0x00010670,0x00000005,20070209 # I,0x00010671,0x00000106,20070329 # I,0x00010674,0x84050100,20070726 # I,0x00010676,0x00000612,20150802 # I,0x00010677,0x0000070D,20150802 # I,0x0001067A,0x00000A0E,20150729 # I,0x000106A0,0xFFFF001A,20071128 # I,0x000106A1,0xFFFF000B,20080220 # I,0x000106A2,0xFFFF0019,20080714 # I,0x000106A4,0x00000013,20150630 # I,0x000106A5,0x0000001D,20180511 # I,0x000106C0,0x00000007,20070824 # I,0x000106C1,0x00000109,20071203 # I,0x000106C2,0x00000217,20090410 # I,0x000106C9,0x00000007,20090213 # I,0x000106CA,0x00000107,20090825 # I,0x000106D0,0x00000005,20071204 # I,0x000106D1,0x0000002A,20150803 # I,0x000106E0,0xFFFF0022,20090116 # I,0x000106E1,0xFFFF000D,20090206 # I,0x000106E3,0xFFFF0011,20090512 # I,0x000106E4,0x00000003,20130701 # I,0x000106E5,0x0000000A,20180508 # I,0x000106F0,0xFFFF0009,20090210 # I,0x000106F1,0xFFFF0007,20090210 # I,0x00020650,0xFFFF0008,20090218 # I,0x00020651,0xFFFF0018,20090818 # I,0x00020652,0x00000011,20180508 # I,0x00020654,0xFFFF0007,20091124 # I,0x00020655,0x00000007,20180423 # I,0x00020661,0x00000105,20110718 # I,0x000206A0,0x00000029,20091102 # I,0x000206A1,0x00000007,20091223 # I,0x000206A2,0x00000027,20100502 # I,0x000206A3,0x00000009,20100609 # I,0x000206A4,0x00000022,20100414 # I,0x000206A5,0x00000007,20100722 # I,0x000206A6,0x90030028,20100924 # I,0x000206A7,0x0000002E,20180410 # I,0x000206C0,0xFFFF001C,20091214 # I,0x000206C1,0x00000006,20091222 # I,0x000206C2,0x0000001F,20180508 # I,0x000206D0,0x80000006,20100816 # I,0x000206D1,0x80000106,20101201 # I,0x000206D2,0x9584020C,20110622 # I,0x000206D3,0x80000304,20110420 # I,0x000206D5,0x00000513,20111013 # I,0x000206D6,0x0000061D,20180508 # I,0x000206D7,0x00000714,20180508 # I,0x000206E0,0xE3493401,20090108 # I,0x000206E1,0xE3493402,20090224 # I,0x000206E2,0xFFFF0004,20081001 # I,0x000206E3,0xE4486547,20090701 # I,0x000206E4,0xFFFF0008,20090619 # I,0x000206E5,0xFFFF0018,20091215 # I,0x000206E6,0x0000000D,20180515 # I,0x000206F0,0x00000004,20100630 # I,0x000206F1,0x00000008,20101013 # I,0x000206F2,0x0000003B,20180516 # I,0x00030650,0x00000009,20120118 # I,0x00030651,0x00000110,20131014 # I,0x00030660,0x00000003,20101103 # I,0x00030661,0x0000010F,20150721 # I,0x00030669,0x0000010D,20130515 # I,0x00030671,0x00000117,20130410 # I,0x00030672,0x0000022E,20140401 # I,0x00030673,0x00000326,20180110 # I,0x00030678,0x00000837,20180125 # I,0x00030679,0x0000090A,20180110 # I,0x000306A0,0x00000007,20110407 # I,0x000306A2,0x0000000C,20110725 # I,0x000306A4,0x00000007,20110908 # I,0x000306A5,0x00000009,20111110 # I,0x000306A6,0x00000004,20111114 # I,0x000306A8,0x00000010,20120220 # I,0x000306A9,0x00000020,20180410 # I,0x000306C0,0xFFFF0013,20111110 # I,0x000306C1,0xFFFF0014,20120725 # I,0x000306C2,0xFFFF0006,20121017 # I,0x000306C3,0x00000025,20180402 # I,0x000306D1,0xFFFF0009,20131015 # I,0x000306D2,0xFFFF0009,20131219 # I,0x000306D3,0xE3121338,20140825 # I,0x000306D4,0x0000002B,20180322 # I,0x000306E0,0x00000008,20120726 # I,0x000306E2,0x0000020D,20130321 # I,0x000306E3,0x00000308,20130321 # I,0x000306E4,0x0000042D,20180425 # I,0x000306E6,0x00000600,20130619 # I,0x000306E7,0x00000714,20180425 # I,0x000306F0,0xFFFF0017,20130730 # I,0x000306F1,0x00000014,20140110 # I,0x000306F2,0x0000003D,20180420 # I,0x000306F3,0x0000000D,20160211 # I,0x000306F4,0x00000012,20180420 # I,0x00040650,0xFFFF000B,20121206 # I,0x00040651,0x00000024,20180402 # I,0x00040660,0xFFFF0011,20121012 # I,0x00040661,0x0000001A,20180402 # I,0x00040670,0xFFFF0006,20140304 # I,0x00040671,0x0000001E,20180403 # I,0x000406A0,0x80124001,20130521 # I,0x000406A8,0x0000081F,20140812 # I,0x000406A9,0x0000081F,20140812 # I,0x000406C1,0x0000010B,20140814 # I,0x000406C2,0x00000221,20150218 # I,0x000406C3,0x00000367,20171225 # I,0x000406C4,0x00000410,20180104 # I,0x000406D0,0x0000000E,20130612 # I,0x000406D8,0x0000012A,20180104 # I,0x000406E1,0x00000020,20141111 # I,0x000406E2,0x0000002C,20150521 # I,0x000406E3,0x000000C6,20180417 # I,0x000406E8,0x00000026,20160414 # I,0x000406F0,0x00000014,20150702 # I,0x000406F1,0x0B00002E,20180419 # I,0x00050650,0x8000002B,20160208 # I,0x00050651,0x8000002B,20160208 # I,0x00050652,0x80000037,20170502 # I,0x00050653,0x01000144,20180420 # I,0x00050654,0x0200004D,20180515 # I,0x00050655,0x0300000B,20180427 # I,0x00050661,0xF1000008,20150130 # I,0x00050662,0x00000017,20180525 # I,0x00050663,0x07000013,20180420 # I,0x00050664,0x0F000012,20180420 # I,0x00050665,0x0E00000A,20180420 # I,0x00050670,0xFFFF0030,20151113 # I,0x00050671,0x000001B6,20180108 # I,0x000506A0,0x00000038,20150112 # I,0x000506C2,0x00000014,20180511 # I,0x000506C8,0x90011010,20160323 # I,0x000506C9,0x00000032,20180511 # I,0x000506CA,0x0000000C,20180511 # I,0x000506D1,0x00000102,20150605 # I,0x000506E0,0x00000018,20141119 # I,0x000506E1,0x0000002A,20150602 # I,0x000506E2,0x0000002E,20150815 # I,0x000506E3,0x000000C6,20180417 # I,0x000506E8,0x00000034,20160710 # I,0x000506F1,0x00000024,20180511 # I,0x00060660,0x0000000C,20160821 # I,0x00060661,0x0000000E,20170128 # I,0x00060662,0x00000022,20171129 # I,0x00060663,0x0000002A,20180417 # I,0x000706A0,0x00000026,20170712 # I,0x000706A1,0x0000002A,20180725 # I,0x00080650,0x00000018,20180108 # I,0x000806E9,0x00000098,20180626 # I,0x000806EA,0x00000096,20180515 # I,0x000806EB,0x00000098,20180530 # I,0x000906E9,0x0000008E,20180324 # I,0x000906EA,0x00000096,20180502 # I,0x000906EB,0x0000008E,20180324 # I,0x000906EC,0x0000009E,20180826 # A,0x00000F00,0x02000008,20070614 # A,0x00000F01,0x0000001C,20021031 # A,0x00000F10,0x00000003,20020325 # A,0x00000F11,0x0000001F,20030220 # A,0x00000F48,0x00000046,20040719 # A,0x00000F4A,0x00000047,20040719 # A,0x00000F50,0x00000024,20021212 # A,0x00000F51,0x00000025,20030115 # A,0x00010F50,0x00000041,20040225 # A,0x00020F10,0x0000004D,20050428 # A,0x00040F01,0xC0012102,20050916 # A,0x00040F0A,0x00000068,20060920 # A,0x00040F13,0x0000007A,20080508 # A,0x00040F14,0x00000062,20060127 # A,0x00040F1B,0x0000006D,20060920 # A,0x00040F33,0x0000007B,20080514 # A,0x00060F80,0x00000083,20060929 # A,0x000C0F1B,0x0000006E,20060921 # A,0x000F0F00,0x00000005,20020627 # A,0x000F0F01,0x00000015,20020627 # A,0x00100F00,0x01000020,20070326 # A,0x00100F20,0x010000CA,20100331 # A,0x00100F22,0x010000C9,20100331 # A,0x00100F40,0x01000085,20080501 # A,0x00100F41,0x010000DB,20111024 # A,0x00100F42,0x01000092,20081021 # A,0x00100F43,0x010000C8,20100311 # A,0x00100F62,0x010000C7,20100311 # A,0x00100F80,0x010000DA,20111024 # A,0x00100F81,0x010000D9,20111012 # A,0x00100FA0,0x010000DC,20111024 # A,0x00120F00,0x03000002,20100324 # A,0x00200F30,0x02000018,20070921 # A,0x00200F31,0x02000057,20080502 # A,0x00200F32,0x02000034,20080307 # A,0x00300F01,0x0300000E,20101004 # A,0x00300F10,0x03000027,20111309 # A,0x00500F00,0x0500000B,20100601 # A,0x00500F01,0x0500001A,20100908 # A,0x00500F10,0x05000029,20130121 # A,0x00500F20,0x05000119,20130118 # A,0x00580F00,0x0500000B,20100601 # A,0x00580F01,0x0500001A,20100908 # A,0x00580F10,0x05000028,20101124 # A,0x00580F20,0x05000101,20110406 # A,0x00600F00,0x06000017,20101029 # A,0x00600F01,0x0600011F,20110227 # A,0x00600F10,0x06000425,20110408 # A,0x00600F11,0x0600050D,20110627 # A,0x00600F12,0x0600063E,20180207 # A,0x00600F20,0x06000852,20180206 # A,0x00610F00,0x0600100E,20111102 # A,0x00610F01,0x0600111F,20180305 # A,0x00630F00,0x0600301C,20130817 # A,0x00630F01,0x06003109,20180227 # A,0x00660F00,0x06006012,20141014 # A,0x00660F01,0x0600611A,20180126 # A,0x00670F00,0x06006705,20180220 # A,0x00680F00,0x06000017,20101029 # A,0x00680F01,0x0600011F,20110227 # A,0x00680F10,0x06000410,20110314 # A,0x00700F00,0x0700002A,20121218 # A,0x00700F01,0x07000110,20180209 # A,0x00730F00,0x07030009,20131206 # A,0x00730F01,0x07030106,20180209 # A,0x00800F00,0x0800002A,20161006 # A,0x00800F10,0x0800100C,20170131 # A,0x00800F11,0x08001137,20180214 # A,0x00800F12,0x08001227,20180209 # A,0x00800F82,0x0800820B,20180620 # A,0x00810F00,0x08100004,20161120 # A,0x00810F10,0x0810100B,20180212 # A,0x00810F80,0x08108002,20180605 # A,0x00820F00,0x08200002,20180214 07070101CC7346000081A40000294E00000032000000015C8B3EB900001895000000080000000700000000000000000000002800000000spectre-meltdown-checker-0.40/README.mdSpectre & Meltdown Checker ========================== A shell script to tell if your system is vulnerable against the several "speculative execution" CVEs that were made public in 2018. - CVE-2017-5753 [bounds check bypass] aka 'Spectre Variant 1' - CVE-2017-5715 [branch target injection] aka 'Spectre Variant 2' - CVE-2017-5754 [rogue data cache load] aka 'Meltdown' aka 'Variant 3' - CVE-2018-3640 [rogue system register read] aka 'Variant 3a' - CVE-2018-3639 [speculative store bypass] aka 'Variant 4' - CVE-2018-3615 [L1 terminal fault] aka 'Foreshadow (SGX)' - CVE-2018-3620 [L1 terminal fault] aka 'Foreshadow-NG (OS)' - CVE-2018-3646 [L1 terminal fault] aka 'Foreshadow-NG (VMM)' Supported operating systems: - Linux (all versions, flavors and distros) - BSD (FreeBSD, NetBSD, DragonFlyBSD) Supported architectures: - x86 (32 bits) - amd64/x86_64 (64 bits) - ARM and ARM64 - other architectures will work, but mitigations (if they exist) might not always be detected For Linux systems, the script will detect mitigations, including backported non-vanilla patches, regardless of the advertised kernel version number and the distribution (such as Debian, Ubuntu, CentOS, RHEL, Fedora, openSUSE, Arch, ...), it also works if you've compiled your own kernel. For BSD systems, the detection will work as long as the BSD you're using supports `cpuctl` and `linprocfs` (this is not the case of OpenBSD for example). ## Easy way to run the script - Get the latest version of the script using `curl` *or* `wget` ```bash curl -L https://meltdown.ovh -o spectre-meltdown-checker.sh wget https://meltdown.ovh -O spectre-meltdown-checker.sh ``` - Inspect the script. You never blindly run scripts you downloaded from the Internet, do you? ```bash vim spectre-meltdown-checker.sh ``` - When you're ready, run the script as root ```bash chmod +x spectre-meltdown-checker.sh sudo ./spectre-meltdown-checker.sh ``` ### Run the script in a docker container #### With docker-compose ```shell docker-compose build docker-compose run --rm spectre-meltdown-checker ``` #### Without docker-compose ```shell docker build -t spectre-meltdown-checker . docker run --rm --privileged -v /boot:/boot:ro -v /dev/cpu:/dev/cpu:ro -v /lib/modules:/lib/modules:ro spectre-meltdown-checker ``` ## Example of script output - Intel Haswell CPU running under Ubuntu 16.04 LTS ![haswell](https://framapic.org/1kWmNwE6ll0p/ayTRX9JRlHJ7.png) - AMD Ryzen running under OpenSUSE Tumbleweed ![ryzen](https://framapic.org/TkWbuh421YQR/6MAGUP3lL6Ne.png) - Batch mode (JSON flavor) ![batch](https://framapic.org/HEcWFPrLewbs/om1LdufspWTJ.png) ## Quick summary of the CVEs **CVE-2017-5753** bounds check bypass (Spectre Variant 1) - Impact: Kernel & all software - Mitigation: recompile software *and* kernel with a modified compiler that introduces the LFENCE opcode at the proper positions in the resulting code - Performance impact of the mitigation: negligible **CVE-2017-5715** branch target injection (Spectre Variant 2) - Impact: Kernel - Mitigation 1: new opcode via microcode update that should be used by up to date compilers to protect the BTB (by flushing indirect branch predictors) - Mitigation 2: introducing "retpoline" into compilers, and recompile software/OS with it - Performance impact of the mitigation: high for mitigation 1, medium for mitigation 2, depending on your CPU **CVE-2017-5754** rogue data cache load (Meltdown) - Impact: Kernel - Mitigation: updated kernel (with PTI/KPTI patches), updating the kernel is enough - Performance impact of the mitigation: low to medium **CVE-2018-3640** rogue system register read (Variant 3a) - Impact: TBC - Mitigation: microcode update only - Performance impact of the mitigation: negligible **CVE-2018-3639** speculative store bypass (Variant 4) - Impact: software using JIT (no known exploitation against kernel) - Mitigation: microcode update + kernel update making possible for affected software to protect itself - Performance impact of the mitigation: low to medium **CVE-2018-3615** l1 terminal fault (Foreshadow) - TBC **CVE-2018-3620** l1 terminal fault (Foreshadow-NG) - TBC **CVE-2018-3646** l1 terminal fault (Foreshadow-NG) - TBC ## Understanding what this script does and doesn't This tool does its best to determine whether your system is immune (or has proper mitigations in place) for the collectively named "speculative execution" vulnerabilities. It doesn't attempt to run any kind of exploit, and can't guarantee that your system is secure, but rather helps you verifying whether your system has the known correct mitigations in place. However, some mitigations could also exist in your kernel that this script doesn't know (yet) how to detect, or it might falsely detect mitigations that in the end don't work as expected (for example, on backported or modified kernels). Your system exposure also depends on your CPU. As of now, AMD and ARM processors are marked as immune to some or all of these vulnerabilities (except some specific ARM models). All Intel processors manufactured since circa 1995 are thought to be vulnerable, except some specific/old models, such as some early Atoms. Whatever processor one uses, one might seek more information from the manufacturer of that processor and/or of the device in which it runs. The nature of the discovered vulnerabilities being quite new, the landscape of vulnerable processors can be expected to change over time, which is why this script makes the assumption that all CPUs are vulnerable, except if the manufacturer explicitly stated otherwise in a verifiable public announcement. Please also note that for Spectre vulnerabilities, all software can possibly be exploited, this tool only verifies that the kernel (which is the core of the system) you're using has the proper protections in place. Verifying all the other software is out of the scope of this tool. As a general measure, ensure you always have the most up to date stable versions of all the software you use, especially for those who are exposed to the world, such as network daemons and browsers. This tool has been released in the hope that it'll be useful, but don't use it to jump to conclusions about your security. 07070101CC7347000081A40000294E00000032000000015C8B3EB90000015A000000080000000700000000000000000000003100000000spectre-meltdown-checker-0.40/docker-compose.ymlversion: '2' services: spectre-meltdown-checker: build: context: ./ dockerfile: ./Dockerfile image: spectre-meltdown-checker:latest container_name: spectre-meltdown-checker privileged: true network_mode: none volumes: - /boot:/boot:ro - /dev/cpu:/dev/cpu:ro - /lib/modules:/lib/modules:ro 07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!394 blocks
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor