Skip to content

Commit

Permalink
Merge pull request #329 from yast/trusted-boot
Browse files Browse the repository at this point in the history
Reintroduce Trusted Boot (FATE#316553).
  • Loading branch information
mvidner committed May 16, 2016
2 parents 0a2ff17 + 6cbc4f1 commit ab82908
Show file tree
Hide file tree
Showing 13 changed files with 173 additions and 53 deletions.
2 changes: 1 addition & 1 deletion .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Metrics/ClassLength:

# Configuration parameters: CountComments.
Metrics/ClassLength:
Max: 250 # TODO this should be lower for new code
Max: 256 # TODO this should be lower for new code
Include:
- 'src/lib/**/*.rb' # be more strict for new code in lib

Expand Down
6 changes: 6 additions & 0 deletions package/yast2-bootloader.changes
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
-------------------------------------------------------------------
Mon May 16 09:36:28 UTC 2016 - mvidner@suse.com

- Reintroduce Trusted Boot (FATE#316553).
- 3.1.184

-------------------------------------------------------------------
Thu May 12 15:46:49 CEST 2016 - snwint@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: 3.1.183
Version: 3.1.184
Release: 0

BuildRoot: %{_tmppath}/%{name}-%{version}-build
Expand Down
24 changes: 24 additions & 0 deletions src/lib/bootloader/autoyast_converter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def import(data)
# let it be empty if not defined to keep code simplier as effect is same
data["global"] ||= {}

import_grub2(data, bootloader)
import_stage1(data, bootloader)
import_default(data, bootloader.grub_default)
# TODO: import Initrd
Expand All @@ -48,6 +49,7 @@ def export(config)

res["global"] = {}
global = res["global"]
export_grub2(global, config) if config.name == "grub2"
export_stage1(global, config.stage1) if config.respond_to?(:stage1)
export_default(global, config.grub_default)

Expand All @@ -56,6 +58,17 @@ def export(config)

private

def import_grub2(data, bootloader)
return unless bootloader.name == "grub2"

GRUB2_BOOLEAN_MAPPING.each do |key, method|
val = data["global"][key]
next unless val

bootloader.public_send(:"#{method}=", val == "true")
end
end

def import_default(data, default)
DEFAULT_BOOLEAN_MAPPING.each do |key, method|
val = data["global"][key]
Expand Down Expand Up @@ -180,6 +193,17 @@ def export_stage1(res, stage1)
res["boot_custom"] = stage1.custom_devices.join(",") unless stage1.custom_devices.empty?
end

# only for grub2, not for others
GRUB2_BOOLEAN_MAPPING = {
"trusted_grub" => :trusted_boot
}
def export_grub2(res, bootloader)
GRUB2_BOOLEAN_MAPPING.each do |key, method|
val = bootloader.public_send(method)
res[key] = val ? "true" : "false" unless val.nil?
end
end

DEFAULT_BOOLEAN_MAPPING = {
"os_prober" => :os_prober
}
Expand Down
53 changes: 26 additions & 27 deletions src/lib/bootloader/grub2.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ module Bootloader
class Grub2 < Grub2Base
attr_reader :stage1
attr_reader :device_map
# @return [Boolean]
attr_accessor :trusted_boot

def initialize
super
Expand All @@ -25,6 +27,7 @@ def initialize
@stage1 = Stage1.new
@grub_install = GrubInstall.new(efi: false)
@device_map = DeviceMap.new
@trusted_boot = false
end

# Read settings from disk
Expand All @@ -50,6 +53,8 @@ def read(reread: false)
log.info "grub2/device.map does not exist. Using empty one."
@device_map = DeviceMap.new
end

@trusted_boot = Sysconfig.from_system.trusted_boot if reread || @trusted_boot.nil?
end

# Write bootloader settings to disk
Expand All @@ -65,7 +70,9 @@ def write
pmbr_setup(*gpt_disks_devices)

# powernv must not call grub2-install (bnc#970582)
@grub_install.execute(devices: stage1.devices) unless Yast::Arch.board_powernv
unless Yast::Arch.board_powernv
@grub_install.execute(devices: stage1.devices, trusted_boot: trusted_boot)
end
# Do some mbr activations ( s390 do not have mbr nor boot flag on its disks )
# powernv do not have prep partition, so we do not have any partition to activate (bnc#970582)
MBRUpdate.new.run(stage1) if !Yast::Arch.s390 && !Yast::Arch.board_powernv
Expand All @@ -79,31 +86,16 @@ def propose
# boot, safer option for legacy booting (bnc#872054)
self.pmbr_action = :add if Yast::BootStorage.gpt_boot_disk?
device_map.propose if Yast::Arch.x86_64 || Yast::Arch.i386
@trusted_boot = false
end

def merge(other)
super

@device_map = other.device_map if !other.device_map.empty?
@trusted_boot = other.trusted_boot unless other.trusted_boot.nil?

# merge here is a bit tricky, as for stage1 does not exist `defined?`
# because grub_installdevice contain value or not, so it is not
# possible to recognize if chosen or just not set
# so logic is following
# 1) if any flag is set to true, then use it because e.g. autoyast defined flags,
# but devices usually not
# 2) if there is devices specified, then set also flags to value in other
# as it mean, that there is enough info to decide
log.info "stage1 to merge #{other.stage1.inspect}"

# so first part of logic
stage1.activate = stage1.activate? || other.stage1.activate?
stage1.generic_mbr = stage1.generic_mbr? || other.stage1.generic_mbr?

# use second part described above if there is some device
replace_with(other) unless other.stage1.devices.empty?

log.info "stage1 after merge #{stage1.inspect}"
stage1.merge(other.stage1)
end

# Display bootloader summary
Expand All @@ -113,6 +105,10 @@ def summary
Yast::Builtins.sformat(
_("Boot Loader Type: %1"),
"GRUB2"
),
Yast::Builtins.sformat(
_("Enable Trusted Boot: %1"),
@trusted_boot ? _("yes") : _("no")
)
]
locations_val = locations
Expand Down Expand Up @@ -149,19 +145,22 @@ def packages
res << "syslinux"
end

if Yast::Arch.x86_64 || Yast::Arch.i386
res << "trustedgrub2" << "trustedgrub2-i386-pc" if @trusted_boot
end

res
end

private

def replace_with(other)
stage1.clear_devices
other.stage1.devices.each { |d| stage1.add_udev_device(d) }

stage1.activate = other.stage1.activate?
stage1.generic_mbr = other.stage1.generic_mbr?
# FIXME: refactor with injection like super(prewrite: prewrite, sysconfig = ...)
# overwrite BootloaderBase version to save trusted boot
def write_sysconfig(prewrite: false)
sysconfig = Bootloader::Sysconfig.new(bootloader: name, trusted_boot: @trusted_boot)
prewrite ? sysconfig.pre_write : sysconfig.write
end

private

def gpt_disks_devices
boot_devices = stage1.devices
boot_discs = boot_devices.map { |d| Yast::Storage.GetDisk(Yast::Storage.GetTargetMap, d) }
Expand Down
45 changes: 39 additions & 6 deletions src/lib/bootloader/grub2_widgets.rb
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,32 @@ def store
end
end

# Represents switcher for Trusted Boot
class TrustedBootWidget < CWM::CheckBox
include Grub2Widget

def initialize
textdomain "bootloader"
end

def label
_("Enable &Trusted Boot Support")
end

def help
# TRANSLATORS: TrustedGRUB2 is a name, don't translate it
_("<b>Trusted Boot</b> will install TrustedGRUB2 instead of regular GRUB2.\n")
end

def init
self.value = grub2.trusted_boot
end

def store
grub2.trusted_boot = value
end
end

# Represents grub password protection widget
class GrubPasswordWidget < CWM::CustomWidget
include Grub2Widget
Expand Down Expand Up @@ -749,19 +775,22 @@ def label
def contents
widgets = []

widgets << indented_widget(LoaderLocationWidget.new) if loader_location_widget?
widgets << LoaderLocationWidget.new if loader_location_widget?

if generic_mbr_widget?
widgets << indented_widget(ActivateWidget.new)
widgets << indented_widget(GenericMBRWidget.new)
widgets << ActivateWidget.new
widgets << GenericMBRWidget.new
end

widgets << indented_widget(SecureBootWidget.new) if secure_boot_widget?
widgets << SecureBootWidget.new if secure_boot_widget?

widgets << TrustedBootWidget.new if trusted_boot_widget?

widgets << indented_widget(PMBRWidget.new) if pmbr_widget?
widgets << PMBRWidget.new if pmbr_widget?

widgets << indented_widget(DeviceMapWidget.new) if device_map_button?
widgets << DeviceMapWidget.new if device_map_button?

widgets = widgets.map { |w| indented_widget(w) }
VBox(
LoaderTypeWidget.new,
*widgets,
Expand All @@ -787,6 +816,10 @@ def secure_boot_widget?
(Yast::Arch.x86_64 || Yast::Arch.i386) && grub2.name == "grub2-efi"
end

def trusted_boot_widget?
(Yast::Arch.x86_64 || Yast::Arch.i386) && grub2.name == "grub2"
end

def pmbr_widget?
(Yast::Arch.x86_64 || Yast::Arch.i386) &&
(Yast::BootStorage.gpt_boot_disk? || grub2.name == "grub2-efi")
Expand Down
1 change: 0 additions & 1 deletion src/lib/bootloader/grub2efi.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ def initialize
# Read settings from disk
# @param [Boolean] reread boolean true to force reread settings from system
# internal data
# @return [Boolean] true on success
def read(reread: false)
@secure_boot = Sysconfig.from_system.secure_boot if reread || @secure_boot.nil?

Expand Down
4 changes: 3 additions & 1 deletion src/lib/bootloader/grub_install.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ def initialize(efi: false)
@efi = efi
end

def execute(devices: nil, secure_boot: false)
def execute(devices: nil, secure_boot: false, trusted_boot: false)
raise "cannot have secure boot without efi" if secure_boot && !@efi
raise "cannot have trusted boot with efi" if trusted_boot && @efi

cmd = []
if secure_boot
Expand All @@ -21,6 +22,7 @@ def execute(devices: nil, secure_boot: false)
# Do skip-fs-probe to avoid error when embedding stage1
# to extended partition
cmd << "--force" << "--skip-fs-probe"
cmd << "--directory=/usr/lib/trustedgrub2/#{target}" if trusted_boot
end

# EFI has 2 boot paths. The default is that there is a target file listed
Expand Down
25 changes: 25 additions & 0 deletions src/lib/bootloader/stage1.rb
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,31 @@ def can_use_boot?
true
end

def merge(other)
# merge here is a bit tricky, as for stage1 does not exist `defined?`
# because grub_installdevice contain value or not, so it is not
# possible to recognize if chosen or just not set
# so logic is following
# 1) if any flag is set to true, then use it because e.g. autoyast defined flags,
# but devices usually not
# 2) if there is devices specified, then set also flags to value in other
# as it mean, that there is enough info to decide
log.info "stage1 to merge #{other.inspect}"

if other.devices.empty?
self.activate = activate? || other.activate?
self.generic_mbr = generic_mbr? || other.generic_mbr?
else
clear_devices
other.devices.each { |d| add_udev_device(d) }

self.activate = other.activate?
self.generic_mbr = other.generic_mbr?
end

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

private

def available_partitions(res)
Expand Down
Loading

0 comments on commit ab82908

Please sign in to comment.