Capsicumization of the base system
Student: ShubhGupta (shubh@freebsd.org)
- Mentors:
MariuszZaborski (oshogbo@)
MarkJohnston (markj@)
Project description
Writing an application which makes use of capsicum’s principles is not difficult. But what poses a challenge is to modify the existing applications. Most of the applications’ code was not written with privilege separation in mind. So, in order to capsicumize an application, we need to study what all does an application interact with, what all resources does it require, which can be a good point to enter the capability mode. The application might require a casper service, either out of the existing casper services or a new one. While working on a new casper service we need to focus on:
- what API we are willing to offer, mapping out the necessary functions
- what all limitations should be enforced on this service
We aim to capsicumize i.e sandbox all of the existing base applications. Many applications have been sandboxed but still a lot of applications need to be capsicumized. This project aims to sandbox some of them, namely traceroute6, fsck_ffs, fsdb, fsck_msdosfs, syslogd/file(1).
Differential revisions Submitted
Differential |
Title |
Status |
Capsicumize traceroute6 |
Accepted |
|
Capsicumize fsck_msdosfs |
Under Review |
|
Capsicumize fsdb |
Under Review |
|
Capsicumize fsck_ffs |
Under Review |
|
Capsicumize file(1) |
Under Review |
Bugs Reported
Title |
Status |
traceroute6: Fix most warnings at the default WARNS level |
Approach used
The generic approach that we will use to sandbox an application will involve:
Read the code
The first phase involves getting to know the application, reading the code and understanding what the application does. This will help in identifying which part of the code is allowed in the capability mode and which is not.
Reorganize the code
After we are well versed with the application, we are ready to sandbox it. After understanding what all descriptors does the application need before entering the sandbox, we can provide those descriptors before cap_enter() We can further read the code to understand what all capabilities do the descriptors need. For example in D9303(capsicumizing traceroute) it can be clearly seen that the connect() call was made before the call to cap_enter()
See if any casper service is required
The application might need a service such as a DNS lookup or opening multiple files, which won't be allowed in the sandbox. Casper makes it possible to utilise these services from inside the sandbox. If writing a new casper service, we need to figure out what API are we trying to provide and what limitations it enforces.
Enter the sandbox
Finally, we select the most suitable point of calling cap_enter() and enter inside the sandbox. Now, our application runs inside a sandbox making use of Capsicum and Casper.
Project Overview
The project involved picking up applications one by one and sandboxing them while working on the reviews that my mentors provided.
traceroute6
- My initial guess was that sandboxing traceroute6 should be pretty similar to sandboxing traceroute which was already done
- It turned out it wasn't because in traceroute6, send_probe() changed the address of each packet, which is something that is not allowed for UDP sockets in the capability mode.
- The fix around this problem was to use a raw socket instead of the IDP socket and create its header in the user space.
- This helped me understand how the headers in the various protocols work and how can I create one
Also, while sandboxing traceroute6, I figured out the MakeFile was ignoring some warnings. I fixed them too
Code
fsck_ffs
- Our first guess at entering the capability mode was to get inside the setup() call because the file system is opened there.
- I was able to sandbox using this approach. I had to utilize capsicum helpers as well as cap_sysctl and cap_pwd services
- Later when I began to sandbox fsdb, I realized it uses the same setup() which fsck_ffs uses. Which means they both enter the capability mode at the same piece of code, which wasn't good because I wanted their sandboxing to be decoupled and wanted to enter capability mode somewhere else in fsdb.
- I moved the cap_enter() calls to their respective main() just after setup() call was finished
- The main issue that still needs a resolve, is that if the PID of the process modifying the sysctl is not equal to the main fsck process, it will return an error. In case of sandboxing, cap_sysctl will try to do that job for us and it has a different PID. For this, we came up with a fix of modifying the kernel to allow the main process's children to also modify the sysctl.
- Testing fsck_ffs was a little tricky. I had to use mdconfig to create a fake disk with FFS file system on it, tweak its inode counts using fsdb and then run fsck_ffs on it.
Code
fsdb
Where and why did I enter the capability mode?
- fsdb calls setup() from the fsck_ffs directory, which opens the arg device
- doing cap_enter() inside wouldn't allow el_init() to open termcap.db and el_source() to open ~/.editrc
- Hence, I did a cap_enter after el_source() inside cmdloop()
Why did I use cap_pwd and cap_grp casper services
- printactive() from fsdbutil.c calls getpwuid() and getgrgid()
- printactive() is called before entering the capabality mode, hence I checked if the casper service is opened or not in fsdbutil.c
- printactive() is also called after entering the capability mode, for fsdb commands such as *active*. Hence, casper service was needed here
Code
fsck_msdosfs
- My initial guess was fsck_msdosfs should be trivial to sandbox, wherein I just have to cap_enter() inside the checksys() call after the filesystem is opened.
- The code revision worked for a single device but failed to work for multiple devices given through the command line.
- Which is why I had to use cap_fileargs to open the different file systems. Also, to keep the code elegant, I moved the code for opening a filesystem inside main() instead of checksys()
- The code was being used n different platforms, which is why I wrapped up the sandboxing logic inside HAVE_CAPSICUM
- Testing fsck_msdosfs was similar to fsck_ffs
Code
file(1)
- file(1) was a little difficult to understand at first to be able to begin sandboxing it
- I started with Allan Jude's revision, wherein he opened a set of file descriptors prior to entering the capability mode and then provided these descriptors to the functions which needed them
- I tried to reciprocate a similar approach wherein I used cap_fileargs to open those descriptors and then feed them to the functions wherever needed
- It required changes in the libmagic and file(1) logic, which as a matter of fact lived inside file's src directory together.
- The application works if a file is provided to it in an argument, but breaks for the case wherein a file with the paths of all those files which are to be checked is given
- This requires a little change in the code, which is not trivial and I am yet working on it
- The moment I am able to resolve this, I should be able to send a diff and see file(1) running in a sandbox
Code
Testing
- I used ktrace and truss actively to trace the system calls and test the code.
- Testing of traceroute6 could not be done effectively because my ISP does not provide me with V6 connectivity, hence testing of it was only limited to localhost
- Testing of fsck, fsdb utilities required me to create fake disks using mdconfig and create inconsistencies in them and then try to fix them up
Future
This year, GSoC was a tremendous learning experience for me, wherein I worked for hands on modifying legacy applications and understand the logic that they use. Trying to sandbox an application requires you to understand the underlying logic that the application uses, then only we can begin sandboxing it. Everything from writing a UDP header for traceroute to utilizing the casper services for our purpose, analyzing the different approaches, and understanding which one to choose added immensely to my learning curve.
I plan on staying in touch with my mentors and sandboxing file(1) and then start picking up some advanced work like sandboxing syslogd, which might require writing a new casper service. FreeBSD community has always been very helpful and supporting, which makes me more excited about working with them ahead in time.
My Fork
https://github.com/ShubhGupta2125/freebsd
Useful links
My Past Contributions to FreeBSD