« Previous 1 2 3 Next »
Capsicum – Additional seasoning for FreeBSD
Hot and Spicy
Split
A nice example of compartmentalization is provided by the rwhod
program. This system daemon is responsible for retrieving system information. The information includes which user is currently logged in, as well the use period and time of login.
To switch the daemon to Capsicum, the code must be cleaned up, and the areas to be protected need to be split into functions: The two main functions are void receiver_process(void)
for receiving data and void sender_process(void)
for sending the requested information to a client.
After completing the hardening in this example, the programmer needs to consider which access rights the tool requires for proper operation. In particular, you need to focus on the void receiver_process(void)
function, because it is used to write data to the whod.<hostname>
file in the /var/rwho
directory.
Earlier in the text, I explained that a file descriptor created for writing data to a file has the ability to read a file. For malicious code, this situation is welcome, because it means that undesirable information can be propagated. However, the Capsicum cap_rights_limit()
function prevents precisely this situation if you set the CAP_WRITE | CAP_FTRUNCATE | CAP_FSTAT
flags:
if (cap_rights_limit(whod,CAP_WRITE | CAP_FTRUNCATE | CAP_FSTAT) < 0 && errno != ENOSYS) { syslog(LOG_WARNING, "cap_rights_limit: %m"); exit(1); }
Check out the complete source code [4] starting at line 404 for more details. The flags indicate that the whod
file descriptor can only write to the file (CAP_WRITE
), change the size of the file (CAP_FTRUNCATE
), and retrieve the file status information (CAP_FSTAT
). Any other operation is prevented. If malicious code does try to manipulate the flags, it has no chance of success. Flags that have been set can no longer be changed.
Additionally, you need to define clearly which file operations can be executed in the /var/whod
directory. The code [4] as of line 358 (Listing 2) handles this.
Listing 2
File Operations
if (cap_rights_limit(dirfd, CAP_CREATE | CAP_WRITE | CAP_FTRUNCATE | CAP_SEEK | CAP_LOOKUP | CAP_FSTAT) < 0 && errno != ENOSYS) { syslog(LOG_WARNING, "cap_rights_limit: %m"); exit(1); } if (cap_enter() < 0 && errno != ENOSYS) { syslog(LOG_ERR, "cap_enter: %m"); exit(1); }
These few lines of C code are responsible for ensuring that files can be created in or added to the already open directory using the dirfd
file handle. However, the program can read the files created here.
Window to the World
Many utilities and tools need access to certain resources. One example has already been mentioned in connection with tcpdump. This tool requires access to the domain name server to convert host names to IP addresses. Within the program, the name service switch (NSS) is called to handle this task, but because Capsicum prevents this access, another solution had to be found. It came in the form of the Casper tool (Capsicum Service), which – as a daemon – provides a controlled option for allowing exceptions.
The function of Casper is quickly explained by Figure 4. Casper starts a program, such as tcpdump, which is locked into a sandbox. Before any monitoring mechanisms can be armed, the program logs the exception rules with the Casper daemon and then activates the protection mechanisms. Such an action must be done beforehand because no communication with system services – and this includes Casper – is possible after enabling Capsicum. In the example, this was handled as shown in Listing 3. The complete code is available online [7].
Listing 3
Casper
[...] #ifdef HAVE_LIBCAPSICUM if (nflag) { capcas = NULL; capdns = NULL; } else { capcas = cap_init(); if (capcas == NULL) error("unable to contact Casper"); capdns = cap_service_open(capcas, "system.dns"); if (capdns == NULL) error("unable to open system.dns service"); /*Limit system.dns to rev. DNS lookups.*/ limits = nvlist_create(0); nvlist_add_string(limits,"type", "ADDR"); nvlist_add_number(limits,"family", (uint64_t)AF_INET); nvlist_add_number( limits, "family", (uint64_t)AF_INET6); if (cap_limit_set(capdns, limits) < 0) error( "unable to limit access to system.dns service"); nvlist_destroy(limits); / * Casper capability no longer needed. * / cap_close(capcas); } #endif /* HAVE_LIBCAPSICUM */ [...]
First, cap_init()
is called to contact the Casper daemon and register the program. In the next step, the cap_service_open(...)
function reports the desired exception to the daemon. In this example, this is DNS requests, as shown by the system.dns
option. The daemon expects a list designated by = nvlist_create(...)
with details of the functionality. The first element states that the function relates to converting IP addresses to hostnames, as shown by type
and ADDR
. The two next entries describe the IP address family. This example contains both IPv4 and IPv6 addresses (AF_INET
and AFINET6
).
The script passes this list, using cap_limit_set(...)
, to the Casper daemon and then deletes it, because it is no longer required by the tcpdump program. From this point, Casper has all the information needed to allow the tool access to the domain name service.
You might ask whether this approach does not undermine the sandbox concept. Casper does not grant free access to the resource but uses the finely granular rights provided under Capsicum. Additionally, the author of the program specifies how this communication with the outside world takes place, rather than some external program.
Hot Applications
To demonstrate that not only system programs, but also user programs, can be hardened with Capsicum, Google adapted the new environment for the Google Chromium web browser. When launched, Chromium spawns several processes that handle tasks such as processing HTML code, processing JavaScript, or encrypting data. The original FreeBSD port of the browser contained no security features like sandboxing.
The fact that the program is already compartmentalized facilitated adaptation to the FreeBSD Capsicum environment. The subprocess that retrieves the graphical representation of the website receives special privileges that allow it to communicate with the Xorg graphics system. Protected memory areas are used for transporting data between the various subprocesses. Subprocesses have no access to locations outside the sandbox for compiling JavaScript, HTML, and XML.
Although the code size of Chromium is huge – it is said to be around 4.3 million lines of code – the Capsicum implementation was trouble-free and took just a hundred lines of code. If you want to achieve the same level of security on Windows, for example, you need more than 23,000 lines of code [8]. Also the developer of the GNUstep desktop suite has already announced the intent to use Capsicum in applications.
« Previous 1 2 3 Next »