Skip to content

Commit

Permalink
Merge pull request #142 from WOnder93/selinux-disable-kernel
Browse files Browse the repository at this point in the history
selinux: update kernel boot params when disabling/re-enabling SELinux

SUMMARY
The ability to disable SELinux from userspace based on the configuration
file is being deprecated in favor of the selinux=0 kernel boot
parameter. (Note that this affects only the "full" disable; switching
to/from permissive mode will work the same as before.)
Therefore, enhance the selinux module to try to set/unset the kernel
command-line parameter using grubby when enabling/disabling SELinux.
If the grubby package is not present on the system, the module will only
update the config file and report a warning. Note that even with the
runtime disable functionality removed, setting SELINUX=disabled in the
config file will lead to a system with no SELinux policy loaded, which
will behave in a very similar way as if SELinux was fully disabled, only
there could still be some minor performance impact, since the kernel
hooks will still be active.
More information:
https://lore.kernel.org/selinux/157836784986.560897.13893922675143903084.stgit@chester/
https://fedoraproject.org/wiki/Changes/Remove_Support_For_SELinux_Runtime_Disable
ISSUE TYPE

Feature Pull Request

COMPONENT NAME
selinux module

Reviewed-by: Adam Miller <[email protected]>
Reviewed-by: Ondrej Mosnáček <[email protected]>
Reviewed-by: Abhijeet Kasurde <None>
Reviewed-by: quidame <None>
Reviewed-by: Hideki Saito <[email protected]>
Reviewed-by: None <None>
  • Loading branch information
ansible-zuul[bot] authored Sep 24, 2021
2 parents 96c342f + 53d47e1 commit 595ee76
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 1 deletion.
2 changes: 2 additions & 0 deletions changelogs/fragments/disable_selinux_via_kernel_cmdline.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
minor_changes:
- selinux - optionally update kernel boot params when disabling/re-enabling SELinux (https://github.com/ansible-collections/ansible.posix/pull/142).
71 changes: 71 additions & 0 deletions plugins/modules/selinux.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@
required: true
choices: [ disabled, enforcing, permissive ]
type: str
update_kernel_param:
description:
- If set to I(true), will update also the kernel boot parameters when disabling/enabling SELinux.
- The C(grubby) tool must be present on the target system for this to work.
default: no
type: bool
version_added: '1.4.0'
configfile:
description:
- The path to the SELinux configuration file, if non-standard.
Expand Down Expand Up @@ -97,6 +104,7 @@
HAS_SELINUX = False

from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils.common.process import get_bin_path
from ansible.module_utils.facts.utils import get_file_lines


Expand All @@ -119,6 +127,34 @@ def get_config_policy(configfile):
return line.split('=')[1].strip()


def get_kernel_enabled(module, grubby_bin):
if grubby_bin is None:
module.fail_json(msg="'grubby' command not found on host",
details="In order to update the kernel command line"
"enabled/disabled setting, the grubby package"
"needs to be present on the system.")

rc, stdout, stderr = module.run_command([grubby_bin, '--info=ALL'])
if rc != 0:
module.fail_json(msg="unable to run grubby")

all_enabled = True
all_disabled = True
for line in stdout.split('\n'):
match = re.match('^args="(.*)"$', line)
if match is None:
continue
args = match.group(1).split(' ')
if 'selinux=0' in args:
all_enabled = False
else:
all_disabled = False
if all_disabled == all_enabled:
# inconsistent config - return None to force update
return None
return all_enabled


# setter subroutines
def set_config_state(module, state, configfile):
# SELINUX=permissive
Expand Down Expand Up @@ -153,6 +189,17 @@ def set_state(module, state):
module.fail_json(msg=msg)


def set_kernel_enabled(module, grubby_bin, value):
rc, stdout, stderr = module.run_command([grubby_bin, '--update-kernel=ALL',
'--remove-args' if value else '--args',
'selinux=0'])
if rc != 0:
if value:
module.fail_json(msg='unable to remove selinux=0 from kernel config')
else:
module.fail_json(msg='unable to add selinux=0 to kernel config')


def set_config_policy(module, policy, configfile):
if not os.path.exists('/etc/selinux/%s/policy' % policy):
module.fail_json(msg='Policy %s does not exist in /etc/selinux/' % policy)
Expand Down Expand Up @@ -183,6 +230,7 @@ def main():
policy=dict(type='str'),
state=dict(type='str', required=True, choices=['enforcing', 'permissive', 'disabled']),
configfile=dict(type='str', default='/etc/selinux/config', aliases=['conf', 'file']),
update_kernel_param=dict(type='bool', default=False),
),
supports_check_mode=True,
)
Expand All @@ -196,9 +244,11 @@ def main():
configfile = module.params['configfile']
policy = module.params['policy']
state = module.params['state']
update_kernel_param = module.params['update_kernel_param']
runtime_enabled = selinux.is_selinux_enabled()
runtime_policy = selinux.selinux_getpolicytype()[1]
runtime_state = 'disabled'
kernel_enabled = None
reboot_required = False

if runtime_enabled:
Expand All @@ -215,6 +265,12 @@ def main():

config_policy = get_config_policy(configfile)
config_state = get_config_state(configfile)
if update_kernel_param:
try:
grubby_bin = get_bin_path('grubby')
except ValueError:
grubby_bin = None
kernel_enabled = get_kernel_enabled(module, grubby_bin)

# check to see if policy is set if state is not 'disabled'
if state != 'disabled':
Expand Down Expand Up @@ -269,6 +325,21 @@ def main():
msgs.append("Config SELinux state changed from '%s' to '%s'" % (config_state, state))
changed = True

requested_kernel_enabled = state in ('enforcing', 'permissive')
# Update kernel enabled/disabled config only when setting is consistent
# across all kernels AND the requested state differs from the current state
if update_kernel_param and kernel_enabled != requested_kernel_enabled:
if not module.check_mode:
set_kernel_enabled(module, grubby_bin, requested_kernel_enabled)
if requested_kernel_enabled:
states = ('disabled', 'enabled')
else:
states = ('enabled', 'disabled')
if kernel_enabled is None:
states = ('<inconsistent>', states[1])
msgs.append("Kernel SELinux state changed from '%s' to '%s'" % states)
changed = True

module.exit_json(changed=changed, msg=', '.join(msgs), configfile=configfile, policy=policy, state=state, reboot_required=reboot_required)


Expand Down
48 changes: 47 additions & 1 deletion tests/integration/targets/selinux/tasks/selinux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
# ##############################################################################
# Test changing the state, which requires a reboot

- name: TEST 1 | Make sure grubby is present
package:
name: grubby
state: present

- name: TEST 1 | Get current SELinux config file contents
set_fact:
selinux_config_original: "{{ lookup('file', '/etc/sysconfig/selinux').split('\n') }}"
Expand Down Expand Up @@ -104,11 +109,52 @@
- selinux_config_after[selinux_config_after.index('SELINUX=disabled')] is search("^SELINUX=\w+$")
- selinux_config_after[selinux_config_after.index('SELINUXTYPE=targeted')] is search("^SELINUXTYPE=\w+$")

- name: TEST 1 | Reset SELinux configuration for next test
- name: TEST 1 | Disable SELinux again, with kernel arguments update
selinux:
state: disabled
policy: targeted
update_kernel_param: true
register: _disable_test2

- name: Check kernel command-line arguments
ansible.builtin.command: grubby --info=DEFAULT
register: _grubby_test1

- name: TEST 1 | Assert that kernel cmdline contains selinux=0
assert:
that:
- "' selinux=0' in _grubby_test1.stdout"

- name: TEST 1 | Enable SELinux, without kernel arguments update
selinux:
state: disabled
policy: targeted
register: _disable_test2

- name: Check kernel command-line arguments
ansible.builtin.command: grubby --info=DEFAULT
register: _grubby_test1

- name: TEST 1 | Assert that kernel cmdline still contains selinux=0
assert:
that:
- "' selinux=0' in _grubby_test1.stdout"

- name: TEST 1 | Reset SELinux configuration for next test (also kernel args)
selinux:
state: enforcing
update_kernel_param: true
policy: targeted

- name: Check kernel command-line arguments
ansible.builtin.command: grubby --info=DEFAULT
register: _grubby_test2

- name: TEST 1 | Assert that kernel cmdline doesn't contain selinux=0
assert:
that:
- "' selinux=0' not in _grubby_test2.stdout"


# Second Test
# ##############################################################################
Expand Down

0 comments on commit 595ee76

Please sign in to comment.