[RFC][PATCH 0/2] (#6 U2) filesystem auditing

Timothy R. Chavez tinytim at us.ibm.com
Tue Mar 29 01:54:52 UTC 2005


Hello,

:: TERMINOLOGY ::

watch : data that describes a file or directory that should be audited
watchlist : a linked list of watchlist entries residing on a directory
watchlist entry (wentry): an entry to a watchlist that contains a watch

:: INTRODUCTION ::

In an effort to make the mainline kernel's audit subsystem Controlled Access 
Protection Profile (CAPP)/Evaluation Assurance Level (EAL) 4 compliant, this 
patch adds file system auditing support to the audit subsystem.  Such 
support is essential in meeting certification requirements because it allows 
the evaluator to confirm all claims made about the Target of Evaluation (TOE) 
regarding the behavior of file system objects (which are outlined in the 
Security Target for the given evaluation) by consulting the audit log.

To achieve such results, it's necessary for the audit subsystem to identify 
and keep track of such objects.  Due to the abstract nature of "identity" 
with regards to file system objects and how that "identity" translates 
between the user's perspective and the kernel's perspective and visa-versa, a 
fairly strict definition is devised.  This implementation uses a scheme by 
which parent directories have a "watchlist" that qualifying children may 
point into at the "watchlist entry" that holds their "watch".  Pointing at a 
"watchlist entry" translates into "being watched".

It is also important to keep in mind that in a CAPP environment, we assume the 
administrator to be benign and that we are preventing subversion of the audit 
subsystem for the purpose of evaluation and not user/process malice. 

This component is not designed for filesystem notifications, process/user 
snooping, intrusion detection, etc.

:: DESCRIPTION ::

Below is a basic description of this patches capabilities.  These capabilities 
are enabled by the user space program, auditctl, which is available in the 
audit package (found at: http://people.redhat.com/sgrubb).  

1.  Insertions

When the administrator targets a file system object for audit, they do so by 
<path> name.  This is an absolute target -- meaning, the administrator targets 
the file system object by name, on a given device, in a given namespace.  
Provided the parent directory of the targeted object exists, we add to it's 
"watchlist" the "watch" for our targeted object.  Thus, all information about 
the watched object is stored on inodes, in memory, and not on disk.  When 
adding a "watch" at <path>, the terminating file or directory at <path> need 
not exist.  (ie: if we wish to watch /tmp/foo, /tmp must exist, but 'foo' 
does not have too).  This is reasonable in a CAPP environment.

2.  Removal

Likewise to inserting watches, we may remove a watch in the same fashion.  
If the terminating file or directory name was found in its parent's watchlist, 
the corresponding "watchlist entry" is unhashed.  Once this "watchlist entry" 
is unhashed, it becomes invalid (ie: it may be overwritten and will no longer 
generate audit records).

3.  Listings

It'd be helpful for the administrator to be able to determine what watches 
already exist directly under a directory, on a given device, in a given 
namespace.  To do so, the admistrator must target a specific directory via a 
path (using the given device, in the given namespace) and a list of any 
watches in that directory's watchlist will be returned.

4. Hooks

To make this all work, there are three sets of hooks the audit subsystem uses.  

1.  The first set of hooks manage the inode's audit_data memory.  Two hooks: 
one to allocate memory and one to free memory.  

2.  The second set of hooks is used in the dcache to attach watches to a 
dentry's inode->i_audit->wentry field (ie: these hooks are responsible for 
*watching* a file system object).  

Creation:
We use hooks in d_instantiate() and d_splice_alias() to immediately attach 
watches, if they exist, to newly created / spliced dentries.  

Watch/removal:
We use the __d_lookup() hook for two reasons: to assign a new "watch", if one 
exists at this location (ie: a hardlink that's just become "unwatched" exists 
in a location that has a "watch") and to detach unhashed (invalid) watchlist 
entries (wentries) on inodes.  

Deletion:
The d_delete() hook is used to drain watchlists and detach from a "watch".  
We've effectively left the "watch".

Movement:
The d_move() hook is used to remove the "watch" and drain the "watchlist" from 
a dentry prior to "moving" it (leaving the "watch"), and then attach to it, a 
new "watch", if the location it's now at is being "watched".

3.  The third set of hooks are all used to notify the audit subsystem about 
access to a "watched" object.  These hooks tell the audit subsystem to 
generate a record. 

Permissions:
This is a good junction to place a hook that generates audit records.  These 
functions are consulted before we commit to action, thus, whether we fail or 
not, we get records.  Not always can we map a permissions check one-to-one 
with a watched file system object (ie: unlink), thus other hooks are 
required.

An added benefit of hooking permission functions, is the ability to "watch" 
the parent directory of a "watched" file, to see how it was consulted when 
attempting access of the "watched" file.  We have hooks at permission() and 
exec_permission_lite().

Creation:
For creation, we have hooks in vfs_link()/symlink()/create()/mkdir()/mknod().  
Once we have the inode (post creation), and we're attached (post 
audit_attach_watch), we want to generate a record.

Deletion:

For deletion, we hook may_delete().  We do so because vfs_unlink()/rmdir() 
both make use of this function; it is a good junction.  

Rename:

For renaming, we hook vfs_rename_other()/rename_dir() to genereate audit 
records describing the rename in to a "watched" location, and rely on the 
may_delete() hook to give us an audit record describing the rename out of a 
"watched" location.

Open:
I think these hooks can be dropped.  Will do before we send out to 
linux-fsdevel.

5.  Notable Behavior

This system allows for only one type of implicit watch; hardlinks.  One may 
create a hardlink to a "watched" file and it too, will be watched.  They can 
"move" this hardlink around, and it will remain watched.  This is because 
both the watched object and the hardlink share the same inode.  However, 
should the "watched" object (ie: the dentry belonging to this inode that meets 
the aforementioned criteria) no longer meet this criteria, the hardlink will 
no longer be attached to this "watch" -- In fact, the next time the inode is 
accessed, should a hardlink exist in another "watched" location, the inode 
would attach to this "watch" (See, 4.  Hooks).  This makes sense, but in a 
subtle way.  If we create a dentry, such that we become watched again, even 
though there are now at least two files on the system that could contain the 
same content, our one time hardlink, has effectively become a separate object 
to us.  Thus it is important to realize that we are not auditing access to 
specific content.

This being said, if we decide to "move" in any way, out of a "watched" 
location, we lose the "watch" -- Thus, if we: mv, cp, rm (or use their 
underlying syscalls), we'll lose the "watch" and thus, we will no longer be 
audited.  It's important, however, to keep in mind that we will get final 
records based on these actions (ie: if we do mv /tmp/foo to /tmp/bar 
and /tmp/foo is being watched, we will see a record for the rename out 
of /tmp/foo.  And, if we do mv /tmp/bar /tmp/foo, we will see a record for 
the rename into /tmp/foo).

-tim




More information about the Linux-audit mailing list