Tuesday, April 26, 2022

[SOLVED] SELinux syntax error when optional is used inside a tunable_policy macro

Issue

TLDR: An interface I'm trying to use contains a few "optional_policy" macros. Using it (or any form of "optional") inside a tunable_policy macro results in a syntax error. What is the correct way to accomplish this? See update below.

Long Version: I'm new to SELinux and currently working on a module to constrain a user application on Debian. One of the things I'd like to do is add a boolean to toggle network access. I created a basic policy module using the something similar to the following:

sepolicy generate --application -n mymodule /usr/share/foo/foo

I added a new tunable to the generated module.

gen_tunable(mymodule_use_network,false)

tunable_policy(`mymodule_use_network',`
   sysnet_dns_name_resolve(mymodule_t)
')

The interface call shown above was generated by sepolicy and I just moved it into the tunable_policy macro. Once I get the DNS working I'll move the rest of the network permissions in.

I have experimented using both the optional_policy macro and the plain optional statement directly. When using the generated script to build and load my module I get the following output in all cases:

Building and Loading Policy
+ make -f /usr/share/selinux/devel/Makefile mymodule.pp
Compiling default mymodule module
mymodule.te:65:ERROR 'syntax error' at token 'optional' on line 4858:
        optional {
#line 65
/usr/bin/checkmodule:  error(s) encountered while parsing configuration
make: *** [/usr/share/selinux/devel/include/Makefile:166: tmp/mymodule.mod] Error 1
+ exit

I have noticed that the file that defines these macros has a helper function regarding commented lines and m4, but I have no idea what it's doing. Is something like that my issue here? As a workaround I can copy the contents of the interface into my macro but that defeats the purpose. What am I missing here? Is it really the case that this is expected and no other tunable in the reference policy contains a nested optional statement?

Update:I've boiled it down to the following if/optional statement combination. According to the SELinux Notebook optional statements are valid within if statements in policy modules so I'm really at a loss.

if(`mymodule_use_network'){
    optional {
        require {
            type fonts_t;
        }

        allow mymodule_t fonts_t:dir getattr;
    }
}

Solution

Actually, it only now starts to sink in here that according to documentation "optional" statement is not allowed in conditionals.

A workaround is to wrap the "tunable_policy","if" or "booleanif" construct with an "optional" instead.

native module policy, something like:

module myfoo 1.0;
bool foo true;
type bar;
require { class process signal; }
if (foo) {
allow bar self:process signal;
} else {
dontaudit bar self:process signal;
}
optional {
if (foo) {
require { type baz; class file read; }
allow bar baz:file read;
}
}

or refpolicy, something along the lines of:

policy_module(myfoo, 1.0)
gen_tunable(foo, true)
type bar;
tunable_policy(`foo',`
allow bar self:process signal;
',`
dontaudit bar self:process signal;
')
optional_policy(`
tunable_policy(`foo',`
gen_require(` type baz; ')
allow bar baz:file read;
')
')

or native common intermediate language:

(boolean foo true)
(type bar)
(booleanif foo
(true
(allow bar self (process (signal))))
(false
(dontaudit bar self (process (signal)))))
(optional foo_optional
(booleanif foo
(true
(allow bar baz (file (read))))))


Answered By - dac.override
Answer Checked By - Candace Johnson (WPSolving Volunteer)