There are 3 project options available to 509 students this semester. Students in 409 must do Option 1.
Note: For students in 409 or 509, if you would like to do a different class project, feel free to come discuss your project ideas with me.
In this project, you will audit open-source software projects for security bugs. You can complete the project in three ways: finding bugs, writing patches, and writing exploits. The number of bugs you must find depends on the size of your team:
| Team Size | 509 Total Points | 409 Total Points |
|---|---|---|
| 1 | 50 | 35 |
| 2 | 90 | 60 |
| 3 | 120 | 90 |
Each task earns points as follows (you can submit a patch and develop an exploit for the same bug, if you want):
| Task | Points |
|---|---|
| Find bug | 1 |
| + Confirm Bug | 1 |
| + Write patch | 1 |
| + Write exploit | 3 |
Each team member is required to demo one exploit to me at the end of the semester (you may work together to develop the exploits, but each member must demo a separate exploit). Note that simply causing the program to crash from malformed input (which is a denial-of-service attack), is not sufficient to count for your exploit demo, although I will give 1 point (instead of 3) for developing such an attack. You should send bug reports (and possibly patches) to the authors of the programs you audit. Your final report should include copies of all the bug reports you make and, whenever possible, a copy of the email from the authors acknowledging that you found a real, exploitable security bug.
Deadlines are:
| Date | Task | Weight of Grade | |
|---|---|---|---|
| 5/12 | Demo exploit | 20 | |
| 5/14 | Final report | 80 |
You can use Freshmeat and SourceForge to find projects to audit.
The following code auditing tools may be helpful
The Unix file-system interface is moving slowly towards a more capability-oriented model. In this project, we will help it along.
The first task is to enable users to grant capabilities to executable files, similar to the Unix setuid executable facility, but with finer-grained controls. You will need to write user-space programs to manage the capabilities granted to an executable, kernel support for implementing the capabilities, and an API with which the executable can use capabilities granted to it.
At a high-level, a capability will grant the application the
ability to access some resource using the granter's authority. Thus,
a capability must specify the authorithy and the resource. However,
when the resource being accessed is a file, then accessing it may
require traversing multiple directories in the file-system, and the
granter may want the application to use different powers for each
step. For example, the grantee may wish the application to use his
user id for one step of the traversal, but one of his group ids for
another step. Thus, a capability for accessing the filesystem should
look like
(/p1/p2/p3/.../pn, c0, c1, c2, ..., cn, allowed-operations)where credential c0 is used to access "/", and each other element pi is accessed using credential ci. Credentials are either user ids or group ids.
Your system should be extensible to support other types of resources, e.g. network sockets, shared memory, etc, although you do not have to implement these extensions. However, do include a "resource class" field in your capability data structures, so that the same data-structure can be extended later.
The allowed operations are resource-dependent. For files, they will be the standard read, write, and execute permissions. Note that a file capability may specify a file or a directory. For directories, the read, write, and execute bits will have their standard meanings.
Each credential will be a pair (user id, group id). The group id may be nil, in which case the user id will be used to access the corresponding resource. If the group id is not nil, then it will be used to access the corresponding resource. In this case, the user id is only present for auditing reasons, as explained below.
Capabilities will be stored with executable files via extended attributes. See attr(5), getfattr(1), and setfattr(1) for information on extended attributes. Linux extended attributes are divided into several namespaces. You should store capabilities under the "security" namespace.
Each capability should have a name that the running process can use to refer to that capability. By default, the identifier for a file capability can just be the path to the file. However, the user should be able to over-ride this default.
You should provide a user-space program, cap, for managing the capabilities associated with files. Your cap program should be able to list the capabilities granted to an executable file, add capabilities to a file, and remove capabilites from a file:
cap ls <executable> cap add [identifier] [-g gid|-u [uid]] <path> <allowed-operations> <executable> cap del <identifier> <executable>The ls and del commands are self-explanatory. Anyone who can read the executable file may list the capabilities granted to that file. Anyone who can write to the file may add or delete capabilities. The add command enables the user to optionally specify an identifier for the capability to be added. If no identifier is given, then the path is used as the capability. The user may also indicate that the capability should use a given group id to access the given path. If the user running cap is not root, then they must be a member of the specified group. Root may also specify that the capability should use a specific user id by giving the -u option. Non-root users cannot specify an alternative user via -u. If neither -u or -g are given, then the capability should use the invoker's userid. The path must be absolute. If the path contains multiple elements, then the specified user id or group id applies to every element of the path. The user may create more complex capabilities that use different credentials for each path component by breaking the path into segments and specifying the credentials for each segment immediately before that segment. The allowed-operations must be a substring of "rwx".
int capuse(const char *identifier, ...);The extra optional arguments to this function are for future use. For file capabilities (the focus of this project), the program can simply call
fd = capuse(identifier);This will attempt to open the file (or directory) specified in the capability identified by identifier in the mode (read, write, and/or execute) specified by the allowed operations in the capability. The open will use the user or group ids specified in the capability for each step of the path resolution. Success will yield a file descriptor. Failure will result in -1. You will have to implement the capuse system call inside the Linux kernel. The kernel will need to scan the capabilities granted to the process to find the corresponding entry and then walk the path, using the specified user or group ids. Since capabilities are used much later than they are granted, we should take steps to ensure that the capability is being used as intended. Whenever the kernel traverses a path element using a user id, it should ensure that the containing directory is only writable by that user (or root), or that the containing directory has the sticky bit set and the current path element is owned by the user. Whenever the kernel traverses a path element using a group id, it should ensure that the containing directory is only writable by members of that group (or root). You may also extend file capabilities to distinguish directory capabilities from file capabilities, and have the kernel verify that the filename resolves to the correct object type at run time.
Deadlines are:
| Date | Task | Weight of Grade | |
|---|---|---|---|
| 5/12 | Demo project | 70 | |
| 5/14 | Code due | 30 |
Before starting on this project, you should write a 1-2 page plan of attack and submit it to me for approval. Your plan should identify the class of bugs you hope to detect (including a few examples), give some recent bug reports demonstrating that this is an important security bug, describe a high-level algorithm for detecting them, and list several open source projects you can use to test your algorithm.
After developing your bug-finding tool, you should test it on several open-source projects. You should plan a demo of your project with me sometime before the end of the semester, and you must turn in a 6-8 page final report describing your algorithm and experimental results at the end of the semester. You may work in teams of 2-3 students.
Deadlines are:
| Date | Task | Weight of Grade | |
|---|---|---|---|
| 4/13 | 1-2 page proposal | 10 | |
| 5/12 | Demo | 40 | |
| 5/14 | Final report | 50 |
You can use Freshmeat and SourceForge to find projects to audit.