diff options
author | Tim Smith <tsmith@chef.io> | 2020-05-06 09:12:38 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-06 09:12:38 -0700 |
commit | 46e5e9d9fd81eaa99a87ece2fe6cc895307c04b4 (patch) | |
tree | ca43f968a51208ddd41b95a7df7f67a2b3b190e9 | |
parent | 45dff3307b8509dd52e1432c4ff1c2a6c43f316b (diff) | |
parent | 23215ba7f9149ff44f216284350b1b7f8b656ddf (diff) | |
download | ohai-46e5e9d9fd81eaa99a87ece2fe6cc895307c04b4.tar.gz |
Merge pull request #1455 from davide125/selinux
Add new selinux plugin for Linux
-rw-r--r-- | lib/ohai/plugins/linux/selinux.rb | 68 | ||||
-rw-r--r-- | spec/unit/plugins/linux/selinux_spec.rb | 101 |
2 files changed, 169 insertions, 0 deletions
diff --git a/lib/ohai/plugins/linux/selinux.rb b/lib/ohai/plugins/linux/selinux.rb new file mode 100644 index 00000000..996ce78e --- /dev/null +++ b/lib/ohai/plugins/linux/selinux.rb @@ -0,0 +1,68 @@ +# +# Author:: Davide Cavalca <dcavalca@fb.com> +# Copyright:: Copyright (c) 2020 Facebook +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +Ohai.plugin(:Selinux) do + provides "selinux/status", "selinux/policy_booleans", "selinux/process_contexts", "selinux/file_contexts" + optional true + + collect_data(:linux) do + sestatus_path = which("sestatus") + if sestatus_path + sestatus = shell_out("#{sestatus_path} -v -b") + + selinux Mash.new unless selinux + selinux[:status] ||= Mash.new + selinux[:policy_booleans] ||= Mash.new + selinux[:process_contexts] ||= Mash.new + selinux[:file_contexts] ||= Mash.new + section = nil + + sestatus.stdout.split("\n").each do |line| + line.chomp! + + case line + when "Policy booleans:" + section = :policy_booleans + next + when "Process contexts:" + section = :process_contexts + next + when "File contexts:" + section = :file_contexts + next + else + if section.nil? + section = :status + end + end + + key, val = line.split(/:?\s\s+/, 2) + next if key.nil? + + unless key.start_with?("/") + key.downcase! + key.tr!(" ", "_") + end + + selinux[section][key] = val + end + else + logger.debug("Plugin Selinux: Could not find sestatus. Skipping plugin.") + end + end +end diff --git a/spec/unit/plugins/linux/selinux_spec.rb b/spec/unit/plugins/linux/selinux_spec.rb new file mode 100644 index 00000000..6f8ceef4 --- /dev/null +++ b/spec/unit/plugins/linux/selinux_spec.rb @@ -0,0 +1,101 @@ +# +# Author:: Davide Cavalca <dcavalca@fb.com> +# Copyright:: Copyright (c) 2020 Facebook +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require "spec_helper" + +describe Ohai::System, "Linux selinux plugin" do + let(:plugin) { get_plugin("linux/selinux") } + + before do + allow(plugin).to receive(:collect_os).and_return(:linux) + end + + it "populates selinux if sestatus is found" do + sestatus_out = <<-SESTATUS_OUT +SELinux status: enabled +SELinuxfs mount: /sys/fs/selinux +SELinux root directory: /etc/selinux +Loaded policy name: test +Current mode: permissive +Mode from config file: permissive +Policy MLS status: disabled +Policy deny_unknown status: allowed +Max kernel policy version: 31 + +Policy booleans: +secure_mode_policyload off + +Process contexts: +Current context: user_u:base_r:admin_t +Init context: system_u:system_r:init_t +/usr/sbin/sshd system_u:base_r:base_t + +File contexts: +Controlling terminal: system_u:object_r:file_t +/etc/passwd user_u:object_r:file_t +/etc/shadow user_u:object_r:file_t +/bin/bash user_u:object_r:file_t +/bin/login user_u:object_r:file_t +/bin/sh user_u:object_r:file_t -> user_u:object_r:file_t +/sbin/agetty user_u:object_r:file_t +/sbin/init user_u:object_r:file_t -> user_u:object_r:init_exec_t +/usr/sbin/sshd user_u:object_r:file_t + SESTATUS_OUT + allow(plugin).to receive(:which).with("sestatus").and_return("/usr/sbin/sestatus") + allow(plugin).to receive(:shell_out).with("/usr/sbin/sestatus -v -b").and_return(mock_shell_out(0, sestatus_out, "")) + plugin.run + expect(plugin[:selinux].to_hash).to eq({ + "file_contexts" => { + "/bin/bash" => "user_u:object_r:file_t", + "/bin/login" => "user_u:object_r:file_t", + "/bin/sh" => "user_u:object_r:file_t -> user_u:object_r:file_t", + "/etc/passwd" => "user_u:object_r:file_t", + "/etc/shadow" => "user_u:object_r:file_t", + "/sbin/agetty" => "user_u:object_r:file_t", + "/sbin/init" => "user_u:object_r:file_t -> user_u:object_r:init_exec_t", + "/usr/sbin/sshd" => "user_u:object_r:file_t", + "controlling_terminal" => "system_u:object_r:file_t", + }, + "policy_booleans" => { + "secure_mode_policyload" => "off", + }, + "process_contexts" => { + "/usr/sbin/sshd" => "system_u:base_r:base_t", + "current_context" => "user_u:base_r:admin_t", + "init_context" => "system_u:system_r:init_t", + }, + "status" => { + "current_mode" => "permissive", + "loaded_policy_name" => "test", + "max_kernel_policy_version" => "31", + "mode_from_config_file" => "permissive", + "policy_deny_unknown_status" => "allowed", + "policy_mls_status" => "disabled", + "selinux_root_directory" => "/etc/selinux", + "selinux_status" => "enabled", + "selinuxfs_mount" => "/sys/fs/selinux", + }, + }) + end + + it "does not populate selinux if sestatus is not found" do + allow(plugin).to receive(:which).with("sestatus").and_return(false) + plugin.run + expect(plugin[:selinux]).to be(nil) + end +end |