linuxsecuritydebianselinux

SELinux syntax error when optional is used inside a tunable_policy macro


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))))))