diff options
author | Sean E. Millichamp <sean@bruenor.org> | 2008-11-13 16:54:50 -0500 |
---|---|---|
committer | James Turnbull <james@lovedthanlost.net> | 2008-11-14 09:52:19 +1100 |
commit | cebadd9296ad9193f583f698ec77f0fc99ae6fc9 (patch) | |
tree | 99ea357263b9e010e4c8f30ae501f5629f39cceb | |
parent | 60455e708cbf3069a64ed4a0af6ce457c65c684e (diff) | |
download | puppet-cebadd9296ad9193f583f698ec77f0fc99ae6fc9.tar.gz puppet-cebadd9296ad9193f583f698ec77f0fc99ae6fc9.tar.xz puppet-cebadd9296ad9193f583f698ec77f0fc99ae6fc9.zip |
Fix bug #1681: Add filesystem type check to test for per-file SELinux context support
-rw-r--r-- | lib/puppet/util/selinux.rb | 64 | ||||
-rw-r--r-- | spec/unit/util/selinux.rb | 41 |
2 files changed, 105 insertions, 0 deletions
diff --git a/lib/puppet/util/selinux.rb b/lib/puppet/util/selinux.rb index 0df137370..70f244507 100644 --- a/lib/puppet/util/selinux.rb +++ b/lib/puppet/util/selinux.rb @@ -44,6 +44,11 @@ module Puppet::Util::SELinux unless selinux_support? return nil end + # If the filesystem has no support for SELinux labels, return a default of nil + # instead of what matchpathcon would return + unless selinux_label_support?(file) + return nil + end # If the file exists we should pass the mode to matchpathcon for the most specific # matching. If not, we can pass a mode of 0. begin @@ -144,4 +149,63 @@ module Puppet::Util::SELinux end return nil end + + # Internal helper function to read and parse /proc/mounts + def read_mounts + begin + mounts = File.read("/proc/mounts") + rescue + return nil + end + + mntpoint = {} + + # Read all entries in /proc/mounts. The second column is the + # mountpoint and the third column is the filesystem type. + # We skip rootfs because it is always mounted at / + mounts.collect do |line| + params = line.split(' ') + next if params[2] == 'rootfs' + mntpoint[params[1]] = params[2] + end + return mntpoint + end + + # Internal helper function to return which type of filesystem a + # given file path resides on + def find_fs(file) + unless mnts = read_mounts() + return nil + end + + # For a given file: + # Check if the filename is in the data structure; + # return the fstype if it is. + # Just in case: return something if you're down to "/" or "" + # Remove the last slash and everything after it, + # and repeat with that as the file for the next loop through. + ary = file.split('/') + while not ary.empty? do + path = ary.join('/') + if mnts.has_key?(path) + return mnts[path] + end + ary.pop + end + return mnts['/'] + end + + # Check filesystem a path resides on for SELinux support against + # whitelist of known-good filesystems. + # Returns true if the filesystem can support SELinux labels and + # false if not. + def selinux_label_support?(file) + fstype = find_fs(file) + if fstype.nil? + return false + end + filesystems = ['ext2', 'ext3', 'ext4', 'gfs', 'gfs2', 'xfs', 'jfs'] + return filesystems.include?(fstype) + end + end diff --git a/spec/unit/util/selinux.rb b/spec/unit/util/selinux.rb index 076ebd293..763dd3bf6 100644 --- a/spec/unit/util/selinux.rb +++ b/spec/unit/util/selinux.rb @@ -25,6 +25,38 @@ describe Puppet::Util::SELinux do end end + describe "filesystem detection" do + before :each do + File.expects(:read).with("/proc/mounts").returns "rootfs / rootfs rw 0 0\n/dev/root / ext3 rw,relatime,errors=continue,user_xattr,acl,data=ordered 0 0\n/dev /dev tmpfs rw,relatime,mode=755 0 0\n/proc /proc proc rw,relatime 0 0\n/sys /sys sysfs rw,relatime 0 0\n192.168.1.1:/var/export /mnt/nfs nfs rw,relatime,vers=3,rsize=32768,wsize=32768,namlen=255,hard,nointr,proto=tcp,timeo=600,retrans=2,sec=sys,mountaddr=192.168.1.1,mountvers=3,mountproto=udp,addr=192.168.1.1 0 0\n" + end + + it "should parse the contents of /proc/mounts" do + read_mounts().should == { + '/' => 'ext3', + '/sys' => 'sysfs', + '/mnt/nfs' => 'nfs', + '/proc' => 'proc', + '/dev' => 'tmpfs' } + end + + it "should match a path on / to ext3" do + find_fs('/etc/puppet/testfile').should == "ext3" + end + + it "should match a path on /mnt/nfs to nfs" do + find_fs('/mnt/nfs/testfile/foobar').should == "nfs" + end + + it "should reture true for a capable filesystem" do + selinux_label_support?('/etc/puppet/testfile').should be_true + end + + it "should return false for a noncapable filesystem" do + selinux_label_support?('/mnt/nfs/testfile').should be_false + end + + end + describe "get_selinux_current_context" do it "should return nil if no SELinux support" do self.expects(:selinux_support?).returns false @@ -54,6 +86,7 @@ describe Puppet::Util::SELinux do self.expects(:selinux_support?).returns true fstat = stub 'File::Stat', :mode => 0 File.expects(:lstat).with("/foo").returns fstat + self.expects(:find_fs).with("/foo").returns "ext3" Selinux.expects(:matchpathcon).with("/foo", 0).returns [0, "user_u:role_r:type_t:s0"] get_selinux_default_context("/foo").should == "user_u:role_r:type_t:s0" end @@ -62,9 +95,17 @@ describe Puppet::Util::SELinux do self.expects(:selinux_support?).returns true fstat = stub 'File::Stat', :mode => 0 File.expects(:lstat).with("/foo").returns fstat + self.expects(:find_fs).with("/foo").returns "ext3" Selinux.expects(:matchpathcon).with("/foo", 0).returns -1 get_selinux_default_context("/foo").should be_nil end + + it "should return nil if selinux_label_support returns false" do + self.expects(:selinux_support?).returns true + self.expects(:find_fs).with("/foo").returns "nfs" + get_selinux_default_context("/foo").should be_nil + end + end describe "parse_selinux_context" do |