From cc7ed38d091b6f0e180daf8e8525ae41b300d303 Mon Sep 17 00:00:00 2001 From: Aaron Lippold Date: Wed, 5 Jul 2017 05:41:44 -0400 Subject: [PATCH] kernel_module resource: added blacklisting, enabled, disabled, docs and unit tests (#1798) * Fix up methods, add command mock, do string matching in ruby instead of command Fixes #1643 Fixes #1673 Signed-off-by: Aaron Lippold --- docs/resources/kernel_module.md.erb | 74 +++++++++++- lib/resources/kernel_module.rb | 80 +++++++++++-- test/helper.rb | 2 + .../integration/default/kernel_module_spec.rb | 27 +++++ test/unit/mock/cmd/lsmod | 1 + test/unit/mock/cmd/modprobe-config | 3 + test/unit/resources/kernel_module_test.rb | 111 ++++++++++++++++-- 7 files changed, 275 insertions(+), 23 deletions(-) create mode 100644 test/unit/mock/cmd/modprobe-config diff --git a/docs/resources/kernel_module.md.erb b/docs/resources/kernel_module.md.erb index f52a1a5f2..4890ca550 100644 --- a/docs/resources/kernel_module.md.erb +++ b/docs/resources/kernel_module.md.erb @@ -4,20 +4,45 @@ title: About the kernel_module Resource # kernel_module -Use the `kernel_module` InSpec audit resource to test kernel modules on Linux platforms. These parameters are located under `/lib/modules`. Any submodule may be tested using this resource. +Use the `kernel_module` InSpec audit resource to test kernel modules on Linux +platforms. These parameters are located under `/lib/modules`. Any submodule may +be tested using this resource. + +The `kernel_module` resource can also verify if a kernel module is `blacklisted` +or if a module is disabled via a fake install using the `bin_true` or `bin_false` +method. ## Syntax -A `kernel_module` resource block declares a module name, and then tests if that module is a loadable kernel module: +A `kernel_module` resource block declares a module name, and then tests if that +module is a loadable kernel module, if it is enabled, disabled or if it is +blacklisted: - describe kernel_module('module_name') do + describe kernel_module('video') do it { should be_loaded } + it { should_not be_disabled } + it { should_not be_blacklisted } + end + + describe kernel_module('sstfb') do + it { should_not be_loaded } + it { should be_disabled } + end + + describe kernel_module('floppy') do + it { should be_blacklisted } + end + + describe kernel_module('dhcp') do + it { should_not be_loaded } end where * `'module_name'` must specify a kernel module, such as `'bridge'` * `{ should be_loaded }` tests if the module is a loadable kernel module +* `{ should be_blacklisted }` tests if the module is blacklisted or if the module is disabled via a fake install using /bin/false or /bin/true +* `{ should be_disabled }` tests if the module is disabled via a fake install using /bin/false or /bin/true ## Matchers @@ -59,9 +84,50 @@ The `version` matcher tests if the named module version is on the system: The following examples show how to use this InSpec audit resource. -### Test if a module is loaded + ### Test a modules 'version' describe kernel_module('bridge') do it { should be_loaded } its(:version) { should cmp >= '2.2.2' } end + + ### Test if a module is loaded, not disabled and not blacklisted + + describe kernel_module('video') do + it { should be_loaded } + it { should_not be_disabled } + it { should_not be_blacklisted } + end + + ### Check if a module is blacklisted + + describe kernel_module('floppy') do + it { should be_blacklisted } + end + + ### Ensure a module is *not* blacklisted and it is loaded + + describe kernel_module('video') do + it { should_not be_blacklisted } + it { should be_loaded } + end + + ### Ensure a module is disabled via 'bin_false' + + describe kernel_module('sstfb') do + it { should_not be_loaded } + it { should be_disabled } + end + + ### Ensure a module is 'blacklisted'/'disabled' via 'bin_true' + + describe kernel_module('nvidiafb') do + it { should_not be_loaded } + it { should be_blacklisted } + end + + ### Ensure a module is not loaded + + describe kernel_module('dhcp') do + it { should_not be_loaded } + end diff --git a/lib/resources/kernel_module.rb b/lib/resources/kernel_module.rb index 88a3a9476..d3b6ed023 100644 --- a/lib/resources/kernel_module.rb +++ b/lib/resources/kernel_module.rb @@ -1,20 +1,44 @@ # encoding: utf-8 # author: Christoph Hartmann # author: Dominik Richter +# author: Aaron Lippold +# author: Adam Leff module Inspec::Resources class KernelModule < Inspec.resource(1) name 'kernel_module' - desc 'Use the kernel_module InSpec audit resource to test kernel modules on Linux platforms. These parameters are located under /lib/modules. Any submodule may be tested using this resource.' + desc 'Use the kernel_module InSpec audit resource to test kernel modules on + Linux platforms. These parameters are located under /lib/modules. Any submodule + may be tested using this resource. + + The `kernel_module` resource can also verify if a kernel module is `blacklisted` + or if a module is disabled via a fake install using the `bin_true` or `bin_false` + method.' + example " - describe kernel_module('bridge') do - it { should be_loaded } - end + + describe kernel_module('video') do + it { should be_loaded } + it { should_not be_disabled } + it { should_not be_blacklisted } + end + + describe kernel_module('sstfb') do + it { should_not be_loaded } + it { should be_disabled } + end + + describe kernel_module('floppy') do + it { should be_blacklisted } + end + + describe kernel_module('dhcp') do + it { should_not be_loaded } + end " def initialize(modulename = nil) @module = modulename - # this resource is only supported on Linux return skip_resource 'The `kernel_parameter` resource is not supported on your OS.' if !inspec.os.linux? end @@ -36,19 +60,51 @@ module Inspec::Resources !found.nil? end - def version - if inspec.os.redhat? || inspec.os.name == 'fedora' - modinfo_cmd = "/sbin/modinfo -F version #{@module}" - else - modinfo_cmd = "modinfo -F version #{@module}" - end + def disabled? + !modprobe_output.match(%r{^install\s+#{@module}\s+/(s?)bin/(true|false)}).nil? + end - cmd = inspec.command(modinfo_cmd) + def blacklisted? + !modprobe_output.match(/^blacklist\s+#{@module}/).nil? || disabled_via_bin_true? || disabled_via_bin_false? + end + + def version + cmd = inspec.command("#{modinfo_cmd_for_os} -F version #{@module}") cmd.exit_status.zero? ? cmd.stdout.delete("\n") : nil end def to_s "Kernel Module #{@module}" end + + private + + def modprobe_output + @modprobe_output ||= inspec.command("#{modprobe_cmd_for_os} --showconfig").stdout + end + + def modinfo_cmd_for_os + if inspec.os.redhat? || inspec.os.name == 'fedora' + '/sbin/modinfo' + else + 'modinfo' + end + end + + def modprobe_cmd_for_os + if inspec.os.redhat? || inspec.os.name == 'fedora' + '/sbin/modprobe' + else + 'modprobe' + end + end + + def disabled_via_bin_true? + !modprobe_output.match(%r{^install\s+#{@module}\s+/(s?)bin/true}).nil? + end + + def disabled_via_bin_false? + !modprobe_output.match(%r{^install\s+#{@module}\s+/(s?)bin/false}).nil? + end end end diff --git a/test/helper.rb b/test/helper.rb index d358d1ccf..fddd98e90 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -335,6 +335,8 @@ class MockLoader "docker inspect 71b5df59442b" => cmd.call('docker-inspec'), # docker images "83c36bfade9375ae1feb91023cd1f7409b786fd992ad4013bf0f2259d33d6406" => cmd.call('docker-images'), + # modprobe for kernel_module + "modprobe --showconfig" => cmd.call('modprobe-config'), # get-process cmdlet for processes resource '$Proc = Get-Process -IncludeUserName | Where-Object {$_.Path -ne $null } | Select-Object PriorityClass,Id,CPU,PM,VirtualMemorySize,NPM,SessionId,Responding,StartTime,TotalProcessorTime,UserName,Path | ConvertTo-Csv -NoTypeInformation;$Proc.Replace("""","").Replace("`r`n","`n")' => cmd.call('get-process_processes'), # host resource: check to see if netcat is installed diff --git a/test/integration/default/kernel_module_spec.rb b/test/integration/default/kernel_module_spec.rb index a7807e3da..ca89fc8ea 100644 --- a/test/integration/default/kernel_module_spec.rb +++ b/test/integration/default/kernel_module_spec.rb @@ -9,13 +9,40 @@ if !os.linux? return end +# @todo add a disabled kernel module with /bin/true and /bin/false # Test kernel modules on all linux systems + describe kernel_module('video') do it { should be_loaded } + it { should_not be_disabled } + it { should_not be_blacklisted } +end + +describe kernel_module('video') do + it { should_not be_blacklisted } + it { should be_enabled } +end + +describe kernel_module('sstfb') do + it { should_not be_loaded } + it { should be_disabled } + it { should be_disabled_via_bin_false } +end + +describe kernel_module('nvidiafb') do + it { should_not be_loaded } + it { should be_disabled } + it { should be_disabled_via_bin_true } +end + +describe kernel_module('floppy') do + it { should be_blacklisted } + it { should_not be_enabled } end describe kernel_module('bridge') do it { should_not be_loaded } + it { should_not be_enabled } end describe kernel_module('dhcp') do diff --git a/test/unit/mock/cmd/lsmod b/test/unit/mock/cmd/lsmod index 5ba9f57b2..98dbc3146 100644 --- a/test/unit/mock/cmd/lsmod +++ b/test/unit/mock/cmd/lsmod @@ -1,2 +1,3 @@ Module Size Used by bridge 73728 1 br_netfilter +video 24400 0 diff --git a/test/unit/mock/cmd/modprobe-config b/test/unit/mock/cmd/modprobe-config new file mode 100644 index 000000000..e58a6810c --- /dev/null +++ b/test/unit/mock/cmd/modprobe-config @@ -0,0 +1,3 @@ +blacklist floppy +install nvidiafb /bin/true +install sstfb /sbin/false diff --git a/test/unit/resources/kernel_module_test.rb b/test/unit/resources/kernel_module_test.rb index 475bde10a..95d7a75a4 100644 --- a/test/unit/resources/kernel_module_test.rb +++ b/test/unit/resources/kernel_module_test.rb @@ -6,23 +6,120 @@ require 'helper' require 'inspec/resource' describe 'Inspec::Resources::KernelModule' do - it 'verify kernel_module parsing' do + + #kernel version + # 1 + it 'Verify kernel_module version' do + resource = load_resource('kernel_module', 'dhcp') + _(resource.version).must_equal '3.2.2' + end + + # loaded + # 2 + it 'Verify kernel_module parsing `loaded` - true' do resource = load_resource('kernel_module', 'bridge') _(resource.loaded?).must_equal true end - it 'verify kernel_module parsing' do + # 3 + it 'Verify kernel_module parsing `loaded` - false' do resource = load_resource('kernel_module', 'bridges') _(resource.loaded?).must_equal false end - it 'verify kernel_module parsing' do - resource = load_resource('kernel_module', 'dhcp') + #disabled + # 4 + it 'Verify kernel_module parsing `disabled` - true ' do + resource = load_resource('kernel_module', 'nvidiafb') + _(resource.disabled?).must_equal true + end + + # 5 + it 'Verify kernel_module parsing `disabled` - false' do + resource = load_resource('kernel_module', 'bridge') + _(resource.disabled?).must_equal false + end + + #/bin/true + # 6 + it 'Verify a kernel_module is disabled via /bin/true - true' do + resource = load_resource('kernel_module', 'nvidiafb') + _(resource.blacklisted?).must_equal true + end + + # 7 + it 'Verify a kernel_module is not disabled via /bin/true - false' do + resource = load_resource('kernel_module', 'ssftb') + _(resource.blacklisted?).must_equal false + end + + # 8 + #/bin/false + it 'Verify a kernel_module is disabled via /bin/false - true' do + resource = load_resource('kernel_module', 'sstfb') + _(resource.blacklisted?).must_equal true + end + + # 9 + it 'Verify a kernel_module is not disabled via /bin/false - true ' do + resource = load_resource('kernel_module', 'bridge') + _(resource.blacklisted?).must_equal false + end + + # 10 + # unlisted bin/true,/bin/false + it 'Verify an unlisted kernel_module is not disabled via /bin/true - false' do + resource = load_resource('kernel_module', 'fakemod') + _(resource.blacklisted?).must_equal false + end + + # 11 + it 'Verify an unlisted kernel_module is not disabled via /bin/false - false' do + resource = load_resource('kernel_module', 'fakemod') + _(resource.blacklisted?).must_equal false + end + + # 12 + #blacklisting + it 'Verify a kernel_module is blacklisted - true' do + resource = load_resource('kernel_module', 'floppy') + _(resource.blacklisted?).must_equal true + end + + # 13 + it 'Verify a kernel_module is not blacklisted - false' do + resource = load_resource('kernel_module', 'ssftb') + _(resource.blacklisted?).must_equal false + end + + # 14 + #unlisted moduled + it 'Verify an unlisted kernel_module is not `loaded` - false' do + resource = load_resource('kernel_module', 'not_a_module') _(resource.loaded?).must_equal false end - it 'verify kernel_module version' do - resource = load_resource('kernel_module', 'dhcp') - _(resource.version).must_equal '3.2.2' + # 15 + it 'Verify an unlisted kernel_module is not `disabled` - false' do + resource = load_resource('kernel_module', 'not_a_module') + _(resource.disabled?).must_equal false + end + + # 16 + it 'Verify an unlisted kernel_module is not blacklisted - false' do + resource = load_resource('kernel_module', 'not_a_module') + _(resource.blacklisted?).must_equal false + end + + # 17 + it 'Verify an unlisted kernel_module is not disabled_via_bin_true - false' do + resource = load_resource('kernel_module', 'not_a_module') + _(resource.blacklisted?).must_equal false + end + + # 18 + it 'Verify an unlisted kernel_module is not disabled_via_bin_false - false' do + resource = load_resource('kernel_module', 'not_a_module') + _(resource.blacklisted?).must_equal false end end