Principles of Operating Systems

CMSC 421 - Fall 2019


Project 2

Initial design due by 11:59 PM EST on November 15, 2019

Final design and implementation due by 11:59PM EST on December 6, 2019

Changelog

November 19, 2019: Added Extra Credit description.

November 17, 2019: Added note about putting .h files in include/linux and added template for final design.

November 13, 2019: Fixed typo about syscall being greater than 0 instead of greater than or equal to zero. Thanks to Joseph Robinson for pointing it out on Piazza.

November 6, 2019: Clarified point about root permissions being needed sometimes only applies to the system calls being written in the project.

Introduction/Objectives

In this project, you will create a new version of the Linux kernel that adds functionality to support a simple permission system for using system calls. This system will operate by maintaining a list associated with each system call to keep track of which processes are disallowed from using the system call. This project is designed to teach some basics of system security and to reinforce the idea of how userland and kernel-space interact through the use of system calls.

Before you begin, be sure to create your new GitHub repository for Project 2 by using the link posted on the course Piazza page. Then, follow the same steps you did in Project 0 to clone this new repository (obviously, substitute project2 for project0 from the earlier instructions). You may, at this time, remove the /usr/src/vanilla-project1 directory you created for Project 1, as you will be cloning your new project 2 repository into a new directory named /usr/src/vanilla-project2.

As a first step, change the version string of the new kernel to reflect that it is for Project 2 for this course. That is, make the version string read 5.2.11-cmsc421project2-USERNAME (substituting your UMBC username where appropriate).

For this project, we request that any new code/documentation be placed in your kernel source tree as follows:

/usr/src/project2/                   - Root of your kernel source tree
|- README.proj2                      - README file for your Project 2 implementation. This should include
|                                      the normal stuff you'd expect in a README file, including a list
|                                      of references and anything the TAs should know while grading.
|                                      This must be ASCII or UTF-8 plain text (not markdown).
|- include/                          - Root directory for most kernel header files.
   |- linux/                         - General kernel header file directory.
      |- *.h                         - Any new header files you need to include from existing Linux kernel
                                       source files (so you can include them as >linux/myfile.h<)
|- proj2/                            - All new code/documentation will be in this subdirectory
   |- Makefile                       - Kernel-space Makefile (only referring to the kernel/ subdirectory)
   |- design/                        - Directory containing design documentation
      |- initial.pdf                 - Initial design document (due November 15th)
      |- final.pdf                   - Final design document (due with final submission)
   |- userland/                      - Directory containing userspace code that is required by the project
      |- Makefile                    - Used to build the userspace code
      |- *.c, *.h, *.py, *.cpp, etc. - User-space code for your project
   |- kernel/                        - Directory containing kernel-space code
      |- Makefile                    - Used to build the kernel-space code
      |- source files and directories- Your kernel-space code, possibly in subdirectories as needed
   |- testing/                       - Optional directory containing any testcases you wish to turn in
      |- source files and directories- As needed.
   |- misc/                          - Optional directory containing any other miscelaneous information/data
      |- README                      - Plain text document describing what any data/documentation here is.
      |- * (files and directories)   - As needed. This is where you should put any prototype code.

In order to ensure timely grading of the assignment, if you intend to turn in this assignment late, you must inform us before the due date of the assignment. There will be a form to inform us that you will be turning the assignment in late which will be linked to as the deadline grows near. In addition, all submissions must be completed by 11:59 PM EST on Tuesday, December 10. No submissions will be accepted after this date.

Incremental Development

One of the nice things about using GitHub for submitting assignments is that it lends itself nicely to an incremental development process. As they say, Rome wasn't built in a day — nor is most software. Part of our goal in using GitHub for assignment submission is to give all of the students in the class experience with using an source control system for incremental development.

You are required in this project to plan out an incremental development process for yourself — one that works for you. There is no one-size-fits-all approach here.

You should not attempt to complete this entire project in one sitting. Also, we don't want you all waiting until the last minute to even start on the assignment. Students doing either of these in this course tend to end up with poor grades on assignments. To this end, we are requiring you to make at least six non-trivial commits to your GitHub repository for the assignment. These six commits must be made on different dates and at least two must be done during the initial design phase of the project (that is to say that two commits must be done by 11:59 PM EST on November 15 for full credit).

A non-trivial commit is defined for this assignment as one that meets all of these requirements:

Failure to adhere to these requirments will result in a significant deduction in your score for the assignment. This deduction will be applied after the rest of your score is calculated, much like a deduction for turning in the assigment with a late penalty.

Project Design

Much of your grade on this assignment (35%) is based on the design of your system (so, only 65% of the grade is based on your actual code). A system of this scope should warrant careful design consideration, especially considering the portions of the kernel source code that you will be required to modify in order to make it work. To that end, we are requiring you to submit a design document early on in the project period to ensure that you are on the right track with your thought process on the assignment.

For a project of this scope, we are expecting a 3-5 page initial design document explaining what code you will write, both in userland and in kernel-space. In particular you should document where you intend to make changes to the kernel source code (including files and approximate line numbers). You should strive to make your design a simple to follow as possible, and to minimize any changes to the kernel source code where possible. That is not to say that you should make your changes so small that the system cannot work, but it also means that you should not be writing several thousands of lines of code in the kernel either. Your initial design document should show that you have taken the time to put careful consideration into the proposed implementation of the system. The more detailed your initial design, the more likely that we will be able to evaluate the feasibility of your design (and provide guidance to potentially correct any design issues early on).

Your final design document should be detailed enough that a skilled kernel programmer could follow the document and re-implement your design without consulting your code. We expect you to revise your document to keep up with any changes you make in your design as you move forward with the implementation of the project — that is to say that your final design document should be more detailed than your initial one, and may even contain segments of your code to help explain the system, if necessary. As this document should be more detailed than your initial design, we are also expecting it to probably be of a greater length than the initial design document. To this end, we are expecting the final design document to be at least 5 pages long. We will be providing a template for this design document via Piazza after the initial design is due. You can find the template for your final design here.

Sandboxing

One of the most common ideas in computer security is the idea of sandboxing. Sandboxing is setting up a limited environment for a program, usually before it is run, to ensure that it only has access to the resources that it absolutely needs to complete its task. In this way, if a process were to be compromised by an attacker, the amount of damage that could be done to the system at large is limited.

In Linux (and other UNIX-like systems), the primary method of sandboxing applications has long been the use of process credentials. The credentials of a process generally refer to the user id of the user running the process, the groups to which that user belongs, and the process id of the process itself (along with various other forms of those, like effective user ids and saved user ids). Many server applications on Linux run as an extremely limited user account to ensure that if a remote attacker were to find a code execution vulnerability in the server that the attacker would not be able to compromise files on the system.

Another form of sandboxing is to limit an application from using various system services. This form of sandboxing is often used in mobile OSes, like iOS and Android.

In this project, you will be adding a form of sandboxing to the Linux kernel. Your system will work by maintaining a list of processes that are not allowed to access each system call in the kernel. If a process is in a system call's list, then that process is never allowed to call the given system call (unless that process were to be removed from the list).

Your system for this project will require you to find and modify the code that is responsible for dispatching system calls in the Linux kernel. You will need to modify this code to check your permissions list and to make the system call return an error code of -EPERM without executing the real code of the system call if the process is to be denied access to the system call.

Your code must also keep track of how many times each process attempts to access each blocked system call. The counter should be of type int and should be initialized to 0 when a system call is initially blocked. No records need be kept if the system call is unblocked.

Design Hints

In the kernel itself, look in the arch/x86/entry/ directory in your kernel source tree for the code that handles entry into the kernel by way of system calls. Remember that you are working with a 64-bit kernel, so you don't want to look at files that have _32 in the filename, most likely. Specifically, the entry_64.S file contains the actual entry point in the kernel where system call software interrupts end up going.

If you end up modifying any assembly code, remember that you must save and restore any registers that you modify to ensure that you do not break the normal operation of the code. That is not to say that you have to modify any assembly to complete this assignment, as it is possible to do so without modifying any assembly.

Finally, there is a system called ptrace in Linux that is able to trace the usage of system calls. In addition, there is an auditing framework, a system called SECCOMP, as well as SELinux support in the kernel. You are not allowed to use any of these systems to implement your assignment — you must write the code yourself.

Extra Credit

In this assignment, you will have the opportunity to get extra credit for completing additional work beyond the basic set of requirements. Information about this extra credit will be released later during the project assignment.

In order to qualify for any extra credit on the assignment, you must make a reasonable attempt at all of the basic requirements of the assignment. That is to say that extra credit cannot make up for you failing to do a design document, for instance.

There are multiple parts to the extra credit for this assignment. The first part of the extra credit may be completed without doing the second. The second may be completed without doing the third, but does require the first part be completed. The third part of the extra credit requires that you have completed both earlier parts.

Part 1 - 5%

The first part of the extra credit is to make it so that your sandbox system is able to be turned on or off at configure time when building the kernel. That is to say that you will make it so that during the make xconfig step in the kernel build that there is an option presented for your system call sandboxing, complete with a description of what it is and how it works to be presented to the user like any other option at compile time. Your option must be set so that by default it is on. Keep in mind that your system calls must be defined whether the system is on or off, so you must provide stub versions of the system calls if the system is configured off.

Part 2 - 15%

In part 2 of the extra credit, you will be adding two new system calls to support a second sandbox system. This one will be separate from the sandbox system in the main project and can be used at the same time. This sandbox system will have permissions directly associated with processes rather than being sorted on the system call level. That is to say that you will store the list of blocked system calls in the task_struct structure in the Linux kernel that are blocked by way of these two new system calls. In doing this, you should ensure that you add no more than the minimal amount of extra data to the task_struct structure. Also, the system calls blocked this way do not require you to keep any sort of statistics on them (there is no count call involved here).

The two new system calls are as follows:

You must also provide the ability to turn this system on or off at configure time, as in Part 1 of the extra credit. It should default to being turned on.

Finally, as this portion of the extra credit does add additional system calls, you must account for this in the code for the regular credit portion of the assignment. That is to say that it must be possible for us to block the two sbx421alt system calls with the sbx421_block system call (and conversely we must be able to block the sbx421 system calls with sbx421alt_block as well).

Part 3 - 10%

In part 3 of the extra credit, you will be required to make it so that the configure permissions in Part 2 of the extra credit are automatically propagated to child processes when a process forks a new process. That is to say that if a process does a sbx421alt_block(0, 123); fork(); then system call 123 must be blocked not only in the parent process that originally blocked it, but also in the child process.

You must provide a configure time option to turn this behavior off. It should default to being turned on.

Notes on Extra Credit

You are not allowed to ask for help on any of the extra credit portions of this assignment. The TAs have all been instructed to not answer any questions that may arise in relation to it. Any questions that are asked on Piazza in relation to the extra credit will be deleted. You must complete the extra credit on your own.

Also, if you complete any/all of the extra credit, you must inform us of this in your README.proj2 file, as well as in your final design document. If you do not inform us that you have completed the extra credit, you will receive no extra credit even if you complete it.

Kernel Development

Remember when developing your kernel-space components that code in the kernel is often being accessed by multiple processes at a time. As there may be many processes running that you will be logging system calls from, you must ensure that you lock properly where needed to ensure concurrent access does not corrupt the state of your system.

As this system will involve adding code into the path of every system call made, you should also ensure that your code is as efficient as possible. System calls are made extremely often, so even a small unnecessary delay in your code will cause your system to slow down signficantly as it snowballs across all of the processes that are running on your system.

As this code will be part of the kernel itself, correctness and efficiency should be of primary concern to you in the implementation. Particularly inefficient (memory-wise, algorithmic, or other poor coding choices) solutions to the problem at hand may be penalized in grading.

If something requires root privileges to run, then the user id or effective user id running the system call must be that of root (numerically 0). Otherwise, an error of -EACCES should be returned. Some system calls required by this process may require root access under limited circumstances, so be careful to implement the required permissions correctly. Please note that this only applies to the system calls specified below in the "New System Calls Required" section. You are not modifying permissions for any other system calls in the kernel, nor are you to implement any method for specific users (including root) to bypass the block lists that you are implementing. Also, please note that the system calls you are implementing in this project can also be blocked using the system calls, and in that regard they should be treated as any other system call for the purpose of enforcing the block lists. Take this example, say that a root-owned process does this:

sbx421_block(0, __NR_sbx421_unblock);
sbx421_block(0, __NR_sbx421_block);
That process will no longer be able to call sbx421_block or sbx421_unblock after those two lines run, even though it is owned by root.

Finally, you are to implement this system on your own -- no group work is allowed on this assignment. If you use any external resources, you must cite them in your README file in the proj2/ directory.

New System Calls Required

Userspace Requirements

You must provide with your implementation 4 separate userspace programs to utilize the functionality of the system calls required by the project. Three of these programs will simply be simple wrappers for the system calls to call them with the parameters provided on the command line. These programs should have the same names as the system calls they are designed to call when compiled. That is to say, from the appropriate directory, we should be able to do ./sbx421_block 1234 23 as root to block process 1234 from running system call 23. These programs should do basic error checking to ensure that the arguements provided are correct (i.e, that both arguments are valid integers (greater than 0 for the PID and greater than or equal to zero for the syscall number) and that the system call number is in range (that is to say, less than the maximum system call number that you will write for this assignment)), as well as printing out an appropriate error message if the user would not have permission to run the system call (that is to say that the user isn't root).

The fourth userspace program you must provide with your assignment is a program called "sbx421_run" to run any other application installed on your system with the credentials of a specific user, with a list of system calls from start up. The list of system calls will be provided in a plain text file (the name of which will be given as an argument to the program) as a whitespace-separated list of numbers. As an example, if we wanted to run the command "gcc -v" as the user bob with a list of blocked system calls in the file "/etc/blocked_syscalls", we should be able to do the following from the correct directory, as root: ./sbx421_run bob /etc/blocked_syscalls gcc -v . You need not parse any of the arguments given on the command line after the filename for the list of system calls — just run the program as specified. If the user specified does not exist on the system or the filename specified for blocked system calls cannot be opened or parsed successfully, then you should print out an error message to stderr and exit without running the command given.

Testing

While your system call code and userspace programs required by this project should be adequately tested before turning them in, we are not requiring you to turn in any testcases with this assignment. You are welcome to do so if you want — be sure to follow the directory structure given at the beginning of the project if you do.

Submission Instructions

You should follow the same basic set of instructions for submitting Project 2 that you did in previous projects. That is to say, you should do a git status to ensure that any files you modified are detected as such, then do a git add and a git commit to add each modified/newly created file or directory to the local git repository. Then do a git push origin master to push the changes up to your GitHub account.

Be sure that you have included all of your modified/newly created files, including the required documentation and that it all is in the correct directory layout, as specified in the introduction to the project.

You should also verify that your changes are reflected in the GitHub repository by viewing your repository in your web browser.

Submission artifacts that are required for the possiblity of full credit on this assignment are as follows:

  1. Six non-trivial commits during the course of the assignment, with at least two committed and pushed to GitHub by 11:59 PM EST on November 15, 2019.
  2. A three to five page initial design document in PDF format, which must be commited and pushed to GitHub by 11:59 PM EST on November 15, 2019.
  3. A five or more page final design document following the template that will be distributed on Piazza after the initial design document is due.
  4. Compilable kernel-space source code implementing the sandboxing system described in the project (and all of the auxiliary modifications that must be made to the kernel in order to accomplish the compilation of the system).
  5. Userspace code (in a language of your choice that is usable without requiring any additional packages to be installed on the VM beyond those installed in the setup of Project 0) to implement the four required userspace programs for the assignment. If this code is in a compiled language, a Makefile to build the code is also required.
As mentioned in the testing section above, no userspace test cases need to be provided for this assignment, however you may do so if you wish.

References

Below is a list of references that you may find useful in your quest to complete this project:

If in doubt, the Kernel API and Linux Cross Reference should be your ultimate guides.

What to do if you want to lose points on this project

Please do not make us take off points for any of these things!