* [RFC][PATCH 1/2] file system auditing
@ 2005-04-05 22:04 Timothy R. Chavez
2005-04-05 22:20 ` [RFC][PATCH 2/2] " Timothy R. Chavez
0 siblings, 1 reply; 3+ messages in thread
From: Timothy R. Chavez @ 2005-04-05 22:04 UTC (permalink / raw)
To: linux-fsdevel
Hello,
The audit subsystem is currently incapable of auditing a file system object
based on its location and name. This is critical for auditing well-defined
and security-relevant locations such as /etc/shadow, where the file is
re-created on each transaction, and cannot rely on the (device, inode)-based
filters to ensure persistence of auditing across transactions. This patch adds
the necessary functionality to the audit subsystem and VFS to support file
system auditing in which an object is audited based on its location and name.
This work is being done to make the audit subsystem compliant with Common
Criteria's Controlled Access Protection Profile (CAPP) specification.
The patch has been split in two for RFC.
[PATCH 1/2]
The first patch consists of the file system hooks and appears at the bottom of
this message preceded by brief explanations of each hook. The quoted
terminology is defined in the high-level overview of the design that's been
included with the second patch in the next message.
[PATCH 2/2]
The second patch consists of the file system auditing implementation preceded
by a high-level overview of the design.
The entire patch was diffed against linux-2.6.11-rc2-mm1
-tim
----
1. Setup
Placement in fs/inode.c
audit_inode_alloc()/audit_inode_free():
These hooks are responsible for allocating and deallocating inode audit data.
2. Management
Management of "watches" starts at the dentry level.
Placement in fs/dcache.c
Initial setup:
d_instantiate()/d_splice_alias() :
These hooks cover initial audit setup for inodes that are newly created and
for existing inodes when they are first looked up, prior to becoming
accessible via the dcache.
Update:
__d_lookup():
This hook covers updating the inode audit data if necessary upon subsequent
lookups when the inode is already accessible via dcache, both to reflect
removal of "watches" and to handle changes in state since the initial setup.
d_move():
This hook covers resetting the inode audit data and updating it accordingly
post-move.
Deletion:
dentry_iput():
This hook covers resetting the inode audit data if the dentry being deleted is
at a "watch point".
3. Notification
Any time we access a "watched" object we are auditable. These hooks are used
to notify the audit subsystem of relevant access.
Placement in fs/namei.c.
Permissions:
permission()/exec_permission_lite():
Notify the audit subsystem when a "watched" object is consulted about
permissions requirements.
Creation:
vfs_link()/symlink()/create()/mkdir()/mknod():
Notify the audit subsystem when an object has successfully manifested at a
"watch point".
Deletion:
may_delete() [vfs_unlink()/rmdir()]:
Notify the audit subsystem when an object attempts to leave a "watch point".
This hook appears in may_delete() after its been determined the object has an
inode.
Note: We are unable to use may_create() in a similar fashion to may_delete()
because the object should not have an inode associated with it yet.
Rename:
may_delete(),vfs_rename_other()/rename_dir():
Notify the audit subsystem when an object has been moved out of a "watch
point" using the may_delete() hook. Notify the audit subsystem when an
object already exists at our destination and our destination is a "watch
point". Notify the audit subsystem when an object moves in to a "watch
point" using the vfs_rename_other/rename_dir() hooks.
diff -Nurp linux-2.6.12-rc2-mm1/fs/dcache.c linux-2.6.12-rc2-mm1~audit/fs/dcache.c
--- linux-2.6.12-rc2-mm1/fs/dcache.c 2005-04-05 14:05:16.000000000 -0500
+++ linux-2.6.12-rc2-mm1~audit/fs/dcache.c 2005-04-05 13:16:04.000000000 -0500
@@ -32,6 +32,7 @@
#include <linux/seqlock.h>
#include <linux/swap.h>
#include <linux/bootmem.h>
+#include <linux/audit.h>
/* #define DCACHE_DEBUG 1 */
@@ -97,6 +98,7 @@ static inline void dentry_iput(struct de
{
struct inode *inode = dentry->d_inode;
if (inode) {
+ audit_attach_watch(dentry, 1);
dentry->d_inode = NULL;
list_del_init(&dentry->d_alias);
spin_unlock(&dentry->d_lock);
@@ -802,6 +804,7 @@ void d_instantiate(struct dentry *entry,
if (inode)
list_add(&entry->d_alias, &inode->i_dentry);
entry->d_inode = inode;
+ audit_attach_watch(entry, 0);
spin_unlock(&dcache_lock);
security_d_instantiate(entry, inode);
}
@@ -978,6 +981,7 @@ struct dentry *d_splice_alias(struct ino
new = __d_find_alias(inode, 1);
if (new) {
BUG_ON(!(new->d_flags & DCACHE_DISCONNECTED));
+ audit_attach_watch(new, 0);
spin_unlock(&dcache_lock);
security_d_instantiate(new, inode);
d_rehash(dentry);
@@ -987,6 +991,7 @@ struct dentry *d_splice_alias(struct ino
/* d_instantiate takes dcache_lock, so we do it by hand */
list_add(&dentry->d_alias, &inode->i_dentry);
dentry->d_inode = inode;
+ audit_attach_watch(dentry, 0);
spin_unlock(&dcache_lock);
security_d_instantiate(dentry, inode);
d_rehash(dentry);
@@ -1090,6 +1095,7 @@ struct dentry * __d_lookup(struct dentry
if (!d_unhashed(dentry)) {
atomic_inc(&dentry->d_count);
found = dentry;
+ audit_attach_watch(found, 0);
}
spin_unlock(&dentry->d_lock);
break;
@@ -1299,6 +1305,8 @@ void d_move(struct dentry * dentry, stru
spin_lock(&target->d_lock);
}
+ audit_attach_watch(dentry, 1);
+
/* Move the dentry to the target hash queue, if on different bucket */
if (dentry->d_flags & DCACHE_UNHASHED)
goto already_unhashed;
@@ -1332,6 +1340,7 @@ already_unhashed:
list_add(&target->d_child, &target->d_parent->d_subdirs);
}
+ audit_attach_watch(dentry, 0);
list_add(&dentry->d_child, &dentry->d_parent->d_subdirs);
spin_unlock(&target->d_lock);
spin_unlock(&dentry->d_lock);
diff -Nurp linux-2.6.12-rc2-mm1/fs/inode.c linux-2.6.12-rc2-mm1~audit/fs/inode.c
--- linux-2.6.12-rc2-mm1/fs/inode.c 2005-04-05 14:06:28.000000000 -0500
+++ linux-2.6.12-rc2-mm1~audit/fs/inode.c 2005-04-05 13:16:04.000000000 -0500
@@ -22,6 +22,7 @@
#include <linux/cdev.h>
#include <linux/bootmem.h>
#include <linux/inotify.h>
+#include <linux/audit.h>
/*
* This is needed for the following functions:
@@ -140,9 +141,11 @@ static struct inode *alloc_inode(struct
inode->i_bdev = NULL;
inode->i_cdev = NULL;
inode->i_rdev = 0;
+ inode->i_audit = NULL;
inode->i_security = NULL;
inode->dirtied_when = 0;
- if (security_inode_alloc(inode)) {
+ if (audit_inode_alloc(inode) || security_inode_alloc(inode)) {
+ audit_inode_free(inode);
if (inode->i_sb->s_op->destroy_inode)
inode->i_sb->s_op->destroy_inode(inode);
else
@@ -180,6 +183,7 @@ void destroy_inode(struct inode *inode)
{
if (inode_has_buffers(inode))
BUG();
+ audit_inode_free(inode);
security_inode_free(inode);
if (inode->i_sb->s_op->destroy_inode)
inode->i_sb->s_op->destroy_inode(inode);
diff -Nurp linux-2.6.12-rc2-mm1/fs/namei.c linux-2.6.12-rc2-mm1~audit/fs/namei.c
--- linux-2.6.12-rc2-mm1/fs/namei.c 2005-04-05 14:06:28.000000000 -0500
+++ linux-2.6.12-rc2-mm1~audit/fs/namei.c 2005-04-05 13:16:04.000000000 -0500
@@ -225,6 +225,8 @@ int permission(struct inode *inode, int
{
int retval, submask;
+ audit_notify_watch(inode, mask);
+
if (mask & MAY_WRITE) {
umode_t mode = inode->i_mode;
@@ -358,6 +360,8 @@ static inline int exec_permission_lite(s
if (inode->i_op && inode->i_op->permission)
return -EAGAIN;
+ audit_notify_watch(inode, MAY_EXEC);
+
if (current->fsuid == inode->i_uid)
mode >>= 6;
else if (in_group_p(inode->i_gid))
@@ -1172,6 +1176,8 @@ static inline int may_delete(struct inod
BUG_ON(victim->d_parent->d_inode != dir);
+ audit_notify_watch(victim->d_inode, MAY_WRITE);
+
error = permission(dir,MAY_WRITE | MAY_EXEC, NULL);
if (error)
return error;
@@ -1296,6 +1302,7 @@ int vfs_create(struct inode *dir, struct
DQUOT_INIT(dir);
error = dir->i_op->create(dir, dentry, mode, nd);
if (!error) {
+ audit_notify_watch(dentry->d_inode, MAY_WRITE);
fsnotify_create(dir, dentry->d_name.name);
security_inode_post_create(dir, dentry, mode);
}
@@ -1601,6 +1608,7 @@ int vfs_mknod(struct inode *dir, struct
DQUOT_INIT(dir);
error = dir->i_op->mknod(dir, dentry, mode, dev);
if (!error) {
+ audit_notify_watch(dentry->d_inode, MAY_WRITE);
fsnotify_create(dir, dentry->d_name.name);
security_inode_post_mknod(dir, dentry, mode, dev);
}
@@ -1674,6 +1682,7 @@ int vfs_mkdir(struct inode *dir, struct
DQUOT_INIT(dir);
error = dir->i_op->mkdir(dir, dentry, mode);
if (!error) {
+ audit_notify_watch(dentry->d_inode, MAY_WRITE);
fsnotify_mkdir(dir, dentry->d_name.name);
security_inode_post_mkdir(dir,dentry, mode);
}
@@ -1915,6 +1924,7 @@ int vfs_symlink(struct inode *dir, struc
DQUOT_INIT(dir);
error = dir->i_op->symlink(dir, dentry, oldname);
if (!error) {
+ audit_notify_watch(dentry->d_inode, MAY_WRITE);
fsnotify_create(dir, dentry->d_name.name);
security_inode_post_symlink(dir, dentry, oldname);
}
@@ -1988,6 +1998,7 @@ int vfs_link(struct dentry *old_dentry,
error = dir->i_op->link(old_dentry, dir, new_dentry);
up(&old_dentry->d_inode->i_sem);
if (!error) {
+ audit_notify_watch(new_dentry->d_inode, MAY_WRITE);
fsnotify_create(dir, new_dentry->d_name.name);
security_inode_post_link(old_dentry, dir, new_dentry);
}
@@ -2111,6 +2122,7 @@ int vfs_rename_dir(struct inode *old_dir
}
if (!error) {
d_move(old_dentry,new_dentry);
+ audit_notify_watch(old_dentry->d_inode, MAY_WRITE);
security_inode_post_rename(old_dir, old_dentry,
new_dir, new_dentry);
}
@@ -2139,6 +2151,7 @@ int vfs_rename_other(struct inode *old_d
/* The following d_move() should become unconditional */
if (!(old_dir->i_sb->s_type->fs_flags & FS_ODD_RENAME))
d_move(old_dentry, new_dentry);
+ audit_notify_watch(old_dentry->d_inode, MAY_WRITE);
security_inode_post_rename(old_dir, old_dentry, new_dir, new_dentry);
}
if (target)
-
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [RFC][PATCH 2/2] file system auditing
2005-04-05 22:04 [RFC][PATCH 1/2] file system auditing Timothy R. Chavez
@ 2005-04-05 22:20 ` Timothy R. Chavez
[not found] ` <1112740621.4397.65.camel@localhost.localdomain>
0 siblings, 1 reply; 3+ messages in thread
From: Timothy R. Chavez @ 2005-04-05 22:20 UTC (permalink / raw)
To: linux-fsdevel
Hello,
In user space, the administrator refers to a file system object to be audited
by its location and name. In the kernel, this reference is walked to the
parent directory where the name of the file system object is put into a list
called the "watchlist". Each entry in this "watchlist" refers to a "watch
point" directly beneath the parent. Every object will search its parent's
"watchlist" for an entry that describes a "watch point" at its location. If
one is found, it will point at this entry and become "watched"[1]. "Watched"
objects are auditable objects. Should the object ever leave this "watch
point" it will lose this "watch".
I suspect there will be questions framed around specific parts of this design
and I will address them as they come. Please keep in mind that we are not
auditing based on content, but based on location and name.
[1] If a "watched" file is hard linked then the hardlink will implicitly be
"watched". Should the location of the hardlink be a "watch point" itself or
become a "watch point", the hardlink retains its original "watch".
-tim
diff -Nurp linux-2.6.12-rc2-mm1/fs/dcache.c linux-2.6.12-rc2-mm1~audit/fs/dcache.c
--- linux-2.6.12-rc2-mm1/fs/dcache.c 2005-04-05 14:05:16.000000000 -0500
+++ linux-2.6.12-rc2-mm1~audit/fs/dcache.c 2005-04-05 13:16:04.000000000 -0500
@@ -32,6 +32,7 @@
#include <linux/seqlock.h>
#include <linux/swap.h>
#include <linux/bootmem.h>
+#include <linux/audit.h>
/* #define DCACHE_DEBUG 1 */
@@ -97,6 +98,7 @@ static inline void dentry_iput(struct de
{
struct inode *inode = dentry->d_inode;
if (inode) {
+ audit_attach_watch(dentry, 1);
dentry->d_inode = NULL;
list_del_init(&dentry->d_alias);
spin_unlock(&dentry->d_lock);
@@ -802,6 +804,7 @@ void d_instantiate(struct dentry *entry,
if (inode)
list_add(&entry->d_alias, &inode->i_dentry);
entry->d_inode = inode;
+ audit_attach_watch(entry, 0);
spin_unlock(&dcache_lock);
security_d_instantiate(entry, inode);
}
@@ -978,6 +981,7 @@ struct dentry *d_splice_alias(struct ino
new = __d_find_alias(inode, 1);
if (new) {
BUG_ON(!(new->d_flags & DCACHE_DISCONNECTED));
+ audit_attach_watch(new, 0);
spin_unlock(&dcache_lock);
security_d_instantiate(new, inode);
d_rehash(dentry);
@@ -987,6 +991,7 @@ struct dentry *d_splice_alias(struct ino
/* d_instantiate takes dcache_lock, so we do it by hand */
list_add(&dentry->d_alias, &inode->i_dentry);
dentry->d_inode = inode;
+ audit_attach_watch(dentry, 0);
spin_unlock(&dcache_lock);
security_d_instantiate(dentry, inode);
d_rehash(dentry);
@@ -1090,6 +1095,7 @@ struct dentry * __d_lookup(struct dentry
if (!d_unhashed(dentry)) {
atomic_inc(&dentry->d_count);
found = dentry;
+ audit_attach_watch(found, 0);
}
spin_unlock(&dentry->d_lock);
break;
@@ -1299,6 +1305,8 @@ void d_move(struct dentry * dentry, stru
spin_lock(&target->d_lock);
}
+ audit_attach_watch(dentry, 1);
+
/* Move the dentry to the target hash queue, if on different bucket */
if (dentry->d_flags & DCACHE_UNHASHED)
goto already_unhashed;
@@ -1332,6 +1340,7 @@ already_unhashed:
list_add(&target->d_child, &target->d_parent->d_subdirs);
}
+ audit_attach_watch(dentry, 0);
list_add(&dentry->d_child, &dentry->d_parent->d_subdirs);
spin_unlock(&target->d_lock);
spin_unlock(&dentry->d_lock);
diff -Nurp linux-2.6.12-rc2-mm1/fs/inode.c linux-2.6.12-rc2-mm1~audit/fs/inode.c
--- linux-2.6.12-rc2-mm1/fs/inode.c 2005-04-05 14:06:28.000000000 -0500
+++ linux-2.6.12-rc2-mm1~audit/fs/inode.c 2005-04-05 13:16:04.000000000 -0500
@@ -22,6 +22,7 @@
#include <linux/cdev.h>
#include <linux/bootmem.h>
#include <linux/inotify.h>
+#include <linux/audit.h>
/*
* This is needed for the following functions:
@@ -140,9 +141,11 @@ static struct inode *alloc_inode(struct
inode->i_bdev = NULL;
inode->i_cdev = NULL;
inode->i_rdev = 0;
+ inode->i_audit = NULL;
inode->i_security = NULL;
inode->dirtied_when = 0;
- if (security_inode_alloc(inode)) {
+ if (audit_inode_alloc(inode) || security_inode_alloc(inode)) {
+ audit_inode_free(inode);
if (inode->i_sb->s_op->destroy_inode)
inode->i_sb->s_op->destroy_inode(inode);
else
@@ -180,6 +183,7 @@ void destroy_inode(struct inode *inode)
{
if (inode_has_buffers(inode))
BUG();
+ audit_inode_free(inode);
security_inode_free(inode);
if (inode->i_sb->s_op->destroy_inode)
inode->i_sb->s_op->destroy_inode(inode);
diff -Nurp linux-2.6.12-rc2-mm1/fs/namei.c linux-2.6.12-rc2-mm1~audit/fs/namei.c
--- linux-2.6.12-rc2-mm1/fs/namei.c 2005-04-05 14:06:28.000000000 -0500
+++ linux-2.6.12-rc2-mm1~audit/fs/namei.c 2005-04-05 13:16:04.000000000 -0500
@@ -225,6 +225,8 @@ int permission(struct inode *inode, int
{
int retval, submask;
+ audit_notify_watch(inode, mask);
+
if (mask & MAY_WRITE) {
umode_t mode = inode->i_mode;
@@ -358,6 +360,8 @@ static inline int exec_permission_lite(s
if (inode->i_op && inode->i_op->permission)
return -EAGAIN;
+ audit_notify_watch(inode, MAY_EXEC);
+
if (current->fsuid == inode->i_uid)
mode >>= 6;
else if (in_group_p(inode->i_gid))
@@ -1172,6 +1176,8 @@ static inline int may_delete(struct inod
BUG_ON(victim->d_parent->d_inode != dir);
+ audit_notify_watch(victim->d_inode, MAY_WRITE);
+
error = permission(dir,MAY_WRITE | MAY_EXEC, NULL);
if (error)
return error;
@@ -1296,6 +1302,7 @@ int vfs_create(struct inode *dir, struct
DQUOT_INIT(dir);
error = dir->i_op->create(dir, dentry, mode, nd);
if (!error) {
+ audit_notify_watch(dentry->d_inode, MAY_WRITE);
fsnotify_create(dir, dentry->d_name.name);
security_inode_post_create(dir, dentry, mode);
}
@@ -1601,6 +1608,7 @@ int vfs_mknod(struct inode *dir, struct
DQUOT_INIT(dir);
error = dir->i_op->mknod(dir, dentry, mode, dev);
if (!error) {
+ audit_notify_watch(dentry->d_inode, MAY_WRITE);
fsnotify_create(dir, dentry->d_name.name);
security_inode_post_mknod(dir, dentry, mode, dev);
}
@@ -1674,6 +1682,7 @@ int vfs_mkdir(struct inode *dir, struct
DQUOT_INIT(dir);
error = dir->i_op->mkdir(dir, dentry, mode);
if (!error) {
+ audit_notify_watch(dentry->d_inode, MAY_WRITE);
fsnotify_mkdir(dir, dentry->d_name.name);
security_inode_post_mkdir(dir,dentry, mode);
}
@@ -1915,6 +1924,7 @@ int vfs_symlink(struct inode *dir, struc
DQUOT_INIT(dir);
error = dir->i_op->symlink(dir, dentry, oldname);
if (!error) {
+ audit_notify_watch(dentry->d_inode, MAY_WRITE);
fsnotify_create(dir, dentry->d_name.name);
security_inode_post_symlink(dir, dentry, oldname);
}
@@ -1988,6 +1998,7 @@ int vfs_link(struct dentry *old_dentry,
error = dir->i_op->link(old_dentry, dir, new_dentry);
up(&old_dentry->d_inode->i_sem);
if (!error) {
+ audit_notify_watch(new_dentry->d_inode, MAY_WRITE);
fsnotify_create(dir, new_dentry->d_name.name);
security_inode_post_link(old_dentry, dir, new_dentry);
}
@@ -2111,6 +2122,7 @@ int vfs_rename_dir(struct inode *old_dir
}
if (!error) {
d_move(old_dentry,new_dentry);
+ audit_notify_watch(old_dentry->d_inode, MAY_WRITE);
security_inode_post_rename(old_dir, old_dentry,
new_dir, new_dentry);
}
@@ -2139,6 +2151,7 @@ int vfs_rename_other(struct inode *old_d
/* The following d_move() should become unconditional */
if (!(old_dir->i_sb->s_type->fs_flags & FS_ODD_RENAME))
d_move(old_dentry, new_dentry);
+ audit_notify_watch(old_dentry->d_inode, MAY_WRITE);
security_inode_post_rename(old_dir, old_dentry, new_dir, new_dentry);
}
if (target)
diff -Nurp linux-2.6.12-rc2-mm1/include/linux/audit.h linux-2.6.12-rc2-mm1~audit/include/linux/audit.h
--- linux-2.6.12-rc2-mm1/include/linux/audit.h 2005-04-05 14:06:32.000000000 -0500
+++ linux-2.6.12-rc2-mm1~audit/include/linux/audit.h 2005-04-05 13:38:40.000000000 -0500
@@ -24,18 +24,27 @@
#ifndef _LINUX_AUDIT_H_
#define _LINUX_AUDIT_H_
+#ifdef __KERNEL__
#include <linux/sched.h>
#include <linux/elf.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+#endif
+
/* Request and reply types */
-#define AUDIT_GET 1000 /* Get status */
-#define AUDIT_SET 1001 /* Set status (enable/disable/auditd) */
-#define AUDIT_LIST 1002 /* List filtering rules */
-#define AUDIT_ADD 1003 /* Add filtering rule */
-#define AUDIT_DEL 1004 /* Delete filtering rule */
-#define AUDIT_USER 1005 /* Send a message from user-space */
-#define AUDIT_LOGIN 1006 /* Define the login id and informaiton */
-#define AUDIT_KERNEL 2000 /* Asynchronous audit record. NOT A REQUEST. */
+#define AUDIT_GET 1000 /* Get status */
+#define AUDIT_SET 1001 /* Set status (enable/disable/auditd) */
+#define AUDIT_LIST 1002 /* List filtering rules */
+#define AUDIT_ADD 1003 /* Add filtering rule */
+#define AUDIT_DEL 1004 /* Delete filtering rule */
+#define AUDIT_USER 1005 /* Send a message from user-space */
+#define AUDIT_LOGIN 1006 /* Define the login id and informaiton */
+#define AUDIT_WATCH_INS 1007 /* Insert file/dir watch entry */
+#define AUDIT_WATCH_REM 1008 /* Remove file/dir watch entry */
+#define AUDIT_WATCH_LIST 1009 /* List all watches */
+#define AUDIT_KERNEL 2000 /* Asynchronous audit record. NOT A REQUEST. */
/* Rule flags */
#define AUDIT_PER_TASK 0x01 /* Apply rule at task creation (not syscall) */
@@ -132,6 +141,9 @@
#define AUDIT_ARCH_V850 (EM_V850|__AUDIT_ARCH_LE)
#define AUDIT_ARCH_X86_64 (EM_X86_64|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE)
+/* 32 byte max key size */
+#define AUDIT_FILTERKEY_MAX 32
+
#ifndef __KERNEL__
struct audit_message {
struct nlmsghdr nlh;
@@ -159,8 +171,28 @@ struct audit_rule { /* for AUDIT_LIST,
__u32 values[AUDIT_MAX_FIELDS];
};
+struct audit_watch {
+ __u32 namelen;
+ __u32 fklen;
+ char *name;
+ char *filterkey;
+ __u32 perms;
+};
+
#ifdef __KERNEL__
+struct audit_data {
+ struct audit_wentry *wentry;
+ struct hlist_head watchlist;
+ rwlock_t lock;
+};
+
+struct audit_wentry {
+ struct hlist_node w_node;
+ struct audit_watch *w_watch;
+ atomic_t w_count;
+};
+
struct audit_buffer;
struct audit_context;
struct inode;
@@ -190,6 +222,7 @@ extern void audit_get_stamp(struct audit
extern int audit_set_loginuid(struct audit_context *ctx, uid_t loginuid);
extern uid_t audit_get_loginuid(struct audit_context *ctx);
extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode);
+extern int audit_notify_watch(struct inode *inode, int mask);
#else
#define audit_alloc(t) ({ 0; })
#define audit_free(t) do { ; } while (0)
@@ -200,6 +233,28 @@ extern int audit_ipc_perms(unsigned long
#define audit_inode(n,i) do { ; } while (0)
#define audit_get_loginuid(c) ({ -1; })
#define audit_ipc_perms(q,u,g,m) ({ 0; })
+#define audit_notify_watch(i,m) ({ 0; })
+#endif
+
+#ifdef CONFIG_AUDITFILESYSTEM
+extern int audit_list_watches(int type, int pid, int uid, int seq, char *path);
+extern int audit_receive_watch(int type, int pid, int uid, int seq,
+ struct audit_watch *req);
+extern int audit_filesystem_init(void);
+extern int audit_inode_alloc(struct inode *inode);
+extern void audit_inode_free(struct inode *inode);
+extern void audit_attach_watch(struct dentry *dentry, int remove);
+extern void audit_wentry_put(struct audit_wentry *wentry);
+extern struct audit_wentry *audit_wentry_get(struct audit_wentry *wentry);
+#else
+#define audit_list_watches(t,p,u,s,r) ({ -EOPNOTSUPP; })
+#define audit_receive_watch(t,p,u,s,r) ({ -EOPNOTSUPP; })
+#define audit_filesystem_init() ({ 0; })
+#define audit_inode_alloc(i) ({ 0; })
+#define audit_inode_free(i) do { ; } while(0)
+#define audit_attach_watch(d,r) do { ; } while (0)
+#define audit_wentry_put(w) do { ; } while(0)
+#define audit_wentry_get(w) ({ 0; })
#endif
#ifdef CONFIG_AUDIT
diff -Nurp linux-2.6.12-rc2-mm1/include/linux/fs.h linux-2.6.12-rc2-mm1~audit/include/linux/fs.h
--- linux-2.6.12-rc2-mm1/include/linux/fs.h 2005-04-05 14:06:32.000000000 -0500
+++ linux-2.6.12-rc2-mm1~audit/include/linux/fs.h 2005-04-05 16:11:48.000000000 -0500
@@ -214,6 +214,7 @@ extern int dir_notify_enable;
#include <linux/prio_tree.h>
#include <linux/init.h>
#include <linux/sched.h>
+#include <linux/audit.h>
#include <asm/atomic.h>
#include <asm/semaphore.h>
@@ -477,6 +478,7 @@ struct inode {
struct semaphore inotify_sem; /* protects the watches list */
#endif
+ struct audit_data *i_audit;
unsigned long i_state;
unsigned long dirtied_when; /* jiffies of first dirtying */
diff -Nurp linux-2.6.12-rc2-mm1/init/Kconfig linux-2.6.12-rc2-mm1~audit/init/Kconfig
--- linux-2.6.12-rc2-mm1/init/Kconfig 2005-04-05 14:06:32.000000000 -0500
+++ linux-2.6.12-rc2-mm1~audit/init/Kconfig 2005-04-05 13:16:26.000000000 -0500
@@ -198,6 +198,16 @@ config AUDITSYSCALL
can be used independently or with another kernel subsystem,
such as SELinux.
+config AUDITFILESYSTEM
+ bool "Enable file system auditing support"
+ depends on AUDITSYSCALL
+ default n
+ help
+ Enable file system auditing for regular files and directories.
+ When a targeted file or directory is accessed, an audit record
+ is generated describing the inode accessed, how it was accessed,
+ and by whom (ie: pid and system call).
+
config HOTPLUG
bool "Support for hot-pluggable devices" if !ARCH_S390
default ARCH_S390
diff -Nurp linux-2.6.12-rc2-mm1/kernel/Makefile linux-2.6.12-rc2-mm1~audit/kernel/Makefile
--- linux-2.6.12-rc2-mm1/kernel/Makefile 2005-04-05 14:06:32.000000000 -0500
+++ linux-2.6.12-rc2-mm1~audit/kernel/Makefile 2005-04-05 13:21:20.000000000 -0500
@@ -25,6 +25,7 @@ obj-$(CONFIG_IKCONFIG_PROC) += configs.o
obj-$(CONFIG_STOP_MACHINE) += stop_machine.o
obj-$(CONFIG_AUDIT) += audit.o
obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
+obj-$(CONFIG_AUDITFILESYSTEM) += auditfs.o
obj-$(CONFIG_KPROBES) += kprobes.o
obj-$(CONFIG_SYSFS) += ksysfs.o
obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o
diff -Nurp linux-2.6.12-rc2-mm1/kernel/audit.c linux-2.6.12-rc2-mm1~audit/kernel/audit.c
--- linux-2.6.12-rc2-mm1/kernel/audit.c 2005-04-05 14:56:28.000000000 -0500
+++ linux-2.6.12-rc2-mm1~audit/kernel/audit.c 2005-04-05 15:02:21.000000000 -0500
@@ -322,6 +322,9 @@ static int audit_netlink_ok(kernel_cap_t
case AUDIT_SET:
case AUDIT_ADD:
case AUDIT_DEL:
+ case AUDIT_WATCH_INS:
+ case AUDIT_WATCH_REM:
+ case AUDIT_WATCH_LIST:
if (!cap_raised(eff_cap, CAP_AUDIT_CONTROL))
err = -EPERM;
break;
@@ -416,6 +419,19 @@ static int audit_receive_msg(struct sk_b
err = -EOPNOTSUPP;
#endif
break;
+ case AUDIT_WATCH_INS:
+ case AUDIT_WATCH_REM:
+ if (nlh->nlmsg_len < sizeof(struct audit_watch))
+ return -EINVAL;
+ err = audit_receive_watch(nlh->nlmsg_type,
+ NETLINK_CB(skb).pid,
+ uid, seq, data);
+ break;
+ case AUDIT_WATCH_LIST:
+ err = audit_list_watches(nlh->nlmsg_type,
+ NETLINK_CB(skb).pid,
+ uid, seq, data);
+ break;
default:
err = -EINVAL;
break;
@@ -560,6 +576,7 @@ static int __init audit_init(void)
audit_initialized = 1;
audit_enabled = audit_default;
+ audit_filesystem_init();
audit_log(NULL, "initialized");
return 0;
}
diff -Nurp linux-2.6.12-rc2-mm1/kernel/auditfs.c linux-2.6.12-rc2-mm1~audit/kernel/auditfs.c
--- linux-2.6.12-rc2-mm1/kernel/auditfs.c 1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.12-rc2-mm1~audit/kernel/auditfs.c 2005-04-05 13:16:26.000000000 -0500
@@ -0,0 +1,511 @@
+/* auditfs.c -- Filesystem auditing support -*- linux-c -*-
+ * Implements filesystem auditing support, depends on kernel/auditsc.c
+ *
+ * Copyright 2005 International Business Machines Corp. (IBM)
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ *
+ * Written by Timothy R. Chavez <chavezt@us.ibm.com>
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/namei.h>
+#include <linux/mount.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/audit.h>
+#include <asm/uaccess.h>
+
+kmem_cache_t *audit_watch_cache;
+kmem_cache_t *audit_wentry_cache;
+
+/* Private Interface */
+
+static inline struct audit_wentry *audit_wentry_fetch(const char *name,
+ struct audit_data *data)
+{
+ struct audit_wentry *wentry, *ret = NULL;
+ struct hlist_node *pos;
+
+ hlist_for_each_entry(wentry, pos, &data->watchlist, w_node)
+ if(!strcmp(wentry->w_watch->name, name)) {
+ ret = audit_wentry_get(wentry);
+ break;
+ }
+
+ return ret;
+}
+
+static inline struct audit_wentry *audit_wentry_fetch_lock(const char *name,
+ struct audit_data *data)
+{
+ struct audit_wentry *ret = NULL;
+
+ if (name && data) {
+ read_lock(&data->lock);
+ ret = audit_wentry_fetch(name, data);
+ read_unlock(&data->lock);
+ }
+
+ return ret;
+}
+
+static inline struct audit_watch *audit_watch_alloc(void)
+{
+ struct audit_watch *watch;
+
+ watch = kmem_cache_alloc(audit_watch_cache, GFP_KERNEL);
+ if (watch) {
+ watch->namelen = 0;
+ watch->fklen = 0;
+ watch->name = NULL;
+ watch->filterkey = NULL;
+ watch->perms = 0;
+ }
+
+ return watch;
+}
+
+static inline void audit_watch_free(struct audit_watch *watch)
+{
+ if (watch) {
+ kfree(watch->name);
+ kfree(watch->filterkey);
+ kmem_cache_free(audit_watch_cache, watch);
+ }
+}
+
+static struct audit_watch *audit_create_watch(const char *name,
+ const char *filterkey,
+ __u32 perms)
+{
+ struct audit_watch *err = NULL;
+ struct audit_watch *watch = NULL;
+
+ err = ERR_PTR(-ENOMEM);
+ watch = audit_watch_alloc();
+ if (watch) {
+ watch->namelen = strlen(name) + 1;
+ watch->name = kmalloc(watch->namelen, GFP_KERNEL);
+ if (!watch->name)
+ goto audit_create_watch_fail;
+ strcpy(watch->name, name);
+
+ if (filterkey) {
+ watch->fklen = strlen(filterkey) + 1;
+ watch->filterkey = kmalloc(watch->fklen, GFP_KERNEL);
+ if (!watch->filterkey)
+ goto audit_create_watch_fail;
+ strcpy(watch->filterkey, filterkey);
+ }
+
+ watch->perms = perms;
+
+ goto audit_create_watch_exit;
+ }
+
+
+audit_create_watch_fail:
+ audit_watch_free(watch);
+ watch = err;
+audit_create_watch_exit:
+ return watch;
+}
+
+static inline struct audit_wentry *audit_wentry_alloc(void)
+{
+ struct audit_wentry *wentry;
+
+ wentry = kmem_cache_alloc(audit_wentry_cache, GFP_KERNEL);
+ if (wentry) {
+ atomic_set(&wentry->w_count, 1);
+ wentry->w_watch = NULL;
+ }
+
+ return wentry;
+}
+
+static inline void audit_wentry_free(struct audit_wentry *wentry)
+{
+ if (wentry) {
+ audit_watch_free(wentry->w_watch);
+ kmem_cache_free(audit_wentry_cache, wentry);
+ }
+}
+
+static inline void audit_destroy_wentry(struct audit_wentry *wentry)
+{
+ if (wentry) {
+ hlist_del_init(&wentry->w_node);
+ audit_wentry_put(wentry);
+ }
+}
+
+struct audit_wentry *audit_wentry_get(struct audit_wentry *wentry)
+{
+ if (wentry) {
+ BUG_ON(!atomic_read(&wentry->w_count));
+ atomic_inc(&wentry->w_count);
+ }
+
+ return wentry;
+}
+
+void audit_wentry_put(struct audit_wentry *wentry)
+{
+ if (wentry && atomic_dec_and_test(&wentry->w_count))
+ audit_wentry_free(wentry);
+}
+
+/* The only time the new wentry gets updated is when it is inaccessible
+ * (out of the list).
+ */
+static int audit_create_wentry(const char *name,
+ const char *filterkey,
+ __u32 perms, struct audit_data *data)
+{
+ int ret;
+ struct audit_wentry *wentry = NULL;
+ struct audit_wentry *new_wentry = NULL;
+
+ ret = -ENOMEM;
+ new_wentry = audit_wentry_alloc();
+ if (!new_wentry)
+ goto audit_create_wentry_fail;
+
+ new_wentry->w_watch = audit_create_watch(name, filterkey, perms);
+ if (IS_ERR(new_wentry->w_watch)) {
+ ret = PTR_ERR(new_wentry->w_watch);
+ new_wentry->w_watch = NULL;
+ goto audit_create_wentry_fail;
+ }
+
+ ret = 0;
+ write_lock(&data->lock);
+ wentry = audit_wentry_fetch(name, data);
+ if (!wentry) {
+ hlist_add_head(&new_wentry->w_node, &data->watchlist);
+ write_unlock(&data->lock);
+ goto audit_create_wentry_exit;
+ }
+ audit_wentry_put(wentry);
+ write_unlock(&data->lock);
+
+ ret = -EEXIST;
+
+audit_create_wentry_fail:
+ audit_wentry_put(new_wentry);
+audit_create_wentry_exit:
+ return ret;
+}
+
+/* Caller must hold data->lock */
+
+static inline void audit_drain_watchlist(struct audit_data *data)
+{
+ struct audit_wentry *wentry;
+ struct hlist_node *pos, *buf;
+
+ hlist_for_each_entry_safe(wentry, pos, buf, &data->watchlist, w_node)
+ audit_destroy_wentry(wentry);
+}
+
+static inline struct audit_data *audit_data_alloc(void)
+{
+ struct audit_data *data;
+
+ data = kmalloc(sizeof(struct audit_data), GFP_KERNEL);
+ if (data) {
+ data->wentry = NULL;
+ INIT_HLIST_HEAD(&data->watchlist);
+ data->lock = RW_LOCK_UNLOCKED;
+ }
+
+ return data;
+}
+
+static inline void audit_data_free(struct audit_data *data)
+{
+ if (data) {
+ write_lock(&data->lock);
+ audit_drain_watchlist(data);
+ audit_wentry_put(data->wentry);
+ write_unlock(&data->lock);
+ kfree(data);
+ }
+}
+
+static inline int audit_insert_watch(char *path, char *filterkey, __u32 perms)
+{
+ int ret;
+ struct nameidata nd;
+
+ ret = path_lookup(path, LOOKUP_PARENT|LOOKUP_FOLLOW, &nd);
+ if (ret < 0)
+ goto audit_insert_watch_exit;
+
+ ret = -EPERM;
+ if (nd.last_type != LAST_NORM || !nd.last.name)
+ goto audit_insert_watch_release;
+
+ ret = audit_create_wentry(nd.last.name, filterkey, perms,
+ nd.dentry->d_inode->i_audit);
+
+audit_insert_watch_release:
+ path_release(&nd);
+audit_insert_watch_exit:
+ return ret;
+}
+
+static inline int audit_remove_watch(char *path)
+{
+ int ret;
+ struct nameidata nd;
+ struct audit_data *data;
+ struct audit_wentry *wentry;
+
+ ret = path_lookup(path, LOOKUP_PARENT|LOOKUP_FOLLOW, &nd);
+ if (ret < 0)
+ goto audit_remove_watch_exit;
+
+ ret = -EPERM;
+ if (nd.last_type != LAST_NORM || !nd.last.name)
+ goto audit_remove_watch_release;
+
+ data = nd.dentry->d_inode->i_audit;
+
+ write_lock(&data->lock);
+ wentry = audit_wentry_fetch(nd.last.name, data);
+ if (!wentry) {
+ write_unlock(&data->lock);
+ goto audit_remove_watch_release;
+ }
+ audit_destroy_wentry(wentry);
+ audit_wentry_put(wentry);
+ write_unlock(&data->lock);
+
+ ret = 0;
+
+audit_remove_watch_release:
+ path_release(&nd);
+audit_remove_watch_exit:
+ return ret;
+}
+
+/* Eventually we'll want to have serialization routines to send audit_watch
+ * structures to and from the kernel. For the time being, we send back a
+ * watch in a formatted string to the userspace.
+ */
+static inline char *audit_watch_to_string(struct audit_watch *watch)
+{
+ int buflen;
+ char *buf = NULL;;
+
+ if (!watch)
+ goto audit_watch_to_string_exit;
+
+ buflen = watch->namelen + (watch->fklen ? watch->fklen : 6) + 22;
+ buf = kmalloc(buflen, GFP_KERNEL);
+ if (!buf)
+ goto audit_watch_to_string_exit;
+
+ snprintf(buf, buflen, "%s(filterkey=%s, perms=%d)",
+ watch->name, watch->filterkey, watch->perms);
+
+audit_watch_to_string_exit:
+ return buf;
+}
+
+/*
+ * Hook appears in fs/dcache.c:
+ * d_move(),
+ * d_delete(),
+ * d_instantiate(),
+ * d_splice_alias()
+ * __d_lookup()
+ */
+void audit_attach_watch(struct dentry *dentry, int remove)
+{
+ struct audit_wentry *wentry;
+ struct audit_data *data, *parent;
+
+ if (!dentry || !dentry->d_inode)
+ return;
+
+ if (!dentry->d_parent || !dentry->d_parent->d_inode)
+ return;
+
+ data = dentry->d_inode->i_audit;
+ parent = dentry->d_parent->d_inode->i_audit;
+
+ wentry = audit_wentry_fetch_lock(dentry->d_name.name, parent);
+
+ write_lock(&data->lock);
+ /* FIXME: long watchlist == too much spinning? */
+ if (remove) {
+ audit_drain_watchlist(data);
+ if (wentry && data->wentry) {
+ if (!strcmp(wentry->w_watch->name,
+ data->wentry->w_watch->name)) {
+ audit_wentry_put(data->wentry);
+ dentry->d_inode->i_audit->wentry = NULL;
+ }
+ }
+ } else if (!data->wentry || hlist_unhashed(&data->wentry->w_node)) {
+ audit_wentry_put(data->wentry);
+ dentry->d_inode->i_audit->wentry = audit_wentry_get(wentry);
+ }
+ audit_wentry_put(wentry);
+ write_unlock(&data->lock);
+}
+
+int audit_list_watches(int type, int pid, int uid, int seq, char *path)
+{
+ int ret;
+ char *watch = NULL;
+ struct nameidata nd;
+ struct hlist_node *pos;
+ struct audit_data *data;
+ struct audit_wentry *wentry;
+
+ ret = path_lookup(path, LOOKUP_FOLLOW, &nd);
+ if (ret < 0)
+ goto audit_list_watches_exit;
+
+ ret = -ENOMEM;
+ data = nd.dentry->d_inode->i_audit;
+ read_lock(&data->lock);
+ hlist_for_each_entry(wentry, pos, &data->watchlist, w_node) {
+ audit_wentry_get(wentry);
+ watch = audit_watch_to_string(wentry->w_watch);
+ if (!watch)
+ goto audit_list_watches_release;
+ audit_send_reply(pid, seq, AUDIT_WATCH_LIST, 0, 1,
+ watch, strlen(watch) + 1);
+ kfree(watch);
+ audit_wentry_put(wentry);
+ }
+ read_unlock(&data->lock);
+
+ audit_send_reply(pid, seq, AUDIT_WATCH_LIST, 1, 1, NULL, 0);
+ ret = 0;
+
+audit_list_watches_release:
+ path_release(&nd);
+audit_list_watches_exit:
+ return ret;
+}
+
+int audit_receive_watch(int type, int pid, int uid, int seq,
+ struct audit_watch *req)
+{
+ int ret = 0;
+ char *path = NULL;
+ char *filterkey = NULL;
+
+ ret = -EINVAL;
+ path = getname(req->name);
+ if (IS_ERR(path)) {
+ ret = PTR_ERR(path);
+ goto audit_receive_watch_exit;
+ }
+
+ if (!path || strlen(path) + 1 > PATH_MAX)
+ goto audit_receive_watch_exit;
+
+ /* Includes terminating '\0' */
+ if (req->fklen > AUDIT_FILTERKEY_MAX)
+ goto audit_receive_watch_exit;
+
+ if (req->perms > (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND))
+ goto audit_receive_watch_exit;
+
+ if (req->fklen) {
+ ret = -ENOMEM;
+ filterkey = kmalloc(req->fklen, GFP_KERNEL);
+ if (!filterkey)
+ goto audit_receive_watch_exit;
+
+ ret = strncpy_from_user(filterkey, req->filterkey, req->fklen);
+ if (ret < 0)
+ goto audit_receive_watch_exit;
+ }
+
+ switch (type) {
+ case AUDIT_WATCH_INS:
+ ret = audit_insert_watch(path, filterkey, req->perms);
+ break;
+ case AUDIT_WATCH_REM:
+ ret = audit_remove_watch(path);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+audit_receive_watch_exit:
+ putname(path);
+ kfree(filterkey);
+ return ret;
+}
+
+int audit_inode_alloc(struct inode *inode)
+{
+ if (inode) {
+ inode->i_audit = audit_data_alloc();
+ if (!inode->i_audit)
+ return ENOMEM;
+ }
+
+ return 0;
+}
+
+void audit_inode_free(struct inode *inode)
+{
+ if (inode)
+ audit_data_free(inode->i_audit);
+}
+
+int audit_filesystem_init()
+{
+ int ret = 0;
+
+ audit_watch_cache =
+ kmem_cache_create("audit_watch_cache",
+ sizeof(struct audit_watch), 0, 0, NULL, NULL);
+ if (!audit_watch_cache)
+ goto audit_filesystem_init_fail;
+
+ audit_wentry_cache =
+ kmem_cache_create("audit_wentry_cache",
+ sizeof(struct audit_wentry), 0, 0, NULL, NULL);
+ if (!audit_wentry_cache)
+ goto audit_filesystem_init_fail;
+
+ goto audit_filesystem_init_exit;
+
+audit_filesystem_init_fail:
+ ret = -ENOMEM;
+ kmem_cache_destroy(audit_watch_cache);
+ kmem_cache_destroy(audit_wentry_cache);
+audit_filesystem_init_exit:
+ return ret;
+
+}
diff -Nurp linux-2.6.12-rc2-mm1/kernel/auditsc.c linux-2.6.12-rc2-mm1~audit/kernel/auditsc.c
--- linux-2.6.12-rc2-mm1/kernel/auditsc.c 2005-04-05 14:06:32.000000000 -0500
+++ linux-2.6.12-rc2-mm1~audit/kernel/auditsc.c 2005-04-05 13:16:26.000000000 -0500
@@ -102,6 +102,7 @@ struct audit_aux_data {
};
#define AUDIT_AUX_IPCPERM 0
+#define AUDIT_AUX_WATCH 1
struct audit_aux_data_ipcctl {
struct audit_aux_data d;
@@ -112,6 +113,16 @@ struct audit_aux_data_ipcctl {
mode_t mode;
};
+struct audit_aux_data_watched {
+ struct audit_aux_data link;
+ struct audit_wentry *wentry;
+ unsigned long ino;
+ int mask;
+ uid_t uid;
+ gid_t gid;
+ dev_t dev;
+ dev_t rdev;
+};
/* The per-task audit context. */
struct audit_context {
@@ -665,6 +676,24 @@ static void audit_log_exit(struct audit_
audit_log_format(ab,
" qbytes=%lx uid=%d gid=%d mode=%x",
axi->qbytes, axi->uid, axi->gid, axi->mode);
+ break;
+ }
+
+ case AUDIT_AUX_WATCH: {
+ struct audit_aux_data_watched *axi = (void *)aux;
+ audit_log_format(ab, " name=");
+ audit_log_untrustedstring(ab, axi->wentry->w_watch->name);
+ audit_log_format(ab,
+ " filterkey=%s perm=%u perm_mask=%d"
+ " inode=%lu inode_uid=%d inode_gid=%d"
+ " inode_dev=%02x:%02x inode_rdev=%02x:%02x",
+ axi->wentry->w_watch->filterkey,
+ axi->wentry->w_watch->perms,
+ axi->mask, axi->ino, axi->uid, axi->gid,
+ MAJOR(axi->dev), MINOR(axi->dev),
+ MAJOR(axi->rdev), MINOR(axi->rdev));
+ audit_wentry_put(axi->wentry);
+ break;
}
}
audit_log_end(ab);
@@ -1024,3 +1053,52 @@ int audit_ipc_perms(unsigned long qbytes
context->aux = (void *)ax;
return 0;
}
+
+int audit_notify_watch(struct inode *inode, int mask)
+{
+ int ret = 0;
+ struct audit_context *context = current->audit_context;
+ struct audit_aux_data_watched *ax;
+ struct audit_wentry *wentry = NULL;
+
+ if (likely(!context))
+ goto audit_notify_watch_fail;
+
+ if (!inode)
+ goto audit_notify_watch_fail;
+
+ wentry = audit_wentry_get(inode->i_audit->wentry);
+ if (!wentry)
+ goto audit_notify_watch_fail;
+
+ if (mask && (wentry->w_watch->perms && !(wentry->w_watch->perms&mask)))
+ goto audit_notify_watch_fail;
+
+ ret = -ENOMEM;
+ ax = kmalloc(sizeof(*ax), GFP_KERNEL);
+ if (!ax)
+ goto audit_notify_watch_fail;
+
+ ret = 0;
+ if (context->in_syscall && !context->auditable)
+ context->auditable = 1;
+
+ ax->wentry = wentry;
+ ax->mask = mask;
+ ax->ino = inode->i_ino;
+ ax->uid = inode->i_uid;
+ ax->gid = inode->i_gid;
+ ax->dev = inode->i_sb->s_dev;
+ ax->rdev = inode->i_rdev;
+
+ ax->link.type = AUDIT_AUX_WATCH;
+ ax->link.next = context->aux;
+ context->aux = (void *)ax;
+
+ goto audit_notify_watch_exit;
+
+audit_notify_watch_fail:
+ audit_wentry_put(wentry);
+audit_notify_watch_exit:
+ return ret;
+}
diff -Nurp linux-2.6.12-rc2-mm1/security/selinux/nlmsgtab.c linux-2.6.12-rc2-mm1~audit/security/selinux/nlmsgtab.c
--- linux-2.6.12-rc2-mm1/security/selinux/nlmsgtab.c 2005-03-02 01:38:19.000000000 -0600
+++ linux-2.6.12-rc2-mm1~audit/security/selinux/nlmsgtab.c 2005-04-05 13:16:26.000000000 -0500
@@ -98,6 +98,8 @@ static struct nlmsg_perm nlmsg_audit_per
{ AUDIT_DEL, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
{ AUDIT_USER, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
{ AUDIT_LOGIN, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
+ { AUDIT_WATCH_INS, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
+ { AUDIT_WATCH_REM, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
};
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [RFC][PATCH 2/2] file system auditing
[not found] ` <1112740621.4397.65.camel@localhost.localdomain>
@ 2005-04-05 22:45 ` Timothy R. Chavez
0 siblings, 0 replies; 3+ messages in thread
From: Timothy R. Chavez @ 2005-04-05 22:45 UTC (permalink / raw)
To: linux-fsdevel; +Cc: David Woodhouse, linux-audit
On Tuesday 05 April 2005 05:37 pm, you wrote:
> On Tue, 2005-04-05 at 17:20 -0500, Timothy R. Chavez wrote:
> > --- linux-2.6.12-rc2-mm1/security/selinux/nlmsgtab.c 2005-03-02
> > 01:38:19.000000000 -0600 +++
> > linux-2.6.12-rc2-mm1~audit/security/selinux/nlmsgtab.c 2005-04-05
> > 13:16:26.000000000 -0500 @@ -98,6 +98,8 @@ static struct nlmsg_perm
> > nlmsg_audit_per
> > { AUDIT_DEL, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
> > { AUDIT_USER, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
> > { AUDIT_LOGIN, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
> > + { AUDIT_WATCH_INS, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
> > + { AUDIT_WATCH_REM, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
> > };
>
> Do you not need to add AUDIT_WATCH_LIST to this?
Oh yes, that's right. I'm not sure its pertinent ATM. The feature isn't
supported in the downloadable version of the user space tools yet. But
regardless, it should be added. Thanks David.
-tim
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2005-04-05 22:44 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-04-05 22:04 [RFC][PATCH 1/2] file system auditing Timothy R. Chavez
2005-04-05 22:20 ` [RFC][PATCH 2/2] " Timothy R. Chavez
[not found] ` <1112740621.4397.65.camel@localhost.localdomain>
2005-04-05 22:45 ` Timothy R. Chavez
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.