SELinux: How to create a CIL from a TE file
For a project, I needed to compile and install a SELinux module only when necessary. Unfortunatelly, there is no versioning on stored modules; I can't check and compare with the source module. I came up with an idea: using MD5 signatures.
Modules are stored in /var/lib/selinux/Policy/active/modules/400/ModuleName/cil
The Policy can be found with sestatus:
# sestatus SELinux status: enabled SELinuxfs mount: /sys/fs/selinux SELinux root directory: /etc/selinux Loaded policy name: targeted ...Stored modules are actually compressed CIL, which can easily been dumped with
bzcat:
# bzcat /var/lib/selinux/targeted/active/modules/400/my-httpd/cil (typeattributeset cil_gen_require httpd_t) (typeattributeset cil_gen_require default_t) (typeattributeset cil_gen_require sysstat_log_t) (typeattributeset cil_gen_require usr_t) (allow httpd_t usr_t (file (write create unlink setattr))) (allow httpd_t default_t (file (open read))) (allow httpd_t sysstat_log_t (dir (add_name write))) (allow httpd_t sysstat_log_t (file (open create)))Piping the result to
md5sum provides a signature.The trickiest part is transforming the source (a .te file) to a CIL. A TE files looks like:
module my-httpd 1.2;
require {
type httpd_t;
type default_t;
type sysstat_log_t;
type usr_t;
class dir { add_name write };
class file { open read write create unlink setattr };
}
#============= httpd_t ==============
allow httpd_t usr_t:file { write create unlink setattr };
allow httpd_t default_t:file { open read };
allow httpd_t sysstat_log_t:dir { add_name write };
allow httpd_t sysstat_log_t:file { create open };
Hopefully, both syntax are similar, so the transformation can be achieved via sed with this simple program:
# remove semi-columns
s/;//g
# remove comments
s/#.*$//g
# turn multiple space chars into one
s/[ \t]\+/ /g
# remove leading and trailing spaces
s/^ \+\| \+$//
# Turn { to (
s/ *{ */ (/
# Turn } to )
s/ *}/)/
# For each declaration of new type, add a line with the typeattribute,
# another line with the typeattributeset and a third line with the type.
s/^type \(.\+_t\), *\(.\+\)/(typeattribute \2)\n(typeattributeset \2 (\1))\n(type \2)/
# Turn the declaration of a existing type to a typeattributeset
s/^type \(.\+_t\)/(typeattributeset cil_gen_require \1)/
# Rule with 3 levels
s/^\(allow\|deny\|dontaudit\) *\(.\+_t\) \(.\+\):\(.\+\) \((.\+)\)/(\1 \2 \3 (\4 \5))/
# Rule with 4 levels
s/^\(allow\|deny\|dontaudit\) *\(.\+_t\) \(.\+\):\(.\+\) \(.\+\)/(\1 \2 \3 (\4 (\5)))/
# Remove any space before )
s/ \+)/)/g
# Remove lines not starting with (
/^(/!d
Then, to turn the TE into CIL, simply do: # sed -f te2cil.sed source-module.teHowever, another issue arose: the order of attributes within a class.
(allow ... (file (open create)))will not provide the same signature as
(allow ... (file (create open))).
Sure enough, I could check all my sources and make sure the attributes are in alphabetical order, but I always prefer automation. So I came up with this awk file which does the trick:
NF>4 { gsub(/\(|\)/,"");
for(i=5;i<=NF;i++) A[i-5]=$i;
n=asort(A);
C="";
for(i=5;i<=NF;i++)C=C" "A[i-4];
delete A;
print "("$1,$2,$3" ("$4,"("substr(C,2)")))"
}
Hence, getting the signature of the CIL becomes:
# sed -f te2cil.sed source-module.te | awk -f te2cil.awk | sort | md5sum
Finally, I make sure to sort the stored module as well:
# bzcat /var/lib/selinux/targeted/active/modules/400/my-httpd/cil | sed -f te2cil.sed | awk -f te2cil.awk | sort | md5sum

Comments