Skip to content

Commit

Permalink
(PUP-7126) Replace matchpathcon with selabel_lookup
Browse files Browse the repository at this point in the history
Since Selinux.matchpathcon is deprecated, selabel_lookup needs to be used
instead.

This commit replaces calls to matchpathcon with selabel_lookup by deprecating
get_selinux_default_context and replacing it with
get_selinux_default_context_with_handle. The new method requires a handle
since it calls selabel_lookup instead of matchpathcon and selabel_lookup
requires a handle.

Co-authored-by: William Bradford Clark <wclark@redhat.com>
  • Loading branch information
AriaXLi and wbclark committed Jun 3, 2024
1 parent 74811af commit fd32e68
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 12 deletions.
14 changes: 8 additions & 6 deletions lib/puppet/type/file/selcontext.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,13 @@ def retrieve
end

def retrieve_default_context(property)
return nil if Puppet::Util::Platform.windows?

if @resource[:selinux_ignore_defaults] == :true
return nil
end

context = get_selinux_default_context(@resource[:path], @resource[:ensure])
context = get_selinux_default_context_with_handle(@resource[:path], @resource[:ensure], provider.class.selinux_handle)
unless context
return nil
end
Expand Down Expand Up @@ -85,7 +87,7 @@ def sync
end

Puppet::Type.type(:file).newparam(:selinux_ignore_defaults) do
desc "If this is set then Puppet will not ask SELinux (via matchpathcon) to
desc "If this is set then Puppet will not ask SELinux (via selabel_lookup) to
supply defaults for the SELinux attributes (seluser, selrole,
seltype, and selrange). In general, you should leave this set at its
default and only set it to true when you need Puppet to not try to fix
Expand All @@ -98,7 +100,7 @@ def sync
Puppet::Type.type(:file).newproperty(:seluser, :parent => Puppet::SELFileContext) do
desc "What the SELinux user component of the context of the file should be.
Any valid SELinux user component is accepted. For example `user_u`.
If not specified it defaults to the value returned by matchpathcon for
If not specified it defaults to the value returned by selabel_lookup for
the file, if any exists. Only valid on systems with SELinux support
enabled."

Expand All @@ -109,7 +111,7 @@ def sync
Puppet::Type.type(:file).newproperty(:selrole, :parent => Puppet::SELFileContext) do
desc "What the SELinux role component of the context of the file should be.
Any valid SELinux role component is accepted. For example `role_r`.
If not specified it defaults to the value returned by matchpathcon for
If not specified it defaults to the value returned by selabel_lookup for
the file, if any exists. Only valid on systems with SELinux support
enabled."

Expand All @@ -120,7 +122,7 @@ def sync
Puppet::Type.type(:file).newproperty(:seltype, :parent => Puppet::SELFileContext) do
desc "What the SELinux type component of the context of the file should be.
Any valid SELinux type component is accepted. For example `tmp_t`.
If not specified it defaults to the value returned by matchpathcon for
If not specified it defaults to the value returned by selabel_lookup for
the file, if any exists. Only valid on systems with SELinux support
enabled."

Expand All @@ -132,7 +134,7 @@ def sync
desc "What the SELinux range component of the context of the file should be.
Any valid SELinux range component is accepted. For example `s0` or
`SystemHigh`. If not specified it defaults to the value returned by
matchpathcon for the file, if any exists. Only valid on systems with
selabel_lookup for the file, if any exists. Only valid on systems with
SELinux support enabled and that have support for MCS (Multi-Category
Security)."

Expand Down
32 changes: 29 additions & 3 deletions lib/puppet/util/selinux.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ def get_selinux_current_context(file)

# Retrieve and return the default context of the file. If we don't have
# SELinux support or if the SELinux call fails to file a default then return nil.
# @deprecated matchpathcon is a deprecated method, selabel_lookup is preferred
def get_selinux_default_context(file, resource_ensure = nil)
return nil unless selinux_support?
# If the filesystem has no support for SELinux labels, return a default of nil
Expand All @@ -68,11 +69,36 @@ def get_selinux_default_context(file, resource_ensure = nil)
end

retval = Selinux.matchpathcon(file, mode)
if retval == -1
return nil
retval == -1 ? nil : retval[1]
end

def get_selinux_default_context_with_handle(file, handle, resource_ensure = nil)
return nil unless selinux_support?
# If the filesystem has no support for SELinux labels, return a default of nil
# instead of what selabel_lookup would return
return nil unless selinux_label_support?(file)
# If the file exists we should pass the mode to selabel_lookup for the most specific

# Handle is needed for selabel_lookup
raise ArgumentError, _("Cannot get default context with nil handle") unless handle

# If the file exists we should pass the mode to selabel_lookup for the most specific
# matching. If not, we can pass a mode of 0.
begin
filestat = file_lstat(file)
mode = filestat.mode
rescue Errno::EACCES
mode = 0
rescue Errno::ENOENT
if resource_ensure
mode = get_create_mode(resource_ensure)
else
mode = 0
end
end

retval[1]
retval = Selinux.selabel_lookup(handle, file, mode)
retval == -1 ? nil : retval[1]
end

# Take the full SELinux context returned from the tools and parse it
Expand Down
9 changes: 6 additions & 3 deletions spec/unit/type/file/selinux_spec.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#skip if Puppet::Util::Platform.windows?
require 'spec_helper'

[:seluser, :selrole, :seltype, :selrange].each do |param|
Expand Down Expand Up @@ -50,13 +51,15 @@
end

it "should handle no default gracefully" do
expect(@sel).to receive(:get_selinux_default_context).with(@path, :file).and_return(nil)
skip if Puppet::Util::Platform.windows?
expect(@sel).to receive(:get_selinux_default_context_with_handle).with(@path, :file, nil).and_return(nil)
expect(@sel.default).to be_nil
end

it "should be able to detect matchpathcon defaults" do
it "should be able to detect default context" do
skip if Puppet::Util::Platform.windows?
allow(@sel).to receive(:debug)
expect(@sel).to receive(:get_selinux_default_context).with(@path, :file).and_return("user_u:role_r:type_t:s0")
expect(@sel).to receive(:get_selinux_default_context_with_handle).with(@path, :file, nil).and_return("user_u:role_r:type_t:s0")
expectedresult = case param
when :seluser; "user_u"
when :selrole; "role_r"
Expand Down
31 changes: 31 additions & 0 deletions spec/unit/util/selinux_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,37 @@
end
end

describe "get_selinux_default_context_with_handle" do
it "should return a context if a default context exists" do
without_partial_double_verification do
expect(self).to receive(:selinux_support?).and_return(true)
fstat = double('File::Stat', :mode => 0)
expect(Puppet::FileSystem).to receive(:lstat).with('/foo').and_return(fstat)
expect(self).to receive(:find_fs).with("/foo").and_return("ext3")
hnd = double("SWIG::TYPE_p_selabel_handle")
expect(Selinux).to receive(:selabel_lookup).with(hnd, '/foo', 0).and_return([0, "user_u:role_r:type_t:s0"])
expect(get_selinux_default_context_with_handle("/foo", hnd)).to eq("user_u:role_r:type_t:s0")
end
end

it "should raise an ArgumentError when handle is nil" do
allow(self).to receive(:selinux_support?).and_return(true)
allow(self).to receive(:selinux_label_support?).and_return(true)
expect{get_selinux_default_context_with_handle("/foo", nil)}.to raise_error(ArgumentError, /Cannot get default context with nil handle/)
end

it "should return nil if there is no SELinux support" do
expect(self).to receive(:selinux_support?).and_return(false)
expect(get_selinux_default_context_with_handle("/foo", nil)).to be_nil
end

it "should return nil if selinux_label_support returns false" do
expect(self).to receive(:selinux_support?).and_return(true)
expect(self).to receive(:find_fs).with("/foo").and_return("nfs")
expect(get_selinux_default_context_with_handle("/foo", nil)).to be_nil
end
end

describe "parse_selinux_context" do
it "should return nil if no context is passed" do
expect(parse_selinux_context(:seluser, nil)).to be_nil
Expand Down

0 comments on commit fd32e68

Please sign in to comment.