Skip to content

Commit

Permalink
Merge 1cea68e into 2d22fd6
Browse files Browse the repository at this point in the history
  • Loading branch information
jreidinger committed Apr 26, 2019
2 parents 2d22fd6 + 1cea68e commit 466db54
Show file tree
Hide file tree
Showing 14 changed files with 235 additions and 86 deletions.
7 changes: 7 additions & 0 deletions package/yast2-bootloader.changes
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
-------------------------------------------------------------------
Fri Apr 26 12:27:34 UTC 2019 - jreidinger <jreidinger@suse.com>

- renamed "smt" to "cpu_mitigations", improved naming and help
(bsc#1098559)
- 4.1.24

-------------------------------------------------------------------
Mon Mar 25 15:45:54 CET 2019 - schubi@suse.de

Expand Down
2 changes: 1 addition & 1 deletion package/yast2-bootloader.spec
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@


Name: yast2-bootloader
Version: 4.1.23
Version: 4.1.24
Release: 0

BuildRoot: %{_tmppath}/%{name}-%{version}-build
Expand Down
4 changes: 2 additions & 2 deletions src/autoyast-rnc/bootloader.rnc
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ bl_global =
boot_extended? &
boot_mbr? &
stage1_dev? &
smt? &
cpu_mitigations? &
element vgamode { text }?
}

Expand All @@ -86,7 +86,7 @@ boot_root = element boot_root { "true" | "false" }
boot_boot = element boot_boot { "true" | "false" }
boot_extended = element boot_extended { "true" | "false" }
boot_mbr = element boot_mbr { "true" | "false" }
smt = element smt { "true" | "false" }
cpu_mitigations = element cpu_mitigations { "nosmt", "auto", "off", "manual" }

sections =
element sections {
Expand Down
8 changes: 5 additions & 3 deletions src/lib/bootloader/autoyast_converter.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
require "yast"

require "bootloader/bootloader_factory"
require "bootloader/cpu_mitigations"

Yast.import "BootStorage"
Yast.import "Arch"
Expand Down Expand Up @@ -37,7 +38,8 @@ def import(data)
# always nil pmbr as autoyast does not support it yet,
# so use nil to always use proposed value (bsc#1081967)
bootloader.pmbr_action = nil
bootloader.smt = data["global"]["smt"] == "true" unless data["global"]["smt"].nil?
cpu_mitigations = data["global"]["cpu_mitigations"]
bootloader.cpu_mitigations = CpuMitigations.from_string(cpu_mitigations) if cpu_mitigations
# TODO: import Initrd

log.warn "autoyast profile contain sections which won't be processed" if data["sections"]
Expand All @@ -57,7 +59,7 @@ def export(config)
global = res["global"]
export_grub2(global, config) if config.name == "grub2"
export_default(global, config.grub_default)
res["global"]["smt"] = config.smt ? "true" : "false"
res["global"]["cpu_mitigations"] = config.cpu_mitigations.value.to_s
# Do not export device map as device name are very unpredictable and is used only as
# work-around when automatic ones do not work for what-ever reasons ( it can really safe
# your day in L3 )
Expand All @@ -79,7 +81,7 @@ def import_grub2(data, bootloader)
end

def import_default(data, default)
# import first kernel params as smt can later modify it
# import first kernel params as cpu_mitigations can later modify it
DEFAULT_KERNEL_PARAMS_MAPPING.each do |key, method|
val = data["global"][key]
next unless val
Expand Down
29 changes: 22 additions & 7 deletions src/lib/bootloader/config_dialog.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ class ConfigDialog
include Yast::I18n
include Yast::UIShortcuts

# param initial_tab [:boot_code|:kernel|:bootloader] initial tab when dialog open
def initialize(initial_tab: :boot_code)
@initial_tab = initial_tab
end

def run
guarded_run
rescue ::Bootloader::BrokenConfiguration, ::Bootloader::UnsupportedOption => e
Expand Down Expand Up @@ -63,13 +68,6 @@ def guarded_run
end
# F#300779: end

if BootloaderFactory.current.is_a?(NoneBootloader)
contents = VBox(LoaderTypeWidget.new)
else
tabs = CWM::Tabs.new(BootCodeTab.new, KernelTab.new, BootloaderTab.new)
contents = VBox(tabs)
end

Yast::CWM.show(
contents,
caption: _("Boot Loader Settings"),
Expand All @@ -79,5 +77,22 @@ def guarded_run
skip_store_for: [:redraw]
)
end

def contents
return VBox(LoaderTypeWidget.new) if BootloaderFactory.current.is_a?(NoneBootloader)

boot_code_tab = BootCodeTab.new
kernel_tab = KernelTab.new
bootloader_tab = BootloaderTab.new
case @initial_tab
when :boot_code then boot_code_tab.initial = true
when :kernel then kernel_tab.initial = true
when :bootloader then bootloader_tab.initial = true
else
raise "unknown initial tab #{@initial_tab.inspect}"
end

VBox(CWM::Tabs.new(boot_code_tab, kernel_tab, bootloader_tab))
end
end
end
75 changes: 75 additions & 0 deletions src/lib/bootloader/cpu_mitigations.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
require "yast"

require "cfa/matcher"
require "cfa/placer"

module Bootloader
# Specialized class to handle CPU mitigation settings.
# @see https://www.suse.com/support/kb/doc/?id=7023836
class CpuMitigations
include Yast::Logger
include Yast::I18n
extend Yast::I18n
KERNEL_MAPPING = {
nosmt: "auto,nosmt",
auto: "auto",
off: "off",
manual: nil
}.freeze

HUMAN_MAPPING = {
nosmt: N_("Auto + No SMT"),
auto: N_("Auto"),
off: N_("Off"),
manual: N_("Manually")
}.freeze

attr_reader :value

def initialize(value)
textdomain "bootloader"

@value = value
end

# Note: order of ALL is used also in UI as order of combobox.
ALL = KERNEL_MAPPING.keys.map { |k| CpuMitigations.new(k) }
DEFAULT = CpuMitigations.new(:auto)

def self.from_kernel_params(kernel_params)
log.info "kernel params #{kernel_params.inspect}"
param = kernel_params.parameter("mitigations")
log.info "mitigation param #{param.inspect}"
param = nil if param == false
reverse_mapping = KERNEL_MAPPING.invert
raise "Unknown mitigations value #{param.inspect}" if !reverse_mapping.key?(param)

new(reverse_mapping[param])
end

def self.from_string(string)
raise "Unknown mitigations value #{string.inspect}" unless KERNEL_MAPPING.key?(string.to_sym)

new(string.to_sym)
end

def to_human_string
_(HUMAN_MAPPING[value])
end

def kernel_value
KERNEL_MAPPING[value] or raise "Invalid value #{value.inspect}"
end

def modify_kernel_params(kernel_params)
matcher = CFA::Matcher.new(key: "mitigations")

kernel_params.remove_parameter(matcher)
if value != :manual
# TODO: fix cfa_grub2 with replace placer
kernel_params.add_parameter("mitigations", kernel_value)
log.info "replacing old config with #{kernel_value}: #{kernel_params.inspect}"
end
end
end
end
45 changes: 32 additions & 13 deletions src/lib/bootloader/grub2_widgets.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require "bootloader/generic_widgets"
require "bootloader/device_map_dialog"
require "bootloader/serial_console"
require "bootloader/cpu_mitigations"
require "cfa/matcher"

Yast.import "BootStorage"
Expand Down Expand Up @@ -113,30 +114,53 @@ def store
end

# Represents decision if smt is enabled
class Smt < CWM::CheckBox
class CpuMitigationsWidget < CWM::ComboBox
include Grub2Widget

def initialize
textdomain "bootloader"
end

def label
_("Disable Simultaneous &Multithreading")
_("CPU Mitigations")
end

def items
::Bootloader::CpuMitigations::ALL.map do |m|
[m.value, m.to_human_string]
end
end

def help
_(
"<p><b>Disable Simultaneous Multithreading</b><br>\n" \
"To disable sharing physical cores by more virtual ones."
"<p><b>CPU Mitigations</b><br>\n" \
"The option selects which default settings should be used for CPU " \
"side channels mitigations. A highlevel description is on our Technical Information " \
"Document TID 7023836. Following options are available:<ul>" \
"<li><b>Auto</b>: This option enables all the mitigations needed for your CPU model. " \
"This setting can impact performance to some degree, depending on CPU model and " \
"workload. It provides all security mitigations, but it does not protect against " \
"cross-CPU thread attacks.</li>" \
"<li><b>Auto + No SMT</b>: This option enables all the above mitigations in \"Auto\", " \
"and also disables Simultaneous Multithreading to avoid side channel attacks across " \
"multiple CPU threads. This setting can further impact performance, depending on your " \
"workload. This setting provides the full set of available security mitigations.</li>" \
"<li><b>Off</b>: All CPU Mitigations are disabled. This setting has no performance " \
"impact, but side channel attacks against your CPU are possible, depending on CPU " \
"model.</li>" \
"<li><b>Manual</b>: This setting does not specify a mitigation level and leaves " \
"this to be the kernel default. The administrator can add other mitigations options " \
"in the <i>kernel command line</i> widget." \
"All CPU mitigation specific options can be set manually.</li></ul></p>"
)
end

def init
self.value = !grub2.smt
self.value = grub2.cpu_mitigations.value
end

def store
grub2.smt = !value
grub2.cpu_mitigations = ::Bootloader::CpuMitigations.new(value)
end
end

Expand Down Expand Up @@ -240,7 +264,7 @@ def help
end

def init
self.value = grub_default.kernel_params.serialize.gsub(/nosmt/, "")
self.value = grub_default.kernel_params.serialize.gsub(/mitigations=\S+/, "")
end

def store
Expand Down Expand Up @@ -872,11 +896,10 @@ def label

def contents
console_widget = Yast::Arch.s390 ? CWM::Empty.new("console") : ConsoleWidget.new
smt_widget = Yast::Arch.x86_64 ? MarginBox(1, 0.5, Smt.new) : CWM::Empty.new("smt")
VBox(
VSpacing(1),
MarginBox(1, 0.5, KernelAppendWidget.new),
Left(smt_widget),
MarginBox(1, 0.5, Left(CpuMitigationsWidget.new)),
MarginBox(1, 0.5, console_widget),
VStretch()
)
Expand All @@ -887,10 +910,6 @@ def contents
class BootCodeTab < CWM::Tab
include Grub2Widget

def initialize
self.initial = true
end

def label
textdomain "bootloader"

Expand Down
62 changes: 33 additions & 29 deletions src/lib/bootloader/grub2base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def initialize
@grub_default = ::CFA::Grub2::Default.new
@sections = ::Bootloader::Sections.new
@pmbr_action = :nothing
@smt = nil # nil means not set explicitly, otherwise boolean
@explicit_cpu_mitigations = false
end

# general functions
Expand All @@ -75,24 +75,18 @@ def pmbr_setup(*devices)
end
end

def smt
!grub_default.kernel_params.parameter("nosmt")
def cpu_mitigations
CpuMitigations.from_kernel_params(grub_default.kernel_params)
end

def explicit_smt
@smt
def explicit_cpu_mitigations
@explicit_cpu_mitigations ? cpu_mitigations : nil
end

def smt=(value)
log.info "setting smt to #{value}"
@smt = value

if value
matcher = CFA::Matcher.new(key: "nosmt")
grub_default.kernel_params.remove_parameter(matcher)
elsif !grub_default.kernel_params.parameter("nosmt")
grub_default.kernel_params.add_parameter("nosmt", true)
end
def cpu_mitigations=(value)
log.info "setting mitigations to #{value}"
@explicit_cpu_mitigations = true
value.modify_kernel_params(grub_default.kernel_params)
end

def read
Expand Down Expand Up @@ -219,28 +213,37 @@ def merge_grub_default(other)
log.info "before merge other #{other_default.inspect}"

KERNEL_FLAVORS_METHODS.each do |method|
other_params = other_default.public_send(method)
default_params = default.public_send(method)
next if other_params.empty?

default_serialize = default_params.serialize
# handle specially noresume as it should lead to remove all other resume
default_serialize.gsub!(/resume=\S+/, "") if other_params.parameter("noresume")

new_kernel_params = default_serialize + " " + other_params.serialize

default_params.replace(new_kernel_params)
merge_kernel_params(method, other_default)
end

merge_attributes(default, other_default)

# explicitly set smt
self.smt = other.explicit_smt unless other.explicit_smt.nil?
log.info "smt after merge #{smt}"
# explicitly set mitigations means overwrite of our
if other.explicit_cpu_mitigations
log.info "merging cpu_mitigations"
self.cpu_mitigations = other.cpu_mitigations
end
log.info "mitigations after merge #{cpu_mitigations}"

log.info "after merge default #{default.inspect}"
end

def merge_kernel_params(method, other_default)
other_params = other_default.public_send(method)
default_params = grub_default.public_send(method)
return if other_params.empty?

default_serialize = default_params.serialize
# handle specially noresume as it should lead to remove all other resume
default_serialize.gsub!(/resume=\S+/, "") if other_params.parameter("noresume")
# prevent double cpu_mitigations params
default_serialize.gsub!(/mitigations=\S+/, "") if other_params.parameter("mitigations")

new_kernel_params = default_serialize + " " + other_params.serialize

default_params.replace(new_kernel_params)
end

def merge_attributes(default, other)
# string attributes
[:serial_console, :timeout, :hidden_timeout, :distributor,
Expand Down Expand Up @@ -338,4 +341,5 @@ def propose_encrypted
grub_default.cryptodisk.value = !!Yast::BootStorage.encrypted_boot?
end
end
# rubocop:enable Metrics/ClassLength
end
Loading

0 comments on commit 466db54

Please sign in to comment.