Skip to content

Commit

Permalink
Improve Y2Security::Selinux#mode initialization
Browse files Browse the repository at this point in the history
Taking into account not only the running and boot mode, but the defined
through the configuration file too.
  • Loading branch information
dgdavid committed Feb 10, 2021
1 parent 768b5f7 commit cc3de2e
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 83 deletions.
73 changes: 48 additions & 25 deletions src/lib/y2security/selinux.rb
Expand Up @@ -67,11 +67,20 @@ class Selinux
Yast.import "Bootloader"
Yast.import "ProductFeatures"

# @return [Selinux::Mode] the last set mode, which can be differrent to the
# {#running_mode} and {#configured_mode}. A call to {#save} is needed to make it the
# {#configured_mode} for the next boot.
# The current set mode
#
# @note initially, it will be set to the {#proposed_mode}, #{boot_mode}, or
# {#configured_mode}, as applicable. When SELinux is enabled (i.e., detected #{boot_mode} was
# not "disabled") but the mode was set through neither, a boot kernel param nor configuration
# file, the "permissive" mode is assumed.
#
# @note a #{save} call is needed to make it the SELinux mode starting with the next boot.
#
# @return [Selinux::Mode] the current set mode, which initially can be the {#proposed_mode},
# {#boot_mode} or the {#configured_mode} as applicable. A {#save} call is needed to make it the
# for the next boot.
def mode
@mode ||= make_proposal || configured_mode
@mode ||= make_proposal || boot_mode || configured_mode || Mode.find(:permissive)
end

# Returns the configured mode in the SELinux config file
Expand All @@ -84,16 +93,40 @@ def configured_mode
# Returns the mode applied in the running system
#
# @note the system can be booted with a different SELinux mode that the configured one. To
# know the running mode getenforce tool is used.
# know the running mode getenforce SELinux tool is used.
#
# @return [Mode] running SELinux mode if command executed successfully; :disabled otherwise
# @return [Mode, nil] running SELinux mode if command executed successfully; nil otherwise
def running_mode
id = Yast::Execute.locally!(GETENFORCE_PATH, stdout: :capture).chomp.downcase.to_sym
Mode.find(id)
rescue Cheetah::ExecutionFailed => e
log.info(e.message)

Mode.find(:disabled)
nil
end

# Returns the SELinux mode according to boot kernel params
#
# @see #mode_from_kernel_params
#
# @return [Mode,nil] the selected mode through boot kernel params or nil if SELinux is enabled
# but there is not enough information to guess the mode because it will depend on the SELINUX
# value in the configuration file (see {#configured_mode} and {#mode}).
def boot_mode
options = mode_from_kernel_params
security_module = options["security"]
module_disabled = options["selinux"].to_i <= 0

return Mode.find(:disabled) if security_module != "selinux" || module_disabled

# enforcing missing or with a negative value means that SELinux mode will be determined
# by the SELINUX value in the configuration file. "permissive" by default. See {#mode}
enforcing_mode = options["enforcing"]&.to_i
return if enforcing_mode.nil? || enforcing_mode < 0

# enforcing=0 means that "permissive" mode will be used, despite the SELINUX value used in the
# configuration file.
enforcing_mode > 0 ? Mode.find(:enforcing) : Mode.find(:permissive)
end

# Returns a collection holding all known SELinux modes
Expand Down Expand Up @@ -217,10 +250,16 @@ def make_proposal
# @return [Mode] disabled or found SELinux mode
def proposed_mode
id = product_feature_settings[:mode]
found_mode = Mode.find(id)

log.info("Proposing `#{id}` SELinux mode.")
if found_mode.nil?
log.info("Proposed SELinux mode `#{id}` not found.")

find_mode(id)
return
end

log.info("Proposing `#{id}` SELinux mode.")
found_mode
end

# Returns the SELinux configuration based on options set in the kernel command line
Expand Down Expand Up @@ -278,22 +317,6 @@ def self.find(id)
ALL.find { |mode| mode.id == id&.to_sym }
end

# Finds the SELinux mode which fits better to given options
#
# @return [Mode] proper mode according to values of given options
def self.match(options)
return find(:disabled) if options.empty?

security_module = options["security"]
module_disabled = options["selinux"].to_i <= 0
enforcing_mode = options["enforcing"].to_i > 0

return find(:disabled) if security_module != "selinux" || module_disabled
return find(:permissive) unless enforcing_mode

find(:enforcing)
end

# Constructor
#
# Intended to be used internally by the class
Expand Down
60 changes: 2 additions & 58 deletions test/y2security/selinux_test.rb
Expand Up @@ -191,8 +191,8 @@
subject.running_mode
end

it "returns the :disabled mode" do
expect(subject.running_mode.id).to eq(:disabled)
it "returns nil" do
expect(subject.running_mode).to be_nil
end
end
end
Expand Down Expand Up @@ -371,62 +371,6 @@
end
end

describe ".match" do
let(:security_param) { nil }
let(:selinux_param) { nil }
let(:enforcing_param) { nil }

let(:params) do
{ "security" => security_param, "selinux" => selinux_param, "enforcing" => enforcing_param }
end

let(:mode) { subject.match(params) }

context "when 'security' is not 'selinux'" do
let(:security_param) { "apparmor" }
let(:selinux_param) { "1" }

it "returns the :disabled mode" do
expect(mode.id).to eq(:disabled)
end
end

context "when 'security' is 'selinux'" do
let(:security_param) { "selinux" }

context "and 'selinux' is missing" do
it "returns the :disabled mode" do
expect(mode.id).to eq(:disabled)
end
end

context "and 'selinux' is a number greater than zero" do
let(:selinux_param) { "1" }

it "returns the :permissive mode" do
expect(mode.id).to eq(:permissive)
end

context "but 'enforcing' is a number greater than zero" do
let(:enforcing_param) { "1" }

it "returns the :enforcing mode" do
expect(mode.id).to eq(:enforcing)
end
end
end

context "but 'selinux' is zero" do
let(:selinux_param) { "0" }
let(:enforcing_param) { "1" }

it "returns the :disabled mode" do
expect(mode.id).to eq(:disabled)
end
end
end
end

describe "#id" do
let(:mode) { described_class.find("enforcing") }

Expand Down

0 comments on commit cc3de2e

Please sign in to comment.