Skip to content

Commit

Permalink
Merge pull request #94 from yast/move_selinux_autorelabel_file
Browse files Browse the repository at this point in the history
[SLE-15-SP2] Move SELinux .autorelabel file
  • Loading branch information
dgdavid committed Feb 23, 2021
2 parents 0ad18aa + b1b786c commit a8f6b8f
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 3 deletions.
7 changes: 7 additions & 0 deletions package/yast2-security.changes
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
-------------------------------------------------------------------
Mon Feb 22 13:45:58 UTC 2021 - David Diaz <dgonzalez@suse.com>

- Move SELinux .autorelabel file from / to /etc/selinux if root
filesystem will be mounted as read only (jsc#SLE-17307).
- 4.2.19

-------------------------------------------------------------------
Sun Feb 14 21:13:17 UTC 2021 - David Diaz <dgonzalez@suse.com>

Expand Down
6 changes: 5 additions & 1 deletion package/yast2-security.spec
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@


Name: yast2-security
Version: 4.2.18
Version: 4.2.19
Release: 0
Group: System/YaST
License: GPL-2.0-only
Expand All @@ -40,6 +40,8 @@ BuildRequires: rubygem(%{rb_default_ruby_abi}:rspec)
BuildRequires: yast2 >= 4.2.66
# CFA::Selinux
BuildRequires: augeas-lenses
# Y2Storage::StorageManager
BuildRequires: yast2-storage-ng
# Unfortunately we cannot move this to macros.yast,
# bcond within macros are ignored by osc/OBS.
%bcond_with yast_run_ci_tests
Expand All @@ -56,6 +58,8 @@ Requires: yast2-ruby-bindings >= 1.0.0
Requires: yast2-bootloader
# CFA::Selinux
Requires: augeas-lenses
# Y2Storage::StorageManager
Requires: yast2-storage-ng

Provides: y2c_sec yast2-config-security
Provides: yast2-trans-security y2t_sec
Expand Down
66 changes: 64 additions & 2 deletions src/lib/y2security/selinux.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

require "yast"
require "yast2/execute"
require "y2storage/storage_manager"
require "cfa/selinux"

module Y2Security
Expand Down Expand Up @@ -181,18 +182,28 @@ def mode=(id)
# @see Yast::Bootloader#modify_kernel_params
# @see CFA::Selinux#save
#
# @return [Boolean] true if running in installation where selinux is configurable;
# false if running in installation where selinux is not configurable;
# @return [Boolean] true if running in installation where SELinux is configurable;
# false if running in installation where SELinux is not configurable;
# the Yast::Bootloader#Write return value otherwise
def save
return false unless configurable?

log.info("Modifying Bootlooader kernel params using #{mode.options}")
Yast::Bootloader.modify_kernel_params(mode.options)

log.info("Saving SELinux config file to set #{mode.id} mode")
config_file.selinux = mode.id.to_s
config_file.save

if relocate_autorelabel_file?
log.info("Detected a read-only root fs: relocating .autorelabel file")

relocate_autorelabel_file
end

return true if Yast::Mode.installation

log.info("Saving Bootloader configuration")
Yast::Bootloader.Write
end

Expand Down Expand Up @@ -223,6 +234,22 @@ def configurable?
GETENFORCE_PATH = "/usr/sbin/getenforce".freeze
private_constant :GETENFORCE_PATH

# Path to .autorelabel file in root
ROOT_AUTORELABEL_PATH = "/.autorelabel".freeze
private_constant :ROOT_AUTORELABEL_PATH

# Path to .autorelabel file in /etc
ETC_AUTORELABEL_PATH = "/etc/selinux/.autorelabel".freeze
private_constant :ETC_AUTORELABEL_PATH

# Path to `rm` command
RM_COMMAND = "/usr/bin/rm".freeze
private_constant :RM_COMMAND

# Path to `touch` command
TOUCH_COMMAND = "/usr/bin/touch".freeze
private_constant :TOUCH_COMMAND

# Returns the values for the SELinux setting from the product features
#
# @return [Hash{Symbol => String, Boolean, nil}] e.g., { mode: "enforcing", configurable: false }
Expand Down Expand Up @@ -296,6 +323,41 @@ def read_param(key)
Yast::Bootloader.kernel_param(:common, key.to_s)
end

# Whether the .autorelabel file should be relocated
#
# @see https://jira.suse.com/browse/SLE-17307
#
# @return [Booelan] true if root fs will mounted as read only, SELinux is not disabled,
# and running in the installation mode; false otherwise
def relocate_autorelabel_file?
mode.to_sym != :disabled && Yast::Mode.installation && read_only_root_fs?
end

# Relocates the .autorelabel file from #{ROOT_AUTORELABEL_PATH} to #{ETC_AUTORELABEL_PATH} by
# removing the first and touching the latter.
#
# @see #save
# @see https://jira.suse.com/browse/SLE-17307
def relocate_autorelabel_file
log.info("Deleting #{ROOT_AUTORELABEL_PATH} file")
Yast::Execute.stdout.on_target!(RM_COMMAND, ROOT_AUTORELABEL_PATH)

log.info("Touching #{ETC_AUTORELABEL_PATH} file")
Yast::Execute.stdout.on_target!(TOUCH_COMMAND, ETC_AUTORELABEL_PATH)
end

# Whether the root file system will be mounted as read only
#
# @return [Booelan] true if "ro" is one of the root fs mount options; false otherwise
def read_only_root_fs?
staging_graph = Y2Storage::StorageManager.instance.staging
root_fs = staging_graph.filesystems.find(&:root?)

return false unless root_fs

root_fs.mount_options.include?("ro")
end

# Model that represents a SELinux mode
class Mode
extend Yast::I18n
Expand Down
71 changes: 71 additions & 0 deletions test/y2security/selinux_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@

let(:configured_mode) { enforcing_mode }

let(:read_only_root_fs) { false }

before do
Yast::ProductFeatures.Import(product_features)

Expand All @@ -63,6 +65,7 @@
.and_return(selinux_param)
allow(Yast::Bootloader).to receive(:kernel_param).with(:common, "enforcing")
.and_return(enforcing_param)
allow(subject).to receive(:read_only_root_fs?).and_return(read_only_root_fs)
end

describe "#mode" do
Expand Down Expand Up @@ -365,12 +368,16 @@
describe "#save" do
let(:write_result) { true }
let(:selinux_configurable) { true }
let(:mode) { enforcing_mode }
let(:config_file) { double("CFA::Selinux", load: true, save: true, :selinux= => true) }
let(:executor) { double("Yast::Execute", on_target!: "") }

before do
allow(Yast::Bootloader).to receive(:modify_kernel_params)
allow(Yast::Bootloader).to receive(:Write).and_return(write_result)
allow(Yast::Execute).to receive(:stdout).and_return(executor)
allow(subject).to receive(:config_file).and_return(config_file)
allow(subject).to receive(:mode).and_return(mode)

subject.mode = enforcing_mode
end
Expand Down Expand Up @@ -399,6 +406,37 @@
subject.save
end

context "and root filesystem will be mounted read-only" do
let(:read_only_root_fs) { true }

it "touches .autorelable file" do
expect(executor).to receive(:on_target!).with(/rm/, /autorelabel/)
expect(executor).to receive(:on_target!).with(/touch/, /autorelabel/)

subject.save
end

context "but SELinux is disabled" do
let(:mode) { disabled_mode }

it "does not touch .autorelable file" do
expect(executor).to_not receive(:on_target!).with(/rm/, /autorelabel/)
expect(executor).to_not receive(:on_target!).with(/touch/, /autorelabel/)

subject.save
end
end
end

context "and root filesystem will not be mounted as read-only" do
it "does not touch the .autorelable file" do
expect(executor).to_not receive(:on_target!).with(/rm/, /autorelabel/)
expect(executor).to_not receive(:on_target!).with(/touch/, /autorelabel/)

subject.save
end
end

it "returns true" do
expect(subject.save).to eq(true)
end
Expand All @@ -420,6 +458,19 @@
subject.save
end

it "does not touch the .autorelable file" do
expect(executor).to_not receive(:on_target!).with(/rm/, /autorelabel/)
expect(executor).to_not receive(:on_target!).with(/touch/, /autorelabel/)

subject.save
end

it "does not write the bootloader configuration" do
expect(Yast::Bootloader).to_not receive(:Write)

subject.save
end

it "returns false" do
expect(subject.save).to eq(false)
end
Expand All @@ -434,6 +485,26 @@
subject.save
end

it "writes the bootloader configuration" do
expect(Yast::Bootloader).to receive(:Write)

subject.save
end

it "changes the mode in the configuration file" do
expect(config_file).to receive(:selinux=).with("enforcing")
expect(config_file).to receive(:save)

subject.save
end

it "does not touch the .autorelable file" do
expect(executor).to_not receive(:on_target!).with(/rm/, /autorelabel/)
expect(executor).to_not receive(:on_target!).with(/touch/, /autorelabel/)

subject.save
end

context "and configuration has been successfully written" do
it "returns true" do
expect(subject.save).to eq(true)
Expand Down

0 comments on commit a8f6b8f

Please sign in to comment.