\documentclass[twocolumn]{article}
%\documentclass{article}
\usepackage{tikz}
\usepackage{setspace}

%opening
\title{Stateful access control in Linux using the LSM}
\author{Thomas Howard Uphill}

\begin{document}

\maketitle

%\doublespacing
\begin{abstract}
Modern computing environments are subjected to a greater number of security problems than the operating systems were originally designed to withstand\cite{web}.  Only a small number of programs should be able to manipulate sensitive information\cite{verify}.  Current operating system security policies are inadequate to address this problem.  Maintaining the state of a system can be used to maintain order\cite{lgi}.  We propose that maintaining state can be used to not only reduce the complexity of a security policy but also achieve results not possible without maintaining state.

To implement our model we use the LSM framework in the Linux kernel.  LSM is a mature security framework with several real world implementations\cite{selinux}.  We implement a simple system we call lsmlgi which maintains counters for the operations of read, write, execute and delete.  We also create unique identities for processes and attach these ids to files created by a process.

We are able to test a visitor law which prevents a user of an account from deleting or modifying files created by another session of his/her account. We implement an Apache law which prevents an account from executing files that it has created (to be used on a webserver to prevent the webserver from running files it has created).  In our budget law example we prevent a process running as a certain user from executing more than a set number of subprocesses.

Maintaining state in Linux is possible.  In future work we would implement several of the LGI paradigms such as doAdd() which allows an arbitrary element to be added to the state of an agent (process)\cite{lgi}.  Our law system is very rigid, one of the strengths of a system like LGI is that laws can do almost anything and are not restricted to a simple yes or no answer when performing an operation.  Of the LSM implementations studied, SELinux appears to be the most mature, future work should attempt to augment SELinux with dynamic state information.
\end{abstract}

\section{Introduction}
When UNIX was first developed in 1969, access control was not a great concern.  The systems of the day were simple and there were very few users.  Intrusion and attack were not yet a problem.  Security in general was not a concern. However, due to increases in connectivity and data sharing, the assumption that existing security mechanisms are adequate is fading\cite{flawed}.     

The simple access control provided by UNIX is a discretionary access control mechanism based on three 3-bit access vectors.  Permissions to do anything on the system are broken into three groups.  For each file there is an ``owner'', a ``group'' and the catchall bucket of ``other''.  The ``owner'' is the owner of the file. The ``group'' is the group owner of the file, a group is a collection of users. Any user in the specified group is granted the permissions specified in the 3-bit group vector. 
``Other'' is any user on the system, id est anyone.  Other includes the owner and the group and therefore precludes preventing access for the owner or group while allowing access for ``other''.  Each of these three octets can have the permission to read, write or execute the file (as well as some special permissions not addressed here).  This system was adequate in 1969 and was adopted by Linus Torvalds when he wrote Linux in 1991. Not much has changed in 20 years.

These permissions make it difficult to properly secure a system as there is not enough resolution to finely tune the access control on the system.  For example, certain files on the system need to be accessible by more than one user or group but should not be accessible by everyone on the system (other).
 
To address the issue of fine grain access control, POSIX Access Control Lists (POSIX ACLs\footnote{The name POSIX is used by the POSIX security drafts, .1e and .2c, were never ratified.}) were created.  An ACL is a list of permissions assigned to an object.  Each permission in an ACL is known as an access control element (ACE).  ACLs may contain multiple entries for multiple groups, in this way files may belong to more than one group. ACLs may also contain negative permissions.  For example a file may belong to group X and be readable and writable by group X.  An ACE can be applied to the file that says user Y cannot read or write the file.  Even if Y belongs to group X, she cannot access the file.  To support ACLs, Linux stores the ACL in an extended attribute on the filesystem (we mention this here as we make use of this as discussed in section \ref{implementation}).

POSIX ACLs increase the resolution of permissions but are still a form of discretionary access control (DAC).  A more secure system of access control is mandatory access control (MAC).  With a discretionary policy, the user is involved in the definition of the policy and assignment.  Carelessness by any one user can result in a violation of the systems security policy\cite{flawed}.  Mandatory policy removes the user from the equation and states that all access is denied by default.  The policy must allow operations to take place or else they are denied.  However, even with a very restrictive mandatory policy, an application may misbehave within its sandbox\cite{flawed}.

A better system of assigning permissions is needed, a system of least privilege and separation of duty.  One solution is to assign permissions to roles and then assign users to roles, this is the approach taken in \cite{rbac}.

The problem all these systems suffer is that to achieve useful results, the policy must become enormous.  As well, system administrators ``must resort to complex policy modifications to resolve conflicts''\cite{acs}.  A well designed security framework should be flexible, economic and have a simple policy\cite{flawed}.  No model can meet all the security needs of modern operating system.  A successful policy must be flexible; there must be a clean separation of policy from enforcement\cite{which}.  We believe that maintaining state will reduce the complexity of the policy and still achieve the same level of security.  Our increasing use of web protocols and network communication means that access control needs to be stateful in order to ensure proper {\em conversations} are taking place between agents\cite{web}.  It has been suggested that conversations can be modeled with a finite state transition system\cite{web}.  
 
The next few sections introduce the key kernel concepts and background required to implement our model.



\subsection{Linux Kernel and Files}


The Linux kernel views everything as a file (keyboards, disks, printers, screens, etc).  For example when a process wishes to update the screen with some information, it simply writes the information to the screen file and the kernel updates the screen accordingly.

Real files, things that live on a disk or other media are represented as inodes or information nodes in the filesystem.\footnote{Although some things are are not real files also have inodes associated with them.}  An inode is a data structure that contains information about files, such as owner, group, type of file (directory, plain file or special file) or permissions and pointers to blocks of data.

Directories are files, which means they are actually inodes, the permission to write a file to a directory is granted by first checking that permission is given to update the directory inode.  A directory is just a mapping between filenames and inodes\footnote{This is why a move command on linux is so fast, move is just deleting an entry in one directory and inserting it in another; rename is equally quick.}.

In UNIX\footnote{Actually in the ufs and ext2/ext3 filesystems}, files may be listed in several directories, the filename of a file is just a string in a directory.  The multiple filenames are known as hard links to the inode (this is not to be confused with symbolic linking).  The Linux kernel does not maintain file information for the purposes of permissions, it only deals with inodes, since inodes are the ultimate target of filenames (and this removes any ambiguity).  Our implementation only addresses inodes for this same issue.

\label{files}



\subsection{Programs and threads}

When a program is executed on Linux it becomes a process.  Running processes may start subprocesses or enable several threads.  Since threads share the same process information, concurrency is an issue when attempting to maintain the state of the task.  We use semaphores to protect updates of the state.  Processes are spawned by other processes, each process has a unique parent and may have several children.

One of the first things the kernel does when booting is to start a process called init, since it is the first true process on the system, it is assigned the process id (pid) of 1.  All subsequent processes are children of init.

\subsection{LSM}
In order for Linux to remain secure in the changing environment, a stronger mechanism had to be built to prevent Linux from becoming a ``fortress built upon sand.''\cite{flawed}.  To address growing concerns over security, the Linux Security Modules (LSM) framework was created.  LSM has been part of the Linux kernel since version 2.6. In 2001, the NSA presented its work on SELinux to Linus Torvalds\cite{nsa} and expressed an interest in having SELinux incorporated into the mainstream kernel.  Linus acknowledged that some sort of enhanced security was needed, but didn't want to choose the implementation.  Linus opted to create a framework for Linux security modules (LSM).

A kernel module is a self contained piece of the kernel that can be dynamically inserted and removed from the running kernel\footnote{The module framework also allows for modules to be compiled statically into the kernel.  Modules that are statically compiled still behave as though they were dynamically loaded.}.  Kernel modules have previously been used without the LSM for policy enforcement.

In Linux the kernel runs in a memory space that is separate from user programs.  The kernel has access to the hardware and memory of the system and user processes must access hardware via the kernel as shown in figure \ref{separation}.  User processes access hardware and memory via system calls. 

\begin{figure}
\begin{center}
\begin{tikzpicture}
 \draw (0.2,0) node[rectangle,minimum width = 4.4cm, rounded corners, draw, fill=blue!20] {kernel};
 \draw (0.2,1) node[rectangle,minimum width = 4.4cm, rounded corners, draw, fill=red!20] {user space};
 \draw[dashed] (-1.6,0.5) -- (2,0.5);
 \draw (-1.5,-0.6) node [rectangle, minimum width = 1cm, rounded corners, draw, fill=green!20] {CPU};
 \draw (-0.15,-0.6) node [rectangle, minimum width = 1cm, rounded corners, draw, fill=yellow!20] {memory};
 \draw (1.55,-0.6) node [rectangle, minimum width = 1cm, rounded corners, draw, fill=black!20] {hardware};
\end{tikzpicture}
\end{center}
\caption{Separation of user space and kernel space\label{separation}}
\end{figure}

Most modules resort to system call interposition to {\em overpower} the system call\cite{lsm}.  To exemplify system call interposition, assume a module wishes to affect the outcome of {\tt open} calls.  The module {\em x} will inform the kernel that {\tt open} calls are now handled by {\em x}.  The module must then perform the checks it wishes to do on incoming data and pass the results to the original system call of {\tt open}, or perform the work of the {\tt open} system call itself.  System call interposition is a potentially dangerous mechanism because it requires that the security module directly interfere with the system calls.  The module needs to know if the API for the system call has changed in any way.  Also the interposition function must return appropriate return values to the calling program or risk crashing the program (or worse, crashing the kernel).   

LSM uses a series of hooks in the kernel that allow a security module to either allow or reject an operation.  In this way the LSM API can remain relatively unchanged while the system calls upon which it depends remain fluid.  LSM asks the security module the question 
``May a subject S perform a kernel operation OP on an internal kernel object OBJ?''\cite{lsm}.   

LSM is layered on top of the existing DAC system in Linux.  The discretionary access control checks are made before the LSM is consulted, if the DAC checks are negative (indicating permission denied) then LSM is never consulted.  This serves two purposes, it reduces the amount of time that LSM checks are made (which improves performance) and it greatly reduces the amount of modification to the kernel required to make the LSM hooks authoritative\cite{lsm}.  A diagram of the implementation of LSM is shown in figure \ref{lsmimpl}.

\begin{figure}
\begin{center}
\tikzstyle=[semithick]
 \begin{tikzpicture}
  \draw (0,0) node (kernel) [anchor=south west, fill=blue!20,minimum size = 5cm,rounded corners, rectangle] {};
  \draw (2.5,4.5) node {kernel};
  \draw (0,5.25) node (app) [anchor=south west, fill=red!20,minimum width = 5cm, rounded corners, rectangle] {application};
  \draw[dashed] (0.1,5.125) -- (4.9,5.125);
  \draw (1.25,4) node (open) [fill=green!20, rounded corners, rectangle] {open};
  \draw[->] (app.south) -| (2.5,4.75) -| (open.north);
  \draw (1.25,3.25) node (look-up) [fill=green!20, rounded corners, rectangle] {look-up inode};
  \draw[->] (open.south) -- (look-up.north);
  \draw (1.25,2.5) node (dac) [fill=green!20, rounded corners, rectangle] {DAC};
  \draw[->] (look-up.south) -- (dac.north);
  \draw (1.25,1.75) node (lsmhook) [fill=green!20, rounded corners, rectangle] {LSM hook};
  \draw[->] (dac.south) -- (lsmhook.north);
  \draw (3.75,2.25) node (lsm) [fill=black!20,minimum height=1.5cm, circle] {LSM Module};
  \draw[>-] (lsmhook.north east) -| (2.5,2.25) -| (lsm.west);
  \draw[>-] (lsm.south) -| (3.75,1) -| (2.5,1.5) -| (lsmhook.south east);
  \draw (0,-0.75) node (inode) [anchor=south west, fill=yellow!20,minimum width = 5cm, rounded corners] {inode};
  \draw[->] (lsmhook.south) -| (1.25,0.5) -| (inode.north);
 \end{tikzpicture}

\end{center}

 \caption{LSM Implementation\label{lsmimpl}}
\end{figure}


LSM adds a security field to key kernel structures.  As described in section \ref{files}, files on disk are inodes.  An inode loaded into memory is held internally by the kernel in a struct inode structure as shown in figure \ref{inode}. To support LSM, a security field has been added to the inode struct which is a pointer to type void ({\tt void *i\_security}).  Using a void pointer allows the pointer to point to anything or nothing depending on what the security module decides. 

\begin{figure}
\begin{center}
\begin{tikzpicture}
\draw (0,0) node [fill=blue!20,text width=6cm] {
\begin{verbatim}
struct inode {
	struct hlist_node	i_hash;
	struct list_head	i_list;
	...
	void			*i_security;
	...
}
\end{verbatim}
};
\end{tikzpicture}
\end{center}
\caption{inode struct\label{inode}}
\end{figure}

Calls are made to LSM functions (hooks) when a new inode is created or when any inode is accessed by the kernel (read and write operations).  As an example, when a new inode is created, a call is made to the lsm function {\tt inode\_alloc\_security}, this creates an {\tt inode\_security\_struct} and attaches it to the inode struct.  An entry is placed in the kernels inode security cache at this time as well.  A call is then made to {\tt inode\_create} which determines if permission should be granted to create the inode.  LSM is compartmentalized in this way so that the operation of creating a security context is independent from the verification of permission.  Similarly when a request is made to delete an inode, the permission to do so is determined before calling the function which removes the inode ({\tt inode\_free\_security}).

A module identifies itself as an LSM module by calling the function register\_security, it can unregister with unregister\_security.  LSM also provides a notion of stacking.  A module may register itself with a primary LSM module as a secondary module\footnote{We attempted to stack with our SELinux implementation and were unsuccessful.}.

LSM does not provide any locking for the security fields, the module must perform any required locking (for synchronization).  Allocation and deallocation of the security structures is also the responsibility of the LSM module.  Our module maintains an inode cache, the module must create and destroy entries in this cache as inodes are created, deleted or accessed.  To persistently bind security attributes to files, a set of extended attributes are set on the inodes in the filesystem, a complex task\cite{lsm}.

\subsection{SELinux}

SELinux was developed by the National Security Agency (NSA) and released to the public on December 22, 2000\cite{nsa}.  SELinux is a mandatory access control (MAC) system for Linux.  SELinux provides support for several types of MAC policies including role-based access control (RBAC) and multi-level security (MLS).  An SELinux policy is composed of allow statements\footnote{allow statements are only one of several statements possible in SELinux policy, they are however, the only type of concern in our context.} of the form:

\centerline{\tt allow type target\_type : file \{ permission \};}

This is an example of an allow statement, with MAC systems anything not allowed is denied by default.  This line would allow a process running with type {\tt type} to do {\tt permission} on a file with type {\tt target\_type}.
Each file on the system has an selinux security context assigned to it.  The security context of the file {\tt /etc/passwd} on our system is {\tt system\_u:object\_r:etc\_t}.  The security context is a concatenation of the form {\tt user:role:type}.
An SELinux user is similar to a UNIX user.  Role is a concept based on role-based access control, it connects a series of users with a collection of programs that they should be allowed to execute\cite{verify}.
 This means for an application to read the /etc/passwd file, its type must have the right to read a file of type etc\_t.  There are potentially hundreds if not thousands of different types on the system and each type must have rules to access the files it needs to access.  This results in several thousand rules in the policy.  On our RedHat Enterprise Linux 5$^{\textregistered}$\ system the default ``targeted'' SELinux policy has 82460 allow lines.  Clearly this is a very complex policy that is difficult to debug and difficult to audit.  Our system will attempt to use state to achieve similar goals with more compact policies.

The rest of the paper is organized as follows: in section \ref{lsmlgi} we introduce our model and its implementation.  In section \ref{examples} we present examples of Laws and the results achieved on our system.  We present further work in section \ref{further} and conclude in section \ref{conclusion}.

\section{LSMLGI}
\label{lsmlgi}
Our LSM module, lsmlgi, uses the LSM framework to maintain the state of a running process on the system.  We maintain the state by incrementing counters of the major file operations being performed by the process.  When a process is born we assign unique identifiers to the process.  Currently we track read, write, create, delete and execute operations.  When a process writes a file, we increment the write counter (likewise for read, delete and execute operations).  We update the parent of the process as well so that subprocesses cannot run unrestricted with respect to their parents.

Law Governed Interaction (LGI) is a system of access control that regulates the interaction of agents in a distributed system via laws\cite{lgi}.  The processes running on a system can be thought of as autonomous agents running in a closed system.  We attempt to regulate the interactions between these agents (processes) using a simple law system.  The main tenant of LGI is that the state of the agents may be updated by any interaction (message), and that the law is not restricted in the actions it may take.  The law is not restricted to a simple yes or no answer and may do anything it pleases.  With LSM we can only say no to an operation, but we can update the state via our security struct in any way we please.  Our initial implementation is restricted in action to a  simple yes or no answer and is therefore not as powerful as a system like LGI.  We suggest in section \ref{further} that further work should allow our module to take more actions.

\subsection{Implementation}
\label{implementation}
A note on running in the kernel: kernel programs do not have direct access to user level data.  There is a separation of user space and kernel space.  The kernel only knows about uids and gids. To translate usernames into uids on behalf of the kernel, we use a user space helper application ({\tt lawloader}).  Our system requires that a law be loaded dynamically; we load the law by using a user space program to send the law in compiled form to the kernel module using the proc filesystem.  The proc filesystem (procfs) is a window to kernel space. It stores information about running processes and modules.  We create a procfs ``file'' called {\tt /proc/lsmlgi}.  We load a law into lsmlgi by writing to /proc/lsmlgi.  When a new law is received on /proc/lsmlgi, the law is compiled and then replaces the current law on the system as depicted in figure \ref{proclsmlgi}

\begin{figure}
\begin{center}
\begin{tikzpicture} 
\draw (0,0) node [text width=5cm, fill=blue!20] {
\begin{verbatim}
sid: 1197282269
law:
law initialized: 5 rules
        48:-1:6:2:14:2
        500:-1:6:6:12:-20
        500:-1:7:2:15:2
        48:-1:6:2:13:2
        500:-1:7:2:15:2
\end{verbatim}
};
\end{tikzpicture}
\end{center}
\caption{Contents of {\tt /proc/lsmlgi} \label{proclsmlgi}}
\end{figure}


When a new law is loaded, we populate a list of uids that the module will consider.  Any uid's that are not listed will bypass the module.  This allows us to ignore the root account and test scenarios while developing the system.  Eventually all accounts will be monitored, but for now we only consider specific accounts.

At each critical lsm hook function we perform the necessary memory check requirements then call the function {\tt lsmlgi\_check\_law}, {\tt lsmlgi\_check\_law} has access to the currently running tasks' security structure and makes the decision to allow or deny the access based on the current state.  If the access is permitted we then call lsmlgi\_update\_parent to update the state on the current process and recursively to update the state of the parent\footnote{and the grandparents, and the great grandparents, and the great great grandparents, and ... We recurse until we reach pid =1 (init)}.  It is worth noting that we do not update the state of process id 1.  The process with id 1 is {\tt init}, {\tt init} is the master process on the system, it is the first process started on the system. All processes are descendants of {\tt init}\footnote{We do not update the state on init due to time constraints, init is an important system process, preventing init from operating properly would significantly increase debugging time.}.   The process of loading our module, initializing a law and then acting upon the law is shown in figure \ref{lsmlgiimpl}.

\begin{figure}
\begin{center}
 \begin{tikzpicture}
  \draw (7,5) node[circle] (lawloader) [fill=yellow!20] {lawloader};
  \draw[dashed] (5.5,6) -- (5.5,0);

  \draw (4,5) node (lsmlgi) [fill=red!20] {\tt /proc/lsmlgi};
  \draw[->] (lawloader.west) -| (5.5,5) -- (lsmlgi.east);

  \draw (4,4) node (law) [fill=blue!20] {\bf LAW};
  \draw[->] (lsmlgi.south) -- (law.north);

  \draw (4,3) node (checklaw) [fill=black!20, rounded corners] {\tt check\_law};
  \draw[->] (law.south) -- (checklaw.north);

  \draw (7,3) node (user) [circle,fill=yellow!20] {user process};
  \draw[->] (user.north west) -- (checklaw.north east);
  \draw[->] (checklaw.south east) -- (user.south west);

  \draw (1,6) node (init) [fill=black!20,rounded corners] {\tt init\_module};
  \draw (1,5) node (register) [fill=black!20,rounded corners] {\tt register\_security};
  \draw[->] (init.south) -- (register.north);
  
  \draw (1.5,4) node (create) [fill=black!20, rounded corners] {\tt create\_proc\_entry};
  \draw[->] (register.south) .. controls +(right:5mm) and +(up:5mm) .. (create.north);
  \draw[->] (create.north) .. controls +(right:10mm) and +(down:5mm) .. (lsmlgi.south west);

  %\draw (1.25,3) node (cache) [fill=black!20, rounded corners] {\tt kmem\_cache\_alloc};
  %\draw[->] (init.west) -| (-1,3) --  (cache.west);

  \draw (2,2) node (inodealloc) [fill=black!20,rounded corners] {\tt inode\_alloc\_security};
  \draw (3,0) node (taskalloc) [fill=black!20,rounded corners] {\tt task\_alloc\_security};  

  \draw (0,1) node (inode) [fill=green!20,circle] {inode};
  \draw (1.5,-1) node (task) [fill=green!20,circle] {task};

  \draw[->] (checklaw.west) -| (-1,3) -- (-1,1) -- (inode.west);
  \draw[->] (inode.east) -| (inodealloc.south);

  \draw[->] (checklaw.west) -| (-1.25,3) -- (-1.25,-1) -- (task.west);
  \draw[->] (task.east) -| (taskalloc.south);

  \draw[->] (inodealloc.north) -| (2,2.5) -| (checklaw.south);
  \draw[->] (taskalloc.north) -| (3,1) -| (checklaw.south);
 \end{tikzpicture}

\end{center}

 \caption{Implementation of our module\label{lsmlgiimpl}}
\end{figure}


We defined the following three security structs, {\tt bprm\_security\_struct}, {\tt task\_security\_struct} and {\tt inode\_security\_struct}.  We added the fields of sid, tsid and fsid to these structs.  We initially use the time in seconds on the system as a unique identifier.  To the {\tt task\_security\_struct} we added the additional counters of read, write, delete and execute.  

We use sid (security id) to contain the id of the running lsmlgi implementation, that is, it is a unique key that identifies the running system, when the system is rebooted, a new sid will be created.  The task sid is tsid and fsid is the file sid.

When a task is created, we create the security struct for the task using task\_alloc\_security and create a new tsid for the task.  When a task spawns a subprocess, it receives the task sid of its parent.  To differentiate between parents and children, the fsid is created uniquely for each task and is independent of lineage.  An example context is shown in figure \ref{context}.

\begin{figure}
\begin{center}
\begin{tikzpicture}
\draw (0,0) node [fill=blue!20,text width=7.5cm] {\scriptsize\tt security.lsmlgi=``1197221584:1197221793:1197221939:$\backslash$000''};
\end{tikzpicture}
\end{center}
\caption{Security Context\label{context}}
\end{figure}


The read, write, execute and delete counters of the task structure are updated when each of the respective operations is performed by a task or its children.  For example if a child task deletes a file, the child's task structure is updated and the child's parent task structure is also updated.  In this way we are able to accurately track a process that spawns helper processes\footnote{such as a shell}.  The current state of the process is exposed to the user in the proc filesystem.  For a process with pid 42, the file {\tt /proc/42/attr/current} contains the current state of the process as shown in figure \ref{current}

\begin{figure}
\begin{center}
\begin{tikzpicture}
\draw (0,0) node[fill=blue!20, text width=5cm] {
\begin{verbatim}
sid=1197282269
tsid=1197282275
fsid=0
read=28
write=0
del=0
exec=1
\end{verbatim}
};
\end{tikzpicture}
\end{center}
\caption{Process State information\label{current}}
\end{figure}

When a task creates a file, the inode security structure is initialized.  We also create an entry in the kernel inode cache table to identify the inode's security to the kernel.  This is required if we wish to set a security struct on the inode, in the interest of efficiency when dealing with inodes, the kernel requires that these structures be placed in a cache.  We then set the sid of the {\tt inode\_security\_struct} to the sid of the running system.  Next we set the tsid to the tsid of the task creating the file and finally we set the fsid to a new unique sid.  We call the combination of {\tt sid:tsid:fsid} is our security context, it is written to the filesystem in the extended attributes of the file.  The security context is written to the extended attributes to ensure that the security context is persistent across reboots or if the inode is cleared from memory and/or it needs to be reloaded.  The security context of the inode may be updated or overwritten while the inode is in memory, we are currently not updating the context, but this could be used in future work to maintain the tsid of the last task to update the inode.

\section{Law Examples}
\label{examples}
In this section we present examples of simple laws that could be used on a real system to affect a result that is not possible without maintaining state on the system.  Our law language is very simple, it consists of a user or group designation followed by a user or group name.  We then specify the operation we are interested in controlling (read, write, delete or execute).  Next we specify the rule, that is the combination of current task state versus inode state or current task state versus current task state that we wish to block.  The rule can be any one of the identifiers (sid, tsid, fsid) or any of the counters (read, write, delete, execute) or a constant.  An example law is shown in figure \ref{laws}.
\begin{figure}
\begin{center}
\begin{tikzpicture}
\draw (0,0) node [fill=blue!20,text width=6cm] {
\begin{verbatim}
group apache exec { tsid == tsid }
user thomas exec { exec > 20 }
user thomas del { tsid != tsid }
\end{verbatim}
}; % node
\end{tikzpicture}
\end{center}
\caption{Example Law \label{laws}}
\end{figure}


\subsection{Visitor Account}

At our institution there are numerous visitors each day that require some sort of short term account.  Most users are using the system to access their home institution accounts.  We provide a visitor account for the users to share, but to allow the users to work properly, we cannot restrict their ability to write files in the home directory.  Since the account is shared, any user of the account can delete or modify the files of any other user of the account.  We implement a visitor law that restricts the delete and write functions of a task to only those files that the task created as shown in figure \ref{visitor}  From the visitors point of view, they can only modify or delete the files that they created in this session.  Any files that they leave on the system after logging out will be write and delete locked the next time they log into the system.
\begin{figure}
\begin{center}
\begin{tikzpicture}
\draw (0,0) node [fill=blue!20,text width=6cm] {
\begin{verbatim}
user visitor del { tsid != tsid }
user visitor write { tsid != tsid }
\end{verbatim}
};
\end{tikzpicture}
\end{center}
\caption{Visitor law\label{visitor}}
\end{figure}

\subsection{Web Server}

A web server may create files while running to track remote users or to log traffic.  We consider that the web server should only be able to execute files that were created before it started running, that is, it cannot run any scripts or programs placed on the system after it was started.  These files could potentially be maliciously created through some unknown exploit of the web server.  We implement this law as shown in figure \ref{apache}. This law states that files created by this task (process) cannot be executed by this task.  This prevents the web server from writing a file and then immediately executing it.

\begin{figure}
\begin{center}
\begin{tikzpicture}
\draw (0,0) node [fill=blue!20,text width=6cm] {
\begin{verbatim}
user apache exec { tsid == tsid }
\end{verbatim}
};
\end{tikzpicture}
\end{center}
\caption{Web Server law\label{apache}}
\end{figure}

\subsection{Budget}

In this example we track the number of subprocesses launched by a user or group.  This example was inspired by the database query budget suggested in \cite{roles}.  When the number reaches a critical number, we deny the user or group from starting any further tasks (the user can, however, simply logout and login again to renew her budget)  In future the state could be maintained for a user, independent of process information.  This would require another structure in the module but would be straight-forward to implement.  We did not implement such a system due to time constraints.  Our budget example law is shown in figure \ref{budget}.

\begin{figure}
\begin{center}
 \begin{tikzpicture}
  \draw (0,0) node [fill=blue!20,text width=6cm] {
   \begin{verbatim}
user thomas exec { exec > 20 } 
\end{verbatim}
};
 \end{tikzpicture}

\end{center}

 \caption{Budget Law\label{budget}}
\end{figure}

\section{Further Work} 
\label{further}

Our module is a very simple implementation of a stateful system.  Future work should expand the law language to allow variables to be set dynamically in the security structure.  Many applications have well defined ``conversations''\cite{web} that could be used in a stateful system to deny any non-conversational actions.

SELinux has support for controlling network operations.  Controlling network operations in a stateful manner is very useful, but currently this is handled by another package (iptables).  Implementing stateful network control in the same package as access control has the potential to streamline the security policy and make policy validation a simpler task.

SELinux is a mature implementation of the LSM, several user space programs exist to validate policy and to digest error logs for system administrators\cite{verify}.  Future work should include a mechanism to inform the user at a decision point why an action was blocked.  In SELinux this is taken care of by the sealert (SE-Alert) applet which displays human readable interpretations of why access was denied.  SELinux is a mature security policy enforcement system, there would be great benefit to making the state transition system of SELinux dynamic.  That is, to allow processes to transition dynamically depending on their current state.

More examples of why state is useful to maintain will need to be developed if a real world system is to be created.  Adding support for network operations should increase acceptance.  Perhaps the most promising method of implementation may be to augment the existing SELinux system with some state saving capabilities.

\section{Conclusion}
\label{conclusion}

The need for enhanced security policy and access control in modern operating systems is apparent.  The LSM framework for Linux is a free and open API.
Writing LSM modules has become an accessible way for researchers to work on access control projects.  This implementation was completed in a little over 8 weeks by a non-kernel programmer.

Maintaining state allows our module to achieve interesting results with minimal policy.  Simple policies are trivial to validate.  Most security policy implementations rely on enormous and complex policies to affect similar results.  Perhaps the greatest benefit of maintaining state is simplicity.  

Stateful access control can achieve very different results than non-stateful access control.  Our budget example is simply not possible without maintaining state.  The visitor account example may be possible without maintaining state but would require a very complicated non-stateful policy.


\section{Acknowledgments}
We would like to thank the NSA for releasing the source code for SELinux to the public.  Much of our work was achieved by reading the SELinux implementation and adapting it to our model.  We would also like to thank Chris Wright and Stephen Smalley for their work on LSM, making the framework available and providing documentation made this project possible for someone unfamiliar with kernel coding.

We would also like to thank Jo\v{s}ko Plazoni\v{c} for assistance with coding and debugging the module.  Vinod Ganapathy for his suggestion of \cite{verify}.  And finally Naftaly Minsky for the inspiration for the project with his work on LGI. 

\onecolumn
\section{Resources}
Source code for this module is available online at:

\centerline{\tt http://ramblings.narrabilis.com/wp/linux/stateful-access-control-using-lsm/}

\noindent Slides from a talk about this project are available at:

\centerline{\tt http://ramblings.narrabilis.com/lsmlgi/lsmlgi-presentation.pdf}


\bibliographystyle{plain}
\bibliography{lsm}

\end{document}