Rough Guide to CerbNG

Table of Contents

1 Introduction

UNIX systems historically were not designed to provide extensive security and auditing features. It's notion of superuser who is never stopped from interfering with system's policies and internals is considered, even by it's most dedicated fans, too dangerous. Permission bits for files are often too generous, which is caused not only by lack of standard ACL support in many systems (FreeBSD 4.x included), but also by need for setuid-bit existence in UNIX. In the old days UNIX was used in friendly academic communities where security was never top priority. Now it's widespread commerce, critical data processing and network security uses make enhancements to traditional UNIX security model essential for it's success.

CerbNG is written for FreeBSD operating system. The base OS offers many security enhancements beyond the standard UNIX feature set. Mechanisms like: Jail, ACLs, MACs, securelevels, enhanced file attributes (flags) help making the system more secure but not immune to remote and local security breaches. FreeBSD developers are known for safe coding practices, careful testing of new system features and good design. But very often system administrators and security officers are faced with critical bugs which were not caught despite so many eyes watching. Sometimes checking is not enough. Restricting applications beyond their initial rights, given by UID and GID bits of user running them, is crucial for maintaining system integrity.

Sysadmins can never assert, that the only threat to their systems are so called script kiddies - non-thinking, always boasting, clueless users of readily available exploits; looking for root level access because it sounds cool. What about determined attackers who often spend weeks finding system and application bugs which can be used for privilege elevation? You can't assume they will go public with their findings or notify software vendors before exploiting or sharing found vulnerabilities. Many of them don't. How can we fight the enemy? How can we prevent exploiting bugs we are not aware of?

For sure, many of the conscious FreeBSD users are bothered by generosity of credentials in base installation. Programs like ping(8) or named(8) are setuid root for very basic operations (raw sockets and low port binding respectively). FreeBSD as for version 4, doesn't offer any mechanisms restricting processes running with root UID to performing single operation with elevated credentials.

All of the above issues motivated development of CerbNG.

2 Architecture

CerbNG contains two building blocks. First one, is kernel loadable module, second is userland compiler which translates rules from human readable format to rules and variables used by kernel module. CerbNG is a kind of interface between userland and kernel space. Without CerbNG loaded, all system calls are immediately executed by kernel. After loading CerbNG, all system calls and their arguments are passed through a series of tests defined in configuration rules. Before and after system call execution, system administrator using CerbNG is allowed to perform numerous modifications to running process environment and syscall arguments. Set of changeable parameters contains all the *UID registers permitting privilege elevation of running process. Additional assumptions in design of CerbNG were flexibility and nearly complete transparency. CerbNG can be configured in ways which don't require any changes to program source code and filesystem permissions.

3 Examples

Next we present some examples which uncover some of CerbNG mechanisms for access control. Let's start with securing ping. Ping was chosen as first example for simplicity not it's insecurity.

3.1 Ping

if (syscall == SYS_execve) {
reg[0] = realpath(arg[0]);
if (reg[0] == "/sbin/ping") {
reg[0] = call();
if (reg[0] == 0 && euid == 0) {
setpeuid(ruid);
}
return reg[0];
}
}
if (pname == "ping" && pinode == 123 && pdev == 456) {
if (syscall == SYS_socket) {
if (socket_domain == AF_INET &&
socket_type == SOCK_RAW &&
socket_protocol == IPPROTO_ICMP) {
reg[0] = euid;
setpeuid(0);
reg[1] = call();
setpeuid(reg[0]);
return reg[1];
}
}
}

Explanation

if (syscall == SYS_execve) {

Check if execve(2) was called.

reg[0] = realpath(arg[0]);

Internal register number zero is assigned realpath of program which user owning this syscall is attempting to run (first argument of execve(2)). In other words, register zero will store absolute path of the program which the user is trying to run.

if (reg[0] == "/sbin/ping") {

Check if the program being run is ping(8).

reg[0] = call();

Register zero is assigned return value as the syscall after it's execution (call()).

if (reg[0] == 0 && euid == 0) {

Check if system call succeeded (zero return value), and if effective UID is equal zero (it should be if ping is setuid root).

setpeuid(ruid);

Downgrade credentials of ping(8) to those of user running it.

return reg[0];

Terminate syscall execution returning value stored in register zero.

Purpose of the above fragment was restricting credentials of ping(8) without taking away it's setuid bit.

Next part is responsible for granting root credentials to ping only when it opens raw socket. In practice that's the only reason for ping being setuid root.

if (pname == "ping" && pinode == 123 && pdev == 456) {

Check if process name is ping, program inode equals 123 and it's device number equals 456. These values can be precomputed during compilation with functions GET_INODE and GET_DEV. Precise process identification is crucial. We have to make sure that the process being run is system ping, not any other program called as ping.

if (syscall == SYS_socket) {

Check if syscall started by ping is socket(2)

if (socket_domain == AF_INET &&
        socket_type == SOCK_RAW &&
        socket_protocol == IPPROTO_ICMP) {

Set of comparisons of syscall arguments to check is type of opened socket is SOCK_RAW.

reg[0] = euid;

Store process effective UID in register zero.

setpeuid(0);

Set effective UID to zero, to make the syscall succeed.

reg[1] = call();

Run the syscall and store it's return value in register number 1.

setpeuid(reg[0]);

Restore saved credentials

return reg[1];

Return syscall return value.

That's it all for ping

Using techniques shown above we can restrict most critical setuid programs. But CerbNG can do much more. Here is another example..

3.2 NoExec

if (syscall == SYS_execve) {
if (pruid >= 1000) {
rmld("LD_*");
reg[0] = realpath(arg[1]);
if (reg[0] @ "/usr/home/*" ||
reg[0] @ "/tmp/*" ||
reg[0] @ "/var/tmp/*") {
log(LOG_WARNING, "!WARN! Don't have permission to run "
"%s (proc=%s, ruid=%u, rgid=%u, euid=%u, egid=%u)",
reg[0], pname, ruid, rgid, euid, egid);
return EPERM;
}
}
}

The above rule set is equivalent to noexec option to mount. But it can prevent execution on directory basis additionally stopping LD_ tricks by removal of variables starting with "LD_" prefix. Only users with UID>= 1000 are checked which is more flexible than mount approach. Every unsuccessfully attempt of execve call is logged.

Another more secure approach for allowing execve is assigning all users allowed to run their programs to group "exec".

if (syscall == SYS_execve) {
if (ruid >= 1000) {
if (tabindex(GET_GID("exec")) < 0) {
rmenv("LD_*");
if (getouid(arg[1]) >= 1000) {
log(LOG_WARNING, "!WARN! Don't have permission "
"to run %s (proc=%s, ruid=%u, rgid=%u, "
"euid=%u, egid=%u)", realpath(arg[1]),
pname, ruid, rgid, euid, egid);
return EPERM;
}
}
}
}

We check if the real UID is not less than 1000, next check tests the membership of group "exec". Similarly to previous example, all LD_ variables are removed. If owner of the file being run with execve is not less than 1000 the the unsuccessful attempt is logged and syscall fails (EPERM is returned).

Not all sysadmins like the ability of their users to create hard links to files they don't own (hardlinked file cannot be removed until the link count goes to 0, which can be used to hold buggy setuid programs in the system without administrator's notice). Let's deal with this too:

if (syscall == SYS_link) {
if (ruid >= 1000) {
if (getouid(arg[0]) != ruid) {
log(LOG_WARNING, "!WARN! Don't have permission for link"
" creation to %s (proc=%s, ruid=%u, rgid=%u, "
"euid=%u, egid=%u)", realpath(arg[0]), pname, ruid,
rgid, euid, egid);
return EPERM;
}
}
}

If we care about users' privacy, it's sometimes important to restrict ability of reading the whole /etc/passwd and /etc/pwd.db by any user. It breaks long file listings (ls -l) and some other utilities which use password database for username mapping, but it can be resolved by finer restrictions' tuning. To give users access to only their entries in password databases, we can generate such a file and redirect open to those fake files like this:

if (syscall == SYS_open) {
        if (ruid >= 1000) {
                reg[0] = realpath(arg[0]);
                if (reg[0] == "/etc/passwd") {
                        arg[0] = genstr("/etc/private/%u.passwd", ruid);
                } else {
                        if (reg[0] == "/etc/pwd.db") {
                                arg[0] = genstr("/etc/private/%u.pwd.db", ruid);
                        }
                }
                log(LOG_INFO, "!INFO! Open of file %s was directed to %s "
                    "(proc=%s, ruid=%u, rgid=%u, euid=%u, egid=%u)", reg[0],
                    arg[0], pname, ruid, rgid, euid, egid);
                return call();
        }
}
Now every user with UID not less than 1000 instead of /etc/passwd will open /etc/private/<login name>.passwd and /etc/private/<login name>.pwd.db instead of /etc/pwd.db and /etc/passwd.

3 CerbNG capabilities

4 Sysctls controlling CerbNG

Sysctl name Description
cerb.rules.lock 0/1 toggle, if set to 1 (enabled) new rules cannot be loaded to kernel. Once enabled cannot be disabled without rebooting the system (similar lock takes place when kern.securelevel sysctl is set to 1 or more)
cerb.rules.show setting this sysctl causes listing of rules loaded into specified slot or all rules if set to -1
cerb.rules.set sets specified slot as active, or disables CerbNG if set to -1
cerb.syscalls.show Displays syscall set associated with given rule set. If set to -1 displays syscalls intercepted by all rule sets
cerb.threads.allocated number of slots allocated for CerbNG threads
cerb.rules.rm removes all rules from given slot or all rules if set to -1
cerb.mem.stat set to 1, displays all memory areas allocated by CerbNG
cerb.mem.safe_malloc if set to 0, memory is allocated without debugging information (faster), if set to 1, each memory chunk is allocated with comments to help finding memory leaks
cerb.mem.debug if set to 1, each byte allocated and freed by CerbNG will be set to 0xd0. this idea was taken from phkmalloc
cerb.fdesc.stat if set to 0, file name cache will be disabled and using them for fd2*() operations will be impossible. if set to 1, caching is performed using fdcache() only. if set to 2, each open file is cached, which comes with significant performance hit on I/O oriented machines. thus setting to 1 is recommended
cerb.fdesc.show displays file names matching given pattern
cerb.fdesc.clear flushes the descriptor cache
cerb.ask.wakeup resumes process suspended by ask function and returns passed value to kernel. it should be set to string formated as "<ID>:<retval>". for example setting this sysctl to "666:1" resumes process stopped with ID 666 and returns 1 to to cerb thread holding the process on ask function
cerb.ask.show returns list of suspended processes
cerb.ask.suspended returns number of suspended processes
cerb.ask.maxsuspended contains maximum number of procesess held on the ask hook. can be set to any number.
cerb.misc.off_on_error if set to 1, CerbNG is disabled when error in loaded rules is encountered, which might render the system unusable. should be set to 1 after rules pass your tests
cerb.trace.kind if set to 0, trace output will show only already executed rules. if set to 1, all rules will be shown
cerb.trace.on_error if set to 1, precise location of runtime error will be shown using trace mechanism. set to 0 causes display of the information on error encountered

5. CerbNG operators and functions

5.1 Operators (in increasing precedence)

Operators Operands Binding
= binary right
|| binary left
&& binary left
| binary left
^ binary left
& binary left
== != binary left
@ !@ (pattern matching) binary left
< <= > >= binary left
<< >> binary left
+ - binary left
* / % binary left
! ~ - unary right

All of the above operators work identically to C language operators

5.2 Userland compiler functions

Function name Description
ADD_SYSCALL(<sysc1>[,...]) expands the set of intercepted syscalls
GET_UID(<username>) returns UID of user
GET_UGID(<username>) returns GID of user
GET_GID(<username>) returns GID of group
GET_HOME(<username>) returns home directory of user
GET_SHELL(<username>) returns login shell of user
GET_OUID(<path>) returns UID of file owner
GET_OGID(<path>) returns GID of file owner
GET_INODE(<absolute path>) returns inode number of file designated by path
GET_DEV(<absolute path>) returns device number for specified path
GET_MODE(<absolute path>) returns permission bits for specified file
GET_FLAGS(<absolute path>) returns FreeBSD specific filesystem flags for given path
GET_NLINKS(<absolute path>) returns number of hard links for specified file
GET_SIZE(<path>) returns size of file in bytes
MKNULL(<type>) returns NULL pointer of given type (equivalent of kernel mode null call)

 

5.3 Kernel CerbNG functions

DEF:call()
description Executes currently intercepted syscall
return value return values of executed syscall
documentation syscall(2)
conferr EINVAL - if redundant arguments were passed
DEF:sucall([UDEF:UID])
description Executes currently intercepted syscall changing effective UID to specified UID (or UID 0 if UID is not specified) and changing the UID to saved value after syscall execution.
return value return value of executed syscall
documentation syscall(2), seteuid(2)
conferr EINVAL - incorrect argument number or type
VOID:return(<DEF:errno>)
description Immediate exit with passed errno value
return values none
documentation intro(2)
conferr EINVAL - incorrect argument number or type
STR:realpath(<STR:path>)
description Returns full absolute path of specified relative path (analogous to userland realpath(3) function)
return values absolute path starting with '/', with all symbolic links expanded, with '/' duplicates squashed, '/./'s removed and '/../' resolved. Empty string is returned on failure.
documentation realpath(1), realpath(3), readlink(2), getcwd(2)
notice the last element of path (file/directory name) has to exist for open's and mkdir's sake when new file/directory is created.
conferr EINVAL - incorrect argument number or type
errno EFAULT - passed path was NULL
UDEF:setsyscall(<UDEF:number>)
description

Changes current syscall number. This function might be really useful for calling setuid instead of seteuid or such. Using this function several syscalls can be executed instead of one - current syscall, like this:

if (syscall == SYS_setuid) {
	setsyscall(SYS_setuid); 
	call(); 
	setsyscall(SYS_setgid); 
	return call(};
It's a little strange example, but shows how to use the function.

return values syscall number before the change
documentation syscall(2)
UDEF:exists(<STR:path|UDEF:PID>)  
description Checks for existence of path or process
return values 1 if given entity exists, 0 otherwise
conferr EINVAL - incorrect argument number or type
errno All returned by namei(9)
STR:getpname(<UDEF:PID>)
description Returns name of current process or name of process identified by given PID.
return values string containing name of the process or NULL if process doesn't exist
documentation execve(2)
notice for current use variable pname
conferr EINVAL - incorrect argument number or type
errno

ESRCH - process with given PID unexists
EINVAL -
EBADF -
ENOTDIR -
ENOENT -
ENAMETOOLONG -

STR:setpname([UDEF:PID,]<STR:name>)
description Sets name of current process (or process identified by PID) to string .
return values 1 for success, 0 for failure (process with given PID doesn't exist)
conferr EINVAL - incorrect argument number or type
errno

ESRCH - process with given PID unexists
EFAULT - <name> is NULL

UDEF:setpid([UDEF:PID,]<UDEF:newpid>)  
description Sets PID of current or given process to specified value
return values previous PID or -1 (type DEF) on error
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID unexists
UDEF:getppid([PID])
description Returns parent PID for process with given PID
return PID number of parent process, or -1 if error occurs
documentation getppid(2)
notice Use variable PPID for current process parent PID
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
UDEF:setppid([UDEF:PID,]<UDEF:newpid>)  
description Sets PID of current or given process to specified value
return values previous PID or -1 (type DEF) on error
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID unexists
UDEF:getpgid(<UDEF:pid>)  
description Returns number of process group, given process belongs to
return values process group number or -1 on error
documentation getpgid(2)
notice for current process use pgid variable
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID unexists
UDEF:setpgid([<UDEF:pid>,]<UDEF:newpgid>)  
description Changes process group for current or given process to newpgid
return values previous process group number or -1 (DEF) on error
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given pid unexists or there is no process group with newpgid
UDEF:getpsid(<UDEF:pid>)  
description Returns session number for given process
return values process SID or -1 (DEF) on error
notice for current process use variable psid
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID unexists
STR:getpfile(<UDEF:PID>)
description Returns absolute path to executable of process with given PID
return values absolute path (string) or "" if process doesn't exist
notice for current process use variable fname
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
EINVAL -
EBADF -
ENOTDIR -
ENOENT -
ENAMETOOLONG -
STR:setpfile([UDEF:PID],<STR:path>)
description Sets path to file executed by current process (or some other process with given PID) to string .
return values 1 success, 0 failure (returned only when given process doesn't exist)
notice in fact only p->p_textvp is changed
documentation

vnode(9)

conferr EINVAL - incorrect argument number or type
error

ESRCH - process with given PID doesn't exist
EINVAL - the path is not a regular file
EBADF -
ENOTDIR -
ENOENT -
ENAMETOOLONG -

UDEF:getpruid(<UDEF:PID>)
description Returns real UID for specified process
return values real UID or -1 for non existing process
documentation getuid(2)
notice for current process use variable ruid
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
UDEF:setpruid([UDEF:PID],<UDEF:UID>)
description Sets real UID for given (current) process to
return values 1 for success, 0 for failure (non existing process)
documentation setruid(3), setuid(2)
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
UDEF:getprgid(<UDEF:PID>)
description Returns GID of given process
return values group id or -1 for non existing process
documentation getgid(2)
notice use variable rgid for current process
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
UDEF:setprgid([UDEF:PID],<UDEF:GID>)
description Sets real GID for given (current) process to
return values 1 for success, 0 for failure (non existing process)
documentation setrgid(3), setgid(2)
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
   
UDEF:getpeuid(<UDEF:PID>)
description Returns effective UID of given process
return values real UID or -1 for non existing process
documentation geteuid(2)
notice use variable euid for current process
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
   
UDEF:setpeuid([UDEF:PID],<UDEF:UID>)
description Sets effective UID for given (current) process to
return values 1 for success, 0 for failure (non existing process)
documentation seteuid(3), setuid(2)
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
   
UDEF:getpegid(<UDEF:PID>)
description Returns effective GID of given process
return values effective GID or -1 for non existing process
documentation getegid(2)
notice use egid for current process
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
UDEF:setpegid([UDEF:PID],<UDEF:GID>)
description Sets effective GID for given (current) process to
return values 1 for success, 0 for failure (non existing process)
documentation setegid(3), setgid(2)
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
   
UDEF:getpsvuid(<UDEF:PID>)
description Returns saved UID of given process
return values saved UID or -1 for non existing process
documentation getresuid(2)
notice use variable svuid for current process
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
   
UDEF:setpsvuid([UDEF:PID],<UDEF:UID>)
description Sets saved UID for given (current) process to
return values 1 for success, 0 for failure (non existing process)
documentation setresuid(3), setuid(2)
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
   
UDEF:getpsvgid(<UDEF:PID>)
description Returns saved GID of current (given) process
return values saved GID or -1 for non existing process
documentation getresgid(2)
notice use variable svgid for current process
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
   
UDEF:setpsvgid([UDEF:PID],<UDEF:GID>)
description Sets saved GID for given (current) process to
return values 1 for success, 0 for failure (non existing process)
documentation setresgid(3), setgid(2)
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
   
UDEF:getpumask(<UDEF:PID>)
description Returns umask of given process
return values umask or -1 for non existing process
documentation umask(2)
notice use variable umask for current process
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
   
UDEF:setpumask([UDEF:PID,]<UDEFumask>)
description Sets umask for given (current) process to
return values new umask for success, 0 for failure (non existing process)
documentation umask(2)
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
   
UDEFPTR:getpgroups([UDEF:PID])
description Returns table containing group id's of given process
return values table containing group id's or NULL if given process doesn't exist
documentation getgroups(2)
notice use variable groups for current process
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
STR:getplogin(<UDEF:pid>)  
description Returns login name for session owner, set using setlogin(2) for given process
return values login name or NULL on error
documentation getlogin(2), setlogin(2)
notice for current process use login variable
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID unexists
STR:setplogin(<UDEF:pid>)  
description Sets login name for session owner of process with given PID
return values Previous login name or NULL on error
documentation getlogin(2), setlogin(2)
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID unexists
UDEFPTR:setpgroups([UDEF:PID],<UDEFPTR:gidtab>)
description Sets group list for current (given) process to
return values new GID table or NULL if process doesn't exist
documentation setgroups(2)
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
   
UDEFPTR:addgroup([UDEF:PID,]<UDEF:GID>)  
description Grants membership of given or current process to group with specified GID
return values array with previous groups or NULL if an error occurred
documentation setgroups(2)
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
UDEFPTR:delgroup([UDEF:PID,]<UDEF:GID>)  
description Removes membership of given or current process to group with specified GID
return values array with previous groups or NULL if an error occurred
documentation setgroups(2)
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
   
UDEF:tabindex(<(DEF|UDEF|STR):element>,<(DEF|UDEF|STR)PTR:tab>)
description Checks membership of element in given table
return values number of element if it's in the table (> 0), -1 if it's not a table member
conferr EINVAL - incorrect argument number or type
UDEF:matchmember(<(DEF|UDEF|STR):element>,<(DEF|UDEF|STR)PTR:tab>)  
description Checks if any of tab's elements matches the pattern
return values number of matching element or -1 if no element was found
notice if DEF/UDEF elements are checked, this operation is equivalent to tabindex()
conferr EINVAL - incorrect argument number or type
example matchmember("*ab*", ["def", "abc", "ghi"]) returns 1
UDEF:matchtab(<(DEF|UDEF|STR):element>, <(DEF|UDEF|STR)PTR:matchtab>)  
description Checks if element matches any patterns present in matchtab
return values number of patter in the matchtab matching elem, or -1 if not pattern was found
notice if DEF/UDEF are checked, this operation is equivalent to tabindex()
conferr EINVAL - incorrect argument number or type
example matchtab("abc", [ "*def*", "ab*", "*hi" ]) returns 1.
(DEF|UDEF|STR)PTR:addelem(<(DEF|UDEF|STR)PTR:tab>,<(DEF|UDEF|STR):element>
    [,(DEF|UDEF):after])
 
description Appends element to table tab, or places given element after element number after
return values returns pointer to created array or NULL if an error was encountered
notice to set an element at the beginning of table, put negative number in after argument
conferr EINVAL - incorrect argument number or type
(DEF|UDEF|STR)PTR:rmelem(<(DEF|UDEF|STR)PTR:tab>,<(DEF|UDEF|STR):no>)  
description Removes from table tab element with number no
return values returns pointer to table with one element removed or NULL if an error occurred
conferr EINVAL - incorrect argument number or type
error EFAULT - table pointer is NULL
EINVAL - the table doesn't contain specified element
DEF:ask(<DEF:value>,<UDEF:timeout>,<STR:format>[,?:arg1[,?:arg2...]])  
description Stops the process, sends the ID number of current event and sends to userland information containing the ID, text generated with format and arguments following it. The process will be resumed when an answer from userland comes. It has to contain the ID and a value, which will be later returned by ask. Ask can also return value if there was no answer from userland before `timeout' seconds elapsed or there are cerb.ask.maxsuspended processes already suspended
return values value passed from userland or the default `value' passed as first argument
documentation tsleep(9)
notice timeout is disabled when timeout argument is equal 0
procerr EINTR - the suspended process received signal, or CerbNG is just being unloaded. This error is immediately returned to the userland and further rules are discarded
conferr EINVAL - incorrect argument number or type
errno EINVAL - there are too many suspended processes
UDEF:getfamily(<ST_SOCKADDR:socket>)  
description Retrieves from argument of type sockaddr_in field sin_family
return values socket type or -1 (DEF) on error
documentation socket(2), ip(4)
notice this operation is useful ie for bind(2) syscall
conferr EINVAL - incorrect argument number or type
errno EINVAL - socket argument is NULL
STR:getip(<ST_SOCKADDR:socket>)  
description Retrieves from argument of type sockaddr_in string representing the IP address
return values string containing the IP address or NULL on error
documentation socket(2), ip(4)
notice this operation is useful ie. for bind(2) syscall
conferr EINVAL - incorrect argument number or type
errno EFAULT - socket argument is NULL
STR:getunpath(<ST_SOCKADDR:socket>)  
description Returns filesystem path from argument of type st_sockaddr
return values path or NULL on error
notice this operation is useful ie for bind(2) syscall
conferr EINVAL - incorrect argument number or type
errno EFAULT - socket argument is NULL
UDEF:isjailed([UDEF:PID])
description Check if current (given) process is jailed
return values 1 if process is jailed, 0 process is not jailed, -1 an error occurred
documentation jail(8), jail(2)
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
   
STR:getjailhost([UDEF:PID|ST_PRISON:jail])
description Returns hostname of jail which encloses current (given) process, or hostname of jail with given ST_PRISON.
return values string containing hostname of jail or empty string if process is not jailed
documentation jail(8), jail(2)
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
   
STR:getjaildir([UDEF:PID])
description Returns path to root directory of jail enclosing current (given) process
return values absolute path or empty string if the process is not jailed
documentation jail(8), jail(2)
conferr EINVAL - incorrect argument number or type
error

ESRCH - process with given PID doesn't exist
EINVAL -
EBADF -
ENOTDIR -
ENOENT -
ENAMETOOLONG -

   
STR:getjailip([UDEF:PID|ST_PRISON:jail])
description Returns IP address assigned to jail enclosing given process or IP address assigned to given jail. jail_st type is ST_PRISON.
return values string containing IP address of jail containing given process or empty string is process is `free' or doesn't exist
documentation jail(8), jail(2)
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
   
UDEF:getinode(<STR:path|UDEF:PID>)
description Returns inode number of executable file running as given process or inode number of given path.
return values inode number or -1 if path or process is invalid (doesn't exist)
documentation stat(2)
notice for current process disk file use variable finode
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
EFAULT - path is NULL
UDEF:getdev(<STR:path|UDEF:PID>)
description Similar to getinode, but returns device number of executable/path specified as argument
return values positive number or -1 if PID/path doesn't exist
documentation stat(2)
notice for current process use variable fdev
conferr EINVAL - incorrect argument number or type
error

ESRCH - process with given PID doesn't exist
EFAULT - path is NULL
+ all error codes returned by namei(9) or vn_stat(?)

   
UDEF:getouid(<STR:path|UDEF:PID>)
description Returns owner UID for given file or executable for process with given PID
return values UID number or -1 if path/executable doesn't exist
documentation stat(2), chown(2), chown(8)
notice for current process use variable fuid
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
EFAULT - path is NULL
+ all error codes returned by namei(9) or vn_stat(?)
   
UDEF:getogid(<STR:path|UDEF:PID>)
description Returns owner GID for given file o executable for process with given PID
return values GID number or -1 if path/executable doesn't exist
documentation stat(2), chown(2), chown(8)
notice for current process use variable fgid
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
EFAULT - path is NULL
+ all error codes returned by namei(9) or vn_stat(?)
   
UDEF:getmode(<STR:path|UDEF:PID>)
description Returns mode bits for executable file for specified process or given path
return values number representing access modes or -1 if given path or process doesn't exist
documentation stat(2), chmod(1), chmod(2)
notice for current process use variable fmode
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
EFAULT - path is NULL
+ all error codes returned by namei(9) or vn_stat(?)
   
UDEF:getflags(<STR:path|UDEF:PID>)
description Reports FreeBSD specific flags for given path or executable of running process
return values either proper flags as number or -1 if process/path doesn't exist
documentation stat(2), chflags(1), chflags(2)
notice for current process use variable fflags
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
EFAULT - path is NULL
+ all error codes returned by namei(9) or vn_stat(?)
   
UDEF:getnlinks(<STR:path|UDEF:PID>)
description Reports number of hard links to executable of running process or given path
return values number of hard links or -1 if specified process or directory doesn't exist
documentation stat(2), ln(1), link(2)
notice for current process use variable fnlinks
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
EFAULT - path is NULL
+ all error codes returned by namei(9) or vn_stat(?)
   
UDEF:getsize([STR:path|STR:PID])
description Returns size in bytes of executable of running process or specified file
return values size in bytes or -1 if process/path doesn't exist
documentation stat(2)
notice for current process use variable fsize
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
EFAULT - path is NULL
+ all error codes returned by namei(9) or vn_stat(?)
   
UDEF:fdcache(<DEF:fd>,<STR:path>)  
description Stores given path in file descriptor cache, which can be later retrieved by descriptor fd
return values 0 path has been put into cache, -1 an error occurred
notice Using this operation, retrieving filename associated with given descriptor is possible, using fd2name() function. if cerb.fdesc.stat is equal 2, this function is not necessary, since all descriptors are cached on open(2), but this is very inefficient. thus recommended caching policy is using this function when appropriate and setting cerb.fdesc.stat to 1
conferr EINVAL - incorrect argument number or type
error EINVAL - incorrect descriptor number
EFAULT - path is NULL or finding absolute path was impossible
   
STR:fd2name([UDEF:PID,]<DEF:fd>)
description Returns absolute path of file associated with given descriptor of current or given process
return values full path to file/directory or "" if operation cannot be completed
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
EINVAL - incorrect descriptor number or descriptor is not associated with any open file (although it might be an open socket)
UDEF:fd2inode([UDEF:PID,]<DEF:fd>)
description Returns inode number of file associated with specified descriptor open by current or given process
return values inode number or -1 if descriptor isn't open or process doesn't exist
documentation stat(2)
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
EINVAL - incorrect descriptor number or descriptor is not associated with any open file (although it might be an open socket)
+ all error codes which vn_stat(?) can return
   
UDEF:fd2dev([UDEF:PID,]<DEF:fd>)
description Returns device number for file associated with given descriptor of current or specified process
return values proper device number or -1 if descriptor is closed or process unexists
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
EINVAL - incorrect descriptor number or descriptor is not associated with any open file (although it might be an open socket)
+ all error codes which vn_stat(?) can return
   
UDEF:fd2ouid([UDEF:PID,]<DEF:fd>)
description Returns selected descriptor's associated file owner's UID. If PID is specified, the fd is taken from descriptor table of other process
return values proper UID or -1 if descriptor is closed or process doesn't exist
documentation stat(2), chown(2), chown(8)
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
EINVAL - incorrect descriptor number or descriptor is not associated with any open file (although it might be an open socket)
+ all error codes which vn_stat(?) can return
   
UDEF:fd2ogid([UDEF:PID,]<DEF:fd>)
description Returns selected descriptor's associated file owner's GID. If PID is specified, the fd is taken from descriptor table of other process
return values proper GID or -1 if descriptor is closed or process doesn't exist
documentation stat(2), chown(2), chown(8)
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
EINVAL - incorrect descriptor number or descriptor is not associated with any open file (although it might be an open socket)
+ all error codes which vn_stat(?) can return
   
UDEF:fd2mode([UDEF:PID,]<DEF:fd>)
description Returns selected descriptor's associated file permission bits. If PID is specified, the fd is taken from descriptor table of other process
return values proper mode or -1 if descriptor is closed or process doesn't exist
documentation stat(2), chmod(2), chmod(1)
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
EINVAL - incorrect descriptor number or descriptor is not associated with any open file (although it might be an open socket)
+ all error codes which vn_stat(?) can return
UDEF:fd2type([UDEF:pid,]<DEF:fd>)  
description return type of file associated with given descriptor of given or current process
return values file type or -1 (DEF) on error
documentation stat(2)
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
EINVAL (??) - incorrect descriptor number or descriptor is not associated with open file (can be socket)
+ all error codes returned by vn_stat(?)
UDEF:fd2flags([UDEF:PID,]<DEF:fd>)
description Returns selected descriptor's associated file FreeBSD UFS flags. If PID is specified, the fd is taken from descriptor table of other process
return values proper flags as number or -1 if descriptor is closed or process doesn't exist
documentation stat(2), chflags(1), chflags(2)
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
EINVAL - incorrect descriptor number or descriptor is not associated with any open file (although it might be an open socket)
+ all error codes which vn_stat(?) can return
   
UDEF:fd2nlinks([UDEF:PID,]<DEF:fd>)
description Returns selected descriptor's associated file number of hard links. If PID is specified, the fd is taken from descriptor table of other process
return values number of hard links or -1 if descriptor is closed or process doesn't exist
documentation stat(2), ln(1), link(2)
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
EINVAL - incorrect descriptor number or descriptor is not associated with any open file (although it might be an open socket)
+ all error codes which vn_stat(?) can return
   
UDEF:fd2size([UDEF:PID,]<DEF:fd>)
description Returns selected descriptor's associated file size in bytes. If PID is specified, the fd is taken from descriptor table of other process
return values size in bytes or -1 if descriptor is closed or process doesn't exist
documentation stat(2)
conferr EINVAL - incorrect argument number or type
error ESRCH - process with given PID doesn't exist
EINVAL - incorrect descriptor number or descriptor is not associated with any open file (although it might be an open socket)
+ all error codes which vn_stat(?) can return
   
(DEF|UDEF|STR):sysctl(<(UDEFPTR|STR):name>[,(DEF|UDEF|STR):val])
description Either returns or sets value of sysctl with given name (for setting the value, val must be specified)
return values sysctl number if the value is checked, old value if the sysctl is set or -1 if an error occurs
documentation sysctl(3), sysctl(8)
notice

This operation can modify only sysctls of types:

  • CTLTYPE_INT
  • CTLTYPE_LONG
  • CTLTYPE_UINT
  • CTLTYPE_ULONG
  • CTLTYPE_STRING

name argument can be either string or od table, which can be useful when we want to control sysctl(3) syscall. One should be careful using this operation, because in general you can't be certain value of which type will be returned. also you shouldn't consider -1 to be error indicator, since sysctl's of type CTLTYPE_INT and CTLTYPE_LONG can return -1. an error can occur, before CerbNG is able to determine type of sysctl used, which can make it return -1 when string value is expected (if there is an error determining sysctl type, always -1 of type DEF is returned). regarding all of the above, best way of dealing with this is testing errno variable after each call of this function, like in this example:

reg[0] = sysctl("name.of.sysctl", <value>);
if (errno != 0) {
... handle the error condition ...
}
conferr EINVAL - incorrect argument number or type
error EFAULT = the name argument is NULL or you tried to assign NULL to sysctl of type CTLTYPE_STRING
EINVAL - there was an overflow error, which means you cannot assign large UDEF value to sysctl of type CTLTYPE_INT, or a negative value to sysctl of type CTLTYPE_UINT, CTLTYPE_ULONG.
+all error codes returned by kernel_sysctl() and sysctl_find_oid()
STR:sysctlname(<UDEFPTR:valtab>)  
description Returns name of sysctl represented by oid table valtab
return values name of sysctl or NULL on error condition
documentation sysctl(3), sysctl(8)
conferr EINVAL - incorrect argument number or type
error EFAULT - valtab is NULL or it's size is zero
EINVAL - number of sysctl components is not matching valtab size
UDEF:isnull(<PTR:pointer>)  
description Checks if pointer is NULL
return values 1 - the pointer is NULL
0 - pointer is not NULL
-1 - an error occurred
conferr EINVAL - incorrect argument number or type
PTR:null(<UDEF:type>)  
description Returns NULL value of specified type (XXX)
return values NULL
conferr incorrect argument number or type
UDEF:rmenv(<STR:match>)
description Removes environment variables matching
return values number of variables removed or -1 if current syscall is not execve(2)
documentation environ(7), getenv(3)
notice this operation can be performed only when execve(2) is currently executed
conferr EINVAL - incorrect argument number or type
errno EINVAL - current syscall is not execve(2)
EFAULT - address of array containing environment variables is illegal or the match argument is NULL
(DEF|UDEF|STR)getelem(<(DEF|UDEF|STR)PTR:tab>,<UDEF:number>)
description Returns element with given number from specified table of strings and/or numbers
return values proper element or -1/NULL on error
notice NULL returned when type of the table is STRPTR doesn't have to indicate an error. same for -1 and table type DEFPTR. good way to check for error in this case is checking errno value
conferr EINVAL - incorrect argument number or type
errno EINVAL - the number argument exceeds number of elements in the table
EFAULT - table address is NULL
UDEF:gettabsize(<(DEF|UDEF|STR)PTR:tab>)
description Returns number of elements in specified table
return value number of elements
notice if tab argument is NULL, 0 is returned and errno set to EFAULT
conferr EINVAL - incorrect argument number or type
errno EFAULT - array address is NULL
(DEF|UDEF|STR)PTR:tabrange(<(DEF|UDEF|STR)PTR:tab>[,UDEF:start],<UDEF:size>)
description Returns new table containing <size> elements starting with element <start> from <table>
return value pointer to new table or NULL if an error occurred
notice this operation is also used for determining table size
conferr EINVAL - incorrect argument number or type
errno EINVAL - start+size is larger than size of tab
EFAULT - table is NULL
STR:genstr(<STR:format>[,?:arg1][,...])
description Function formats it's arguments (<arg1>, ...) according to

format argument, which can contain subset of format specifies found in printf(3). Allowed special sequences: %d, %u, %o, %x, %s, %%. \ escapes next character. for full description see manual page for printf(3). additional Cerb-specific characters for format are: %D - array of signed numbers, %U - array of unsigned numbers, %X - array of numbers displayed in hexadecimal encoding, %S - array of strings, %? - argument of any type - CerbNG detects the type by itself, %A - arguments of currently intercepted syscall

return value generated string or NULL if an error occurred
documentation printf(3)
notice maximum length of generated string is defined in kcerb/cerb_globals.h as CB_GENSTRSIZE_G. If number of characters in generated string exceeds this value, the resulting string is truncated
conferr EINVAL - incorrect argument number or type
error EFAULT - format argument is NULL
STR:log(<DEF:loglevel>,<STR:format>[,?:arg1][,...])
description Logs selected information. is defined in /usr/include/sys/syslog.h. and are identical to those in genstr
return value logged string or NULL if an error occurred
documentation syslog(3), printf(3)
notice maximum length of logged message is defined in kcerb/cerb_globals.h as CB_LOGBUFSIZE_G. If number of characters in the message exceeds this value, the resulting string is truncated
conferr EINVAL - incorrect argument number or type
errno EFAULT - format argument is NULL
UDEF:trace()  
description

Displays trace information based on executed rules.
Used symbols:
==> the rule has been executed
--> the rule has not been executed
[X] the last command (should be your trace())

return values always zero.
notice trace has to be compiled into the module, ie. in cerb_globals.h you have to #define CERB_TRACE. on CONFERR errors, trace is always displayed
conferr EINVAL - spurious arguments were passed to trace()
UDEF:type(<?:arg>)  
description returns argument type, all types are declared in cerb_types.h
return values argument type
conferr EINVAL - incorrect argument number
UDEF:size(<?:arg)  
description Returns the size of argument in memory
return values Depending on type of passed argument, return values are:
CB_DEF_T, CB_UDEF_T - always 0
CB_DEFPTR_T, CB_UDEFPTR_T, CB_STRPTR_T - number of elements in corresponding array
CB_STR_T - length of the string
conferr EINVAL - incorrect argument number or type
STR:basename(<STR:path>)  
description Return the last path component additionally removing trailing slashes
return values generated string
documentation basename(1), basename(3)
notice works just like basename(3)
conferr EINVAL - incorrect argument number or type
STR:dirname(<STR:path>)  
description Returns path without it's last component (opposite to basename)
return values generated string
documentation dirname(1), dirname(3)
notice works just like dirname(3)
conferr EINVAL - incorrect argument number or type