hybrid_platforms_conductor 32.3.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/check-node +24 -0
- data/bin/deploy +12 -0
- data/bin/dump_nodes_json +12 -0
- data/bin/free_ips +23 -0
- data/bin/free_veids +17 -0
- data/bin/get_impacted_nodes +43 -0
- data/bin/last_deploys +56 -0
- data/bin/nodes_to_deploy +104 -0
- data/bin/report +10 -0
- data/bin/run +39 -0
- data/bin/setup +11 -0
- data/bin/ssh_config +14 -0
- data/bin/test +13 -0
- data/bin/topograph +54 -0
- data/lib/hybrid_platforms_conductor/action.rb +82 -0
- data/lib/hybrid_platforms_conductor/actions_executor.rb +307 -0
- data/lib/hybrid_platforms_conductor/bitbucket.rb +123 -0
- data/lib/hybrid_platforms_conductor/cmd_runner.rb +188 -0
- data/lib/hybrid_platforms_conductor/cmdb.rb +34 -0
- data/lib/hybrid_platforms_conductor/common_config_dsl/bitbucket.rb +78 -0
- data/lib/hybrid_platforms_conductor/common_config_dsl/confluence.rb +43 -0
- data/lib/hybrid_platforms_conductor/common_config_dsl/file_system_tests.rb +110 -0
- data/lib/hybrid_platforms_conductor/common_config_dsl/idempotence_tests.rb +38 -0
- data/lib/hybrid_platforms_conductor/config.rb +263 -0
- data/lib/hybrid_platforms_conductor/confluence.rb +119 -0
- data/lib/hybrid_platforms_conductor/connector.rb +84 -0
- data/lib/hybrid_platforms_conductor/credentials.rb +127 -0
- data/lib/hybrid_platforms_conductor/current_dir_monitor.rb +42 -0
- data/lib/hybrid_platforms_conductor/deployer.rb +598 -0
- data/lib/hybrid_platforms_conductor/executable.rb +145 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/action/bash.rb +44 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/action/interactive.rb +44 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/action/my_action.rb.sample +79 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/action/remote_bash.rb +63 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/action/ruby.rb +69 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/action/scp.rb +61 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/cmdb/config.rb +78 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/cmdb/host_ip.rb +104 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/cmdb/host_keys.rb +114 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/cmdb/my_cmdb.rb.sample +129 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/cmdb/platform_handlers.rb +66 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/connector/my_connector.rb.sample +156 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/connector/ssh.rb +702 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/platform_handler_plugin.rb.sample +292 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/docker.rb +148 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/my_provisioner.rb.sample +103 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/podman.rb +125 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/proxmox.rb +522 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/proxmox/proxmox_waiter.rb +707 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/proxmox/reserve_proxmox_container +122 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/report/confluence.rb +69 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/report/mediawiki.rb +164 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/report/my_report_plugin.rb.sample +88 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/report/stdout.rb +61 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/report/templates/confluence_inventory.html.erb +33 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/bitbucket_conf.rb +137 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/can_be_checked.rb +21 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/check_deploy_and_idempotence.rb +112 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/check_from_scratch.rb +35 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/connection.rb +28 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/deploy_freshness.rb +44 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/deploy_from_scratch.rb +36 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/deploy_removes_root_access.rb +49 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/divergence.rb +25 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/executables.rb +46 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/file_system.rb +45 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/file_system_hdfs.rb +45 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/hostname.rb +25 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/idempotence.rb +77 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/ip.rb +38 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/jenkins_ci_conf.rb +56 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/jenkins_ci_masters_ok.rb +54 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/linear_strategy.rb +47 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/local_users.rb +82 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/mounts.rb +120 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/my_test_plugin.rb.sample +143 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/orphan_files.rb +74 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/ports.rb +85 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/private_ips.rb +38 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/public_ips.rb +38 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/spectre-meltdown-checker.sh +1930 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/spectre.rb +56 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/veids.rb +31 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/vulnerabilities.rb +159 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test_report/confluence.rb +122 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test_report/my_test_report.rb.sample +48 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test_report/stdout.rb +120 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test_report/templates/_confluence_errors_status.html.erb +46 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test_report/templates/_confluence_gauge.html.erb +49 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test_report/templates/confluence.html.erb +242 -0
- data/lib/hybrid_platforms_conductor/io_router.rb +70 -0
- data/lib/hybrid_platforms_conductor/json_dumper.rb +88 -0
- data/lib/hybrid_platforms_conductor/logger_helpers.rb +319 -0
- data/lib/hybrid_platforms_conductor/mutex_dir +76 -0
- data/lib/hybrid_platforms_conductor/nodes_handler.rb +597 -0
- data/lib/hybrid_platforms_conductor/parallel_threads.rb +97 -0
- data/lib/hybrid_platforms_conductor/platform_handler.rb +188 -0
- data/lib/hybrid_platforms_conductor/platforms_handler.rb +118 -0
- data/lib/hybrid_platforms_conductor/plugin.rb +53 -0
- data/lib/hybrid_platforms_conductor/plugins.rb +101 -0
- data/lib/hybrid_platforms_conductor/provisioner.rb +181 -0
- data/lib/hybrid_platforms_conductor/report.rb +31 -0
- data/lib/hybrid_platforms_conductor/reports_handler.rb +84 -0
- data/lib/hybrid_platforms_conductor/services_handler.rb +274 -0
- data/lib/hybrid_platforms_conductor/test.rb +141 -0
- data/lib/hybrid_platforms_conductor/test_by_service.rb +22 -0
- data/lib/hybrid_platforms_conductor/test_report.rb +282 -0
- data/lib/hybrid_platforms_conductor/tests_runner.rb +590 -0
- data/lib/hybrid_platforms_conductor/thycotic.rb +92 -0
- data/lib/hybrid_platforms_conductor/topographer.rb +859 -0
- data/lib/hybrid_platforms_conductor/topographer/plugin.rb +20 -0
- data/lib/hybrid_platforms_conductor/topographer/plugins/graphviz.rb +127 -0
- data/lib/hybrid_platforms_conductor/topographer/plugins/json.rb +72 -0
- data/lib/hybrid_platforms_conductor/topographer/plugins/my_topographer_output_plugin.rb.sample +37 -0
- data/lib/hybrid_platforms_conductor/topographer/plugins/svg.rb +30 -0
- data/lib/hybrid_platforms_conductor/version.rb +5 -0
- data/spec/hybrid_platforms_conductor_test.rb +159 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/actions/bash_spec.rb +43 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/actions/interactive_spec.rb +18 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/actions/remote_bash_spec.rb +102 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/actions/ruby_spec.rb +108 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/actions/scp_spec.rb +79 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/actions_spec.rb +199 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connection_spec.rb +212 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/cli_options_spec.rb +125 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/config_dsl_spec.rb +50 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/connectable_nodes_spec.rb +28 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/connections_spec.rb +448 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/global_helpers_spec.rb +313 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/node_helpers_spec.rb +32 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/remote_actions_spec.rb +134 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/logging_spec.rb +256 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/parallel_spec.rb +338 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/timeout_spec.rb +101 -0
- data/spec/hybrid_platforms_conductor_test/api/cmd_runner_spec.rb +165 -0
- data/spec/hybrid_platforms_conductor_test/api/config_spec.rb +238 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/check_spec.rb +9 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/deploy_spec.rb +243 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/parse_deploy_output_spec.rb +104 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioner_spec.rb +131 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/docker/Dockerfile +10 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/docker_spec.rb +123 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/podman_spec.rb +211 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/config_dsl_spec.rb +126 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/create_spec.rb +290 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/destroy_spec.rb +43 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/ip_spec.rb +60 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/proxmox.json +3 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/reserve_proxmox_container/destroy_vm_spec.rb +82 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/reserve_proxmox_container/expired_containers_spec.rb +786 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/reserve_proxmox_container/ips_assignment_spec.rb +112 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/reserve_proxmox_container/other_lxc_containers_resources_spec.rb +190 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/reserve_proxmox_container/pve_node_resources_spec.rb +200 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/reserve_proxmox_container/retries_spec.rb +35 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/reserve_proxmox_container/vm_ids_assignment_spec.rb +67 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/start_spec.rb +79 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/state_spec.rb +28 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/stop_spec.rb +41 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/cmdbs/config_spec.rb +33 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/cmdbs/host_ip_spec.rb +64 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/cmdbs/host_keys_spec.rb +133 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/cmdbs/platform_handlers_spec.rb +19 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/cmdbs_plugins_api_spec.rb +446 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/common_spec.rb +127 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/git_diff_impacts_spec.rb +318 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/nodes_selectors_spec.rb +132 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/platform_handlers_plugins_api_spec.rb +60 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/several_platforms_spec.rb +58 -0
- data/spec/hybrid_platforms_conductor_test/api/platform_handler_spec.rb +97 -0
- data/spec/hybrid_platforms_conductor_test/api/platforms_handler_spec.rb +104 -0
- data/spec/hybrid_platforms_conductor_test/api/plugins_spec.rb +243 -0
- data/spec/hybrid_platforms_conductor_test/api/reports_handler_spec.rb +44 -0
- data/spec/hybrid_platforms_conductor_test/api/services_handler/actions_to_deploy_spec.rb +121 -0
- data/spec/hybrid_platforms_conductor_test/api/services_handler/deploy_allowed_spec.rb +142 -0
- data/spec/hybrid_platforms_conductor_test/api/services_handler/log_info_spec.rb +101 -0
- data/spec/hybrid_platforms_conductor_test/api/services_handler/package_spec.rb +388 -0
- data/spec/hybrid_platforms_conductor_test/api/services_handler/parse_deploy_output_spec.rb +274 -0
- data/spec/hybrid_platforms_conductor_test/api/services_handler/prepare_for_deploy_spec.rb +264 -0
- data/spec/hybrid_platforms_conductor_test/api/tests_runner/common_spec.rb +194 -0
- data/spec/hybrid_platforms_conductor_test/api/tests_runner/global_spec.rb +37 -0
- data/spec/hybrid_platforms_conductor_test/api/tests_runner/node_check_spec.rb +194 -0
- data/spec/hybrid_platforms_conductor_test/api/tests_runner/node_spec.rb +137 -0
- data/spec/hybrid_platforms_conductor_test/api/tests_runner/node_ssh_spec.rb +257 -0
- data/spec/hybrid_platforms_conductor_test/api/tests_runner/platform_spec.rb +110 -0
- data/spec/hybrid_platforms_conductor_test/api/tests_runner/reports_spec.rb +367 -0
- data/spec/hybrid_platforms_conductor_test/api/tests_runner/test_plugins/bitbucket_conf_spec.rb +111 -0
- data/spec/hybrid_platforms_conductor_test/api/tests_runner/test_reports_plugins/confluence_spec.rb +29 -0
- data/spec/hybrid_platforms_conductor_test/cmdb_plugins/test_cmdb.rb +166 -0
- data/spec/hybrid_platforms_conductor_test/cmdb_plugins/test_cmdb2.rb +93 -0
- data/spec/hybrid_platforms_conductor_test/cmdb_plugins/test_cmdb_others.rb +60 -0
- data/spec/hybrid_platforms_conductor_test/cmdb_plugins/test_cmdb_others2.rb +58 -0
- data/spec/hybrid_platforms_conductor_test/executables/check-node_spec.rb +35 -0
- data/spec/hybrid_platforms_conductor_test/executables/deploy_spec.rb +35 -0
- data/spec/hybrid_platforms_conductor_test/executables/get_impacted_nodes_spec.rb +158 -0
- data/spec/hybrid_platforms_conductor_test/executables/last_deploys_spec.rb +173 -0
- data/spec/hybrid_platforms_conductor_test/executables/nodes_to_deploy_spec.rb +283 -0
- data/spec/hybrid_platforms_conductor_test/executables/options/actions_executor_spec.rb +28 -0
- data/spec/hybrid_platforms_conductor_test/executables/options/cmd_runner_spec.rb +28 -0
- data/spec/hybrid_platforms_conductor_test/executables/options/common_spec.rb +67 -0
- data/spec/hybrid_platforms_conductor_test/executables/options/deployer_spec.rb +251 -0
- data/spec/hybrid_platforms_conductor_test/executables/options/nodes_handler_spec.rb +111 -0
- data/spec/hybrid_platforms_conductor_test/executables/options/nodes_selectors_spec.rb +71 -0
- data/spec/hybrid_platforms_conductor_test/executables/options/reports_handler_spec.rb +54 -0
- data/spec/hybrid_platforms_conductor_test/executables/options/tests_runner_spec.rb +139 -0
- data/spec/hybrid_platforms_conductor_test/executables/report_spec.rb +60 -0
- data/spec/hybrid_platforms_conductor_test/executables/run_spec.rb +173 -0
- data/spec/hybrid_platforms_conductor_test/executables/ssh_config_spec.rb +35 -0
- data/spec/hybrid_platforms_conductor_test/executables/test_spec.rb +41 -0
- data/spec/hybrid_platforms_conductor_test/helpers/actions_executor_helpers.rb +98 -0
- data/spec/hybrid_platforms_conductor_test/helpers/cmd_runner_helpers.rb +92 -0
- data/spec/hybrid_platforms_conductor_test/helpers/cmdb_helpers.rb +37 -0
- data/spec/hybrid_platforms_conductor_test/helpers/config_helpers.rb +20 -0
- data/spec/hybrid_platforms_conductor_test/helpers/connector_ssh_helpers.rb +130 -0
- data/spec/hybrid_platforms_conductor_test/helpers/deployer_helpers.rb +149 -0
- data/spec/hybrid_platforms_conductor_test/helpers/deployer_test_helpers.rb +812 -0
- data/spec/hybrid_platforms_conductor_test/helpers/executables_helpers.rb +96 -0
- data/spec/hybrid_platforms_conductor_test/helpers/nodes_handler_helpers.rb +20 -0
- data/spec/hybrid_platforms_conductor_test/helpers/platform_handler_helpers.rb +35 -0
- data/spec/hybrid_platforms_conductor_test/helpers/platforms_handler_helpers.rb +127 -0
- data/spec/hybrid_platforms_conductor_test/helpers/plugins_helpers.rb +48 -0
- data/spec/hybrid_platforms_conductor_test/helpers/provisioner_proxmox_helpers.rb +789 -0
- data/spec/hybrid_platforms_conductor_test/helpers/reports_handler_helpers.rb +29 -0
- data/spec/hybrid_platforms_conductor_test/helpers/services_handler_helpers.rb +20 -0
- data/spec/hybrid_platforms_conductor_test/helpers/tests_runner_helpers.rb +38 -0
- data/spec/hybrid_platforms_conductor_test/mocked_lib/my_test_gem/hpc_plugins/test_plugin_type/test_plugin_id1.rb +22 -0
- data/spec/hybrid_platforms_conductor_test/mocked_lib/my_test_gem/hpc_plugins/test_plugin_type/test_plugin_id2.rb +22 -0
- data/spec/hybrid_platforms_conductor_test/mocked_lib/my_test_gem2/sub_dir/hpc_plugins/test_plugin_type/test_plugin_id3.rb +26 -0
- data/spec/hybrid_platforms_conductor_test/mocked_lib/my_test_gem2/sub_dir/hpc_plugins/test_plugin_type2/test_plugin_id4.rb +26 -0
- data/spec/hybrid_platforms_conductor_test/platform_handler_plugins/test.rb +225 -0
- data/spec/hybrid_platforms_conductor_test/platform_handler_plugins/test2.rb +11 -0
- data/spec/hybrid_platforms_conductor_test/report_plugin.rb +35 -0
- data/spec/hybrid_platforms_conductor_test/test_action.rb +66 -0
- data/spec/hybrid_platforms_conductor_test/test_connector.rb +151 -0
- data/spec/hybrid_platforms_conductor_test/test_plugins/global.rb +30 -0
- data/spec/hybrid_platforms_conductor_test/test_plugins/node.rb +53 -0
- data/spec/hybrid_platforms_conductor_test/test_plugins/node_check.rb +47 -0
- data/spec/hybrid_platforms_conductor_test/test_plugins/node_ssh.rb +42 -0
- data/spec/hybrid_platforms_conductor_test/test_plugins/platform.rb +50 -0
- data/spec/hybrid_platforms_conductor_test/test_plugins/several_checks.rb +50 -0
- data/spec/hybrid_platforms_conductor_test/test_provisioner.rb +95 -0
- data/spec/hybrid_platforms_conductor_test/tests_report_plugin.rb +49 -0
- data/spec/spec_helper.rb +111 -0
- metadata +566 -0
@@ -0,0 +1,85 @@
|
|
1
|
+
module HybridPlatformsConductor
|
2
|
+
|
3
|
+
module HpcPlugins
|
4
|
+
|
5
|
+
module Test
|
6
|
+
|
7
|
+
# Various tests on ports
|
8
|
+
class Ports < HybridPlatformsConductor::Test
|
9
|
+
|
10
|
+
# Config DSL extension for this test plugin
|
11
|
+
module ConfigDslExtension
|
12
|
+
|
13
|
+
# List of rules on ports. Each info has the following properties:
|
14
|
+
# * *nodes_selectors_stack* (Array<Object>): Stack of nodes selectors impacted by this rule.
|
15
|
+
# * *ports* (Array<Integer>): List of ports concerned by this rule.
|
16
|
+
# * *state* (Symbol): State those ports should be in. Possible states are:
|
17
|
+
# * *opened*: The port should be opened
|
18
|
+
# * *closed*: The port should be closed
|
19
|
+
# Array< Hash<Symbol, Object> >
|
20
|
+
attr_reader :ports_rules
|
21
|
+
|
22
|
+
# Initialize the DSL
|
23
|
+
def init_ports_test
|
24
|
+
@ports_rules = []
|
25
|
+
end
|
26
|
+
|
27
|
+
# Give a list of ports that should be opened
|
28
|
+
#
|
29
|
+
# Parameters::
|
30
|
+
# * *ports* (Integer or Array<Integer>): List of ports
|
31
|
+
def check_opened_ports(*ports)
|
32
|
+
@ports_rules << {
|
33
|
+
ports: ports.flatten,
|
34
|
+
state: :opened,
|
35
|
+
nodes_selectors_stack: current_nodes_selectors_stack
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
# Give a list of ports that should be closed
|
40
|
+
#
|
41
|
+
# Parameters::
|
42
|
+
# * *ports* (Integer or Array<Integer>): List of ports
|
43
|
+
def check_closed_ports(*ports)
|
44
|
+
@ports_rules << {
|
45
|
+
ports: ports.flatten,
|
46
|
+
state: :closed,
|
47
|
+
nodes_selectors_stack: current_nodes_selectors_stack
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
self.extend_config_dsl_with ConfigDslExtension, :init_ports_test
|
54
|
+
|
55
|
+
# Check my_test_plugin.rb.sample documentation for signature details.
|
56
|
+
def test_for_node
|
57
|
+
@nodes_handler.select_confs_for_node(@node, @config.ports_rules).each do |ports_rule_info|
|
58
|
+
node_ip = @nodes_handler.get_host_ip_of(@node)
|
59
|
+
ports_rule_info[:ports].each do |port|
|
60
|
+
log_debug "Test port #{node_ip}:#{port}"
|
61
|
+
port_opened =
|
62
|
+
begin
|
63
|
+
Socket.tcp(node_ip, port, connect_timeout: 5) { true }
|
64
|
+
rescue
|
65
|
+
false
|
66
|
+
end
|
67
|
+
case ports_rule_info[:state]
|
68
|
+
when :opened
|
69
|
+
error "Port #{port} should be opened but it's not" unless port_opened
|
70
|
+
when :closed
|
71
|
+
error "Port #{port} should be closed but it's not" if port_opened
|
72
|
+
else
|
73
|
+
raise "Unknown desired state for port: #{ports_rule_info[:state]}. Please correct this test plugin."
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module HybridPlatformsConductor
|
2
|
+
|
3
|
+
module HpcPlugins
|
4
|
+
|
5
|
+
module Test
|
6
|
+
|
7
|
+
# Test that Private IPs are assigned correctly
|
8
|
+
class PrivateIps < HybridPlatformsConductor::Test
|
9
|
+
|
10
|
+
# Check my_test_plugin.rb.sample documentation for signature details.
|
11
|
+
def test
|
12
|
+
# Get a map of private IPs per node
|
13
|
+
@nodes_handler.prefetch_metadata_of @nodes_handler.known_nodes, :private_ips
|
14
|
+
private_ips = Hash[@nodes_handler.
|
15
|
+
known_nodes.
|
16
|
+
map { |node| [node, @nodes_handler.get_private_ips_of(node) || []] }
|
17
|
+
]
|
18
|
+
|
19
|
+
# Check there are no duplicates
|
20
|
+
nodes_per_private_ip = {}
|
21
|
+
private_ips.each do |node, private_ips|
|
22
|
+
private_ips.each do |private_ip|
|
23
|
+
nodes_per_private_ip[private_ip] = [] unless nodes_per_private_ip.key?(private_ip)
|
24
|
+
nodes_per_private_ip[private_ip] << node
|
25
|
+
end
|
26
|
+
end
|
27
|
+
nodes_per_private_ip.each do |private_ip, nodes|
|
28
|
+
error "Private IP #{private_ip} is used by the following nodes: #{nodes.join(', ')}" if nodes.size > 1
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module HybridPlatformsConductor
|
2
|
+
|
3
|
+
module HpcPlugins
|
4
|
+
|
5
|
+
module Test
|
6
|
+
|
7
|
+
# Test that Public IPs are assigned correctly
|
8
|
+
class PublicIps < HybridPlatformsConductor::Test
|
9
|
+
|
10
|
+
# Check my_test_plugin.rb.sample documentation for signature details.
|
11
|
+
def test
|
12
|
+
# Get a map of public IPs per node
|
13
|
+
@nodes_handler.prefetch_metadata_of @nodes_handler.known_nodes, :public_ips
|
14
|
+
public_ips = Hash[@nodes_handler.
|
15
|
+
known_nodes.
|
16
|
+
map { |node| [node, @nodes_handler.get_public_ips_of(node) || []] }
|
17
|
+
]
|
18
|
+
|
19
|
+
# Check there are no duplicates
|
20
|
+
nodes_per_public_ip = {}
|
21
|
+
public_ips.each do |node, public_ips|
|
22
|
+
public_ips.each do |public_ip|
|
23
|
+
nodes_per_public_ip[public_ip] = [] unless nodes_per_public_ip.key?(public_ip)
|
24
|
+
nodes_per_public_ip[public_ip] << node
|
25
|
+
end
|
26
|
+
end
|
27
|
+
nodes_per_public_ip.each do |public_ip, nodes|
|
28
|
+
error "Public IP #{public_ip} is used by the following nodes: #{nodes.join(', ')}" if nodes.size > 1
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,1930 @@
|
|
1
|
+
#! /bin/sh
|
2
|
+
# Spectre & Meltdown checker
|
3
|
+
#
|
4
|
+
# Check for the latest version at:
|
5
|
+
# https://github.com/speed47/spectre-meltdown-checker
|
6
|
+
# git clone https://github.com/speed47/spectre-meltdown-checker.git
|
7
|
+
# or wget meltdown.xae -O spectre-meltdown-checker.sh
|
8
|
+
# or curl -L meltdown.xae -o spectre-meltdown-checker.sh
|
9
|
+
#
|
10
|
+
# Stephane Lesimple
|
11
|
+
#
|
12
|
+
VERSION='0.35'
|
13
|
+
|
14
|
+
trap 'exit_cleanup' EXIT
|
15
|
+
trap '_warn "interrupted, cleaning up..."; exit_cleanup; exit 1' INT
|
16
|
+
exit_cleanup()
|
17
|
+
{
|
18
|
+
# cleanup the temp decompressed config & kernel image
|
19
|
+
[ -n "$dumped_config" ] && [ -f "$dumped_config" ] && rm -f "$dumped_config"
|
20
|
+
[ -n "$vmlinuxtmp" ] && [ -f "$vmlinuxtmp" ] && rm -f "$vmlinuxtmp"
|
21
|
+
[ "$mounted_debugfs" = 1 ] && umount /sys/kernel/debug 2>/dev/null
|
22
|
+
[ "$insmod_cpuid" = 1 ] && rmmod cpuid 2>/dev/null
|
23
|
+
[ "$insmod_msr" = 1 ] && rmmod msr 2>/dev/null
|
24
|
+
}
|
25
|
+
|
26
|
+
show_usage()
|
27
|
+
{
|
28
|
+
# shellcheck disable=SC2086
|
29
|
+
cat <<EOFSPECTRE
|
30
|
+
Usage:
|
31
|
+
Live mode: $(basename $0) [options] [--live]
|
32
|
+
Offline mode: $(basename $0) [options] [--kernel <vmlinux_file>] [--config <kernel_config>] [--map <kernel_map_file>]
|
33
|
+
|
34
|
+
Modes:
|
35
|
+
Two modes are available.
|
36
|
+
|
37
|
+
First mode is the "live" mode (default), it does its best to find information about the currently running kernel.
|
38
|
+
To run under this mode, just start the script without any option (you can also use --live explicitly)
|
39
|
+
|
40
|
+
Second mode is the "offline" mode, where you can inspect a non-running kernel.
|
41
|
+
You'll need to specify the location of the vmlinux file, config and System.map files:
|
42
|
+
|
43
|
+
--kernel vmlinux_file Specify a (possibly compressed) vmlinux file
|
44
|
+
--config kernel_config Specify a kernel config file
|
45
|
+
--map kernel_map_file Specify a kernel System.map file
|
46
|
+
|
47
|
+
Options:
|
48
|
+
--no-color Don't use color codes
|
49
|
+
--verbose, -v Increase verbosity level
|
50
|
+
--no-sysfs Don't use the /sys interface even if present
|
51
|
+
--sysfs-only Only use the /sys interface, don't run our own checks
|
52
|
+
--coreos Special mode for CoreOS (use an ephemeral toolbox to inspect kernel)
|
53
|
+
--batch text Produce machine readable output, this is the default if --batch is specified alone
|
54
|
+
--batch json Produce JSON output formatted for Puppet, Ansible, Chef...
|
55
|
+
--batch nrpe Produce machine readable output formatted for NRPE
|
56
|
+
--batch prometheus Produce output for consumption by prometheus-node-exporter
|
57
|
+
--variant [1,2,3] Specify which variant you'd like to check, by default all variants are checked
|
58
|
+
Can be specified multiple times (e.g. --variant 2 --variant 3)
|
59
|
+
|
60
|
+
Return codes:
|
61
|
+
0 (not vulnerable), 2 (vulnerable), 3 (unknown), 255 (error)
|
62
|
+
|
63
|
+
IMPORTANT:
|
64
|
+
A false sense of security is worse than no security at all.
|
65
|
+
Please use the --disclaimer option to understand exactly what this script does.
|
66
|
+
|
67
|
+
EOFSPECTRE
|
68
|
+
}
|
69
|
+
|
70
|
+
show_disclaimer()
|
71
|
+
{
|
72
|
+
cat <<EOFSPECTRE
|
73
|
+
Disclaimer:
|
74
|
+
|
75
|
+
This tool does its best to determine whether your system is immune (or has proper mitigations in place) for the
|
76
|
+
collectively named "speculative execution" vulnerabilities. It doesn't attempt to run any kind of exploit, and can't guarantee
|
77
|
+
that your system is secure, but rather helps you verifying whether your system has the known correct mitigations in place.
|
78
|
+
However, some mitigations could also exist in your kernel that this script doesn't know (yet) how to detect, or it might
|
79
|
+
falsely detect mitigations that in the end don't work as expected (for example, on backported or modified kernels).
|
80
|
+
|
81
|
+
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
|
82
|
+
vulnerabilities (except some specific ARM models). All Intel processors manufactured since circa 1995 are thought to be vulnerable,
|
83
|
+
except some specific/old models, such as some early Atoms. Whatever processor one uses, one might seek more information
|
84
|
+
from the manufacturer of that processor and/or of the device in which it runs.
|
85
|
+
|
86
|
+
The nature of the discovered vulnerabilities being quite new, the lanprdape of vulnerable processors can be expected
|
87
|
+
to change over time, which is why this script makes the assumption that all CPUs are vulnerable, except if the manufacturer
|
88
|
+
explicitly stated otherwise in a verifiable public announcement.
|
89
|
+
|
90
|
+
Please also note that for Spectre vulnerabilities, all software can possibly be exploited, this tool only verifies that the
|
91
|
+
kernel (which is the core of the system) you're using has the proper protections in place. Verifying all the other software
|
92
|
+
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
|
93
|
+
the softwares you use, especially for those who are exposed to the world, such as network daemons and browsers.
|
94
|
+
|
95
|
+
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.
|
96
|
+
|
97
|
+
EOFSPECTRE
|
98
|
+
}
|
99
|
+
|
100
|
+
# parse options
|
101
|
+
opt_kernel=''
|
102
|
+
opt_config=''
|
103
|
+
opt_map=''
|
104
|
+
opt_live_explicit=0
|
105
|
+
opt_live=1
|
106
|
+
opt_no_color=0
|
107
|
+
opt_batch=0
|
108
|
+
opt_batch_format="text"
|
109
|
+
opt_verbose=1
|
110
|
+
opt_variant1=0
|
111
|
+
opt_variant2=0
|
112
|
+
opt_variant3=0
|
113
|
+
opt_allvariants=1
|
114
|
+
opt_no_sysfs=0
|
115
|
+
opt_sysfs_only=0
|
116
|
+
opt_coreos=0
|
117
|
+
|
118
|
+
global_critical=0
|
119
|
+
global_unknown=0
|
120
|
+
nrpe_vuln=""
|
121
|
+
|
122
|
+
# find a sane `echo` command
|
123
|
+
# we'll try to avoid using shell builtins that might not take options
|
124
|
+
if which echo >/dev/null 2>&1; then
|
125
|
+
echo_cmd=$(which echo)
|
126
|
+
else
|
127
|
+
[ -x /bin/echo ] && echo_cmd=/bin/echo
|
128
|
+
[ -x /system/bin/echo ] && echo_cmd=/system/bin/echo
|
129
|
+
fi
|
130
|
+
# still empty ? fallback to builtin
|
131
|
+
[ -z "$echo_cmd" ] && echo_cmd=echo
|
132
|
+
__echo()
|
133
|
+
{
|
134
|
+
opt="$1"
|
135
|
+
shift
|
136
|
+
_msg="$*"
|
137
|
+
|
138
|
+
if [ "$opt_no_color" = 1 ] ; then
|
139
|
+
# strip ANSI color codes
|
140
|
+
# some sed versions (i.e. toybox) can't seem to handle
|
141
|
+
# \033 aka \x1B correctly, so do it for them.
|
142
|
+
_ctrlchar=$($echo_cmd -e "\033")
|
143
|
+
_msg=$($echo_cmd -e "$_msg" | sed -r "s/$_ctrlchar\[([0-9][0-9]?(;[0-9][0-9]?)?)?m//g")
|
144
|
+
fi
|
145
|
+
# shellcheck disable=SC2086
|
146
|
+
$echo_cmd $opt -e "$_msg"
|
147
|
+
}
|
148
|
+
|
149
|
+
_echo()
|
150
|
+
{
|
151
|
+
if [ "$opt_verbose" -ge "$1" ]; then
|
152
|
+
shift
|
153
|
+
__echo '' "$*"
|
154
|
+
fi
|
155
|
+
}
|
156
|
+
|
157
|
+
_echo_nol()
|
158
|
+
{
|
159
|
+
if [ "$opt_verbose" -ge "$1" ]; then
|
160
|
+
shift
|
161
|
+
__echo -n "$*"
|
162
|
+
fi
|
163
|
+
}
|
164
|
+
|
165
|
+
_warn()
|
166
|
+
{
|
167
|
+
_echo 0 "\033[31m$*\033[0m" >&2
|
168
|
+
}
|
169
|
+
|
170
|
+
_info()
|
171
|
+
{
|
172
|
+
_echo 1 "$*"
|
173
|
+
}
|
174
|
+
|
175
|
+
_info_nol()
|
176
|
+
{
|
177
|
+
_echo_nol 1 "$*"
|
178
|
+
}
|
179
|
+
|
180
|
+
_verbose()
|
181
|
+
{
|
182
|
+
_echo 2 "$*"
|
183
|
+
}
|
184
|
+
|
185
|
+
_verbose_nol()
|
186
|
+
{
|
187
|
+
_echo_nol 2 "$*"
|
188
|
+
}
|
189
|
+
|
190
|
+
_debug()
|
191
|
+
{
|
192
|
+
_echo 3 "\033[34m(debug) $*\033[0m"
|
193
|
+
}
|
194
|
+
|
195
|
+
is_cpu_vulnerable_cached=0
|
196
|
+
_is_cpu_vulnerable_cached()
|
197
|
+
{
|
198
|
+
# shellcheck disable=SC2086
|
199
|
+
[ "$1" = 1 ] && return $variant1
|
200
|
+
# shellcheck disable=SC2086
|
201
|
+
[ "$1" = 2 ] && return $variant2
|
202
|
+
# shellcheck disable=SC2086
|
203
|
+
[ "$1" = 3 ] && return $variant3
|
204
|
+
echo "$0: error: invalid variant '$1' passed to is_cpu_vulnerable()" >&2
|
205
|
+
exit 255
|
206
|
+
}
|
207
|
+
|
208
|
+
is_cpu_vulnerable()
|
209
|
+
{
|
210
|
+
# param: 1, 2 or 3 (variant)
|
211
|
+
# returns 0 if vulnerable, 1 if not vulnerable
|
212
|
+
# (note that in shell, a return of 0 is success)
|
213
|
+
# by default, everything is vulnerable, we work in a "whitelist" logic here.
|
214
|
+
# usage: is_cpu_vulnerable 2 && do something if vulnerable
|
215
|
+
if [ "$is_cpu_vulnerable_cached" = 1 ]; then
|
216
|
+
_is_cpu_vulnerable_cached "$1"
|
217
|
+
return $?
|
218
|
+
fi
|
219
|
+
|
220
|
+
variant1=''
|
221
|
+
variant2=''
|
222
|
+
variant3=''
|
223
|
+
|
224
|
+
if is_cpu_specex_free; then
|
225
|
+
variant1=immune
|
226
|
+
variant2=immune
|
227
|
+
variant3=immune
|
228
|
+
elif [ "$cpu_vendor" = GenuineIntel ]; then
|
229
|
+
# Intel
|
230
|
+
# https://github.com/crozone/SpectrePoC/issues/1 ^F E5200 => spectre 2 not vulnerable
|
231
|
+
# https://github.com/paboldin/meltdown-exploit/issues/19 ^F E5200 => meltdown vulnerable
|
232
|
+
# model name : Pentium(R) Dual-Core CPU E5200 @ 2.50GHz
|
233
|
+
if grep -qE '^model name.+ Pentium\(R\) Dual-Core[[:space:]]+CPU[[:space:]]+E[0-9]{4}K? ' /proc/cpuinfo; then
|
234
|
+
variant1=vuln
|
235
|
+
[ -z "$variant2" ] && variant2=immune
|
236
|
+
variant3=vuln
|
237
|
+
fi
|
238
|
+
if [ "$capabilities_rdcl_no" = 1 ]; then
|
239
|
+
# capability bit for future Intel processor that will explicitly state
|
240
|
+
# that they're not vulnerable to Meltdown
|
241
|
+
# this var is set in check_cpu()
|
242
|
+
variant3=immune
|
243
|
+
_debug "is_cpu_vulnerable: RDCL_NO is set so not vuln to meltdown"
|
244
|
+
fi
|
245
|
+
elif [ "$cpu_vendor" = AuthenticAMD ]; then
|
246
|
+
# AMD revised their statement about variant2 => vulnerable
|
247
|
+
# https://www.amd.com/en/corporate/speculative-execution
|
248
|
+
variant1=vuln
|
249
|
+
variant2=vuln
|
250
|
+
[ -z "$variant3" ] && variant3=immune
|
251
|
+
elif [ "$cpu_vendor" = ARM ]; then
|
252
|
+
# ARM
|
253
|
+
# reference: https://developer.arm.com/support/security-update
|
254
|
+
# some devices (phones or other) have several ARMs and as such different part numbers,
|
255
|
+
# an example is "bigLITTLE". we shouldn't rely on the first CPU only, so we check the whole list
|
256
|
+
i=0
|
257
|
+
for cpupart in $cpu_part_list
|
258
|
+
do
|
259
|
+
i=$(( i + 1 ))
|
260
|
+
# do NOT quote $cpu_arch_list below
|
261
|
+
# shellcheck disable=SC2086
|
262
|
+
cpuarch=$(echo $cpu_arch_list | awk '{ print $'$i' }')
|
263
|
+
_debug "checking cpu$i: <$cpupart> <$cpuarch>"
|
264
|
+
# some kernels report AArch64 instead of 8
|
265
|
+
[ "$cpuarch" = "AArch64" ] && cpuarch=8
|
266
|
+
if [ -n "$cpupart" ] && [ -n "$cpuarch" ]; then
|
267
|
+
# Cortex-R7 and Cortex-R8 are real-time and only used in medical devices or such
|
268
|
+
# I can't find their CPU part number, but it's probably not that useful anyway
|
269
|
+
# model R7 R8 A9 A15 A17 A57 A72 A73 A75
|
270
|
+
# part ? ? 0xc09 0xc0f 0xc0e 0xd07 0xd08 0xd09 0xd0a
|
271
|
+
# arch 7? 7? 7 7 7 8 8 8 8
|
272
|
+
#
|
273
|
+
# variant 1 & variant 2
|
274
|
+
if [ "$cpuarch" = 7 ] && echo "$cpupart" | grep -Eq '^0x(c09|c0f|c0e)$'; then
|
275
|
+
# armv7 vulnerable chips
|
276
|
+
_debug "checking cpu$i: this armv7 vulnerable to spectre 1 & 2"
|
277
|
+
variant1=vuln
|
278
|
+
variant2=vuln
|
279
|
+
elif [ "$cpuarch" = 8 ] && echo "$cpupart" | grep -Eq '^0x(d07|d08|d09|d0a)$'; then
|
280
|
+
# armv8 vulnerable chips
|
281
|
+
_debug "checking cpu$i: this armv8 vulnerable to spectre 1 & 2"
|
282
|
+
variant1=vuln
|
283
|
+
variant2=vuln
|
284
|
+
else
|
285
|
+
_debug "checking cpu$i: this arm non vulnerable to 1 & 2"
|
286
|
+
# others are not vulnerable
|
287
|
+
[ -z "$variant1" ] && variant1=immune
|
288
|
+
[ -z "$variant2" ] && variant2=immune
|
289
|
+
fi
|
290
|
+
|
291
|
+
# for variant3, only A75 is vulnerable
|
292
|
+
if [ "$cpuarch" = 8 ] && [ "$cpupart" = 0xd0a ]; then
|
293
|
+
_debug "checking cpu$i: arm A75 vulnerable to meltdown"
|
294
|
+
variant3=vuln
|
295
|
+
else
|
296
|
+
_debug "checking cpu$i: this arm non vulnerable to meltdown"
|
297
|
+
[ -z "$variant3" ] && variant3=immune
|
298
|
+
fi
|
299
|
+
fi
|
300
|
+
_debug "is_cpu_vulnerable: for cpu$i and so far, we have <$variant1> <$variant2> <$variant3>"
|
301
|
+
done
|
302
|
+
fi
|
303
|
+
_debug "is_cpu_vulnerable: temp results are <$variant1> <$variant2> <$variant3>"
|
304
|
+
# if at least one of the cpu is vulnerable, then the system is vulnerable
|
305
|
+
[ "$variant1" = "immune" ] && variant1=1 || variant1=0
|
306
|
+
[ "$variant2" = "immune" ] && variant2=1 || variant2=0
|
307
|
+
[ "$variant3" = "immune" ] && variant3=1 || variant3=0
|
308
|
+
_debug "is_cpu_vulnerable: final results are <$variant1> <$variant2> <$variant3>"
|
309
|
+
is_cpu_vulnerable_cached=1
|
310
|
+
_is_cpu_vulnerable_cached "$1"
|
311
|
+
return $?
|
312
|
+
}
|
313
|
+
|
314
|
+
is_cpu_specex_free()
|
315
|
+
{
|
316
|
+
# return true (0) if the CPU doesn't do speculative execution, false (1) if it does.
|
317
|
+
# if it's not in the list we know, return false (1).
|
318
|
+
# source: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/kernel/cpu/common.c#n882
|
319
|
+
# { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_CEDARVIEW, X86_FEATURE_ANY },
|
320
|
+
# { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_CLOVERVIEW, X86_FEATURE_ANY },
|
321
|
+
# { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_LINCROFT, X86_FEATURE_ANY },
|
322
|
+
# { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_PENWELL, X86_FEATURE_ANY },
|
323
|
+
# { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_PINEVIEW, X86_FEATURE_ANY },
|
324
|
+
# { X86_VENDOR_CENTAUR, 5 },
|
325
|
+
# { X86_VENDOR_INTEL, 5 },
|
326
|
+
# { X86_VENDOR_NSC, 5 },
|
327
|
+
# { X86_VENDOR_ANY, 4 },
|
328
|
+
parse_cpu_details
|
329
|
+
if [ "$cpu_vendor" = GenuineIntel ]; then
|
330
|
+
if [ "$cpu_family" = 6 ]; then
|
331
|
+
if [ "$cpu_model" = "$INTEL_FAM6_ATOM_CEDARVIEW" ] || \
|
332
|
+
[ "$cpu_model" = "$INTEL_FAM6_ATOM_CLOVERVIEW" ] || \
|
333
|
+
[ "$cpu_model" = "$INTEL_FAM6_ATOM_LINCROFT" ] || \
|
334
|
+
[ "$cpu_model" = "$INTEL_FAM6_ATOM_PENWELL" ] || \
|
335
|
+
[ "$cpu_model" = "$INTEL_FAM6_ATOM_PINEVIEW" ]; then
|
336
|
+
return 0
|
337
|
+
fi
|
338
|
+
elif [ "$cpu_family" = 5 ]; then
|
339
|
+
return 0
|
340
|
+
fi
|
341
|
+
fi
|
342
|
+
[ "$cpu_family" = 4 ] && return 0
|
343
|
+
return 1
|
344
|
+
}
|
345
|
+
|
346
|
+
show_header()
|
347
|
+
{
|
348
|
+
_info "Spectre and Meltdown mitigation detection tool v$VERSION"
|
349
|
+
_info
|
350
|
+
}
|
351
|
+
|
352
|
+
parse_opt_file()
|
353
|
+
{
|
354
|
+
# parse_opt_file option_name option_value
|
355
|
+
option_name="$1"
|
356
|
+
option_value="$2"
|
357
|
+
if [ -z "$option_value" ]; then
|
358
|
+
show_header
|
359
|
+
show_usage
|
360
|
+
echo "$0: error: --$option_name expects one parameter (a file)" >&2
|
361
|
+
exit 1
|
362
|
+
elif [ ! -e "$option_value" ]; then
|
363
|
+
show_header
|
364
|
+
echo "$0: error: couldn't find file $option_value" >&2
|
365
|
+
exit 1
|
366
|
+
elif [ ! -f "$option_value" ]; then
|
367
|
+
show_header
|
368
|
+
echo "$0: error: $option_value is not a file" >&2
|
369
|
+
exit 1
|
370
|
+
elif [ ! -r "$option_value" ]; then
|
371
|
+
show_header
|
372
|
+
echo "$0: error: couldn't read $option_value (are you root?)" >&2
|
373
|
+
exit 1
|
374
|
+
fi
|
375
|
+
echo "$option_value"
|
376
|
+
exit 0
|
377
|
+
}
|
378
|
+
|
379
|
+
while [ -n "$1" ]; do
|
380
|
+
if [ "$1" = "--kernel" ]; then
|
381
|
+
opt_kernel=$(parse_opt_file kernel "$2"); ret=$?
|
382
|
+
[ $ret -ne 0 ] && exit 255
|
383
|
+
shift 2
|
384
|
+
opt_live=0
|
385
|
+
elif [ "$1" = "--config" ]; then
|
386
|
+
opt_config=$(parse_opt_file config "$2"); ret=$?
|
387
|
+
[ $ret -ne 0 ] && exit 255
|
388
|
+
shift 2
|
389
|
+
opt_live=0
|
390
|
+
elif [ "$1" = "--map" ]; then
|
391
|
+
opt_map=$(parse_opt_file map "$2"); ret=$?
|
392
|
+
[ $ret -ne 0 ] && exit 255
|
393
|
+
shift 2
|
394
|
+
opt_live=0
|
395
|
+
elif [ "$1" = "--live" ]; then
|
396
|
+
opt_live_explicit=1
|
397
|
+
shift
|
398
|
+
elif [ "$1" = "--no-color" ]; then
|
399
|
+
opt_no_color=1
|
400
|
+
shift
|
401
|
+
elif [ "$1" = "--no-sysfs" ]; then
|
402
|
+
opt_no_sysfs=1
|
403
|
+
shift
|
404
|
+
elif [ "$1" = "--sysfs-only" ]; then
|
405
|
+
opt_sysfs_only=1
|
406
|
+
shift
|
407
|
+
elif [ "$1" = "--coreos" ]; then
|
408
|
+
opt_coreos=1
|
409
|
+
shift
|
410
|
+
elif [ "$1" = "--coreos-within-toolbox" ]; then
|
411
|
+
# don't use directly: used internally by --coreos
|
412
|
+
opt_coreos=0
|
413
|
+
shift
|
414
|
+
elif [ "$1" = "--batch" ]; then
|
415
|
+
opt_batch=1
|
416
|
+
opt_verbose=0
|
417
|
+
shift
|
418
|
+
case "$1" in
|
419
|
+
text|nrpe|json|prometheus) opt_batch_format="$1"; shift;;
|
420
|
+
--*) ;; # allow subsequent flags
|
421
|
+
'') ;; # allow nothing at all
|
422
|
+
*)
|
423
|
+
echo "$0: error: unknown batch format '$1'" >&2
|
424
|
+
echo "$0: error: --batch expects a format from: text, nrpe, json" >&2
|
425
|
+
exit 255
|
426
|
+
;;
|
427
|
+
esac
|
428
|
+
elif [ "$1" = "-v" ] || [ "$1" = "--verbose" ]; then
|
429
|
+
opt_verbose=$(( opt_verbose + 1 ))
|
430
|
+
shift
|
431
|
+
elif [ "$1" = "--variant" ]; then
|
432
|
+
if [ -z "$2" ]; then
|
433
|
+
echo "$0: error: option --variant expects a parameter (1, 2 or 3)" >&2
|
434
|
+
exit 255
|
435
|
+
fi
|
436
|
+
case "$2" in
|
437
|
+
1) opt_variant1=1; opt_allvariants=0;;
|
438
|
+
2) opt_variant2=1; opt_allvariants=0;;
|
439
|
+
3) opt_variant3=1; opt_allvariants=0;;
|
440
|
+
*)
|
441
|
+
echo "$0: error: invalid parameter '$2' for --variant, expected either 1, 2 or 3" >&2;
|
442
|
+
exit 255
|
443
|
+
;;
|
444
|
+
esac
|
445
|
+
shift 2
|
446
|
+
elif [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
|
447
|
+
show_header
|
448
|
+
show_usage
|
449
|
+
exit 0
|
450
|
+
elif [ "$1" = "--version" ]; then
|
451
|
+
opt_no_color=1
|
452
|
+
show_header
|
453
|
+
exit 0
|
454
|
+
elif [ "$1" = "--disclaimer" ]; then
|
455
|
+
show_header
|
456
|
+
show_disclaimer
|
457
|
+
exit 0
|
458
|
+
else
|
459
|
+
show_header
|
460
|
+
show_usage
|
461
|
+
echo "$0: error: unknown option '$1'"
|
462
|
+
exit 255
|
463
|
+
fi
|
464
|
+
done
|
465
|
+
|
466
|
+
show_header
|
467
|
+
|
468
|
+
if [ "$opt_no_sysfs" = 1 ] && [ "$opt_sysfs_only" = 1 ]; then
|
469
|
+
_warn "Incompatible options specified (--no-sysfs and --sysfs-only), aborting"
|
470
|
+
exit 255
|
471
|
+
fi
|
472
|
+
|
473
|
+
# print status function
|
474
|
+
pstatus()
|
475
|
+
{
|
476
|
+
if [ "$opt_no_color" = 1 ]; then
|
477
|
+
_info_nol "$2"
|
478
|
+
else
|
479
|
+
case "$1" in
|
480
|
+
red) col="\033[41m\033[30m";;
|
481
|
+
green) col="\033[42m\033[30m";;
|
482
|
+
yellow) col="\033[43m\033[30m";;
|
483
|
+
blue) col="\033[44m\033[30m";;
|
484
|
+
*) col="";;
|
485
|
+
esac
|
486
|
+
_info_nol "$col $2 \033[0m"
|
487
|
+
fi
|
488
|
+
[ -n "$3" ] && _info_nol " ($3)"
|
489
|
+
_info
|
490
|
+
}
|
491
|
+
|
492
|
+
# Print the final status of a vulnerability (incl. batch mode)
|
493
|
+
# Arguments are: CVE UNK/OK/VULN description
|
494
|
+
pvulnstatus()
|
495
|
+
{
|
496
|
+
if [ "$opt_batch" = 1 ]; then
|
497
|
+
case "$1" in
|
498
|
+
CVE-2017-5753) aka="SPECTRE VARIANT 1";;
|
499
|
+
CVE-2017-5715) aka="SPECTRE VARIANT 2";;
|
500
|
+
CVE-2017-5754) aka="MELTDOWN";;
|
501
|
+
esac
|
502
|
+
|
503
|
+
case "$opt_batch_format" in
|
504
|
+
text) _echo 0 "$1: $2 ($3)";;
|
505
|
+
json)
|
506
|
+
case "$2" in
|
507
|
+
UNK) is_vuln="null";;
|
508
|
+
VULN) is_vuln="true";;
|
509
|
+
OK) is_vuln="false";;
|
510
|
+
esac
|
511
|
+
json_output="${json_output:-[}{\"NAME\":\"$aka\",\"CVE\":\"$1\",\"VULNERABLE\":$is_vuln,\"INFOS\":\"$3\"},"
|
512
|
+
;;
|
513
|
+
|
514
|
+
nrpe) [ "$2" = VULN ] && nrpe_vuln="$nrpe_vuln $1";;
|
515
|
+
prometheus)
|
516
|
+
prometheus_output="${prometheus_output:+$prometheus_output\n}specex_vuln_status{name=\"$aka\",cve=\"$1\",status=\"$2\",info=\"$3\"} 1"
|
517
|
+
;;
|
518
|
+
esac
|
519
|
+
fi
|
520
|
+
|
521
|
+
# always fill global_* vars because we use that do decide the program exit code
|
522
|
+
case "$2" in
|
523
|
+
UNK) global_unknown="1";;
|
524
|
+
VULN) global_critical="1";;
|
525
|
+
esac
|
526
|
+
|
527
|
+
# display info if we're not in quiet/batch mode
|
528
|
+
vulnstatus="$2"
|
529
|
+
shift 2
|
530
|
+
_info_nol "> \033[46m\033[30mSTATUS:\033[0m "
|
531
|
+
case "$vulnstatus" in
|
532
|
+
UNK) pstatus yellow 'UNKNOWN' "$@";;
|
533
|
+
VULN) pstatus red 'VULNERABLE' "$@";;
|
534
|
+
OK) pstatus green 'NOT VULNERABLE' "$@";;
|
535
|
+
esac
|
536
|
+
}
|
537
|
+
|
538
|
+
|
539
|
+
# The 3 below functions are taken from the extract-linux script, available here:
|
540
|
+
# https://github.com/torvalds/linux/blob/master/scripts/extract-vmlinux
|
541
|
+
# The functions have been modified for better integration to this script
|
542
|
+
# The original header of the file has been retained below
|
543
|
+
|
544
|
+
# ----------------------------------------------------------------------
|
545
|
+
# extract-vmlinux - Extract uncompressed vmlinux from a kernel image
|
546
|
+
#
|
547
|
+
# Inspired from extract-ikconfig
|
548
|
+
# (c) 2009,2010 Dick Streefland <dick@streefland.net>
|
549
|
+
#
|
550
|
+
# (c) 2011 Corentin Chary <corentin.chary@gmail.com>
|
551
|
+
#
|
552
|
+
# Licensed under the GNU General Public License, version 2 (GPLv2).
|
553
|
+
# ----------------------------------------------------------------------
|
554
|
+
|
555
|
+
vmlinux=''
|
556
|
+
vmlinux_err=''
|
557
|
+
check_vmlinux()
|
558
|
+
{
|
559
|
+
readelf -h "$1" >/dev/null 2>&1 && return 0
|
560
|
+
return 1
|
561
|
+
}
|
562
|
+
|
563
|
+
try_decompress()
|
564
|
+
{
|
565
|
+
# The obscure use of the "tr" filter is to work around older versions of
|
566
|
+
# "grep" that report the byte offset of the line instead of the pattern.
|
567
|
+
|
568
|
+
# Try to find the header ($1) and decompress from here
|
569
|
+
for pos in $(tr "$1\n$2" "\n$2=" < "$6" | grep -abo "^$2")
|
570
|
+
do
|
571
|
+
_debug "try_decompress: magic for $3 found at offset $pos"
|
572
|
+
if ! which "$3" >/dev/null 2>&1; then
|
573
|
+
vmlinux_err="missing '$3' tool, please install it, usually it's in the '$5' package"
|
574
|
+
return 0
|
575
|
+
fi
|
576
|
+
pos=${pos%%:*}
|
577
|
+
# shellcheck disable=SC2086
|
578
|
+
tail -c+$pos "$6" 2>/dev/null | $3 $4 > "$vmlinuxtmp" 2>/dev/null
|
579
|
+
if check_vmlinux "$vmlinuxtmp"; then
|
580
|
+
vmlinux="$vmlinuxtmp"
|
581
|
+
_debug "try_decompress: decompressed with $3 successfully!"
|
582
|
+
return 0
|
583
|
+
else
|
584
|
+
_debug "try_decompress: decompression with $3 did not work"
|
585
|
+
fi
|
586
|
+
done
|
587
|
+
return 1
|
588
|
+
}
|
589
|
+
|
590
|
+
extract_vmlinux()
|
591
|
+
{
|
592
|
+
[ -n "$1" ] || return 1
|
593
|
+
# Prepare temp files:
|
594
|
+
vmlinuxtmp="$(mktemp /tmp/vmlinux-XXXXXX)"
|
595
|
+
|
596
|
+
# Initial attempt for uncompressed images or objects:
|
597
|
+
if check_vmlinux "$1"; then
|
598
|
+
cat "$1" > "$vmlinuxtmp"
|
599
|
+
vmlinux=$vmlinuxtmp
|
600
|
+
return 0
|
601
|
+
fi
|
602
|
+
|
603
|
+
# That didn't work, so retry after decompression.
|
604
|
+
try_decompress '\037\213\010' xy gunzip '' gunzip "$1" && return 0
|
605
|
+
try_decompress '\3757zXZ\000' abcde unxz '' xz-utils "$1" && return 0
|
606
|
+
try_decompress 'BZh' xy bunzip2 '' bzip2 "$1" && return 0
|
607
|
+
try_decompress '\135\0\0\0' xxx unlzma '' xz-utils "$1" && return 0
|
608
|
+
try_decompress '\211\114\132' xy 'lzop' '-d' lzop "$1" && return 0
|
609
|
+
try_decompress '\002\041\114\030' xyy 'lz4' '-d -l' liblz4-tool "$1" && return 0
|
610
|
+
try_decompress '\177ELF' xxy 'cat' '' cat "$1" && return 0
|
611
|
+
return 1
|
612
|
+
}
|
613
|
+
|
614
|
+
# end of extract-vmlinux functions
|
615
|
+
|
616
|
+
mount_debugfs()
|
617
|
+
{
|
618
|
+
if [ ! -e /sys/kernel/debug/sched_features ]; then
|
619
|
+
# try to mount the debugfs hierarchy ourselves and remember it to umount afterwards
|
620
|
+
mount -t debugfs debugfs /sys/kernel/debug 2>/dev/null && mounted_debugfs=1
|
621
|
+
fi
|
622
|
+
}
|
623
|
+
|
624
|
+
load_msr()
|
625
|
+
{
|
626
|
+
modprobe msr 2>/dev/null && insmod_msr=1
|
627
|
+
_debug "attempted to load module msr, insmod_msr=$insmod_msr"
|
628
|
+
}
|
629
|
+
|
630
|
+
load_cpuid()
|
631
|
+
{
|
632
|
+
modprobe cpuid 2>/dev/null && insmod_cpuid=1
|
633
|
+
_debug "attempted to load module cpuid, insmod_cpuid=$insmod_cpuid"
|
634
|
+
}
|
635
|
+
|
636
|
+
read_cpuid()
|
637
|
+
{
|
638
|
+
_leaf="$1"
|
639
|
+
_bytenum="$2"
|
640
|
+
_and_operand="$3"
|
641
|
+
|
642
|
+
if [ ! -e /dev/cpu/0/cpuid ]; then
|
643
|
+
# try to load the module ourselves (and remember it so we can rmmod it afterwards)
|
644
|
+
load_cpuid
|
645
|
+
fi
|
646
|
+
if [ ! -e /dev/cpu/0/cpuid ]; then
|
647
|
+
return 2
|
648
|
+
fi
|
649
|
+
|
650
|
+
if [ "$opt_verbose" -ge 3 ]; then
|
651
|
+
dd if=/dev/cpu/0/cpuid bs=16 skip="$_leaf" iflag=skip_bytes count=1 >/dev/null 2>/dev/null
|
652
|
+
_debug "cpuid: reading leaf$_leaf of cpuid on cpu0, ret=$?"
|
653
|
+
_debug "cpuid: leaf$_leaf eax-ebx-ecx-edx: $( dd if=/dev/cpu/0/cpuid bs=16 skip="$_leaf" iflag=skip_bytes count=1 2>/dev/null | od -x -A n)"
|
654
|
+
_debug "cpuid: leaf$_leaf edx higher byte is: $(dd if=/dev/cpu/0/cpuid bs=16 skip="$_leaf" iflag=skip_bytes count=1 2>/dev/null | dd bs=1 skip="$_bytenum" count=1 2>/dev/null | od -x -A n)"
|
655
|
+
fi
|
656
|
+
# getting proper byte of edx on leaf$_leaf of cpuinfo in decimal
|
657
|
+
_reg_byte=$(dd if=/dev/cpu/0/cpuid bs=16 skip="$_leaf" iflag=skip_bytes count=1 2>/dev/null | dd bs=1 skip="$_bytenum" count=1 2>/dev/null | od -t u1 -A n | awk '{print $1}')
|
658
|
+
_debug "cpuid: leaf$_leaf byte $_bytenum: $_reg_byte (decimal)"
|
659
|
+
_reg_bit=$(( _reg_byte & _and_operand ))
|
660
|
+
_debug "cpuid: leaf$_leaf byte $_bytenum & $_and_operand = $_reg_bit"
|
661
|
+
[ "$_reg_bit" -eq 0 ] && return 1
|
662
|
+
# $_reg_bit is > 0, so the bit was found: return true (aka 0)
|
663
|
+
return 0
|
664
|
+
}
|
665
|
+
|
666
|
+
dmesg_grep()
|
667
|
+
{
|
668
|
+
# grep for something in dmesg, ensuring that the dmesg buffer
|
669
|
+
# has not been truncated
|
670
|
+
dmesg_grepped=''
|
671
|
+
if ! dmesg | grep -qE '(^|\] )Linux version [0-9]'; then
|
672
|
+
# dmesg truncated
|
673
|
+
return 2
|
674
|
+
fi
|
675
|
+
dmesg_grepped=$(dmesg | grep -E "$1" | head -1)
|
676
|
+
# not found:
|
677
|
+
[ -z "$dmesg_grepped" ] && return 1
|
678
|
+
# found, output is in $dmesg_grepped
|
679
|
+
return 0
|
680
|
+
}
|
681
|
+
|
682
|
+
is_coreos()
|
683
|
+
{
|
684
|
+
which coreos-install >/dev/null 2>&1 && which toolbox >/dev/null 2>&1 && return 0
|
685
|
+
return 1
|
686
|
+
}
|
687
|
+
|
688
|
+
parse_cpu_details()
|
689
|
+
{
|
690
|
+
[ "$parse_cpu_details_done" = 1 ] && return 0
|
691
|
+
cpu_vendor=$( grep '^vendor_id' /proc/cpuinfo | awk '{print $3}' | head -1)
|
692
|
+
cpu_friendly_name=$(grep '^model name' /proc/cpuinfo | cut -d: -f2- | head -1 | sed -e 's/^ *//')
|
693
|
+
# special case for ARM follows
|
694
|
+
if grep -qi 'CPU implementer[[:space:]]*:[[:space:]]*0x41' /proc/cpuinfo; then
|
695
|
+
cpu_vendor='ARM'
|
696
|
+
# some devices (phones or other) have several ARMs and as such different part numbers,
|
697
|
+
# an example is "bigLITTLE", so we need to store the whole list, this is needed for is_cpu_vulnerable
|
698
|
+
cpu_part_list=$(awk '/CPU part/ {print $4}' /proc/cpuinfo)
|
699
|
+
cpu_arch_list=$(awk '/CPU architecture/ {print $3}' /proc/cpuinfo)
|
700
|
+
# take the first one to fill the friendly name, do NOT quote the vars below
|
701
|
+
# shellcheck disable=SC2086
|
702
|
+
cpu_arch=$(echo $cpu_arch_list | awk '{ print $1 }')
|
703
|
+
# shellcheck disable=SC2086
|
704
|
+
cpu_part=$(echo $cpu_part_list | awk '{ print $1 }')
|
705
|
+
[ "$cpu_arch" = "AArch64" ] && cpu_arch=8
|
706
|
+
cpu_friendly_name="ARM"
|
707
|
+
[ -n "$cpu_arch" ] && cpu_friendly_name="$cpu_friendly_name v$cpu_arch"
|
708
|
+
[ -n "$cpu_part" ] && cpu_friendly_name="$cpu_friendly_name model $cpu_part"
|
709
|
+
fi
|
710
|
+
|
711
|
+
cpu_family=$( grep '^cpu family' /proc/cpuinfo | awk '{print $4}' | grep -E '^[0-9]+$' | head -1)
|
712
|
+
cpu_model=$( grep '^model' /proc/cpuinfo | awk '{print $3}' | grep -E '^[0-9]+$' | head -1)
|
713
|
+
cpu_stepping=$(grep '^stepping' /proc/cpuinfo | awk '{print $3}' | grep -E '^[0-9]+$' | head -1)
|
714
|
+
cpu_ucode=$( grep '^microcode' /proc/cpuinfo | awk '{print $3}' | head -1)
|
715
|
+
|
716
|
+
# also define those that we will need in other funcs
|
717
|
+
# taken from ttps://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/include/asm/intel-family.h
|
718
|
+
# shellcheck disable=SC2034
|
719
|
+
{
|
720
|
+
INTEL_FAM6_CORE_YONAH=$(( 0x0E ))
|
721
|
+
|
722
|
+
INTEL_FAM6_CORE2_MEROM=$(( 0x0F ))
|
723
|
+
INTEL_FAM6_CORE2_MEROM_L=$(( 0x16 ))
|
724
|
+
INTEL_FAM6_CORE2_PENRYN=$(( 0x17 ))
|
725
|
+
INTEL_FAM6_CORE2_DUNNINGTON=$(( 0x1D ))
|
726
|
+
|
727
|
+
INTEL_FAM6_NEHALEM=$(( 0x1E ))
|
728
|
+
INTEL_FAM6_NEHALEM_G=$(( 0x1F ))
|
729
|
+
INTEL_FAM6_NEHALEM_EP=$(( 0x1A ))
|
730
|
+
INTEL_FAM6_NEHALEM_EX=$(( 0x2E ))
|
731
|
+
|
732
|
+
INTEL_FAM6_WESTMERE=$(( 0x25 ))
|
733
|
+
INTEL_FAM6_WESTMERE_EP=$(( 0x2C ))
|
734
|
+
INTEL_FAM6_WESTMERE_EX=$(( 0x2F ))
|
735
|
+
|
736
|
+
INTEL_FAM6_SANDYBRIDGE=$(( 0x2A ))
|
737
|
+
INTEL_FAM6_SANDYBRIDGE_X=$(( 0x2D ))
|
738
|
+
INTEL_FAM6_IVYBRIDGE=$(( 0x3A ))
|
739
|
+
INTEL_FAM6_IVYBRIDGE_X=$(( 0x3E ))
|
740
|
+
|
741
|
+
INTEL_FAM6_HASWELL_CORE=$(( 0x3C ))
|
742
|
+
INTEL_FAM6_HASWELL_X=$(( 0x3F ))
|
743
|
+
INTEL_FAM6_HASWELL_ULT=$(( 0x45 ))
|
744
|
+
INTEL_FAM6_HASWELL_GT3E=$(( 0x46 ))
|
745
|
+
|
746
|
+
INTEL_FAM6_BROADWELL_CORE=$(( 0x3D ))
|
747
|
+
INTEL_FAM6_BROADWELL_GT3E=$(( 0x47 ))
|
748
|
+
INTEL_FAM6_BROADWELL_X=$(( 0x4F ))
|
749
|
+
INTEL_FAM6_BROADWELL_XEON_D=$(( 0x56 ))
|
750
|
+
|
751
|
+
INTEL_FAM6_SKYLAKE_MOBILE=$(( 0x4E ))
|
752
|
+
INTEL_FAM6_SKYLAKE_DESKTOP=$(( 0x5E ))
|
753
|
+
INTEL_FAM6_SKYLAKE_X=$(( 0x55 ))
|
754
|
+
INTEL_FAM6_KABYLAKE_MOBILE=$(( 0x8E ))
|
755
|
+
INTEL_FAM6_KABYLAKE_DESKTOP=$(( 0x9E ))
|
756
|
+
|
757
|
+
# /* "Small Core" Processors (Atom) */
|
758
|
+
|
759
|
+
INTEL_FAM6_ATOM_PINEVIEW=$(( 0x1C ))
|
760
|
+
INTEL_FAM6_ATOM_LINCROFT=$(( 0x26 ))
|
761
|
+
INTEL_FAM6_ATOM_PENWELL=$(( 0x27 ))
|
762
|
+
INTEL_FAM6_ATOM_CLOVERVIEW=$(( 0x35 ))
|
763
|
+
INTEL_FAM6_ATOM_CEDARVIEW=$(( 0x36 ))
|
764
|
+
INTEL_FAM6_ATOM_SILVERMONT1=$(( 0x37 ))
|
765
|
+
INTEL_FAM6_ATOM_SILVERMONT2=$(( 0x4D ))
|
766
|
+
INTEL_FAM6_ATOM_AIRMONT=$(( 0x4C ))
|
767
|
+
INTEL_FAM6_ATOM_MERRIFIELD=$(( 0x4A ))
|
768
|
+
INTEL_FAM6_ATOM_MOOREFIELD=$(( 0x5A ))
|
769
|
+
INTEL_FAM6_ATOM_GOLDMONT=$(( 0x5C ))
|
770
|
+
INTEL_FAM6_ATOM_DENVERTON=$(( 0x5F ))
|
771
|
+
INTEL_FAM6_ATOM_GEMINI_LAKE=$(( 0x7A ))
|
772
|
+
|
773
|
+
# /* Xeon Phi */
|
774
|
+
|
775
|
+
INTEL_FAM6_XEON_PHI_KNL=$(( 0x57 ))
|
776
|
+
INTEL_FAM6_XEON_PHI_KNM=$(( 0x85 ))
|
777
|
+
}
|
778
|
+
parse_cpu_details_done=1
|
779
|
+
}
|
780
|
+
|
781
|
+
is_ucode_blacklisted()
|
782
|
+
{
|
783
|
+
parse_cpu_details
|
784
|
+
# if it's not an Intel, don't bother: it's not blacklisted
|
785
|
+
[ "$cpu_vendor" = GenuineIntel ] || return 1
|
786
|
+
# it also needs to be family=6
|
787
|
+
[ "$cpu_family" = 6 ] || return 1
|
788
|
+
# now, check each known bad microcode
|
789
|
+
# source: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/kernel/cpu/intel.c#n105
|
790
|
+
# 2018-02-08 update: https://newsroom.intel.com/wp-content/uploads/sites/11/2018/02/microcode-update-guidance.pdf
|
791
|
+
# model,stepping,microcode
|
792
|
+
ucode_found="model $cpu_model stepping $cpu_stepping ucode $cpu_ucode"
|
793
|
+
for tuple in \
|
794
|
+
$INTEL_FAM6_KABYLAKE_DESKTOP,0x0B,0x80 \
|
795
|
+
$INTEL_FAM6_KABYLAKE_DESKTOP,0x0A,0x80 \
|
796
|
+
$INTEL_FAM6_KABYLAKE_DESKTOP,0x09,0x80 \
|
797
|
+
$INTEL_FAM6_KABYLAKE_MOBILE,0x0A,0x80 \
|
798
|
+
$INTEL_FAM6_KABYLAKE_MOBILE,0x09,0x80 \
|
799
|
+
$INTEL_FAM6_SKYLAKE_X,0x03,0x0100013e \
|
800
|
+
$INTEL_FAM6_SKYLAKE_X,0x04,0x02000036 \
|
801
|
+
$INTEL_FAM6_SKYLAKE_X,0x04,0x0200003a \
|
802
|
+
$INTEL_FAM6_SKYLAKE_X,0x04,0x0200003c \
|
803
|
+
$INTEL_FAM6_BROADWELL_CORE,0x04,0x28 \
|
804
|
+
$INTEL_FAM6_BROADWELL_GT3E,0x01,0x1b \
|
805
|
+
$INTEL_FAM6_BROADWELL_XEON_D,0x02,0x14 \
|
806
|
+
$INTEL_FAM6_BROADWELL_XEON_D,0x03,0x07000011 \
|
807
|
+
$INTEL_FAM6_BROADWELL_X,0x01,0x0b000023 \
|
808
|
+
$INTEL_FAM6_BROADWELL_X,0x01,0x0b000025 \
|
809
|
+
$INTEL_FAM6_HASWELL_ULT,0x01,0x21 \
|
810
|
+
$INTEL_FAM6_HASWELL_GT3E,0x01,0x18 \
|
811
|
+
$INTEL_FAM6_HASWELL_CORE,0x03,0x23 \
|
812
|
+
$INTEL_FAM6_HASWELL_X,0x02,0x3b \
|
813
|
+
$INTEL_FAM6_HASWELL_X,0x04,0x10 \
|
814
|
+
$INTEL_FAM6_IVYBRIDGE_X,0x04,0x42a \
|
815
|
+
$INTEL_FAM6_SANDYBRIDGE_X,0x06,0x61b \
|
816
|
+
$INTEL_FAM6_SANDYBRIDGE_X,0x07,0x712
|
817
|
+
do
|
818
|
+
model=$(echo $tuple | cut -d, -f1)
|
819
|
+
stepping=$(( $(echo $tuple | cut -d, -f2) ))
|
820
|
+
ucode=$(echo $tuple | cut -d, -f3)
|
821
|
+
if [ "$cpu_model" = "$model" ] && [ "$cpu_stepping" = "$stepping" ] && echo "$cpu_ucode" | grep -qi "^$ucode$"; then
|
822
|
+
_debug "is_ucode_blacklisted: we have a match! ($cpu_model/$cpu_stepping/$cpu_ucode)"
|
823
|
+
return 0
|
824
|
+
fi
|
825
|
+
done
|
826
|
+
_debug "is_ucode_blacklisted: no ($cpu_model/$cpu_stepping/$cpu_ucode)"
|
827
|
+
return 1
|
828
|
+
}
|
829
|
+
|
830
|
+
is_skylake_cpu()
|
831
|
+
{
|
832
|
+
# is this a skylake cpu?
|
833
|
+
# return 0 if yes, 1 otherwise
|
834
|
+
#if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
|
835
|
+
# boot_cpu_data.x86 == 6) {
|
836
|
+
# switch (boot_cpu_data.x86_model) {
|
837
|
+
# case INTEL_FAM6_SKYLAKE_MOBILE:
|
838
|
+
# case INTEL_FAM6_SKYLAKE_DESKTOP:
|
839
|
+
# case INTEL_FAM6_SKYLAKE_X:
|
840
|
+
# case INTEL_FAM6_KABYLAKE_MOBILE:
|
841
|
+
# case INTEL_FAM6_KABYLAKE_DESKTOP:
|
842
|
+
# return true;
|
843
|
+
parse_cpu_details
|
844
|
+
[ "$cpu_vendor" = GenuineIntel ] || return 1
|
845
|
+
[ "$cpu_family" = 6 ] || return 1
|
846
|
+
if [ "$cpu_model" = $INTEL_FAM6_SKYLAKE_MOBILE ] || \
|
847
|
+
[ "$cpu_model" = $INTEL_FAM6_SKYLAKE_DESKTOP ] || \
|
848
|
+
[ "$cpu_model" = $INTEL_FAM6_SKYLAKE_X ] || \
|
849
|
+
[ "$cpu_model" = $INTEL_FAM6_KABYLAKE_MOBILE ] || \
|
850
|
+
[ "$cpu_model" = $INTEL_FAM6_KABYLAKE_DESKTOP ]; then
|
851
|
+
return 0
|
852
|
+
fi
|
853
|
+
return 1
|
854
|
+
}
|
855
|
+
|
856
|
+
# check for mode selection inconsistency
|
857
|
+
if [ "$opt_live_explicit" = 1 ]; then
|
858
|
+
if [ -n "$opt_kernel" ] || [ -n "$opt_config" ] || [ -n "$opt_map" ]; then
|
859
|
+
show_usage
|
860
|
+
echo "$0: error: incompatible modes specified, use either --live or --kernel/--config/--map" >&2
|
861
|
+
exit 255
|
862
|
+
fi
|
863
|
+
fi
|
864
|
+
|
865
|
+
# coreos mode
|
866
|
+
if [ "$opt_coreos" = 1 ]; then
|
867
|
+
if ! is_coreos; then
|
868
|
+
_warn "CoreOS mode asked, but we're not under CoreOS!"
|
869
|
+
exit 255
|
870
|
+
fi
|
871
|
+
_warn "CoreOS mode, starting an ephemeral toolbox to launch the script"
|
872
|
+
load_msr
|
873
|
+
load_cpuid
|
874
|
+
mount_debugfs
|
875
|
+
toolbox --ephemeral --bind-ro /dev/cpu:/dev/cpu -- sh -c "dnf install -y binutils which && /media/root$PWD/$0 $* --coreos-within-toolbox"
|
876
|
+
exitcode=$?
|
877
|
+
exit $exitcode
|
878
|
+
else
|
879
|
+
if is_coreos; then
|
880
|
+
_warn "You seem to be running CoreOS, you might want to use the --coreos option for better results"
|
881
|
+
_warn
|
882
|
+
fi
|
883
|
+
fi
|
884
|
+
|
885
|
+
parse_cpu_details
|
886
|
+
if [ "$opt_live" = 1 ]; then
|
887
|
+
# root check (only for live mode, for offline mode, we already checked if we could read the files)
|
888
|
+
if [ "$(id -u)" -ne 0 ]; then
|
889
|
+
_warn "Note that you should launch this script with root privileges to get accurate information."
|
890
|
+
_warn "We'll proceed but you might see permission denied errors."
|
891
|
+
_warn "To run it as root, you can try the following command: sudo $0"
|
892
|
+
_warn
|
893
|
+
fi
|
894
|
+
_info "Checking for vulnerabilities on current system"
|
895
|
+
_info "Kernel is \033[35m$(uname -s) $(uname -r) $(uname -v) $(uname -m)\033[0m"
|
896
|
+
_info "CPU is \033[35m$cpu_friendly_name\033[0m"
|
897
|
+
|
898
|
+
# try to find the image of the current running kernel
|
899
|
+
# first, look for the BOOT_IMAGE hint in the kernel cmdline
|
900
|
+
if [ -r /proc/cmdline ] && grep -q 'BOOT_IMAGE=' /proc/cmdline; then
|
901
|
+
opt_kernel=$(grep -Eo 'BOOT_IMAGE=[^ ]+' /proc/cmdline | cut -d= -f2)
|
902
|
+
_debug "found opt_kernel=$opt_kernel in /proc/cmdline"
|
903
|
+
# if we have a dedicated /boot partition, our bootloader might have just called it /
|
904
|
+
# so try to prepend /boot and see if we find anything
|
905
|
+
[ -e "/boot/$opt_kernel" ] && opt_kernel="/boot/$opt_kernel"
|
906
|
+
# special case for CoreOS if we're inside the toolbox
|
907
|
+
[ -e "/media/root/boot/$opt_kernel" ] && opt_kernel="/media/root/boot/$opt_kernel"
|
908
|
+
_debug "opt_kernel is now $opt_kernel"
|
909
|
+
# else, the full path is already there (most probably /boot/something)
|
910
|
+
fi
|
911
|
+
# if we didn't find a kernel, default to guessing
|
912
|
+
if [ ! -e "$opt_kernel" ]; then
|
913
|
+
# Fedora:
|
914
|
+
[ -e "/lib/modules/$(uname -r)/vmlinuz" ] && opt_kernel="/lib/modules/$(uname -r)/vmlinuz"
|
915
|
+
# Slackare:
|
916
|
+
[ -e "/boot/vmlinuz" ] && opt_kernel="/boot/vmlinuz"
|
917
|
+
# Arch:
|
918
|
+
[ -e "/boot/vmlinuz-linux" ] && opt_kernel="/boot/vmlinuz-linux"
|
919
|
+
# Linux-Libre:
|
920
|
+
[ -e "/boot/vmlinuz-linux-libre" ] && opt_kernel="/boot/vmlinuz-linux-libre"
|
921
|
+
# pine64
|
922
|
+
[ -e "/boot/pine64/Image" ] && opt_kernel="/boot/pine64/Image"
|
923
|
+
# generic:
|
924
|
+
[ -e "/boot/vmlinuz-$(uname -r)" ] && opt_kernel="/boot/vmlinuz-$(uname -r)"
|
925
|
+
[ -e "/boot/kernel-$( uname -r)" ] && opt_kernel="/boot/kernel-$( uname -r)"
|
926
|
+
[ -e "/boot/bzImage-$(uname -r)" ] && opt_kernel="/boot/bzImage-$(uname -r)"
|
927
|
+
# Gentoo:
|
928
|
+
[ -e "/boot/kernel-genkernel-$(uname -m)-$(uname -r)" ] && opt_kernel="/boot/kernel-genkernel-$(uname -m)-$(uname -r)"
|
929
|
+
# NixOS:
|
930
|
+
[ -e "/run/booted-system/kernel" ] && opt_kernel="/run/booted-system/kernel"
|
931
|
+
# systemd kernel-install:
|
932
|
+
[ -e "/etc/machine-id" ] && [ -e "/boot/$(cat /etc/machine-id)/$(uname -r)/linux" ] && opt_kernel="/boot/$(cat /etc/machine-id)/$(uname -r)/linux"
|
933
|
+
fi
|
934
|
+
|
935
|
+
# system.map
|
936
|
+
if [ -e /proc/kallsyms ] ; then
|
937
|
+
opt_map=/proc/kallsyms
|
938
|
+
elif [ -e "/lib/modules/$(uname -r)/System.map" ] ; then
|
939
|
+
opt_map="/lib/modules/$(uname -r)/System.map"
|
940
|
+
elif [ -e "/boot/System.map-$(uname -r)" ] ; then
|
941
|
+
opt_map="/boot/System.map-$(uname -r)"
|
942
|
+
fi
|
943
|
+
|
944
|
+
# config
|
945
|
+
if [ -e /proc/config.gz ] ; then
|
946
|
+
dumped_config="$(mktemp /tmp/config-XXXXXX)"
|
947
|
+
gunzip -c /proc/config.gz > "$dumped_config"
|
948
|
+
# dumped_config will be deleted at the end of the script
|
949
|
+
opt_config="$dumped_config"
|
950
|
+
elif [ -e "/lib/modules/$(uname -r)/config" ]; then
|
951
|
+
opt_config="/lib/modules/$(uname -r)/config"
|
952
|
+
elif [ -e "/boot/config-$(uname -r)" ]; then
|
953
|
+
opt_config="/boot/config-$(uname -r)"
|
954
|
+
fi
|
955
|
+
else
|
956
|
+
_info "Checking for vulnerabilities against specified kernel"
|
957
|
+
_info "CPU is \033[35m$cpu_friendly_name\033[0m"
|
958
|
+
fi
|
959
|
+
|
960
|
+
if [ -n "$opt_kernel" ]; then
|
961
|
+
_verbose "Will use vmlinux image \033[35m$opt_kernel\033[0m"
|
962
|
+
else
|
963
|
+
_verbose "Will use no vmlinux image (accuracy might be reduced)"
|
964
|
+
bad_accuracy=1
|
965
|
+
fi
|
966
|
+
|
967
|
+
if [ -n "$opt_config" ] && ! grep -q '^CONFIG_' "$opt_config"; then
|
968
|
+
# given file is invalid!
|
969
|
+
_warn "The kernel config file seems invalid, was expecting a plain-text file, ignoring it!"
|
970
|
+
opt_config=''
|
971
|
+
fi
|
972
|
+
|
973
|
+
if [ -n "$dumped_config" ] && [ -n "$opt_config" ]; then
|
974
|
+
_verbose "Will use kconfig \033[35m/proc/config.gz (decompressed)\033[0m"
|
975
|
+
elif [ -n "$opt_config" ]; then
|
976
|
+
_verbose "Will use kconfig \033[35m$opt_config\033[0m"
|
977
|
+
else
|
978
|
+
_verbose "Will use no kconfig (accuracy might be reduced)"
|
979
|
+
bad_accuracy=1
|
980
|
+
fi
|
981
|
+
|
982
|
+
if [ -n "$opt_map" ]; then
|
983
|
+
_verbose "Will use System.map file \033[35m$opt_map\033[0m"
|
984
|
+
else
|
985
|
+
_verbose "Will use no System.map file (accuracy might be reduced)"
|
986
|
+
bad_accuracy=1
|
987
|
+
fi
|
988
|
+
|
989
|
+
if [ "$bad_accuracy" = 1 ]; then
|
990
|
+
_info "We're missing some kernel info (see -v), accuracy might be reduced"
|
991
|
+
fi
|
992
|
+
|
993
|
+
if [ -e "$opt_kernel" ]; then
|
994
|
+
if ! which readelf >/dev/null 2>&1; then
|
995
|
+
_debug "readelf not found"
|
996
|
+
vmlinux_err="missing 'readelf' tool, please install it, usually it's in the 'binutils' package"
|
997
|
+
elif [ "$opt_sysfs_only" = 1 ]; then
|
998
|
+
vmlinux_err='kernel image decompression skipped'
|
999
|
+
else
|
1000
|
+
extract_vmlinux "$opt_kernel"
|
1001
|
+
fi
|
1002
|
+
else
|
1003
|
+
_debug "no opt_kernel defined"
|
1004
|
+
vmlinux_err="couldn't find your kernel image in /boot, if you used netboot, this is normal"
|
1005
|
+
fi
|
1006
|
+
if [ -z "$vmlinux" ] || [ ! -r "$vmlinux" ]; then
|
1007
|
+
[ -z "$vmlinux_err" ] && vmlinux_err="couldn't extract your kernel from $opt_kernel"
|
1008
|
+
else
|
1009
|
+
vmlinux_version=$(strings "$vmlinux" 2>/dev/null | grep '^Linux version ' | head -1)
|
1010
|
+
if [ -z "$vmlinux_version" ]; then
|
1011
|
+
# try harder with some kernels (such as Red Hat) that don't have ^Linux version before their version string
|
1012
|
+
vmlinux_version=$(strings "$vmlinux" 2>/dev/null | grep -E '^[[:alnum:]][^[:space:]]+ \([^[:space:]]+\) #[0-9]+ .+ (19|20)[0-9][0-9]$' | head -1)
|
1013
|
+
fi
|
1014
|
+
if [ -n "$vmlinux_version" ]; then
|
1015
|
+
# in live mode, check if the img we found is the correct one
|
1016
|
+
if [ "$opt_live" = 1 ]; then
|
1017
|
+
_verbose "Kernel image is \033[35m$vmlinux_version"
|
1018
|
+
if ! echo "$vmlinux_version" | grep -qF "$(uname -r)" || \
|
1019
|
+
! echo "$vmlinux_version" | grep -qF "$(uname -v)"; then
|
1020
|
+
_warn "Possible disrepancy between your running kernel and the image we found ($opt_kernel), results might be incorrect"
|
1021
|
+
fi
|
1022
|
+
else
|
1023
|
+
_info "Kernel image is \033[35m$vmlinux_version"
|
1024
|
+
fi
|
1025
|
+
else
|
1026
|
+
_verbose "Kernel image version is unknown"
|
1027
|
+
fi
|
1028
|
+
fi
|
1029
|
+
|
1030
|
+
_info
|
1031
|
+
|
1032
|
+
# end of header stuff
|
1033
|
+
|
1034
|
+
# now we define some util functions and the check_*() funcs, as
|
1035
|
+
# the user can choose to execute only some of those
|
1036
|
+
|
1037
|
+
sys_interface_check()
|
1038
|
+
{
|
1039
|
+
[ "$opt_live" = 1 ] && [ "$opt_no_sysfs" = 0 ] && [ -r "$1" ] || return 1
|
1040
|
+
_info_nol "* Mitigated according to the /sys interface: "
|
1041
|
+
if grep -qi '^not affected' "$1"; then
|
1042
|
+
# Not affected
|
1043
|
+
status=OK
|
1044
|
+
pstatus green YES "kernel confirms that your CPU is unaffected"
|
1045
|
+
elif grep -qi '^mitigation' "$1"; then
|
1046
|
+
# Mitigation: PTI
|
1047
|
+
status=OK
|
1048
|
+
pstatus green YES "kernel confirms that the mitigation is active"
|
1049
|
+
elif grep -qi '^vulnerable' "$1"; then
|
1050
|
+
# Vulnerable
|
1051
|
+
status=VULN
|
1052
|
+
pstatus red NO "kernel confirms your system is vulnerable"
|
1053
|
+
else
|
1054
|
+
status=UNK
|
1055
|
+
pstatus yellow UNKNOWN "unknown value reported by kernel"
|
1056
|
+
fi
|
1057
|
+
msg=$(cat "$1")
|
1058
|
+
_debug "sys_interface_check: $1=$msg"
|
1059
|
+
return 0
|
1060
|
+
}
|
1061
|
+
|
1062
|
+
check_cpu()
|
1063
|
+
{
|
1064
|
+
_info "\033[1;34mHardware check\033[0m"
|
1065
|
+
|
1066
|
+
_info "* Hardware support (CPU microcode) for mitigation techniques"
|
1067
|
+
_info " * Indirect Branch Restricted Speculation (IBRS)"
|
1068
|
+
_info_nol " * SPEC_CTRL MSR is available: "
|
1069
|
+
if [ ! -e /dev/cpu/0/msr ]; then
|
1070
|
+
# try to load the module ourselves (and remember it so we can rmmod it afterwards)
|
1071
|
+
load_msr
|
1072
|
+
fi
|
1073
|
+
if [ ! -e /dev/cpu/0/msr ]; then
|
1074
|
+
spec_ctrl_msr=-1
|
1075
|
+
pstatus yellow UNKNOWN "couldn't read /dev/cpu/0/msr, is msr support enabled in your kernel?"
|
1076
|
+
else
|
1077
|
+
# the new MSR 'SPEC_CTRL' is at offset 0x48
|
1078
|
+
# here we use dd, it's the same as using 'rdmsr 0x48' but without needing the rdmsr tool
|
1079
|
+
# if we get a read error, the MSR is not there. bs has to be 8 for msr
|
1080
|
+
# skip=9 because 8*9=72=0x48
|
1081
|
+
dd if=/dev/cpu/0/msr of=/dev/null bs=8 count=1 skip=9 2>/dev/null; ret=$?
|
1082
|
+
if [ $ret -eq 0 ]; then
|
1083
|
+
spec_ctrl_msr=1
|
1084
|
+
pstatus green YES
|
1085
|
+
else
|
1086
|
+
spec_ctrl_msr=0
|
1087
|
+
pstatus red NO
|
1088
|
+
fi
|
1089
|
+
fi
|
1090
|
+
|
1091
|
+
_info_nol " * CPU indicates IBRS capability: "
|
1092
|
+
# from kernel src: { X86_FEATURE_SPEC_CTRL, CPUID_EDX,26, 0x00000007, 0 },
|
1093
|
+
read_cpuid 7 15 4; ret=$?
|
1094
|
+
if [ $ret -eq 0 ]; then
|
1095
|
+
pstatus green YES "SPEC_CTRL feature bit"
|
1096
|
+
cpuid_spec_ctrl=1
|
1097
|
+
elif [ $ret -eq 2 ]; then
|
1098
|
+
pstatus yellow UNKNOWN "couldn't read /dev/cpu/0/cpuid, is cpuid support enabled in your kernel?"
|
1099
|
+
else
|
1100
|
+
pstatus red NO
|
1101
|
+
fi
|
1102
|
+
|
1103
|
+
# hardware support according to kernel
|
1104
|
+
if [ "$opt_verbose" -ge 2 ]; then
|
1105
|
+
# the spec_ctrl flag in cpuinfo is set if and only if the kernel sees
|
1106
|
+
# that the spec_ctrl cpuinfo bit set. we already check that ourselves above
|
1107
|
+
# but let's check it anyway (in verbose mode only)
|
1108
|
+
_verbose_nol " * Kernel has set the spec_ctrl flag in cpuinfo: "
|
1109
|
+
if [ "$opt_live" = 1 ]; then
|
1110
|
+
if grep ^flags /proc/cpuinfo | grep -qw spec_ctrl; then
|
1111
|
+
pstatus green YES
|
1112
|
+
else
|
1113
|
+
pstatus blue NO
|
1114
|
+
fi
|
1115
|
+
else
|
1116
|
+
pstatus blue N/A "not testable in offline mode"
|
1117
|
+
fi
|
1118
|
+
fi
|
1119
|
+
|
1120
|
+
# IBPB
|
1121
|
+
_info " * Indirect Branch Prediction Barrier (IBPB)"
|
1122
|
+
_info_nol " * PRED_CMD MSR is available: "
|
1123
|
+
if [ ! -e /dev/cpu/0/msr ]; then
|
1124
|
+
pstatus yellow UNKNOWN "couldn't read /dev/cpu/0/msr, is msr support enabled in your kernel?"
|
1125
|
+
else
|
1126
|
+
# the new MSR 'PRED_CTRL' is at offset 0x49, write-only
|
1127
|
+
# here we use dd, it's the same as using 'wrmsr 0x49 0' but without needing the wrmsr tool
|
1128
|
+
# if we get a write error, the MSR is not there
|
1129
|
+
$echo_cmd -ne "\0\0\0\0\0\0\0\0" | dd of=/dev/cpu/0/msr bs=8 count=1 seek=73 oflag=seek_bytes 2>/dev/null; ret=$?
|
1130
|
+
if [ $ret -eq 0 ]; then
|
1131
|
+
pstatus green YES
|
1132
|
+
else
|
1133
|
+
pstatus red NO
|
1134
|
+
fi
|
1135
|
+
fi
|
1136
|
+
|
1137
|
+
|
1138
|
+
_info_nol " * CPU indicates IBPB capability: "
|
1139
|
+
# CPUID EAX=0x80000008, ECX=0x00 return EBX[12] indicates support for just IBPB.
|
1140
|
+
read_cpuid 2147483656 5 16; ret=$?
|
1141
|
+
if [ $ret -eq 0 ]; then
|
1142
|
+
pstatus green YES "IBPB_SUPPORT feature bit"
|
1143
|
+
elif [ "$cpuid_spec_ctrl" = 1 ]; then
|
1144
|
+
pstatus green YES "SPEC_CTRL feature bit"
|
1145
|
+
elif [ $ret -eq 2 ]; then
|
1146
|
+
pstatus yellow UNKNOWN "couldn't read /dev/cpu/0/cpuid, is cpuid support enabled in your kernel?"
|
1147
|
+
else
|
1148
|
+
pstatus red NO
|
1149
|
+
fi
|
1150
|
+
|
1151
|
+
# STIBP
|
1152
|
+
_info " * Single Thread Indirect Branch Predictors (STIBP)"
|
1153
|
+
_info_nol " * SPEC_CTRL MSR is available: "
|
1154
|
+
if [ "$spec_ctrl_msr" = 1 ]; then
|
1155
|
+
pstatus green YES
|
1156
|
+
elif [ "$spec_ctrl_msr" = 0 ]; then
|
1157
|
+
pstatus red NO
|
1158
|
+
else
|
1159
|
+
pstatus yellow UNKNOWN "couldn't read /dev/cpu/0/msr, is msr support enabled in your kernel?"
|
1160
|
+
fi
|
1161
|
+
|
1162
|
+
_info_nol " * CPU indicates STIBP capability: "
|
1163
|
+
# A processor supports STIBP if it enumerates CPUID (EAX=7H,ECX=0):EDX[27] as 1
|
1164
|
+
read_cpuid 7 15 8; ret=$?
|
1165
|
+
if [ $ret -eq 0 ]; then
|
1166
|
+
pstatus green YES
|
1167
|
+
elif [ $ret -eq 2 ]; then
|
1168
|
+
pstatus yellow UNKNOWN "couldn't read /dev/cpu/0/cpuid, is cpuid support enabled in your kernel?"
|
1169
|
+
else
|
1170
|
+
pstatus red NO
|
1171
|
+
fi
|
1172
|
+
|
1173
|
+
_info " * Enhanced IBRS (IBRS_ALL)"
|
1174
|
+
_info_nol " * CPU indicates ARCH_CAPABILITIES MSR availability: "
|
1175
|
+
cpuid_arch_capabilities=-1
|
1176
|
+
# A processor supports STIBP if it enumerates CPUID (EAX=7H,ECX=0):EDX[27] as 1
|
1177
|
+
read_cpuid 7 15 32; ret=$?
|
1178
|
+
if [ $ret -eq 0 ]; then
|
1179
|
+
pstatus green YES
|
1180
|
+
cpuid_arch_capabilities=1
|
1181
|
+
elif [ $ret -eq 2 ]; then
|
1182
|
+
pstatus yellow UNKNOWN "couldn't read /dev/cpu/0/cpuid, is cpuid support enabled in your kernel?"
|
1183
|
+
else
|
1184
|
+
pstatus red NO
|
1185
|
+
cpuid_arch_capabilities=0
|
1186
|
+
fi
|
1187
|
+
|
1188
|
+
_info_nol " * ARCH_CAPABILITIES MSR advertises IBRS_ALL capability: "
|
1189
|
+
capabilities_rdcl_no=-1
|
1190
|
+
capabilities_ibrs_all=-1
|
1191
|
+
if [ "$cpuid_arch_capabilities" = -1 ]; then
|
1192
|
+
pstatus yellow UNKNOWN
|
1193
|
+
elif [ "$cpuid_arch_capabilities" != 1 ]; then
|
1194
|
+
capabilities_rdcl_no=0
|
1195
|
+
capabilities_ibrs_all=0
|
1196
|
+
pstatus red NO
|
1197
|
+
elif [ ! -e /dev/cpu/0/msr ]; then
|
1198
|
+
spec_ctrl_msr=-1
|
1199
|
+
pstatus yellow UNKNOWN "couldn't read /dev/cpu/0/msr, is msr support enabled in your kernel?"
|
1200
|
+
else
|
1201
|
+
# the new MSR 'ARCH_CAPABILITIES' is at offset 0x10a
|
1202
|
+
# here we use dd, it's the same as using 'rdmsr 0x10a' but without needing the rdmsr tool
|
1203
|
+
# if we get a read error, the MSR is not there. bs has to be 8 for msr
|
1204
|
+
capabilities=$(dd if=/dev/cpu/0/msr bs=8 count=1 skip=266 iflag=skip_bytes 2>/dev/null | od -t u1 -A n | awk '{print $8}'); ret=$?
|
1205
|
+
capabilities_rdcl_no=0
|
1206
|
+
capabilities_ibrs_all=0
|
1207
|
+
if [ $ret -eq 0 ]; then
|
1208
|
+
_debug "capabilities MSR lower byte is $capabilities (decimal)"
|
1209
|
+
[ $(( capabilities & 1 )) -eq 1 ] && capabilities_rdcl_no=1
|
1210
|
+
[ $(( capabilities & 2 )) -eq 2 ] && capabilities_ibrs_all=1
|
1211
|
+
_debug "capabilities says rdcl_no=$capabilities_rdcl_no ibrs_all=$capabilities_ibrs_all"
|
1212
|
+
if [ "$capabilities_ibrs_all" = 1 ]; then
|
1213
|
+
pstatus green YES
|
1214
|
+
else
|
1215
|
+
pstatus red NO
|
1216
|
+
fi
|
1217
|
+
else
|
1218
|
+
pstatus yellow UNKNOWN
|
1219
|
+
fi
|
1220
|
+
fi
|
1221
|
+
|
1222
|
+
_info_nol " * CPU explicitly indicates not being vulnerable to Meltdown (RDCL_NO): "
|
1223
|
+
if [ "$capabilities_rdcl_no" = -1 ]; then
|
1224
|
+
pstatus yellow UNKNOWN
|
1225
|
+
elif [ "$capabilities_rdcl_no" = 1 ]; then
|
1226
|
+
pstatus green YES
|
1227
|
+
else
|
1228
|
+
pstatus blue NO
|
1229
|
+
fi
|
1230
|
+
|
1231
|
+
_info_nol " * CPU microcode is known to cause stability problems: "
|
1232
|
+
if is_ucode_blacklisted; then
|
1233
|
+
pstatus red YES "$ucode_found"
|
1234
|
+
_warn
|
1235
|
+
_warn "The microcode your CPU is running on is known to cause instability problems,"
|
1236
|
+
_warn "such as intempestive reboots or random crashes."
|
1237
|
+
_warn "You are advised to either revert to a previous microcode version (that might not have"
|
1238
|
+
_warn "the mitigations for Spectre), or upgrade to a newer one if available."
|
1239
|
+
_warn
|
1240
|
+
else
|
1241
|
+
pstatus blue NO "$ucode_found"
|
1242
|
+
fi
|
1243
|
+
|
1244
|
+
_info "* CPU vulnerability to the three speculative execution attacks variants"
|
1245
|
+
for v in 1 2 3; do
|
1246
|
+
_info_nol " * Vulnerable to Variant $v: "
|
1247
|
+
if is_cpu_vulnerable $v; then
|
1248
|
+
pstatus red YES
|
1249
|
+
else
|
1250
|
+
pstatus green NO
|
1251
|
+
fi
|
1252
|
+
done
|
1253
|
+
|
1254
|
+
_info
|
1255
|
+
}
|
1256
|
+
|
1257
|
+
check_redhat_canonical_spectre()
|
1258
|
+
{
|
1259
|
+
# if we were already called, don't do it again
|
1260
|
+
[ -n "$redhat_canonical_spectre" ] && return
|
1261
|
+
|
1262
|
+
if ! which strings >/dev/null 2>&1; then
|
1263
|
+
redhat_canonical_spectre=-1
|
1264
|
+
elif [ -n "$vmlinux_err" ]; then
|
1265
|
+
redhat_canonical_spectre=-2
|
1266
|
+
else
|
1267
|
+
# Red Hat / Ubuntu specific variant1 patch is difficult to detect,
|
1268
|
+
# let's use the same way than the official Red Hat detection script,
|
1269
|
+
# and detect their specific variant2 patch. If it's present, it means
|
1270
|
+
# that the variant1 patch is also present (both were merged at the same time)
|
1271
|
+
if strings "$vmlinux" | grep -qw noibrs && strings "$vmlinux" | grep -qw noibpb; then
|
1272
|
+
_debug "found redhat/canonical version of the variant2 patch (implies variant1)"
|
1273
|
+
redhat_canonical_spectre=1
|
1274
|
+
else
|
1275
|
+
redhat_canonical_spectre=0
|
1276
|
+
fi
|
1277
|
+
fi
|
1278
|
+
}
|
1279
|
+
|
1280
|
+
|
1281
|
+
###################
|
1282
|
+
# SPECTRE VARIANT 1
|
1283
|
+
check_variant1()
|
1284
|
+
{
|
1285
|
+
_info "\033[1;34mCVE-2017-5753 [bounds check bypass] aka 'Spectre Variant 1'\033[0m"
|
1286
|
+
|
1287
|
+
status=UNK
|
1288
|
+
sys_interface_available=0
|
1289
|
+
msg=''
|
1290
|
+
if sys_interface_check "/sys/devices/system/cpu/vulnerabilities/spectre_v1"; then
|
1291
|
+
# this kernel has the /sys interface, trust it over everything
|
1292
|
+
# v0.33+: don't. some kernels have backported the array_index_mask_nospec() workaround without
|
1293
|
+
# modifying the vulnerabilities/spectre_v1 file. that's bad. we can't trust it when it says Vulnerable :(
|
1294
|
+
# see "silent backport" detection at the bottom of this func
|
1295
|
+
sys_interface_available=1
|
1296
|
+
fi
|
1297
|
+
if [ "$opt_sysfs_only" != 1 ]; then
|
1298
|
+
# no /sys interface (or offline mode), fallback to our own ways
|
1299
|
+
_info_nol "* Kernel has array_index_mask_nospec: "
|
1300
|
+
# vanilla: look for the Linus' mask aka array_index_mask_nospec()
|
1301
|
+
# that is inlined at least in raw_copy_from_user (__get_user_X symbols)
|
1302
|
+
#mov PER_CPU_VAR(current_task), %_ASM_DX
|
1303
|
+
#cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX
|
1304
|
+
#jae bad_get_user
|
1305
|
+
# /* array_index_mask_nospec() are the 2 opcodes that follow */
|
1306
|
+
#+sbb %_ASM_DX, %_ASM_DX
|
1307
|
+
#+and %_ASM_DX, %_ASM_AX
|
1308
|
+
#ASM_STAC
|
1309
|
+
# x86 64bits: jae(0x0f 0x83 0x?? 0x?? 0x?? 0x??) sbb(0x48 0x19 0xd2) and(0x48 0x21 0xd0)
|
1310
|
+
# x86 32bits: cmp(0x3b 0x82 0x?? 0x?? 0x00 0x00) jae(0x73 0x??) sbb(0x19 0xd2) and(0x21 0xd0)
|
1311
|
+
if [ -n "$vmlinux_err" ]; then
|
1312
|
+
pstatus yellow UNKNOWN "couldn't check ($vmlinux_err)"
|
1313
|
+
elif ! which perl >/dev/null 2>&1; then
|
1314
|
+
pstatus yellow UNKNOWN "missing 'perl' binary, please install it"
|
1315
|
+
else
|
1316
|
+
perl -ne '/\x0f\x83....\x48\x19\xd2\x48\x21\xd0/ and $found++; END { exit($found) }' "$vmlinux"; ret=$?
|
1317
|
+
if [ $ret -gt 0 ]; then
|
1318
|
+
pstatus green YES "$ret occurence(s) found of 64 bits array_index_mask_nospec()"
|
1319
|
+
v1_mask_nospec=1
|
1320
|
+
else
|
1321
|
+
perl -ne '/\x3b\x82..\x00\x00\x73.\x19\xd2\x21\xd0/ and $found++; END { exit($found) }' "$vmlinux"; ret=$?
|
1322
|
+
if [ $ret -gt 0 ]; then
|
1323
|
+
pstatus green YES "$ret occurence(s) found of 32 bits array_index_mask_nospec()"
|
1324
|
+
v1_mask_nospec=1
|
1325
|
+
else
|
1326
|
+
pstatus red NO
|
1327
|
+
fi
|
1328
|
+
fi
|
1329
|
+
fi
|
1330
|
+
|
1331
|
+
_info_nol "* Kernel has the Red Hat/Ubuntu patch: "
|
1332
|
+
check_redhat_canonical_spectre
|
1333
|
+
if [ "$redhat_canonical_spectre" = -1 ]; then
|
1334
|
+
pstatus yellow UNKNOWN "missing 'strings' tool, please install it, usually it's in the binutils package"
|
1335
|
+
elif [ "$redhat_canonical_spectre" = -2 ]; then
|
1336
|
+
pstatus yellow UNKNOWN "couldn't check ($vmlinux_err)"
|
1337
|
+
elif [ "$redhat_canonical_spectre" = 1 ]; then
|
1338
|
+
pstatus green YES
|
1339
|
+
else
|
1340
|
+
pstatus red NO
|
1341
|
+
fi
|
1342
|
+
|
1343
|
+
if [ "$opt_verbose" -ge 2 ] || ( [ "$v1_mask_nospec" != 1 ] && [ "$redhat_canonical_spectre" != 1 ] ); then
|
1344
|
+
# this is a slow heuristic and we don't need it if we already know the kernel is patched
|
1345
|
+
# but still show it in verbose mode
|
1346
|
+
_info_nol "* Checking count of LFENCE instructions following a jump in kernel... "
|
1347
|
+
if [ -n "$vmlinux_err" ]; then
|
1348
|
+
pstatus yellow UNKNOWN "couldn't check ($vmlinux_err)"
|
1349
|
+
else
|
1350
|
+
if ! which objdump >/dev/null 2>&1; then
|
1351
|
+
pstatus yellow UNKNOWN "missing 'objdump' tool, please install it, usually it's in the binutils package"
|
1352
|
+
else
|
1353
|
+
# here we disassemble the kernel and count the number of occurrences of the LFENCE opcode
|
1354
|
+
# in non-patched kernels, this has been empirically determined as being around 40-50
|
1355
|
+
# in patched kernels, this is more around 70-80, sometimes way higher (100+)
|
1356
|
+
# 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,
|
1357
|
+
# so let's push the threshold to 70.
|
1358
|
+
# v0.33+: now only count lfence opcodes after a jump, way less error-prone
|
1359
|
+
# non patched kernel have between 0 and 20 matches, patched ones have at least 40-45
|
1360
|
+
nb_lfence=$(objdump -d "$vmlinux" | grep -w -B1 lfence | grep -Ewc 'jmp|jne|je')
|
1361
|
+
if [ "$nb_lfence" -lt 30 ]; then
|
1362
|
+
pstatus red NO "only $nb_lfence jump-then-lfence instructions found, should be >= 30 (heuristic)"
|
1363
|
+
else
|
1364
|
+
v1_lfence=1
|
1365
|
+
pstatus green YES "$nb_lfence jump-then-lfence instructions found, which is >= 30 (heuristic)"
|
1366
|
+
fi
|
1367
|
+
fi
|
1368
|
+
fi
|
1369
|
+
fi
|
1370
|
+
|
1371
|
+
else
|
1372
|
+
# we have no sysfs but were asked to use it only!
|
1373
|
+
msg="/sys vulnerability interface use forced, but it's not available!"
|
1374
|
+
status=UNK
|
1375
|
+
fi
|
1376
|
+
|
1377
|
+
# report status
|
1378
|
+
cve='CVE-2017-5753'
|
1379
|
+
if ! is_cpu_vulnerable 1; then
|
1380
|
+
# override status & msg in case CPU is not vulnerable after all
|
1381
|
+
pvulnstatus $cve OK "your CPU vendor reported your CPU model as not vulnerable"
|
1382
|
+
elif [ -z "$msg" ]; then
|
1383
|
+
# if msg is empty, sysfs check didn't fill it, rely on our own test
|
1384
|
+
if [ "$v1_mask_nospec" = 1 ]; then
|
1385
|
+
pvulnstatus $cve OK "Kernel source has been patched to mitigate the vulnerability (array_index_mask_nospec)"
|
1386
|
+
elif [ "$redhat_canonical_spectre" = 1 ]; then
|
1387
|
+
pvulnstatus $cve OK "Kernel source has been patched to mitigate the vulnerability (Red Hat/Ubuntu patch)"
|
1388
|
+
elif [ "$v1_lfence" = 1 ]; then
|
1389
|
+
pvulnstatus $cve OK "Kernel source has PROBABLY been patched to mitigate the vulnerability (jump-then-lfence instructions heuristic)"
|
1390
|
+
elif [ "$vmlinux_err" ]; then
|
1391
|
+
pvulnstatus $cve UNK "Couldn't find kernel image or tools missing to execute the checks"
|
1392
|
+
else
|
1393
|
+
pvulnstatus $cve VULN "Kernel source needs to be patched to mitigate the vulnerability"
|
1394
|
+
fi
|
1395
|
+
else
|
1396
|
+
if [ "$msg" = "Vulnerable" ] && [ "$v1_mask_nospec" = 1 ]; then
|
1397
|
+
pvulnstatus $cve OK "Kernel source has been patched to mitigate the vulnerability (silent backport of array_index_mask_nospec)"
|
1398
|
+
else
|
1399
|
+
[ "$msg" = "Vulnerable" ] && msg="Kernel source needs to be patched to mitigate the vulnerability"
|
1400
|
+
pvulnstatus $cve "$status" "$msg"
|
1401
|
+
fi
|
1402
|
+
fi
|
1403
|
+
}
|
1404
|
+
|
1405
|
+
###################
|
1406
|
+
# SPECTRE VARIANT 2
|
1407
|
+
check_variant2()
|
1408
|
+
{
|
1409
|
+
_info "\033[1;34mCVE-2017-5715 [branch target injection] aka 'Spectre Variant 2'\033[0m"
|
1410
|
+
|
1411
|
+
status=UNK
|
1412
|
+
sys_interface_available=0
|
1413
|
+
msg=''
|
1414
|
+
if sys_interface_check "/sys/devices/system/cpu/vulnerabilities/spectre_v2"; then
|
1415
|
+
# this kernel has the /sys interface, trust it over everything
|
1416
|
+
sys_interface_available=1
|
1417
|
+
fi
|
1418
|
+
if [ "$opt_sysfs_only" != 1 ]; then
|
1419
|
+
_info "* Mitigation 1"
|
1420
|
+
_info_nol " * Kernel is compiled with IBRS/IBPB support: "
|
1421
|
+
ibrs_can_tell=0
|
1422
|
+
|
1423
|
+
if [ "$opt_live" = 1 ]; then
|
1424
|
+
ibrs_can_tell=1
|
1425
|
+
mount_debugfs
|
1426
|
+
for dir in \
|
1427
|
+
/sys/kernel/debug \
|
1428
|
+
/sys/kernel/debug/x86 \
|
1429
|
+
/proc/sys/kernel; do
|
1430
|
+
if [ -e "$dir/ibrs_enabled" ]; then
|
1431
|
+
# if the file is there, we have IBRS compiled-in
|
1432
|
+
# /sys/kernel/debug/ibrs_enabled: vanilla
|
1433
|
+
# /sys/kernel/debug/x86/ibrs_enabled: Red Hat (see https://access.redhat.com/articles/3311301)
|
1434
|
+
# /proc/sys/kernel/ibrs_enabled: OpenSUSE tumbleweed
|
1435
|
+
pstatus green YES
|
1436
|
+
ibrs_knob_dir=$dir
|
1437
|
+
ibrs_supported=1
|
1438
|
+
ibrs_enabled=$(cat "$dir/ibrs_enabled" 2>/dev/null)
|
1439
|
+
_debug "ibrs: found $dir/ibrs_enabled=$ibrs_enabled"
|
1440
|
+
if [ -e "$dir/ibpb_enabled" ]; then
|
1441
|
+
ibpb_enabled=$(cat "$dir/ibpb_enabled" 2>/dev/null)
|
1442
|
+
_debug "ibpb: found $dir/ibpb_enabled=$ibpb_enabled"
|
1443
|
+
else
|
1444
|
+
ibpb_enabled=-1
|
1445
|
+
_debug "ibpb: no ibpb_enabled file in $dir"
|
1446
|
+
fi
|
1447
|
+
break
|
1448
|
+
else
|
1449
|
+
_debug "ibrs: $dir/ibrs_enabled file doesn't exist"
|
1450
|
+
fi
|
1451
|
+
done
|
1452
|
+
# on some newer kernels, the spec_ctrl_ibrs flag in /proc/cpuinfo
|
1453
|
+
# is set when ibrs has been administratively enabled (usually from cmdline)
|
1454
|
+
# which in that case means ibrs is supported *and* enabled for kernel & user
|
1455
|
+
# as per the ibrs patch series v3
|
1456
|
+
if [ "$ibrs_supported" = 0 ]; then
|
1457
|
+
if grep ^flags /proc/cpuinfo | grep -qw spec_ctrl_ibrs; then
|
1458
|
+
_debug "ibrs: found spec_ctrl_ibrs flag in /proc/cpuinfo"
|
1459
|
+
ibrs_supported=1
|
1460
|
+
# enabled=2 -> kernel & user
|
1461
|
+
ibrs_enabled=2
|
1462
|
+
# XXX and what about ibpb ?
|
1463
|
+
fi
|
1464
|
+
fi
|
1465
|
+
fi
|
1466
|
+
if [ "$ibrs_supported" != 1 ] && [ -n "$opt_map" ]; then
|
1467
|
+
ibrs_can_tell=1
|
1468
|
+
if grep -q spec_ctrl "$opt_map"; then
|
1469
|
+
pstatus green YES
|
1470
|
+
ibrs_supported=1
|
1471
|
+
_debug "ibrs: found '*spec_ctrl*' symbol in $opt_map"
|
1472
|
+
fi
|
1473
|
+
fi
|
1474
|
+
if [ "$ibrs_supported" != 1 ]; then
|
1475
|
+
check_redhat_canonical_spectre
|
1476
|
+
if [ "$redhat_canonical_spectre" = 1 ]; then
|
1477
|
+
pstatus green YES "Red Hat/Ubuntu patch"
|
1478
|
+
ibrs_supported=1
|
1479
|
+
fi
|
1480
|
+
fi
|
1481
|
+
if [ "$ibrs_supported" != 1 ]; then
|
1482
|
+
if [ "$ibrs_can_tell" = 1 ]; then
|
1483
|
+
pstatus red NO
|
1484
|
+
else
|
1485
|
+
# if we're in offline mode without System.map, we can't really know
|
1486
|
+
pstatus yellow UNKNOWN "in offline mode, we need System.map to be able to tell"
|
1487
|
+
fi
|
1488
|
+
fi
|
1489
|
+
|
1490
|
+
_info " * Currently enabled features"
|
1491
|
+
_info_nol " * IBRS enabled for Kernel space: "
|
1492
|
+
if [ "$opt_live" = 1 ]; then
|
1493
|
+
if [ "$ibpb_enabled" = 2 ]; then
|
1494
|
+
# if ibpb=2, ibrs is forcefully=0
|
1495
|
+
pstatus blue NO "IBPB used instead of IBRS in all kernel entrypoints"
|
1496
|
+
else
|
1497
|
+
# 0 means disabled
|
1498
|
+
# 1 is enabled only for kernel space
|
1499
|
+
# 2 is enabled for kernel and user space
|
1500
|
+
case "$ibrs_enabled" in
|
1501
|
+
"")
|
1502
|
+
if [ "$ibrs_supported" = 1 ]; then
|
1503
|
+
pstatus yellow UNKNOWN
|
1504
|
+
else
|
1505
|
+
pstatus red NO
|
1506
|
+
fi
|
1507
|
+
;;
|
1508
|
+
0)
|
1509
|
+
pstatus red NO
|
1510
|
+
_verbose " - To enable, \`echo 1 > $ibrs_knob_dir/ibrs_enabled' as root. If you don't have hardware support, you'll get an error."
|
1511
|
+
;;
|
1512
|
+
1 | 2) pstatus green YES;;
|
1513
|
+
*) pstatus yellow UNKNOWN;;
|
1514
|
+
esac
|
1515
|
+
fi
|
1516
|
+
else
|
1517
|
+
pstatus blue N/A "not testable in offline mode"
|
1518
|
+
fi
|
1519
|
+
|
1520
|
+
_info_nol " * IBRS enabled for User space: "
|
1521
|
+
if [ "$opt_live" = 1 ]; then
|
1522
|
+
if [ "$ibpb_enabled" = 2 ]; then
|
1523
|
+
# if ibpb=2, ibrs is forcefully=0
|
1524
|
+
pstatus blue NO "IBPB used instead of IBRS in all kernel entrypoints"
|
1525
|
+
else
|
1526
|
+
case "$ibrs_enabled" in
|
1527
|
+
"")
|
1528
|
+
if [ "$ibrs_supported" = 1 ]; then
|
1529
|
+
pstatus yellow UNKNOWN
|
1530
|
+
else
|
1531
|
+
pstatus red NO
|
1532
|
+
fi
|
1533
|
+
;;
|
1534
|
+
0 | 1)
|
1535
|
+
pstatus red NO
|
1536
|
+
_verbose " - To enable, \`echo 2 > $ibrs_knob_dir/ibrs_enabled' as root. If you don't have hardware support, you'll get an error."
|
1537
|
+
;;
|
1538
|
+
2) pstatus green YES;;
|
1539
|
+
*) pstatus yellow UNKNOWN;;
|
1540
|
+
esac
|
1541
|
+
fi
|
1542
|
+
else
|
1543
|
+
pstatus blue N/A "not testable in offline mode"
|
1544
|
+
fi
|
1545
|
+
|
1546
|
+
_info_nol " * IBPB enabled: "
|
1547
|
+
if [ "$opt_live" = 1 ]; then
|
1548
|
+
case "$ibpb_enabled" in
|
1549
|
+
"")
|
1550
|
+
if [ "$ibrs_supported" = 1 ]; then
|
1551
|
+
pstatus yellow UNKNOWN
|
1552
|
+
else
|
1553
|
+
pstatus red NO
|
1554
|
+
fi
|
1555
|
+
;;
|
1556
|
+
0)
|
1557
|
+
pstatus red NO
|
1558
|
+
_verbose " - To enable, \`echo 1 > $ibrs_knob_dir/ibpb_enabled' as root. If you don't have hardware support, you'll get an error."
|
1559
|
+
;;
|
1560
|
+
1) pstatus green YES;;
|
1561
|
+
2) pstatus green YES "IBPB used instead of IBRS in all kernel entrypoints";;
|
1562
|
+
*) pstatus yellow UNKNOWN;;
|
1563
|
+
esac
|
1564
|
+
else
|
1565
|
+
pstatus blue N/A "not testable in offline mode"
|
1566
|
+
fi
|
1567
|
+
|
1568
|
+
_info "* Mitigation 2"
|
1569
|
+
_info_nol " * Kernel compiled with retpoline option: "
|
1570
|
+
# We check the RETPOLINE kernel options
|
1571
|
+
if [ -r "$opt_config" ]; then
|
1572
|
+
if grep -q '^CONFIG_RETPOLINE=y' "$opt_config"; then
|
1573
|
+
pstatus green YES
|
1574
|
+
retpoline=1
|
1575
|
+
# shellcheck disable=SC2046
|
1576
|
+
_debug 'retpoline: found '$(grep '^CONFIG_RETPOLINE' "$opt_config")" in $opt_config"
|
1577
|
+
else
|
1578
|
+
pstatus red NO
|
1579
|
+
fi
|
1580
|
+
else
|
1581
|
+
pstatus yellow UNKNOWN "couldn't read your kernel configuration"
|
1582
|
+
fi
|
1583
|
+
|
1584
|
+
_info_nol " * Kernel compiled with a retpoline-aware compiler: "
|
1585
|
+
# Now check if the compiler used to compile the kernel knows how to insert retpolines in generated asm
|
1586
|
+
# For gcc, this is -mindirect-branch=thunk-extern (detected by the kernel makefiles)
|
1587
|
+
# See gcc commit https://github.com/hjl-tools/gcc/commit/23b517d4a67c02d3ef80b6109218f2aadad7bd79
|
1588
|
+
# In latest retpoline LKML patches, the noretpoline_setup symbol exists only if CONFIG_RETPOLINE is set
|
1589
|
+
# *AND* if the compiler is retpoline-compliant, so look for that symbol
|
1590
|
+
if [ -e "/sys/devices/system/cpu/vulnerabilities/spectre_v2" ]; then
|
1591
|
+
if grep -qw Minimal /sys/devices/system/cpu/vulnerabilities/spectre_v2; then
|
1592
|
+
pstatus red NO "kernel reports minimal retpoline compilation"
|
1593
|
+
elif grep -qw Full /sys/devices/system/cpu/vulnerabilities/spectre_v2; then
|
1594
|
+
retpoline_compiler=1
|
1595
|
+
pstatus green YES "kernel reports full retpoline compilation"
|
1596
|
+
else
|
1597
|
+
if [ "$retpoline" = 1 ]; then
|
1598
|
+
pstatus yellow UNKNOWN
|
1599
|
+
else
|
1600
|
+
pstatus red NO
|
1601
|
+
fi
|
1602
|
+
fi
|
1603
|
+
elif [ -n "$opt_map" ]; then
|
1604
|
+
# look for the symbol
|
1605
|
+
if grep -qw noretpoline_setup "$opt_map"; then
|
1606
|
+
retpoline_compiler=1
|
1607
|
+
pstatus green YES "noretpoline_setup symbol found in System.map"
|
1608
|
+
else
|
1609
|
+
if [ "$retpoline" = 1 ]; then
|
1610
|
+
pstatus yellow UNKNOWN
|
1611
|
+
else
|
1612
|
+
pstatus red NO
|
1613
|
+
fi
|
1614
|
+
fi
|
1615
|
+
elif [ -n "$vmlinux" ]; then
|
1616
|
+
# look for the symbol
|
1617
|
+
if which nm >/dev/null 2>&1; then
|
1618
|
+
# the proper way: use nm and look for the symbol
|
1619
|
+
if nm "$vmlinux" 2>/dev/null | grep -qw 'noretpoline_setup'; then
|
1620
|
+
retpoline_compiler=1
|
1621
|
+
pstatus green YES "noretpoline_setup found in vmlinux symbols"
|
1622
|
+
else
|
1623
|
+
if [ "$retpoline" = 1 ]; then
|
1624
|
+
pstatus yellow UNKNOWN
|
1625
|
+
else
|
1626
|
+
pstatus red NO
|
1627
|
+
fi
|
1628
|
+
fi
|
1629
|
+
elif grep -q noretpoline_setup "$vmlinux"; then
|
1630
|
+
# if we don't have nm, nevermind, the symbol name is long enough to not have
|
1631
|
+
# any false positive using good old grep directly on the binary
|
1632
|
+
retpoline_compiler=1
|
1633
|
+
pstatus green YES "noretpoline_setup found in vmlinux"
|
1634
|
+
else
|
1635
|
+
if [ "$retpoline" = 1 ]; then
|
1636
|
+
pstatus yellow UNKNOWN
|
1637
|
+
else
|
1638
|
+
pstatus red NO
|
1639
|
+
fi
|
1640
|
+
fi
|
1641
|
+
else
|
1642
|
+
if [ "$retpoline" = 1 ]; then
|
1643
|
+
pstatus yellow UNKNOWN "couldn't find your kernel image or System.map"
|
1644
|
+
else
|
1645
|
+
pstatus red NO
|
1646
|
+
fi
|
1647
|
+
fi
|
1648
|
+
elif [ "$sys_interface_available" = 0 ]; then
|
1649
|
+
# we have no sysfs but were asked to use it only!
|
1650
|
+
msg="/sys vulnerability interface use forced, but it's not available!"
|
1651
|
+
status=UNK
|
1652
|
+
fi
|
1653
|
+
|
1654
|
+
cve='CVE-2017-5715'
|
1655
|
+
if ! is_cpu_vulnerable 2; then
|
1656
|
+
# override status & msg in case CPU is not vulnerable after all
|
1657
|
+
pvulnstatus $cve OK "your CPU vendor reported your CPU model as not vulnerable"
|
1658
|
+
elif [ -z "$msg" ]; then
|
1659
|
+
# if msg is empty, sysfs check didn't fill it, rely on our own test
|
1660
|
+
if [ "$retpoline" = 1 ] && [ "$retpoline_compiler" = 1 ]; then
|
1661
|
+
pvulnstatus $cve OK "retpoline mitigates the vulnerability"
|
1662
|
+
elif [ "$opt_live" = 1 ]; then
|
1663
|
+
if ( [ "$ibrs_enabled" = 1 ] || [ "$ibrs_enabled" = 2 ] ) && [ "$ibpb_enabled" = 1 ]; then
|
1664
|
+
pvulnstatus $cve OK "IBRS/IBPB are mitigating the vulnerability"
|
1665
|
+
elif ( [ "$ibrs_enabled" = 1 ] || [ "$ibrs_enabled" = 2 ] ) && [ "$ibpb_enabled" = -1 ]; then
|
1666
|
+
# IBPB doesn't seem here on this kernel
|
1667
|
+
pvulnstatus $cve OK "IBRS is mitigating the vulnerability"
|
1668
|
+
elif [ "$ibpb_enabled" = 2 ]; then
|
1669
|
+
pvulnstatus $cve OK "Full IBPB is mitigating the vulnerability"
|
1670
|
+
elif [ "$ibrs_supported" = 1 ] && [ "$cpuid_spec_ctrl" != 1 ]; then
|
1671
|
+
pvulnstatus $cve VULN "Your kernel is compiled with IBRS but your CPU microcode is lacking support to successfully mitigate the vulnerability"
|
1672
|
+
else
|
1673
|
+
pvulnstatus $cve VULN "IBRS hardware + kernel support OR kernel with retpoline are needed to mitigate the vulnerability"
|
1674
|
+
fi
|
1675
|
+
else
|
1676
|
+
if [ "$ibrs_supported" = 1 ]; then
|
1677
|
+
pvulnstatus $cve OK "offline mode: IBRS/IBPB will mitigate the vulnerability if enabled at runtime"
|
1678
|
+
elif [ "$ibrs_can_tell" = 1 ]; then
|
1679
|
+
pvulnstatus $cve VULN "IBRS hardware + kernel support OR kernel with retpoline are needed to mitigate the vulnerability"
|
1680
|
+
else
|
1681
|
+
pvulnstatus $cve UNK "offline mode: not enough information"
|
1682
|
+
fi
|
1683
|
+
fi
|
1684
|
+
else
|
1685
|
+
[ "$msg" = "Vulnerable" ] && msg="IBRS hardware + kernel support OR kernel with retpoline are needed to mitigate the vulnerability"
|
1686
|
+
pvulnstatus $cve "$status" "$msg"
|
1687
|
+
fi
|
1688
|
+
}
|
1689
|
+
|
1690
|
+
########################
|
1691
|
+
# MELTDOWN aka VARIANT 3
|
1692
|
+
check_variant3()
|
1693
|
+
{
|
1694
|
+
_info "\033[1;34mCVE-2017-5754 [rogue data cache load] aka 'Meltdown' aka 'Variant 3'\033[0m"
|
1695
|
+
|
1696
|
+
status=UNK
|
1697
|
+
sys_interface_available=0
|
1698
|
+
msg=''
|
1699
|
+
if sys_interface_check "/sys/devices/system/cpu/vulnerabilities/meltdown"; then
|
1700
|
+
# this kernel has the /sys interface, trust it over everything
|
1701
|
+
sys_interface_available=1
|
1702
|
+
fi
|
1703
|
+
if [ "$opt_sysfs_only" != 1 ]; then
|
1704
|
+
_info_nol "* Kernel supports Page Table Isolation (PTI): "
|
1705
|
+
kpti_support=0
|
1706
|
+
kpti_can_tell=0
|
1707
|
+
if [ -n "$opt_config" ]; then
|
1708
|
+
kpti_can_tell=1
|
1709
|
+
if grep -Eq '^(CONFIG_PAGE_TABLE_ISOLATION|CONFIG_KAISER)=y' "$opt_config"; then
|
1710
|
+
# shellcheck disable=SC2046
|
1711
|
+
_debug 'kpti_support: found option '$(grep -E '^(CONFIG_PAGE_TABLE_ISOLATION|CONFIG_KAISER)=y' "$opt_config")" in $opt_config"
|
1712
|
+
kpti_support=1
|
1713
|
+
fi
|
1714
|
+
fi
|
1715
|
+
if [ "$kpti_support" = 0 ] && [ -n "$opt_map" ]; then
|
1716
|
+
# it's not an elif: some backports don't have the PTI config but still include the patch
|
1717
|
+
# so we try to find an exported symbol that is part of the PTI patch in System.map
|
1718
|
+
kpti_can_tell=1
|
1719
|
+
if grep -qw kpti_force_enabled "$opt_map"; then
|
1720
|
+
_debug "kpti_support: found kpti_force_enabled in $opt_map"
|
1721
|
+
kpti_support=1
|
1722
|
+
fi
|
1723
|
+
fi
|
1724
|
+
if [ "$kpti_support" = 0 ] && [ -n "$vmlinux" ]; then
|
1725
|
+
# same as above but in case we don't have System.map and only vmlinux, look for the
|
1726
|
+
# nopti option that is part of the patch (kernel command line option)
|
1727
|
+
kpti_can_tell=1
|
1728
|
+
if ! which strings >/dev/null 2>&1; then
|
1729
|
+
pstatus yellow UNKNOWN "missing 'strings' tool, please install it, usually it's in the binutils package"
|
1730
|
+
else
|
1731
|
+
if strings "$vmlinux" | grep -qw nopti; then
|
1732
|
+
_debug "kpti_support: found nopti string in $vmlinux"
|
1733
|
+
kpti_support=1
|
1734
|
+
fi
|
1735
|
+
fi
|
1736
|
+
fi
|
1737
|
+
|
1738
|
+
if [ "$kpti_support" = 1 ]; then
|
1739
|
+
pstatus green YES
|
1740
|
+
elif [ "$kpti_can_tell" = 1 ]; then
|
1741
|
+
pstatus red NO
|
1742
|
+
else
|
1743
|
+
pstatus yellow UNKNOWN "couldn't read your kernel configuration nor System.map file"
|
1744
|
+
fi
|
1745
|
+
|
1746
|
+
mount_debugfs
|
1747
|
+
_info_nol "* PTI enabled and active: "
|
1748
|
+
if [ "$opt_live" = 1 ]; then
|
1749
|
+
dmesg_grep="Kernel/User page tables isolation: enabled"
|
1750
|
+
dmesg_grep="$dmesg_grep|Kernel page table isolation enabled"
|
1751
|
+
dmesg_grep="$dmesg_grep|x86/pti: Unmapping kernel while in userspace"
|
1752
|
+
if grep ^flags /proc/cpuinfo | grep -qw pti; then
|
1753
|
+
# vanilla PTI patch sets the 'pti' flag in cpuinfo
|
1754
|
+
_debug "kpti_enabled: found 'pti' flag in /proc/cpuinfo"
|
1755
|
+
kpti_enabled=1
|
1756
|
+
elif grep ^flags /proc/cpuinfo | grep -qw kaiser; then
|
1757
|
+
# kernel line 4.9 sets the 'kaiser' flag in cpuinfo
|
1758
|
+
_debug "kpti_enabled: found 'kaiser' flag in /proc/cpuinfo"
|
1759
|
+
kpti_enabled=1
|
1760
|
+
elif [ -e /sys/kernel/debug/x86/pti_enabled ]; then
|
1761
|
+
# Red Hat Backport creates a dedicated file, see https://access.redhat.com/articles/3311301
|
1762
|
+
kpti_enabled=$(cat /sys/kernel/debug/x86/pti_enabled 2>/dev/null)
|
1763
|
+
_debug "kpti_enabled: file /sys/kernel/debug/x86/pti_enabled exists and says: $kpti_enabled"
|
1764
|
+
fi
|
1765
|
+
if [ -z "$kpti_enabled" ]; then
|
1766
|
+
dmesg_grep "$dmesg_grep"; ret=$?
|
1767
|
+
if [ $ret -eq 0 ]; then
|
1768
|
+
_debug "kpti_enabled: found hint in dmesg: $dmesg_grepped"
|
1769
|
+
kpti_enabled=1
|
1770
|
+
elif [ $ret -eq 2 ]; then
|
1771
|
+
_debug "kpti_enabled: dmesg truncated"
|
1772
|
+
kpti_enabled=-1
|
1773
|
+
fi
|
1774
|
+
fi
|
1775
|
+
if [ -z "$kpti_enabled" ]; then
|
1776
|
+
_debug "kpti_enabled: couldn't find any hint that PTI is enabled"
|
1777
|
+
kpti_enabled=0
|
1778
|
+
fi
|
1779
|
+
if [ "$kpti_enabled" = 1 ]; then
|
1780
|
+
pstatus green YES
|
1781
|
+
elif [ "$kpti_enabled" = -1 ]; then
|
1782
|
+
pstatus yellow UNKNOWN "dmesg truncated, please reboot and relaunch this script"
|
1783
|
+
else
|
1784
|
+
pstatus red NO
|
1785
|
+
fi
|
1786
|
+
else
|
1787
|
+
pstatus blue N/A "can't verify if PTI is enabled in offline mode"
|
1788
|
+
fi
|
1789
|
+
|
1790
|
+
# no security impact but give a hint to the user in verbose mode
|
1791
|
+
# about PCID/INVPCID cpuid features that must be present to avoid
|
1792
|
+
# too big a performance impact with PTI
|
1793
|
+
# refs:
|
1794
|
+
# https://marc.info/?t=151532047900001&r=1&w=2
|
1795
|
+
# https://groups.google.com/forum/m/#!topic/mechanical-sympathy/L9mHTbeQLNU
|
1796
|
+
if [ "$opt_verbose" -ge 2 ]; then
|
1797
|
+
_info "* Performance impact if PTI is enabled"
|
1798
|
+
_info_nol " * CPU supports PCID: "
|
1799
|
+
if grep ^flags /proc/cpuinfo | grep -qw pcid; then
|
1800
|
+
pstatus green YES 'performance degradation with PTI will be limited'
|
1801
|
+
else
|
1802
|
+
pstatus blue NO 'no security impact but performance will be degraded with PTI'
|
1803
|
+
fi
|
1804
|
+
_info_nol " * CPU supports INVPCID: "
|
1805
|
+
if grep ^flags /proc/cpuinfo | grep -qw invpcid; then
|
1806
|
+
pstatus green YES 'performance degradation with PTI will be limited'
|
1807
|
+
else
|
1808
|
+
pstatus blue NO 'no security impact but performance will be degraded with PTI'
|
1809
|
+
fi
|
1810
|
+
fi
|
1811
|
+
elif [ "$sys_interface_available" = 0 ]; then
|
1812
|
+
# we have no sysfs but were asked to use it only!
|
1813
|
+
msg="/sys vulnerability interface use forced, but it's not available!"
|
1814
|
+
status=UNK
|
1815
|
+
fi
|
1816
|
+
|
1817
|
+
|
1818
|
+
# Test if the current host is a Xen PV Dom0 / DomU
|
1819
|
+
if [ -d "/proc/xen" ]; then
|
1820
|
+
# XXX do we have a better way that relying on dmesg?
|
1821
|
+
dmesg_grep 'Booting paravirtualized kernel on Xen$'; ret=$?
|
1822
|
+
if [ $ret -eq 2 ]; then
|
1823
|
+
_warn "dmesg truncated, Xen detection will be unreliable. Please reboot and relaunch this script"
|
1824
|
+
elif [ $ret -eq 0 ]; then
|
1825
|
+
if [ -e /proc/xen/capabilities ] && grep -q "control_d" /proc/xen/capabilities; then
|
1826
|
+
xen_pv_domo=1
|
1827
|
+
else
|
1828
|
+
xen_pv_domu=1
|
1829
|
+
fi
|
1830
|
+
fi
|
1831
|
+
fi
|
1832
|
+
|
1833
|
+
if [ "$opt_live" = 1 ]; then
|
1834
|
+
# checking whether we're running under Xen PV 64 bits. If yes, we are affected by variant3
|
1835
|
+
# (unless we are a Dom0)
|
1836
|
+
_info_nol "* Running as a Xen PV DomU: "
|
1837
|
+
if [ "$xen_pv_domu" = 1 ]; then
|
1838
|
+
pstatus red YES
|
1839
|
+
else
|
1840
|
+
pstatus green NO
|
1841
|
+
fi
|
1842
|
+
fi
|
1843
|
+
|
1844
|
+
cve='CVE-2017-5754'
|
1845
|
+
if ! is_cpu_vulnerable 3; then
|
1846
|
+
# override status & msg in case CPU is not vulnerable after all
|
1847
|
+
pvulnstatus $cve OK "your CPU vendor reported your CPU model as not vulnerable"
|
1848
|
+
elif [ -z "$msg" ]; then
|
1849
|
+
# if msg is empty, sysfs check didn't fill it, rely on our own test
|
1850
|
+
if [ "$opt_live" = 1 ]; then
|
1851
|
+
if [ "$kpti_enabled" = 1 ]; then
|
1852
|
+
pvulnstatus $cve OK "PTI mitigates the vulnerability"
|
1853
|
+
elif [ "$xen_pv_domo" = 1 ]; then
|
1854
|
+
pvulnstatus $cve OK "Xen Dom0s are safe and do not require PTI"
|
1855
|
+
elif [ "$xen_pv_domu" = 1 ]; then
|
1856
|
+
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"
|
1857
|
+
else
|
1858
|
+
pvulnstatus $cve VULN "PTI is needed to mitigate the vulnerability"
|
1859
|
+
fi
|
1860
|
+
else
|
1861
|
+
if [ "$kpti_support" = 1 ]; then
|
1862
|
+
pvulnstatus $cve OK "offline mode: PTI will mitigate the vulnerability if enabled at runtime"
|
1863
|
+
elif [ "$kpti_can_tell" = 1 ]; then
|
1864
|
+
pvulnstatus $cve VULN "PTI is needed to mitigate the vulnerability"
|
1865
|
+
else
|
1866
|
+
pvulnstatus $cve UNK "offline mode: not enough information"
|
1867
|
+
fi
|
1868
|
+
fi
|
1869
|
+
else
|
1870
|
+
if [ "$xen_pv_domo" = 1 ]; then
|
1871
|
+
msg="Xen Dom0s are safe and do not require PTI"
|
1872
|
+
status="OK"
|
1873
|
+
elif [ "$xen_pv_domu" = 1 ]; then
|
1874
|
+
msg="Xen PV DomUs are vulnerable and need to be run in HVM, PVHVM or PVH mode"
|
1875
|
+
status="VULN"
|
1876
|
+
elif [ "$msg" = "Vulnerable" ]; then
|
1877
|
+
msg="PTI is needed to mitigate the vulnerability"
|
1878
|
+
fi
|
1879
|
+
pvulnstatus $cve "$status" "$msg"
|
1880
|
+
fi
|
1881
|
+
|
1882
|
+
# Warn the user about XSA-254 recommended mitigations
|
1883
|
+
if [ "$xen_pv_domo" = 1 ]; then
|
1884
|
+
_warn
|
1885
|
+
_warn "This host is a Xen Dom0. Please make sure that you are running your DomUs"
|
1886
|
+
_warn "in HVM, PVHVM or PVH mode to prevent any guest-to-host / host-to-guest attacks."
|
1887
|
+
_warn
|
1888
|
+
_warn "See https://blog.xenproject.org/2018/01/22/xen-project-spectre-meltdown-faq-jan-22-update/ and XSA-254 for details."
|
1889
|
+
fi
|
1890
|
+
}
|
1891
|
+
|
1892
|
+
check_cpu
|
1893
|
+
# now run the checks the user asked for
|
1894
|
+
if [ "$opt_variant1" = 1 ] || [ "$opt_allvariants" = 1 ]; then
|
1895
|
+
check_variant1
|
1896
|
+
_info
|
1897
|
+
fi
|
1898
|
+
if [ "$opt_variant2" = 1 ] || [ "$opt_allvariants" = 1 ]; then
|
1899
|
+
check_variant2
|
1900
|
+
_info
|
1901
|
+
fi
|
1902
|
+
if [ "$opt_variant3" = 1 ] || [ "$opt_allvariants" = 1 ]; then
|
1903
|
+
check_variant3
|
1904
|
+
_info
|
1905
|
+
fi
|
1906
|
+
|
1907
|
+
_info "A false sense of security is worse than no security at all, see --disclaimer"
|
1908
|
+
|
1909
|
+
if [ "$opt_batch" = 1 ] && [ "$opt_batch_format" = "nrpe" ]; then
|
1910
|
+
if [ ! -z "$nrpe_vuln" ]; then
|
1911
|
+
echo "Vulnerable:$nrpe_vuln"
|
1912
|
+
else
|
1913
|
+
echo "OK"
|
1914
|
+
fi
|
1915
|
+
fi
|
1916
|
+
|
1917
|
+
if [ "$opt_batch" = 1 ] && [ "$opt_batch_format" = "json" ]; then
|
1918
|
+
_echo 0 "${json_output%?}]"
|
1919
|
+
fi
|
1920
|
+
|
1921
|
+
if [ "$opt_batch" = 1 ] && [ "$opt_batch_format" = "prometheus" ]; then
|
1922
|
+
echo "# TYPE specex_vuln_status untyped"
|
1923
|
+
echo "# HELP specex_vuln_status Exposure of system to speculative execution vulnerabilities"
|
1924
|
+
echo "$prometheus_output"
|
1925
|
+
fi
|
1926
|
+
|
1927
|
+
# exit with the proper exit code
|
1928
|
+
# [ "$global_critical" = 1 ] && exit 2 # critical
|
1929
|
+
# [ "$global_unknown" = 1 ] && exit 3 # unknown
|
1930
|
+
# exit 0 # ok
|