Skip to content

Commit

Permalink
Added LSM configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
teclator committed Dec 23, 2021
1 parent bdddb73 commit 23190fb
Show file tree
Hide file tree
Showing 13 changed files with 358 additions and 58 deletions.
7 changes: 7 additions & 0 deletions .rubocop.yml
Expand Up @@ -2,6 +2,10 @@
inherit_from:
/usr/share/YaST2/data/devtools/data/rubocop_yast_style.yml


AllCops:
TargetRubyVersion: 2.3

# Offense count: 153
Metrics/AbcSize:
Max: 304
Expand Down Expand Up @@ -69,3 +73,6 @@ Style/PredicateName:
Exclude:
# mocked Registration.is_registered?
- test/lib/upgrade_repo_manager_test.rb

Style/FrozenStringLiteralComment:
Enabled: false
2 changes: 1 addition & 1 deletion src/lib/installation/clients/security_finish.rb
Expand Up @@ -85,7 +85,7 @@ def write
log.info("updating capabilities: #{res}")

# Write down selinux configuration
settings.selinux_config.save
settings.lsm_config.save

true
end
Expand Down
24 changes: 15 additions & 9 deletions src/lib/installation/clients/security_proposal.rb
Expand Up @@ -133,7 +133,7 @@ def call_proposal_action_for(link)
def proposals
# Filter proposals with content
[cpu_mitigations_proposal, firewall_proposal, sshd_proposal,
ssh_port_proposal, vnc_fw_proposal, selinux_proposal,
ssh_port_proposal, vnc_fw_proposal, lsm_proposal,
polkit_default_priv_proposal].compact
end

Expand Down Expand Up @@ -238,16 +238,22 @@ def polkit_default_priv_proposal
format(_("PolicyKit Default Privileges: %s"), human_value)
end

def selinux_proposal
return nil unless @settings.selinux_config.configurable?
def lsm_proposal
return nil unless @settings.lsm_config.configurable?

# add required patterns
Yast::PackagesProposal.SetResolvables("SELinux", :pattern,
@settings.selinux_config.needed_patterns)

_(
"SELinux Default Mode is %s"
) % @settings.selinux_config.mode.to_human_string
log.info("Setting LSM resolvables to : #{@settings.lsm_config.needed_patterns}")
Yast::PackagesProposal.SetResolvables("LSM", :pattern, @settings.lsm_config.needed_patterns)
case @settings.lsm_config.selected&.id
when :selinux
_(
"Linux Security Module: Activate SELinux in '%s' mode"
) % @settings.lsm_config.selinux.mode.to_human_string
when :apparmor
_("Linux Security Module: Activate AppArmor")
when :none
_("Linux Security Module: No major module will be activated")
end
end
end
end
Expand Down
25 changes: 13 additions & 12 deletions src/lib/installation/dialogs/security.rb
Expand Up @@ -19,7 +19,7 @@

require "yast"
require "cwm/dialog"
require "installation/widgets/selinux_mode"
require "installation/widgets/lsm"
require "installation/widgets/polkit_default_priv"

Yast.import "Hostname"
Expand Down Expand Up @@ -47,7 +47,7 @@ def contents

left_col = [firewall_frame, polkit_frame]
right_col = [cpu_frame]
right_col << selinux_frame if selinux_configurable?
right_col << lsm_frame if lsm_configurable?

HBox(
HStretch(),
Expand Down Expand Up @@ -99,8 +99,8 @@ def should_open_dialog?
true
end

def selinux_configurable?
@settings.selinux_config.configurable?
def lsm_configurable?
@settings.lsm_config.configurable?
end

def firewall_frame
Expand All @@ -124,22 +124,23 @@ def cpu_frame
)
end

def selinux_frame
def lsm_frame
frame(
_("SELinux"),
Widgets::SelinuxMode.new(@settings)
_("Linux Security Module"),
Widgets::LSM.new(@settings)
)
end

def frame(label, widget)
Left(
Frame(
label,
HSquash(
MarginBox(
0.5,
0.5,
widget
MarginBox(
0.5,
0.5,
HBox(
widget,
HStretch()
)
)
)
Expand Down
75 changes: 75 additions & 0 deletions src/lib/installation/lsm_config.rb
@@ -0,0 +1,75 @@
require "yast"
require "y2security/lsm/config"

module Installation
# This class stores the LSM configuration needed during the installation like selecting the LSM
# to be used
class LSMConfig
include Yast::Logger
extend Forwardable

# Constructor
def initialize
@config = Y2Security::LSM::Config.new
@config.supported.each do |lsm_module|
self.class.send(:define_method, lsm_module.id.to_s.to_sym) do
lsm_module
end
end
end

# Select the LSM to be used based in the one defined in the control file using apparmor as
# fallback in case that no one is selected
def propose_default
log.info("The settings are #{product_feature_settings.inspect}")
selected = product_feature_settings.fetch(:default, "apparmor")

@config.select(selected)
end

def_delegators :@config, :supported, :selected, :select, :selectable

# Returns whether the LSM is configurable during installation or not based in the control file
# declaration. It returns false in case it is WSL
#
# @return [Boolean] true if LSM is configurable during the installation; false otherwise
def configurable?
return false if Yast::Arch.is_wsl

product_feature_settings[:configurable] || false
end

# Returns the needed patterns for the selected LSM or an empty array if no one is selected
#
# @return [Array<Sting>]
def needed_patterns
return [] unless selected

selected.needed_patterns
end

# Save the configuration of the selected LSM or false in case of no one selected
#
# @return [Boolean] whether the configuration was save or not
def save
return false unless selected

selected.save
end

# Returns the values for the LSM setting from the product features
#
# @return [Hash{Symbol => Object}] e.g., { default: :selinux, selinux: { "selectable" => true }}
# a hash holding the LSM options defined in the control file;
# an empty object if no settings are defined
def product_feature_settings
return @product_feature_settings unless @product_feature_settings.nil?

settings = Yast::ProductFeatures.GetFeature("globals", "lsm").dup
settings = {} if settings.empty?
settings.transform_keys!(&:to_sym)

@product_feature_settings = settings
end
end
end
13 changes: 8 additions & 5 deletions src/lib/installation/security_settings.rb
Expand Up @@ -18,8 +18,8 @@
# find current contact information at www.suse.com.

require "yast"
require "y2security/selinux"
require "y2users"
require "installation/lsm_config"

module Installation
# Class that stores the security proposal settings during installation.
Expand All @@ -40,8 +40,8 @@ class SecuritySettings
# [String, nil] Setting for policy kit default privileges
# For more info see /etc/sysconfig/security#POLKIT_DEFAULT_PRIVS
attr_accessor :polkit_default_privileges
# [Y2Security::Selinux] selinux configuration
attr_accessor :selinux_config
# [LSMConfig] selinux configuration
attr_accessor :lsm_config

# Constructor
def initialize
Expand Down Expand Up @@ -157,8 +157,11 @@ def human_polkit_privileges
# Returns a SELinux configuration handler
#
# @return [Y2Security::Selinux] the SELinux config handler
def selinux_config
@selinux_config ||= Y2Security::Selinux.new
def lsm_config
return @lsm_config if @lsm_config
@lsm_config = ::Installation::LSMConfig.new
@lsm_config.propose_default
@lsm_config
end

private
Expand Down
109 changes: 109 additions & 0 deletions src/lib/installation/widgets/lsm.rb
@@ -0,0 +1,109 @@
require "yast"
require "cwm/custom_widget"
require "cwm/replace_point"
require "cwm/common_widgets"
require "installation/widgets/selinux_mode"

Yast.import "HTML"

module Installation
module Widgets
class LSM < CWM::CustomWidget
attr_accessor :settings

def initialize(settings)
@settings = settings
self.handle_all_events = true
end

def init
lsm_selector_widget.init
refresh
end

def contents
VBox(
lsm_selector_widget,
Left(replace_widget)
)
end

def replace_widget
@replace_widget ||= CWM::ReplacePoint.new(id: "lsm_widget", widget: empty_lsm_widget)
end

def empty_lsm_widget
@empty_lsm_widget ||= CWM::Empty.new("lsm_empty")
end

def lsm_selector_widget
@lsm_selector_widget ||= LSMSelector.new(settings.lsm_config)
end

def selinux_widget
@selinux_widget ||= SelinuxMode.new(settings.lsm_config.selinux)
end

def handle(event)
return if event["ID"] != lsm_selector_widget.widget_id

refresh
nil
end

private

def refresh
case lsm_selector_widget.value
when "selinux" then replace_widget.replace(selinux_widget)
else
replace_widget.replace(empty_lsm_widget)
end
end
end

class LSMSelector < CWM::ComboBox
attr_reader :settings

def initialize(settings)
textdomain "installation"

@settings = settings
end

def init
self.value = settings.selected&.id.to_s
end

def opt
[:notify, :hstretch]
end

def label
# TRANSLATORS: SELinux Mode just SELinux is already content of frame.
_("Selected Module")
end

def items
available_modules.map { |m| [m.id.to_s, m.label] }
end

def store
settings.select(value)
end

def help
Yast::HTML.Para(
_("Allows to choose between available Linux Security major modules like:") +
Yast::HTML.List(available_modules.map(&:label))
)
end

private

def available_modules
settings.selectable
end
end
end
end
39 changes: 20 additions & 19 deletions src/lib/installation/widgets/polkit_default_priv.rb
Expand Up @@ -38,25 +38,26 @@ def items
end

def help
_(
"<p>SUSE ships with three sets of default privilege " \
"settings. These are as follows:<br><ul>" \
"<li>\"restrictive\": conservative settings that " \
"require the root user password for a lot of actions" \
" and disable certain actions completely for remote " \
"users.</li>" \
"<li>\"standard\": balanced settings that restrict " \
"sensitive actions to require root authentication " \
"but allow less dangerous operations for regular " \
"logged in users.</li>" \
"<li>\"easy\": settings that are focused on ease " \
"of use. This sacrifices security to some degree " \
"to allow a more seamless user experience without" \
" interruptions in the workflow due to password " \
"prompts.</li></ul><br>" \
"The \"default\" is to keep value empty and it will be " \
"assigned automatically.</p>"
)
"<b>#{label}</b>\n" +
_(
"<p>SUSE ships with three sets of default privilege " \
"settings. These are as follows:<br><ul>" \
"<li>\"restrictive\": conservative settings that " \
"require the root user password for a lot of actions" \
" and disable certain actions completely for remote " \
"users.</li>" \
"<li>\"standard\": balanced settings that restrict " \
"sensitive actions to require root authentication " \
"but allow less dangerous operations for regular " \
"logged in users.</li>" \
"<li>\"easy\": settings that are focused on ease " \
"of use. This sacrifices security to some degree " \
"to allow a more seamless user experience without" \
" interruptions in the workflow due to password " \
"prompts.</li></ul><br>" \
"The \"default\" is to keep value empty and it will be " \
"assigned automatically.</p>"
)
end

def init
Expand Down

0 comments on commit 23190fb

Please sign in to comment.