Author: Corey Minyard, MontaVista Software

Chapter 4: Overall Policy Structure 

In the previous chapter, we talked about using the OpenWRT policy in a policy file. However, we don’t have one big policy file. It’s separated into individual files in a fairly consistent manner. Looking in the `src` directory, you will find a lot of files ending in `cil` and some directories that generally have the same name as a `cil` file. This is a consistent theme in the policy, which is important to understand. A directory contains subclasses of a specific subject or object, the `cil` file will be the base class for those objects. Sometimes this has to do with directory structure (`/var` is in `varfile.cil`, `/var/run` is in `varfile/runtimevarfile.cil`), but more generally it has to do with function.

fs

The `fs` class has to do with things that might be generally mounted filesystems. They don't have to be mounted, but they are things you will mostly find in `/`, though there.

You use these for base access to the filesystems. If you need access to search `/tmp`, you look in `fs/seclabelfs/tmpseclabelfs.cil`. To be able to create a file in /tmp, you can see that the block `tmp` inherits from `.fs.obj_file_macro_template`, which has `addname_fs_dirs` as a macro. So we can add:

    (call .tmp.addname_fs_dirs (subj))

to an agent's block to allow it to create files in /tmp.

`fs` has two main subclasses, `seclabelfs` for file systems that have normal security labels, and `noseclabelfs` for files that are done (DOS, ISO9660, proc, SELinux, etc.).

xxxfile

In the `src` directory you will find a lot of files that match this pattern. You will also notice that many of these match things you see in the `fs` directory. This is by design, these classes are for files that are in specific directories.

file

The `file` class deals with file types. These are not so much about location as about function. Executable files, for instance, are handled in `file/execfile.cil`. If you create a file or have a file used by your agent, it needs to be represented by one of these types.

If you create your own context, you want to use one of the classes from the file directory to do this, depending on the purpose of the file.

`file.cil` also creates all the classpermissions and basic class information for all the permissions.

Example File Access

Let's say that you want to create the file `asdf` in `/tmp`. You want it to be labeled for your agent to preserve access and protection. It's a data file. First, let's create the macros for dealing with your datafile. Let's say your agent is named myagent, and you have a block with that name for it. In your agent block, add:

    ; Create macros and types for accessing our data files
    (blockinherit .file.data.obj_template)

This will create the `datafile_file_context` in our block. Now add the filecon entry:

    (filecon
    "/tmp/asdf"
    file
    datafile_file_context)

to properly label that file. But when we create that file manually, it will be labeled `u:r:tmp.fs` because that's what files are labeled in `/tmp`. You can find that in `src/fs/seclabelfs/tmpseclabelfs.cil`. You can look in that file and hunt through all the block inherits to find the transition rule. It's in block tmp, so we add:

       (macro obj_type_transition_datafile ((type ARG1))
              (call .tmp.fs_obj_type_transition
                    (ARG1 datafile file "asdf")))

This creates a macro that we will use to assure proper labeling of our file. At the top, outside our agent block, add:

    (in .file
        (call myagent.obj_type_transition_datafile (unconfined.subj_typeattr))
    )

This uses that macro so that the file gets created with the proper label. In essence, it will transition from unconfined to `u:r:tmp.fs`, per the rules in tmpseclablfs.cil, then to `u:r:myagent.datafile` per the above rule.

The basic principle is that, at creation time, object type transitions transition from one context to another based upon the rule. You follow the chain of object type transitions to find the final type.

Now we need access to the file. Add the following in your agent block:

       ; We create/delete /tmp/asdf
      (call .tmp.readwrite_fs_dirs (subj))
      (call manage_datafile_files (subj))

The first call allows us to create and delete files in /tmp. We could have used `manage_fs_dirs` instead of that, but that grants more permission (rename, etc) that is necessary. Use the minimum permissions necessary. The second call gives us access to our data files using the macro created in the `blockinherit`.

But we aren't quite done. If you do all this, when your program creates `/tmp/asdf`, it will not be in the `u:r:myagent.datafile` context. It will still be `u:r:tmp.fs`. But if you create it from an unconfined shell, it will be correct. That is because, in the type transition you added, you allowed `unconfined` to do the transition.

Currently `myagent.subj` does not have permission to do this. So one more rule in the myagent block:

       ; Allow myagent.subj to transition our file in /tmp/asdf
      (call obj_type_transition_tmpfile (subj))

And it should all work ok.

Example New Directory

Now suppose we want to create a directory `/var/lib/myagent`. Searching shows that `/var/lib` is in `src/varfile/statevarfile.cil`, so we will need to interact with that. First we inherit the class from there:

    (blockinherit .varfile.state.obj_template)

and we need `filecon` entries for our files:

    (filecon
    "/var/lib/myagent"
    dir
    statevarfile_file_context)
    (filecon
    "/var/lib/myagent/.*"
    any\
    statevarfile_file_context)

And we need the macro for state transitions when creating the file:

    (macro obj_type_transition_statevarfile ((type ARG1))
        (call .varfile.statevarfile_obj_type_transition
            (ARG1 statevarfile dir "myagent")))

And we need to call it in the file block:

    (in .file
        (call myagent.obj_type_transition_statetmpfile
    (unconfined.subj_typeattr))
    )

And, of course, we need access to our files:

    ; Access to /var/lib/myagent.  We grant full access.
    (call manage_statevarfile (subj))

This is a pretty standard pattern you will see.

You probably don't need an object type transition to allow `myagent.subj` to create files with the proper context, unless you are creating `/var/lib/myagent` from the program itself (thus the labeling done by restorecon won't set it). This is because `/var/lib/myagent` is labeled properly already by restorecon, and thus anything created underneath it will inherit its label.

agent

An agent is generally a program or a set of programs. `agent.cil` contains base class information for agents, and unsurprisingly, the `agent` directory has all the agents.

subj

`subj.cil` contains macros and templates for handling subjects. It also creates all the classpermissions and such for handling permissions for subjects. These are all pretty straightforward. The other SELinux documentation will describe these.

file_contexts.subs_dist

In the main directory (not in src) you will notice this file. It's a set of substitutions for directory names.  For instance, it has:

    /bin /usr/bin

which means treat everything in /bin as if it's in /usr/bin from a `filecon` point of view. This keeps you from having to create a ton of `filecon` entries for things that are basically equivalent.

What's with the `xxx_typeattr` and macros with "all" in them?

You may notice that some blocks have things in them that are similar, but a little different. For instance, in `src/varfile.cil`, we have:

          (macro readwrite_varfile ((type ARG1))
                (allow ARG1 varfile (allfiles (readwrite))))

and it inherits from .file.obj_all_macro_template, so we will also have:

          (macro readwrite_all ((type ARG1))
                (allow ARG1 obj_typeattr (allfiles (readwrite))))

The only difference is the obj_typeattr vs varfile. What would be the difference between:

    (call .varfile.readwrite_varfile (subj))

and

    (call .varfile.readwrite_all (subj))

obj_typeattr is a typeattribute, which is not a great name. It's really more of a type group, or type conglomerate. It can contain one or more types and using it is like putting all those types in that place. This policy uses it more like a type class. So `.varfile.obj_typeclass` is `/var` and everything inside `/var`, in essence everything that descends from `.varfile.varfile` (like `/var/run` and `/var/lib`), includes `.varfile.varfile`, `.varfile.runtimevarfile`, `.varfile.statevarfile`, etc.

The reference to `varfile` or `.varfile.varfile` if you fully reference it, is just to that specific type. So with that access you could look at files directly in `/var` and anything in there that has that specific context, but you couldn't open files in /var/run, which would have a different context.

So which should you use? 

Best policy says use the most restrictive one you can. If you need access to `/var/run` and `/var/lib` but not `/var/log`, don't use `.varfile.obj_typeattr`. That's not best security practice. Specifically, don't do:

    (call .file.manage_all (subj))

or anything like that. That would give you full access to everything, which would be counter-productive, even though it would be easier.

There is also a `subj_typeattr` in some cases, but you don't see that used much. It's the same basic principle, just for processes.

Conclusion

This overview should give you some tools to work on this, but you will struggle.

You need to spend some time digging through the CIL files, grepping for blocks, seeing what's in them, etc. Hopefully my blogs about our MontaVista’s customer case with SELinux will help you get past the initial hurdles I had to jump.

There is good support in the #selinux IRC channel and the SELinux mailing list. People are happy to help you understand things. You can also reach out to MontaVista for any questions and technical support on embedded security issues. 

-----

Learn more about MVSecure services and MVXpert services.