One day your daemons become your enemies

v0.9.4.x stable version


ZeroMAC is a label/rule based Linux kernel LSM Mandatory Access Control security system.

The main goals of ZeroMAC:

The aim of this project, in a nutshell, is to create security entities and make the connection between them (with a kind of set theory and rules) in a snap, providing efficient protection against zero day attacks.

ZeroMAC uses the standard LSM hooks as SELinux but has a quite different structure and simple configuration for easy and effective use.

It cannot be used as a loadable module, because as a module it could not give you the basic functionality which is an important part of the project, provide security right from the very first code load and execution.

You can create label/rule environments to meet the Bell-LaPadula security model as well as Biba but optimised without strictly following the papers.

By default, it does not have the (numeric) linear security level structure and its dedicated fields (do you know about any real existing organizational structure which can be covered by the simple linear MLS theory...?) Although, you can implement read down, write up by labels and rules in seconds.

There is no official mechanism at the moment, which assigns labels on user login, I'll write a pam.d patch set later (maybe for v1.0). (currently, it is more secure without it, but there is an existing workaround to implement, contact me if you would like to use it)

There are lots of kernel configuration options to choose from, you can completely skip compiling the logging and user interface (and a few more) subsystems if you use it in embedded systems.

You can create forced label files or directories, which will be stored in the file system, in extended attributes. It is a very important aim to provide a way to keep the security labels on files consistent, and have to relabel only temporary file systems at boot time. If you do not boot up without a ZeroMAC enabled kernel, probably need no relabel your filesystem.

A very important difference to other LSM based systems, if you copy or move (!) a file or directory to a forced label area, it will change the access label to the forced one. For example, if you create a web root directory, and you set the tree as the forced label to 'webdata', all files and directories will have this label, no matter which process created or moved files there. Any process can place there files only if they have write access to 'webdata' label (and of course can pass the directory walking).

In ZeroMAC, only the admin can change label, or admin can grant a process to change (to specific) label(s). Although admin can give other labels the right to update (specific) ZeroMAC labels or even use the security console's given commands.


To operate ZeroMAC, you have to compile a Linux kernel with the patch (see install section), you need to label your files and directories, you have to create the configuration and rules and you are ready to go. Please read the whole documentation before you try.


ZeroMAC uses labels to identify security contexts for processes, files and sockets and other resources and uses rules to declare the relations of them. There are three kinds of labels, the access label, which is the security identification of the resource or process, the execute label which declares what label change is required if the actual file or directory is executed or used and the create label, which will use the process to create new files.

All labels are limited to 16 characters and can contain letters, numbers, + - _ characters and are case sensitive.

All resources have to have at least one label, the access label, processes should have two labels "access:create", inodes (files and directories) should have three labels, "access:execute:create", and sockets or other resources could have only one, "access" label.


Every process has a label. The process label is the label the owner had when started the process. Every file, directory, or socket has an access label.
Every process has (label level) rights to access all the files and resources which has the very same label but cannot access other label's processes and files unless you create a specific rule to do so. If you do not have rules for a label, then that process and related resources will be isolated from the other labels.

The label named underscore "_" has a special meaning, it is the undefined label. (otherwise, it works the same, you can declare rules for it as usual). If a file has no ZeroMAC access label, it will have an undefined label. (current version 0.9.4.x can handle it as an ordinary label, but current userspace utilities handle it a different way, this could change soon, read later)

If a process will create a file, it will be created by the label of the process. The process cannot change its label, there are two exceptions: execute labels and setting it through /proc/self/attr/current, but the later depends on compile-time options. (not allowed by default)


All the inodes (files and directories) should have an execute label. If there is an exec label and the file executed, the process access label will get the execute label of the file. (else the new process will get the label of the process who executed the file) If a directory has an execute label, files and directories will be forced to get this label as access label, and created directories will have the same access and exec labels, therefore you can be sure if you create a directory with an exec label "foo", all components of that tree will be created with "foo" label, no matter if you create the file there or move there. Files and directories will change labels even if the admin will write or move to there, but admin can change a file or directory access label in a forced label directory.

Please note, all processes can change their label only if you create a rule with "C" change label privilege. For example, if you have a rule (system apache C) then system label can run a file with apache execute label, and the created process will have the apache label.


If an executable file has a create label, when you execute it, the process will get its create label, and all the files it will create will get this label as an access label. This way you can easily separate the files for a label that can read and execute, and files that can write, but cannot execute. (Read the "How to build ZeroMAC security" section for details)

Please note, if you use create label, then you need to apply a rule which will allow your process access label to create files as the create label. If you will not allow it, the process cannot create files, but still can read/write the ones with its access label. (unless you restrict to write its own label by a rule of course)


The access matrix for the labels are defined in rules, it can be used to declare the relationship between labels. The rules are defined in
<subject> <object> [access] [/deny]
form, where the subject is usually the label of the process, the object is the label of the resource, (task, file (inode), socket, etc.). Whitespaces are needed between and after the labels. It is allowed to have 0 or more whitespaces anywhere in the access or deny sections and between them. The rule is valid if it has access or deny privileges, or if it is empty. An empty rule is like
system webdata .
Dot is a fill character, but it is a valid "empty" privilege set in itself. Access and deny sections are letters that represent privileges.
A rule with all the privileges allowed looks like this:
system webdata rwaxsijgpemtcyzl
If you would allow learning but you would not like to ever learn right to write, append and change label, read and write ZeroMAC access labels and mount volumes looks like
system webdata l / wacyzm
The rule provides access for the subject label to resources labelled by the object label with the access rights defined by the access privileges and will deny all the requests which are in deny privileges. Whitespaces (ASCII 32) are allowed in rules everywhere. Deny privileges starts with "/" character which was "!" in previous versions, but changed because of the convenience in shell commands.


Privileges are rights that subject can have on the object. Privileges are grouped based on functionalities, and assigned a letter for each of them, to make it easy to handle with a few characters. If you need different groups, you can change them in seconds (hacking the source code). If you list privileges, you will get it padded with dots, and positioned to the same column (for easy reading).

There are label level privileges that are granted default for labels if they access resources with the same label and system-level privileges which provide access to the system. Letters that represent the privileges are not case sensitive. If you see the log, you will see all the privileges which are asked as lowercase characters and uppercase the letters which are rejected or learned. They are the same if you use them in rule declarations.


Label level privileges affect directly only the subject and object label. (Subject can do something on the object) If the subject and object labels are the same, all label level privileges are allowed by default (although you can restrict it if you create a rule with fewer privileges, see rules priority section, same subject and object label)

can read files and can see contents of directories
can write files, directories
can append files (write privilege also provides append privilege too)
can execute files
can read write sockets
can use inter-process communication
it will allow all kinds of inter process communications, (ipc, shm, sem, msg_queue)
can mmap files
please note, mmap access will be checked only when mmap is asked, so the further read-write operations cannot be checked, and cannot be revoked, even if the mmap access is cleared, or the file relabelled!
can send a signal (all signals, kill, term, sighup etc)
can ptrace and supervise other processes
The process with the subject label also can see and list the processes of the object label.
Maybe I'll rename it, it covers not only ptrace but other rights to get info about object processes.


System-level privileges affect not only subject and object labels but the whole system, and therefore affect other labels, or can change system behaviour somehow. System-level privileges could be harmful, handle those with special care, especially if you create wildcard rules!

write files that have exec label object
writing files with an exec label can be dangerous, an attacker can put there malicious code
can mount file systems
can mount file systems as a trusted mount
the process with the subject label is allowed to change its label to the object label. It is allowed in one direction.
the subject can run a file with execute label of the object only if it has this privilege
or can write a new label to /proc/self/attr/current if it is allowed by the kernel configuration
the subject can read zmac security label if the label is the object
the object can write zmac security labels (have to have this rule for the old and the new labels too)
(this could be changed in future)
the subject can learn privileges to object (see learning section)
bypass higher priority rules, if you use this privilege in a rule section, this section will override any other rules, even the higher priority rules. Use it with special care, and only if you need it!
If you use it in an access section, it will affect only the access section and not deny. You have to use it Access and Deny sections too if you would like the current rule the highest priority of all.


These privileges are asked in some parts of the ZeroMAC security system, but cannot place them in rules, and the system cannot learn these. You can see these letters in log files when access is requested for some reason.

this is an access right that will be asked on some operations, which are allowed only if the subject is the admin
only admin can open and use the user interface console, but there are exceptions, for example when no admin label is declared, or grant/revoke subsystem is chosen as a kernel compile option, or when admin label is not declared, and even it is not allowed to other labels to be admin until admin label declared. The system asks permission to the user interface with this special privilege.
There is no privilege for module loading and unloading at the moment because I do not use modules at all. For embedded systems modules are pointless, for servers modules are not secure (and pointless). But if you use modules, (for desktop systems the modules are a must-have) it is very important to allow only specific modules to load, so I'll create privilege for module handling soon. (this summer maybe)


If you would like to apply a rule for all the labels on a position, then you can use the wildcard label. The wildcard label is "%", it can be used in rule declarations in itself to represent all the labels. It cannot be used to substitute some letters in a label, it can be used only in itself in place of a label. (Previously it was "*", but changed to "%" for shell commands convenience.)
For example the rule
system % rw
means system label has read/write access to all the other labels. Or rule like
% apache /rwax
means none of the labels should have read/write/append/execute access to "apache" label. (unless if you have a higher priority rule)


The more exact the rule has the more (higher) priority. If you use wildcard labels in rules, there are 4 priority levels,

4 % %
3 label %
2 % label
1 label label

the lowest priority is when the rule has a wildcard as the subject and object too. Higher the priority if the subject is a label and the object is the wildcard, etc, and the literal rules which have exact labels for subject and object have the highest priority. The higher priority rules will overwrite the access rights of the lower priority rules. (Access sides will be added to the Access result of the different priority rules, as well as the Deny sides, but when a higher priority rule has the same privilege on the opposite side, then the higher priority rule will overwrite the lower priority.)
For example, if you have rules like:
samba % rw % log /rw apache log r
The first rule has the lowest priority, if there are no higher priority rules declared with the opposite meaning, samba can read and write all the labels. The second rule has higher priority, and it says no one can read and write log labelled files and directories, therefore even samba cannot read log labelled files (just because it has higher priority). The last rule is a literal rule, which has the highest priority, which says apache can read log labelled files. (if you doubt the applicable privileges for two labels, there is the "check rules" console command, which will show you the result for the given labels, read later) Remember, all the rules which contain wildcards can be created and deleted by admin only (learning procedure creates literal rules).

And finally, if you have a literal rule for the same subject and object label, that has higher priority than the system's default behaviour, to allow label level privileges for the same label, and will override it. It means, for example, if apache label would like to write a file which labelled as apache it can do it, because "write" is a label level privilege, but if you declare a rule like
apache apache rg
that means apache can read apache and can send a signal to other apache labelled processes, but if we have a specific rule like this, and "write" is not allowed there, it cannot write. This way you can restrict the labels on themselves, which is very important for several reasons, read later...

The recording, storing, listing order of rules has no priority for the rules, priority will be calculated on the contents of the rules only. The rules will be processed at the very moment of each request.

There are some special cases when you have a lower priority rule, but you would like to apply it even if we have higher priority rules. You can do it if you use '=' privilege at the given place in your rules. For example, if you say
set rule backup % =rwaezy set rule % log /w
then it will override higher priority rules, and backup labelled processes can write log labels even if you have a higher priority rule, which denies all write access to "log" labels. It is important, override higher priority rules scope is valid only for the given access or deny rule section. You can use this privilege for different priority levels, this time the higher priority BHPR sections will apply.


The double wildcard label "%%" can be used to select all existing labels, and can be used only in handling rules, and cannot be used in rule declarations. The double wildcard will select all the existing labels in a given position, even it will select a (single) wildcard label there. For example, the next ZeroMAC console command will delete all the rules which have foo as subject:
delete rule foo %%
another example, if you have rules:
apache % r apache webdata rw apache log s
and you say
delete rules apache %
it will delete only the first rule (because a single wildcard is a specific label used in rules), but if you say
delete rules apache %%
it will delete all the rules which have apache as the subject.

This will delete all the rules:
delete rules %% %%
(read about this later)

To be clear: The (single) wildcard label can be used in rules, and it represents all the labels (meaning all the labels which are existing now and will exist in the future). Double wildcard label can be used only when handling rules, and it selects only rules with existing labels, it is used to select a set of rules to which you will apply modifications. (Please let me know if it is not clear this way.)


You can declare one label as the admin label. The process with the admin label has full access to all labels on the system. Admin can override every rule. Only the admin can change the labels of files and directories and set the rules which regulate how the labels can interoperate. Only the admin can access the ZeroMAC user interface and even the ZeroMAC security labels on any mounted disk. (There are exceptions, see Z,Y privileges, and grant/revoke console commands. You have to compile in these options to the kernel if you would like to use them.)

Initially, the admin label is not set, which means all the labels are admin labels on the system, you have to set the admin label as early as you can do to "seal" ZeroMAC. I highly recommend setting the admin label before boot. You can do it by a kernel configuration option, this way you will boot up with an already sealed kernel.
You can set/change the admin label with userspace (command line) utility:
za admin
or the console command:
set admin admin


Transactions are batched commands which are processed at once when the transaction is committed. Transactions are very important for several reasons:

The first reason is consistency. All the rules can be deleted and created from the ground up in a transaction, do not have to worry about how to change the current rules to get the desired rule set. Partial delete and recreate of rules (or modifications) are also possible. The operating modes and rules can be set at the same time, so after the transaction is committed, you will get a consistent rule/mode set, which cannot be modified by any other learning request or another console submission. Actually, you can save your current running config and reload it any time.

The second reason is transactions are fail safe. You can create rule sets and apply them whenever you want, even when you are under attack, and you are low on resources. The transaction mechanism will guarantee, all the modifications will take place only if there are no errors in the transaction. (Out of memory, syntax error, etc). If there are errors in the transaction, then it will be discarded completely, never applied. If there were no errors, they will be committed, and all rules and settings will be applied at the same time. You can be sure about your current rules will be untouched if the transaction is discarded or rollback asked.

The third reason is atomicity. Sometimes more than one rule will give you the needed results. You have to take special care, what rules you have at the moment, and in what order you have to apply the rules for a flawless operation. For example, you will create a low priority rule which will reject lots of requests for a set of labels, then will create a rule (or rules) for the exceptions as a higher priority rule. If there are requests between the time you apply the rules, they will be rejected, which you do not want in an operative environment.
Transaction mechanism guarantee atomicity, which means all the commands will be applied at once, and will not be distracted by other modifications submitted any way to ZeroMAC.

You can start more transactions that overlap each other, they will be applied in the order of transaction closing commit commands issued. Transactions will not keep the state of the settings at the beginning of the transaction, therefore other's console sessions or the ZeroMAC system itself can apply modifications while you record the content of the transaction. If you write the transactions directly on the console, you can list the current rules if you already started the transaction.
Please note, if you leave the console session (accidentally or intended) while recording the transaction commands, the transaction will be discarded, none of the commands will be executed. If there is an error in the transaction, the system will still check the rest of the commands if there are errors or not, and will be reported.

Transactions are very important if you change console access settings because if you change the admin label, or apply a revoke command (and revoke will take access rights from your current label), you will lose the right to execute the subsequent commands, but using transaction, all commands will be executed if you had access when you issued the transaction commands and commit. If you lose the console access before committing the transaction, an access error will occur and the transaction will be discarded.

You can start the transaction with the console command
and you can commit it with the command
if you do not want your transaction to apply, you can say
and you will quit from the transaction, and all commands will be discarded.

Also note, the
reset learned
command also runs like a transaction in itself, so all learned rules will be rolled back atomically (see LEARNING section). (Also, you can use it in a transaction as an ordinary command.)


There are different operating modes (depends on compile options, see there).
Admin can change between them any time with the (set mode to enforced) console command or with (zm enforced) userspace utility. Compile-time you can tell which mode to start with.
Operating modes are:

All the rules are active, access requests are granted and rejected upon the rules. It is allowed to learn rules if it is enabled by the rules. (see learning section and MAY_LEARN privilege)
This is the default mode if you do not allow mode switching in compile options. This is the only mode you need in a production environment.
Only deny sections of rules are active, so all access requests are granted which are not denied explicitly in rules. As rules access sections are not active, MAY_LEARN privilege is out of order too. Please note that all rules access and deny sections will be used in the rule's calculation (with the priority concerned), and the resulting deny sections will be applied. So if you explicitly allow a privilege in a higher priority rule will override deny mask in a lower priority rule (as in other modes). Please note that admin access is allowed only for admin, so the user interface can be accessed only admin. If you allowed Z,Y privilege compile-time, then reading and writing of ZeroMAC file system labels are allowed. You have to explicitly deny these if you do not want it (highly recommended.)
None of the rules are active, but filesystem and process labels are handled, so any label can run any executable and will get its access label. Be aware, if you switch back to enforced mode, unauthorised processes will not be killed, but rules will be applied, so maybe (upon the rules) they cannot access resources, you can render your system unusable. (be careful) Please note that admin access is allowed only for admin, so the user interface can be accessed only admin.
All rules are active, but all requests are granted which are not denied explicitly in rules and security violations will be learned as literal rules. (after learned, and inserted in rules, there will be no violation for the same request next time). Remember, rules deny sections are active, if you declared what cannot be learned, will be rejected.
restricted learning
All rules are active, label level security violations will be learned as literal rules. Restricted learning mode is the same as the learning mode, except system-level privileges are not learned, they will work like in enforced mode. Please note, as all rules are active, if you explicitly allowed learning for labels by MAY_LEARN privilege, they will learn even system-level privileges unless you set to deny them.
All rules are inactive, filesystem labels are still handled, so forced labels will be applied, but anyone can do any write operations without restrictions. (off mode is about to change, the doc will be updated soon) Please note, if you switch to off mode, you cannot switch to any other mode after it. This is the only mode in this regard.


Learning means ZeroMAC can learn rules which are needed to pass the security violations that happened. Learning mode always creates or modifies only literal rules (rules without wildcard labels). No matter how you switched to learning mode, rules deny sections are always checked, and if something is denied by the rules, that will be rejected and not allowed to learn by any circumstances. It is very important, that learning will learn label level rules even if the subject and object labels are the same. If you are not in learning mode, that will not rise a security violation, so it would be logical to abandon learning for this situation, but learning is about getting the least privileges that are enough to complete the operations asked. (Another very important reason is if you can restrict the access rights for the same label and if we do not learn label level access, and after a while, a rule created with system-level rights, then all the previous label level rights will not be added to the rule, which renders your system unusable... so believe me, you need it, this way)
It is important to note, if your system behaves somehow when you use learning, it does not mean, it will do the same next time. So if you learn rules, you have to be careful about if the application can run other possible ways.
It is also important to know, learning mode will not organise the labels and the security system for you, it will give you only a hint, what security requests you have to allow if you would like to use the system the current way. Sometimes it will show you it needs privileges which you would not allow them to use, and you have to relabel your files, directories and maybe running applications to make your system safe. If you fire up a daemon and you are allowed to learn rules for it, and the system created rules which you do not like, you can stop the daemon and can use "reset learned" console command to rollback all that it has learned.

There are two ways to use the learning mode:

The first method is to switch to "learning" or "restricted learning" operating modes. This way the system will modify and create rules as needed when a security violation occurs, for all the labels. Restricted learning means only label level rules are learned, this is less harmful) To switch you can use "zm" userspace utility or the
set mode to learning
console command.

The other way is to use MAY_LEARN privilege, and this is more interesting :)
You can use the console command
set rule mysql log L
to set mysql label to learn any privileges if there is a request for "mysql" as subject and "log" as the object.
(I wrote a capital L here, but only because small-cap l maybe not be readable with some browsers, but you can use either l or L here.)
If there will be a security violation, this rule will be modified. If you would like to stop learning for this particular rule, you should say:
modify rule mysql log -L
this will remove MAY_LEARN privilege and learning is stopped for this rule. (but the learned privileges will stay)

Remember, you can use MAY_LEARN with wildcard labels too, and rule priority will apply as usual, so if you say
set rule mysql % L/yz set rule % admin /L set rule % apache /emcyz
that means mysql can do and learn anything (L), but cannot read and write ZeroMAC labels on the filesystem (/yz), none of the labels can learn anything to admin label by the next rule, and finally cannot learn system-level privileges to apache label. The last two rules are higher priority rules than the first one, so they will overwrite the first on their scope. (see "RULES PRIORITY" section) (This is a bad example anyway, only for illustration, do not use it like this.) In the "INSTALL" section you can find examples of how to set up ZeroMAC, and how to use learning mode to fire up a new daemon.


Userspace can communicate with ZeroMAC security system by the security console, which is an ordinary asynchronous character device. Only the admin labelled process can open the ZeroMAC security console. (see exceptions grant/revoke console commands.) If the admin is not defined, then any process can open and use it.
You can open it from any application if the application has access rights to the console file. There are two ways you can compile in the console, as a device node in the devfs file system (default: /dev/zmac), or you can have it in proc filesystem (default: /proc/zmac). If you choose to have it in devfs, you can rename, remove etc the console device file, and you can place it anywhere, you can even create it in your home directory with:
mknod ~/zmac_console c 250 0
you can list devices with
cat /proc/devices
and you can find there the major device number of zmac at character devices.

If you choose procfs, you can access the console at /proc/zmac. On this location, you cannot delete, rename, or destroy it. (be sure attacker cannot unmount /proc). Do not forget to set the console file location in userspace utility compile-time.

All the console commands and answers are human-readable. (you can directly open the console with the "zc" userspace utility, see there) The commands are case sensitive, all lowercase letters. All words in the commands can be substituted by (at least) the first 3 letters. Label names cannot be shortened.

You have to close every command line with an LF character. To close the console session, you can send an (ASCII 0) character as an EOF, or use the exit command with LF at the end (or you can simply close the console if you finished, and got all the answers). No commands will be executed after EOF or exit. After the console executed the last command, (and got EOF somehow), it will send 0 length response as EOF, it is safe to close the console after it.

You can send more commands in a batch, the console will process them in the order they issued and will respond to each command (almost). The commands which are not closed with LF or 0 characters will not be processed! The whitespace characters are the space (ASCII 32) and tab (ASCII 7). Any number of whitespace characters are allowed, but you need at least one between the command words and labels, etc. You can have empty lines, and you can have remarks after console commands, remarks must start with "#". All characters are handled as remarks until the end of the line and will be dropped. Quotes are not allowed and there is no (any kind of) escape character. If you exceed the maximum size of a line (which is more than enough), the whole line will be dropped, and you will get an error response.

All the answer lines are closed with LF. You can use the console in two modes: user mode or API mode.

If you open the console, user mode is the default, you have to send the command "api" to switch to API mode. (there is no way to switch back to user mode) (API mode is designed for userspace utilities, if you talk to the console directly, you don't need to change to API mode) There are two kinds of responses you can have: Single line responses and multi-line responses.

Single line responses are result lines. Result lines are composed of an integer response code in square brackets, a white space and a result text, which is closed by an LF character. Like this:
show version [6] Current version is: v0.9.4.1
If there is no error, then the API response code is positive, it usually identifies the type of answer. If there is an error, the response code is negative.

The multi-line console API responses are composed of one or more status lines and 0 or more content lines in the body, and a result line at the end. The multi-line response always starts with a status line and ends with a result line. (all responses must contain one result line, and only one)

The status line is composed of one opening square bracket, then an integer status code, a white space, and a status text, closed by an LF character. (there is no closing bracket in the status line!) Content lines cannot start with the opening bracket, so if you are in API mode, and see a line that does not start with the opening bracket, you know what it is.

If you use the console in user mode, then single line responses will contain the result text only and multi-line responses will contain only the content lines (and status and result texts only if there is an error, but they will be printed without the API response codes). All the answers are human-readable, composed with code page ISO-8859-1.

If you use the userspace console utility (zc) to submit a single command, it will show you the responses in user mode. (but in the background it needs the answers in API mode to get the error codes for return to the shell, and get the idea if print the results to stdout or stderr.)

An API mode multi-line response should look like this:
show rules [13 List of rules system admin r..x.....ce..y. /............... #r..x.....ce..y. system kernel rw......p...... /............... #rw......p...... system _ rwaxs.j....mtyz /............... #rwaxs.j....mtyz system system /............... kernel system /............... kernel kernel .w....j........ /............... #.w....j........ kernel _ /............... [13] Ok
Please note, usually, you will get the name of the list in the first status line, and the response error status in the last (result) line. We should say, all the console command API responses will get one line started with closed brackets, with a response code in it, and all will be positive if no error, and negative if had error(s). Future commands should send more status lines, and some of them could be negative which should mean there were syntax or other errors in execution, but you have to use the last line's (result line) response code to evaluate the success of the response.

(This is simple and logical for me, but maybe not for the readers. If you think this part (or any part) of the docmuentation is not clear enough, please let me know, then I have to improve!)

The error codes reserved for the console are from -20 to -99.
The current errors are:
[-20] Line too long, discarded [-21] Syntax error [-22] Invalid parameter [-23] Incorrect api version [-24] listing interrupted by concurrent operations (only show rules, show config currently) [-25] Out of memory [-26] Access denied (only if UI_GRANT compiled in) [-27] Admin label cannot be modified after set due to the configuration [-28] Command not registered due to previous errors [-29] Error in transaction, discarded [-30] No transaction started


The console commands are:

This is the console NOP command, it does nothing, you can use it to check if the console is ready and connected.
helo [1] ZeroMAC console is ready.
api has more functions. First of all, it will switch the console to API mode, so all the commands issued will be answered with API response codes. Api command will not answer in itself, only if in a case of an error. The other function is to check the console version, to be sure your subsequent commands will work as expected. If you write the desired major version number after API, or write the major.minor version, for example:
api 2.0
it will check if the console current major version is the same as you sent, and if the minor version is higher or equal to what you sent, and will not answer if it's ok, but if differs, it will answer with an error code, and will close the console.
api 3.4 [-23] Incorrect api version requested, console session aborted. The requested version is 3.4, the current version is: 2.0
set rules
Syntax is
set rules <subject> <object> [access] [/deny]
If you use a double wildcard label, then it will select more rules and will modify existing rules, if you give specific labels, it will update the rule if exists or will create one if not. It will report the number of rules which are filtered or handled. (no matter if they are really modified or not) You can set only valid content, which means it must contain access or deny section. If you leave the access or deny section clear, it will clear that section.
set rule system log rs [15] Rule(s) set successfully. (1) show rules [13 List of rules system log r...s.......... /............... [13] Ok
Remember, a wildcard label is a specific label, which represents all the labels in a rule. (if it is not clear, and you cannot understand it, then the documentation is bad... please let me know.)
modify rules
Syntax is
modify rules <subject> <object> [+][-][access] [/ [+][-]deny]
Modifying rules is different from setting rules because it will add or remove privileges. If you write + before the privilege, it will add, if write - it will remove. The same for denying section, but you have to start the deny section with a slash. Modify rules will not create a rule, it will only modify the selected ones. You can use the double wildcard to select more rules. It will report the number of selected rules.
modify rules system %% -g/+g [17] Rules modified successfully. (5)
This operation will be successful even if cannot select rules to update. This time you will get an error message with a positive response code.
modify rules apple ibm +r/-s+x [18] Not found rules to modify.
delete rules
Syntax is
delete rules <subject> <object>
Delete rules will delete the selected rules. You can use the double wildcard to select more rules. It will report the number of deleted rules.
delete rule system %% [19] Rules deleted successfully. (5)
This operation will be successful even if cannot select rules to delete. This time you will get an error message with a positive response code.
check rule
Check rule will help you special cases to find out what permission will be applied for a given subject and object.
check rule <subject> <object>
This will show you the access / deny sections and this equals to the applied result.
check rule system kernel [10] Rule check result: system kernel r..x....p...... /............... = r..x....p......
This operation will be successful even if cannot find given labels. This time you will get an error message with a positive response code.
set admin
You can set admin label with the syntax:
set admin <admin label>
This will show you the access / deny sections and this equals to the applied result.
set admin admin [14] Admin label changed to: admin
If you would like to clear the admin label, you have to set it to undefined label (underscore). This way all labels will get admin rights! If the admin label is invalid, or cannot be set by any reason, you will get an error.
Remember, you can set the admin label to a currently not existent label, so if you mistype the admin label, you will not get an error, but maybe you will render your system unusable.
set mode to
You can change the current operating mode with the syntax:
set mode to <mode>
For example:
set mode to restricted learning [2] ZeroMAC mode changed: restricted learning
If mode change or learning mode is not allowed in the kernel configuration, you will get a syntax error. Remember, if you use it in a transaction, the whole transaction will be aborted on any errors, and this is the case with syntax error! (intentionally)
I've made grant and revoke commands only for test and debug purposes, maybe I will remove it before public release.
If you compile in the grant kernel option, you can give user interface access rights to other labels, with the syntax:
grant <comma separated rights> to <label>
For example:
grant mode,show to system [24] Console access modified successfully.
The current access rights are:

all - all existing rights
rule - modify and list rules
label - list labels
admin - set and get current admin label
mode - set and get current operating mode
show - get any information from the console, cannot modify anything
grant - right to grant and revoke rights to another label

You can use the double wildcard label to apply grant for all labels.
You can revoke user interface access rights from other labels, with the syntax:
revoke <comma separated rights> from <label>
For example:
revoke all from system [24] Console access modified successfully.

You can use the double wildcard label to apply revoke for all labels.
show grants
This command will show you all the labels and their granted console access rights, for example:
show grants [22 Show grants grant mode,show to system [22] Ok
Remember, admin always has full access to the console, nobody can revoke it from admin, and admin is not listed here.
show admin
This command will show you the current admin label. For example:
show admin [8] Current admin label is: admin

show mode
This command will show you the current operating mode. For example:
show mode [5] Current mode is: learning

show labels
This command will show you all the labels ZeroMAC registered at the moment. For example:
show labels [12 List of labels admin kernel system _ [12] Ok

show version
This command will show you the version of the ZeroMAC security system. For example:
show version [6] Current version is: v0.9.4.1

show rules
This command will show you the current rules. For example:
show rules [13 List of rules system admin r..x....pc..... /............... #r..x....pc..... system - rw............. /............... #rw............. system kernel r..x....p...... /............... #r..x....p...... system _ /............... system system /............... kernel system /............... kernel kernel ......j.p...... /............... #......j.p...... kernel _ /............... [13] Ok
You can find the columns for subject, object, access privileges, deny privileges, and at the end of the line you will see what privileges are learned since the last time you switched to learning mode. (this is very handy, see "reset learned" command)
show config
This command will show you the current running-config :)
For example:
show config [23 Current config api 2.0 start delete rules %% %% set rule system admin r..x....pc..... /............... set rule system - rw............. /............... set rule system kernel r..x....p...... /............... set rule system _ /............... set rule system system /............... set rule kernel system /............... set rule kernel kernel ......j.p...... /............... set rule kernel _ /............... revoke all from %% set mode to learning set admin admin commit [23] Ok
Using this command you can see and save the current configuration of ZeroMAC. All the listed lines are in console command format, so you can run them (or parts of them) in a console session. It is embedded in a transaction, so all the changes will take effect only if there are no problems with any of the commands. If you reload this config, you can be sure about you will get the very same rules and settings. Please note, you have to load this configuration in a kernel/console with the same ZeroMAC kernel configuration because some parts of the configuration will be processed only if it has the same kernel config, and commands available. (later maybe I will implement a kernel config check method)
For more info see the Transaction section.
show api version
This command will show you the current version of API. For example:
show api version [7] Current api version is: 2.0

Actually, this is the version of the command set. The first number is the major, the second is the minor version number. If there will be new commands, but the rest are backwards compatible, the minor version will be higher, if new commands are not backwards compatible with the old ones, or some of the commands are missing, then you will see a new major version number.
reset learned
If you change the operating mode to one of the learning modes, the system will start to record what privileges are learned for what rules, it notes what rules are completely created by the learning procedure. If you list the rules, you will see these learned privileges in the last column (starting with #). If you send the reset learned command, all the learned privileges, or the complete rules will be deleted, which are created and learned since the last learning mode change.
It is very important to know if you start learning by adding MAY_LEARN access privilege, that will not clear the list of what the system learned. (maybe I'll introduce a new command for it if you need this, but you can switch to learning mode and back in a transaction to clear the gathered info now...)

(maybe I'll rename this command before public release, I do not like it... what about rollback learned? What if "clear learned" to clear the gathered info, and "rollback learned" to rollback modifications?... I still do not like it.)

If you start a new daemon and create a rule which allows this new label to learn, and you will see you have made wrong labelling, (therefore the learned rules are wrong), you can simply say reset learned, relabel what you need, or modify the rules if you need, and can restart the learning procedure in seconds.
reset learned [25] Learned rules reset successfully.

This command will start the transaction. All the subsequent commands will be joined and will be executed as one atomic command at once if you close the transaction with the commit command or will be discarded with the rollback command. If there is an error in the transaction, or you close the console (even accidentally) all the commands will be discarded. (see TRANSACTIONS section for more info) If you already started a transaction, and issue the start command again, all the transaction data will be discarded, and a new transaction will be started, no error will be reported. If you have errors in the transaction, you will get only one error response at the end, and error status massages after each failed command. (transactions behaviour could change slightly in the future versions)
Start command does not have parameters.
start [27 Transaction started.

This command will close the transaction. If there were no errors in the transaction, all the commands will be executed as one atomic command. If there were errors, you will get an error response after commit, and commands will not be executed. Empty transactions will not cause errors.
commit [28] Transaction committed successfully.

This command will roll back all the transaction commands and will discard and quit the transaction.
rollback [29] Transaction rollback successful.

This command will exit from the security console. If you send en exit, none of the following commands will be processed, this equals an EOF submitted. If you lose the access rights for the console, (changed admin label, or access revoked) the only command which you can execute is the exit. Syntax is:
exit # _


You can download the latest userspace utilities from :

All you have to do is unpack it, and compile:
ZMAC_CONSOLE=/dev/zmac make install
Please note, with ZMAC_CONSOLE environment variable you can tell what console device you would like to use. The default for devfs is /dev/zmac, for procfs it is /proc/zmac. The default install directory is /usr/local/bin, but you can change it in makefile.

I suggest to use GCC 7 or later to compile utilities. (for the best optimization)

All the userspace utilities are returns with error codes to the shell if there were problems, which you can handle. Please see the userspace utilities error codes section.

The userspace utilities are:

Security console utility
With zc you can access the ZeroMAC security console. If you simply start it without parameters, it will connect to the security console, you can send commands and see results: (actually it creates a pipe between the ZeroMAC security console and your virtual terminal)
# zc ZeroMAC console v2.0.1 (c) 2015-2019 Peter Gabor Gyulay <> _
If you give parameters to zc, it will send those parameters as a command to the security console and will display the result. You can use any of the console commands:
# zc show api version Current api version is: 2.0
Please note, if you have any error in execution, then zc will give it back to the shell, so you can verify in a shell script if the result is an error, or not. On success, it will return 0, on errors you will get a positive number. (see the userspace utility and console error codes section)
# zc show my music; echo Return code of zc command is: $? Syntax error in line "show my music" at position 6 Return code of zc command is: 21
zc will print the response message to stdout if it succeeded but will print to stderr if there was an error. If you write a shell script, and would not like to print the result if there is an error, you can say
# zc show api version 2>/dev/null Current api version is: 2.0
but take care of the return value.... you know what I mean :)
You can use zc as a pipe for example:
# zc show config >/config
and later you can upload a previous config with:
# zc </config
Actually, with zc you can do anything you want on the console, this is the swiss army knife of the security console :)
Rule listing utility
With zr you can list the current rules
# zr admin lib rw........e..yz /............... #rw........e..yz admin config r.........e..yz /............... #r.........e..yz admin _ rwax..j.......z /............... #..a...........z admin system rw.xs.j.......z /............... #.w..s.........z admin admin rw....j........ /............... system admin r..x.....ce..y. /............... system kernel rw......p...... /............... system _ rwaxs.j....mtyz /............... system system /............... kernel system /............... kernel kernel .w....j........ /............... kernel _ /...............
The first two columns are the subject and object then you see the access privileges then after the slash there is the deny section, and at the end of the line, you see the privileges which are learned since the last time you changed to (one of the) learning mode(s).
Rule set utility
With zrset you can set one or more rules, if you give two exact labels for it, then it will create the rule if does not exist, or will modify it for the input values if already exists. For example, this will create or set this rule:
# zrset system kernel rwp
If you would like to update more rules, for example, you would like to set all currently existing rules with "lib" as the object to read only privilege, you can say:
# zrset %% lib r
This way the double wildcard will substitute all the labels that currently exists in rules which have "lib" as object and will overwrite these rules with the given privileges.
Note that, this utility is hard linked to the zr utility, and that will detect the last 3 characters of the filename to know what to do.
Rule delete utility
With zrdel you can set the subject and object, which rules you would like to delete. For example, to delete a specific rule you can say:
# zrdel system kernel
If you would like to delete more rules:
# zrdel apache %%
This way the double wildcard will substitute all the labels that currently exist in rules which have "apache" as subject and will delete them (if they exist).
Note that, this utility is hard linked to the zr utility, and that will detect the last 3 characters of the filename to know what to do.
Rule modify utility
With zrmod you can modify selected rule or rules. This will not overwrite the rules but will add or remove selected privileges from them. If you type + before privileges, it will add, if you start with -, it will remove from the section, and of course, you can do lots of modifications at once. For example, remove write and signal privilege and add ptrace for the access section and add write to deny section, you can say:
# zrmod system kernel -wg+p/+w
If you would like to remove read privilege from all the existing rules:
# zrmod %% %% -r
Note that, this utility is hard linked to the zr utility, and that will detect the last 3 characters of the filename to know what to do.
Mode utility
If you run without parameters, it will write the current operating mode to the stdout (with a closing LF at the end)
# zm enforcing
If you run it with a parameter, it will set the operating mode to the parameter.
# zm restricted learning ZeroMAC mode changed: restricted learning
If there is an error, it will return to the shell with a positive number as the error code. See the console error codes and userspace utilities error codes.
Admin utility
If you run without parameters, it will write the current admin label to the stdout (without a closing LF at the end)
# za admin
If you run it with a parameter, it will set the admin label.
# za system Admin label changed to: system
If there is an error, it will return to the shell with a positive number as the error code. See the console error codes and userspace utilities error codes.
like ls command, will display the file and directory labels. It will list all the files with full path, if you specify a directory name with a trailing slash at the end, it will list the contents of the directory. If you cut the slash at the end, it will display the directory entry itself. For example:
# zls /lib/udev/ lib:lib S drwxr-xr-x 4 root root 4096 2019-08-05 02:32:33 /lib/udev/. lib:lib S drwxr-xr-x 9 root root 4096 2019-09-12 15:14:10 /lib/udev/.. lib -rwxr-xr-x 1 root root 101312 2019-08-01 02:40:41 /lib/udev/ata_id lib -rwxr-xr-x 1 root root 113656 2019-08-01 02:40:41 /lib/udev/cdrom_id lib -rwxr-xr-x 1 root root 101392 2019-08-01 02:40:41 /lib/udev/collect lib:lib S drwxr-xr-x 2 root root 4096 2019-08-05 02:32:33 /lib/udev/hwdb.d lib -rwxr-xr-x 1 root root 14288 2019-08-01 02:40:41 /lib/udev/mtd_probe lib -rwxr-xr-x 1 root root 1309 2019-07-16 18:31:28 /lib/udev/ lib:lib S drwxr-xr-x 2 root root 4096 2019-08-13 19:48:28 /lib/udev/rules.d lib -rwxr-xr-x 1 root root 114256 2019-08-01 02:40:41 /lib/udev/scsi_id lib -rwxr-xr-x 1 root root 68480 2019-08-01 02:40:41 /lib/udev/v4l_id
Change label utility
You can change the access and execute security labels of files and directories. The syntax for this command is:
zch accesslabel:execlabel:createlabel filename [ filename ... ]
If you leave access, exec or create label empty, it will not modify it, for example, if you have a file with access label only:
# lsm /lib lib drwxr-xr-x 9 root root 4096 2019-09-12 15:14:10 /lib
And you write only after the colon (to set the exec label):
# zch :lib /lib # zls /lib lib:lib S drwxr-xr-x 9 root root 4096 2019-09-12 15:14:10 /lib
It will not change the access label, only the exec label of the file (a directory this time)

If you would like to delete the execute label, you have to explicitly type an underscore for the position which you would like to delete:
# zch :_ /lib # zls /lib lib drwxr-xr-x 9 root root 4096 2019-09-12 15:14:10 /lib
Label change utility for directory trees
The syntax is:
zchdir <accesslabel> <directory> [ <directory> ... ]
It will set the given accesslabel to all the files in a given directory tree, and the same label for execlabel for all the directories recursively. This way you can be sure about all the files and directories will get the given access label on a given directory tree. This utility is a shell script, which depends on the find shell command and zch userspace utility. For example, you can set the access label to all the files and directories in /lib to lib with the command:
zchdir lib /lib


Please remember, if the console returned an error, then the userspace utility will return that error code (-20 to -99) as a positive number to the shell.
(read the console error codes section)


I have to refresh this section, no install instructions here, maybe I can upload the refreshed instructions this summer.

Current stable patch:

(This stable release is feature frozen, no public development version available at the very moment (as I would not like to post unstable nightly builds))

This patch is for Linux kernel version 5.15.x tested with: 5.15. The patch will not work directly with the older kernel versions, but it isn't too hard to backport. If you would like to patch an older version, please let me know, I'll help you. It is easy to compile for 5.x.x - 5.x.x. (The next generation of the ZeroMAC system (0.9.5.x) would be hard to backport)

Place the ZeroMAC patch file and the kernel source in the same directory, and type:
tar -xvf linux-5.15.tar.xz cd linux-5.15 bzcat ../zmac- | patch -p1
Then you have to create your config, compile, and enjoy your security :)


The project is under development and is before official public release. There are only process and file system access control, there is no network access control at the moment. (I think I'll implement network security a bit different than current solutions, but I have to read tons of source code and documentation and have no time for that now)

I do write and maintain ZeroMAC in my (almost non-existent) free time (it's great fun to write a security system). I wrote it for myself, but feel free to use it, if you like it. :)

The current version seems to be stable, it is feature frozen until 2022. (Please note, I do not support older versions <=0.9.3.x)

If you found a bug, please be sure you used the latest version of ZeroMAC, and please report the bug!!!! Thank you!!!

As you can see I hate writing documentation, so it is far from complete and is far from perfect. (I wrote it in parts, in a hurry, so it can be inconsistent here and there. Please let me know if you find problems in the documentation.) Lots of features are still undocumented, once I'll have some time, I'll rewrite the full doc.

Kernel compile options are entirely undocumented here, but I wrote help in each option, those are up to date.

Currently, the source code is not in kernel style... (lines are longer than 80 and all parts of the source code are placed into one .c file, but for now, it makes it easy to handle and overview...) (btw 80 char wrap makes source code less readable IMHO)
Once I reach 1.0 I'll do a massive code clean, and will convert it to kernel style.
I have lots and lots of ideas about what to implement, so maybe version 1.0 is not here, but I'll create a stable version from every stage before reaching version 1.0. (I also use it (currently earlier versions) in production environment so I need stable versions too.)

Before I reach version 1.0 I will easily sacrifice backwards compatibility for better features or speed, better efficiency. After reaching 1.0, backwards compatibility will be important. If you use 0.9.x, be prepared for some modifications.


Currently, I can handle mails with a delay. (I have to work from early morning to late night) Please excuse me if you do not get an answer so quickly.

Making the system stable and bug free is important, so If you found a bug, please write an email, and start your subject with [BUG] please!
Also if you can do any type of attack against ZeroMAC, (even side-channel attacks) let me know, I'm interested, I'm excited, I'm curious!!!!

(I am not interested in module load attacks, and libc call hijack attacks, they are way too easy.)

You can donate the project if you like it:

Peter Gabor Gyulay