[serue@us.ibm.com: dcache_lock deadlock due to auditing]
by serue@us.ibm.com
----- Forwarded message from serue(a)us.ibm.com -----
Date: Tue, 12 Apr 2005 22:13:20 -0500
From: serue(a)us.ibm.com
To: selinux(a)tycho.nsa.gov
Subject: dcache_lock deadlock due to auditing
Reply-To: serue(a)us.ibm.com
Hi,
a team running some tcp benchmarks on new hardware found a recursive
spinlock(dcache_lock) deadlock. It seems to always be caused by:
A process is doing a d_alloc() which does a spin_lock(dcache_lock).
It is interrupted to receive a packet
selinux_sock_rcv_skb gets called
it calls avc_has_perm
this calls avc_audit
this calls audit_log_d_path
this calls d_path which does spin_lock(dcache_lock)
Deferring the actual audit work to the audit subsystem in a manner
similar to what Stephen's recent audit_log_exit() patch did seems one
possible way to solve this problem. Another might be to determine our
context before the audit_log_d_path( vma->vm_file->f_dentry ), and, if
we can determine that we were called from interrupt, simply print out
the f_dentry->d_name.name itself.
Are there other solutions?
thanks,
-serge
----- End forwarded message -----
19 years, 8 months
Audit daemon going to single user mode
by Steve Grubb
Hello,
When the audit daemon goes to single user mode due to hitting a limit that
causes the action to be performed. Is the audit daemon supposed to stay alive
or should it quit? As of right now, it quits because the init scripts doesn't
have it in the single user run level setting.
Thanks,
-Steve
19 years, 8 months
audit.20 kernel
by David Woodhouse
... contains Chris' version of Steve's fix for audit_log_drain(), and my
thinko in the auditfs patch fixed so the hook in permission() should
work on all file systems.
--
dwmw2
19 years, 8 months
audit_panic
by Steve Grubb
Hi,
If a user has set the failure flag to panic, does it make sense for the kernel
to panic if there's no audit daemon? (Meaning that messages are going to
syslog.)
The reason I ask...is what if during shutdown, the rate is exceeded or the
backlog becomes full, thus triggering a panic before shutdown of the audit
daemon completes?
-Steve
19 years, 8 months
Auditd shutdown
by Steve Grubb
Hello,
Having the kernel detect a signal being sent to the audit daemon is not
working. Is anyone troubleshooting this or do we take another approach?
I spent some time yesterday thinking about the shutdown. I came to the
conclusion that the only way to "do it right" is to get the credentials in
the signal handler. Everything else is racy.
THE PROBLEM
When I get the term signal, I would need to wait for the event to be logged to
disk. So that means I have to inspect each packet and wait until the shutdown
message comes through. But what if the backlog was full when that event would
have been enqueued?
Also, suppose I have a time out. When the timeout occurs, I have 2 choices:
set the audit pid to 0 and then close the socket, or just close the socket.
If I just close the socket, I get this message in the logs:
Apr 11 16:55:04 localhost kernel: audit: *NO* daemon at audit_pid=15734
This looks ugly. But if I set the pid to 0, we don't get that message in the
logs. But I am using the ack flag for positive confirmation of all netlink
communication. So what if the signal event is the first thing I read from the
socket instead of the ack? Meaning the event was delivered just after the
timeout and before the logging thread finished?
Besides, by using a timeout, we do not meet the requirements. If the timeout
occurs and we go ahead and shutdown, we simply don't have the information
about who initiated the shutdown.
I can come up with more scenarios that show we can't meet the CAPP
requirements by having an event placed into the message queue. The only way
to guarantee that we meet requirements is for the credentials to be available
*with* the signal delivery.
ALTERNATIVES
What I believe we should do is one of 2 things. Either create a SA_AUDITINFO
structure that can be delivered with the signal - or to swap the values of 2
entries in the siginfo_t structure. Between the two, I think SA_AUDITINFO is
the correct way to do it. But I would like to examine swapping values first.
We need to think about LSPP as we do this and solve both problems while we are
in this area. LSPP will require that we log the credentials of the initiator.
This would be the SE Linux sid. It is kept in kernel as a u32 data type. The
user id is kept as uid_t. So, we need to find 2 elements in the siginfo_t
structure that we can replace with our data.
The si_uid fits the loginuid perfectly. The si_uid normally indicates the user
that sent the signal. Since the audit daemon runs as root, only root
processes can send signals to it. So basically, every time we get a signal,
this element will be root which is meaningless. We can replace it with the
loginuid and now it has meaning.
The SE Linux uid is tougher to fit. Because linux is deployed on 16 bit
platforms, we cannot use any int in the siginfo_t structure and be correct.
We have to find something that is a long. In include/asm-generic/siginfo.h,
we can see the structure. A quick grep for long finds this:
#ifndef __ARCH_SI_BAND_T
#define __ARCH_SI_BAND_T long
#endif
We do not use poll in the audit daemon, so this might be a good candidate.
Another candidate would be anything with clock_t. Looking at the per arch
definition, they all seem to be long. So this means si_stime or si_utime
have the right sizes.
The only issue left is choosing which one we want to use and agreeing on that.
Since long is signed and the SE Linux sid is u32, we need to take care to
load it correctly so we don't get sign extension. It needs to be cast to
unsigned long and then long.
The other way of delivering credential with the signal is to create a new
SA_AUDITINFO flag and a new structure to hold our information:
typedef struct sigauditinfo {
int sa_signo; /* Signal number */
int sa_errno; /* An errno value */
int sa_code; /* Signal code */
pid_t sa_pid; /* Sending process ID */
sid sa_pidsid; /* Sending process sid */
uid_t sa_uid; /* Real user ID of sending process */
sid sa_uidsid; /* Real user's sid */
uid_t sa_luid; /* Login user ID of sending process */
int si_status; /* Exit value or signal */
} sigauditinfo_t;
This structure could be added to a union to ensure that it is the same size as
siginfo_t. This will keep the stack unwinders happy. The above structure
could be expanded to also include:
clock_t si_utime; /* User time consumed */
clock_t si_stime; /* System time consumed */
sigval_t si_value; /* Signal value */
int si_int; /* POSIX.1b signal */
void * si_ptr; /* POSIX.1b signal */
void * si_addr; /* Memory location which caused fault */
int si_band; /* Band event */
int si_fd; /* File descriptor */
But if we do that, we are too big to be in a union without increasing the
overall size. We could overcome this problem by using si_addr to point to a
new structure whenever there's no address fault. That address would be valid
only until the signal handler returns or is longjmp'ed out of.
NEXT STEP
The next step is to decide which way is cleanest and acceptable by upstream
developers. Are there holes in either way proposed above? Can sending an
shutdown audit event via netlink be done without races?
-Steve
19 years, 8 months
audit.19 kernel
by David Woodhouse
I'm uploading the audit.19 kernel. It has Tim's latest patch and my
patch to log signals sent to the audit dæmon.
--
dwmw2
19 years, 8 months
audit 0.6.10 released
by Steve Grubb
Hello,
Another audit package has been released. This release is mostly code cleanups
and getting things finalized for Fedora Core 4. It can be downloaded from
http://people.redhat.com/sgrubb/audit
The changelog includes:
- Code cleanups
- Support the arch field for auditctl
- Add version to auditctl command
- Documentation updates
- Moved default location of the audit log to /var/log/audit/audit.log
The default location for the audit log was moved for a couple reasons. We want
to put it in a place that could be used as a mount point. People doing any
serious auditing need to have a partition set aside just for auditing. This
move, by default, will make it easier for people to do that. We also wanted
to put it in its own directory so that we can add some SE Linux policy later
to protect the logs.
The audit watch list code is not in this release. I feel that we still need to
discuss the way it needs to work and solidify that before I put it into the
FC4 distribution. The watch add & remove I think are fine and the code is
included so that one day when this gets upstream and that kernel gets
released, everyone can start using it.
Let me know if there are any problems with this latest release.
Thanks,
-Steve Grubb
19 years, 8 months
[RFC][PATCH 1/2] file system auditing (#6U3)
by Timothy R. Chavez
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. Brief explanations of hook
placement and purpose are provided. Terminology, such as "watch" and
"watch point", are defined in the next message.
[PATCH 2/2]
The second patch consists of the file system auditing implementation. A
high-level overview of the design has been provided.
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 successfully leaves a "watch point".
The hook appears in may_delete() after we have determined the victim dentry
has an inode.
Note: We are unable to use may_create() in a similar fashion to may_delete()
because the inode should not exist for the child dentry in question 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.11.5/fs/dcache.c linux-2.6.11.5~auditfs/fs/dcache.c
--- linux-2.6.11.5/fs/dcache.c 2005-03-19 00:34:52.000000000 -0600
+++ linux-2.6.11.5~auditfs/fs/dcache.c 2005-03-31 11:31:09.000000000 -0600
@@ -32,6 +32,7 @@
#include <linux/seqlock.h>
#include <linux/swap.h>
#include <linux/bootmem.h>
+#include <linux/audit.h>
/* #define DCACHE_DEBUG 1 */
@@ -96,6 +97,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);
@@ -798,6 +800,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);
}
@@ -974,6 +977,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);
@@ -983,6 +987,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);
@@ -1086,6 +1091,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;
@@ -1295,6 +1301,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;
@@ -1328,6 +1336,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.11.5/fs/inode.c linux-2.6.11.5~auditfs/fs/inode.c
--- linux-2.6.11.5/fs/inode.c 2005-03-19 00:35:04.000000000 -0600
+++ linux-2.6.11.5~auditfs/fs/inode.c 2005-03-31 11:31:17.000000000 -0600
@@ -21,6 +21,7 @@
#include <linux/pagemap.h>
#include <linux/cdev.h>
#include <linux/bootmem.h>
+#include <linux/audit.h>
/*
* This is needed for the following functions:
@@ -134,9 +135,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
@@ -174,6 +177,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.11.5/fs/namei.c linux-2.6.11.5~auditfs/fs/namei.c
--- linux-2.6.11.5/fs/namei.c 2005-03-19 00:34:54.000000000 -0600
+++ linux-2.6.11.5~auditfs/fs/namei.c 2005-03-31 11:31:24.000000000 -0600
@@ -214,6 +214,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;
@@ -347,6 +349,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))
@@ -1128,6 +1132,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;
@@ -1252,6 +1258,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);
inode_dir_notify(dir, DN_CREATE);
security_inode_post_create(dir, dentry, mode);
}
@@ -1557,6 +1564,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|MAY_EXEC);
inode_dir_notify(dir, DN_CREATE);
security_inode_post_mknod(dir, dentry, mode, dev);
}
@@ -1630,6 +1638,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);
inode_dir_notify(dir, DN_CREATE);
security_inode_post_mkdir(dir,dentry, mode);
}
@@ -1874,6 +1883,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);
inode_dir_notify(dir, DN_CREATE);
security_inode_post_symlink(dir, dentry, oldname);
}
@@ -1947,6 +1957,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);
inode_dir_notify(dir, DN_CREATE);
security_inode_post_link(old_dentry, dir, new_dentry);
}
@@ -2070,6 +2081,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);
}
@@ -2098,6 +2110,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)
19 years, 8 months
audit_log_drain
by Steve Grubb
Hello,
There's design flaw (in my opinion) regarding how this function works. It's
purpose is to try to send packets to userspace. It calls netlink_unicast. If
the return value is < 0, it claims the netlink socket is too busy and marks a
packet as lost.
The fact is that as long as we have space in the backlog, we don't have to
lose a packet do we? Can we not defer claiming we've lost one and try again
later? What is the purpose of the backlog if we can't defer delivery? Also,
shouldn't we put retval in the "too busy" message to help troubleshooting?
-Steve
19 years, 8 months
[RFC][PATCH 1/2] file system auditing
by Timothy R. Chavez
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)
19 years, 8 months