Diagrams, documents, links, patches, etc
by Timothy R. Chavez
Hello,
I've set up a little page here,
http://www.busy-wait.com/projects/audit/
To keep my diagrams, documents, patches, useful links, etc organized.
--
- Timothy R. Chavez
19 years, 10 months
[RFC][PATCH] Prelim in-kernel filesystem auditing support
by Timothy R. Chavez
Hello,
I know this one is a long time coming. My last patch was critically
flawed in that the preallocation mechanism did not take into
consideration multiple references to an inode holding audit info.
This caused a complete melt down of the code. My first solution was a
miserable failure. This one works much better. I went through 40
different tests just to make sure things are behaving [more]
correctly. Two major scenarios that need to be thought over and most
likely need a fixing are the following:
1.
watch /etc/foo,filterkey=foo
watch /etc/bar,filterkey=bar
touch /etc/foo
ln /etc/foo /etc/bar
As of right now, /etc/bar will lose /etc/foo's watch information and
gain /etc/bar's. This is the natural behavior for all other scenarios
(ie: mv /etc/foo /etc/bar). I do not believe this should be allowed
for hardlinks. The filterkey=bar may be a weaker filtering key then
filterkey=foo and thus in any userspace filtering (we might decide to
do) could be subverted. Hardlinks should retain, always, the filter
information of what they're linking against, regardless of where they
are at. This also brings into consideration the need for multiple
watches on a single path? This way we get information for /etc/bar
for both /etc/foo AND /etc/bar.
2.
watch /etc/foo
touch /etc/foo
ln /etc/foo /tmp/foo
(remains audited)
mv /tmp/foo /tmp/bar
(loses audit)
This is also a natural side effect of the code. When we move we
always lose any watch information we are holding onto. If we move
into a location that's being watched we gain that watch information.
Since /tmp/bar was not being watched, the hardlink loses its watch to
/etc/foo. Is this acceptable? I don't think so. From my above
statement, the hardlink must always retain it's watch information to
what it is linked against.. We wouldn't want a user to be able to
create a hardlink and then move it to lose the watch.
But, we must also keep in mind that eventually it gets unreasonable.
For instance:
watch /etc/foo
ln /etc/foo /etc/bar
unwatch /etc/foo
rm /etc/foo
touch /etc/foo
watch /etc/foo
/etc/bar is no longer audited. There's no reasonable way around this.
The data structure for this has become much more complex as I've
incorporated the preallocation mechanism into the audit_watch
structure itself with the assertion, "One chunk of audit_data memory
per watch" -- This effectively introduces a circular data structure
(the audit_data within the audit_wentry (at one time called
audit_watch) is pointing at the audit_wentry itself. It'd take a long
time to explain why, but I intend on releasing to this list, diagrams
describing the data structure visually. I'll take a picture of my
white board and post it for the time being. You might get a good
laugh, I do. :)
Please review and provide comments.
PS: I did not use static inlines as Stephen suggested yet to keep the
code consistent with what is already there. So keep me in check. I
know I'm notorious for providing the wrong number of arguments to my
macros! :(
Patch #4:
This patch will address the above issues in some way. It will finally
take care of dynamic enable/disable of file system auditing from
userspace. It will add permission masks filtering. Fix bugs found in
Patch #3. Begin official Docbook comments. Figure out a good place
to hook so we can cover unlinks and similar syscalls that skip over
permission(). And anything else I'm presently forgetting :-)
Hopefully by then I'll have some userspace code for the public.
I originally wanted to remove some of Rik's code that hooked
path_lookup(), but I actually kind of like it. Even though the inode
he reports is wrong in some cases (ie: unlink()), the path information
is useful. Especially when looking at hardlinks that are being
watched. Might just take out the inode record. How does everyone
feel about this?
--
- Timothy R. Chavez
19 years, 10 months
audit audtid's syscall?
by Junji Kanemaru
I wonder if it is needed to audit auditd's syscalls. For example if I
want to
audit like "write,always -S all" then auditd writes log and it causes
another write call and it causes audit to log and it causes auditd writes
log and so on... I briefly looked into kernel audit code but there's no
check(I could be wrong). In some extreme situation it will cause
kernel panic in kernel audit code 'cuz no memory. Try "exit,always -S all".
So, I'd like to suggest that 1)we should have some option to disable
audit for auditd's pid 2)add option to use netlink_broadcast for kernel
audit error log instead of printk(KERN_ERR) because printk(KERN_ERR)
causes syslog write. Then auditd listens the broadcast channel to detect
error.
Please let me know if any problems. If this is acceptable then I'm going to
do it.
Thanks
--
Junji Kanemaru
Linuon Inc.
Tokyo Japan
19 years, 10 months
Proposal: New Auditd Design
by Junji Kanemaru
Hi,
I'm planning big change in auditd now. But I'd like to hear comments
from people on this list before getting on it.
It is long and my English is bad but I try.
I have own project which is very similar to auditd and after talking with
Steve Grubb I have started porting some part of my stuff into auditd.
First goal was plugin support and it's pretty much done.
I needed it because I wanted to attach plugins for particular use
such as writing audit messages to network(D-BUS or XMLRPC) without
changing auditd itself. With plugin, changing output can be done just
specifying output plugin in config file. This is pretty much done now.
The auditd has interface to register separate methods for auditing.
For example if I want to use current auditd format but want to send
out messages to network, not log out to file for purpose, what I
need to do is just specify plugin for each API's(receiver, interpreter
and consumer) . I'm working on D-BUS plugin now.
Please check it out at:
http://download.linuon.com/audit/
Now I'm planning to port my other stuff(mostly networking stuff) as
plugin of auditd. It is a complement to syslog and does more stuff.
What I really want to do with it is to capture all kernel events and
filter them with plugins and send some critical event messages to
remote server to ask what action needs to be done for the event.
It can be done either server just sends back command number
of the action or connects back to the host with D-BUS or XMLRPC
to call the action.
With this idea, host management will be completely automatic.
It is good for handling network attacks though I have to tweak
kernel netfilter a bit, the host can block itself without operator,
without lag. (BTW, let me know if any problems with this idea)
Now I wonder if I should go with auditd or start new branch for
yet another auditd because people would not want it in main tree.
I think putting above things into auditd makes sense. It won't hurt
current design since all current code had been moved into plugin,
it is matter of which plugins user wants to enable/disable but
not sure if people want this in main tree so.
Please email me if any comments, suggestions and problems.
Thank you,
-- Junji Kanemaru
Linuon Inc.
Tokyo Japan
19 years, 10 months
IPC
by David Woodhouse
Here's an untested first attempt at auditing msgctl, semctl and shmctl
IPC_SET calls. It should print the requested uid, gid, mod and qbytes
values.
We keep a linked list in the audit context, which can be extended to
contain other types of information than the IPC_SET info we add here. I
haven't added any locking -- am I right in thinking that we don't
actually need any?
--- linux-2.6.9/kernel/auditsc.c~ 2005-01-31 13:22:07.000000000 +0000
+++ linux-2.6.9/kernel/auditsc.c 2005-02-01 17:33:59.201084736 +0000
@@ -98,6 +98,23 @@ struct audit_names {
dev_t rdev;
};
+struct audit_aux_data {
+ struct audit_aux_data *next;
+ int type;
+};
+
+#define AUDIT_AUX_IPCPERM 0
+
+struct audit_aux_data_ipcctl {
+ struct audit_aux_data d;
+ struct ipc_perm p;
+ unsigned long qbytes;
+ uid_t uid;
+ gid_t gid;
+ mode_t mode;
+};
+
+
/* The per-task audit context. */
struct audit_context {
int in_syscall; /* 1 if task is in a syscall */
@@ -113,6 +130,7 @@ struct audit_context {
int name_count;
struct audit_names names[AUDIT_NAMES];
struct audit_context *previous; /* For nested syscalls */
+ struct audit_aux_data *aux;
/* Save things to print about task_struct */
pid_t pid;
@@ -560,6 +578,16 @@ static inline void audit_free_files(stru
}
}
+static inline void audit_free_aux(struct audit_context *context)
+{
+ struct audit_aux_data *aux;
+
+ while ((aux = context->aux)) {
+ context->aux = aux;
+ kfree(aux);
+ }
+}
+
static inline void audit_zero_context(struct audit_context *context,
enum audit_state state)
{
@@ -628,6 +656,7 @@ static inline void audit_free_context(st
}
audit_free_names(context);
audit_free_files(context);
+ audit_free_aux(context);
kfree(context);
context = previous;
} while (context);
@@ -666,6 +695,29 @@ static void audit_log_exit(struct audit_
context->euid, context->suid, context->fsuid,
context->egid, context->sgid, context->fsgid);
audit_log_end(ab);
+ while (context->aux) {
+ struct audit_aux_data *aux;
+
+ ab = audit_log_start(context);
+ if (!ab)
+ continue; /* audit_panic has been called */
+
+ aux = context->aux;
+ context->aux = aux->next;
+
+ audit_log_format(ab, "auxitem=%d", aux->type);
+ switch (aux->type) {
+ case AUDIT_AUX_IPCPERM: {
+ struct audit_aux_data_ipcctl *axi = (void *)aux;
+ audit_log_format(ab,
+ " qbytes=%lx uid=%d gid=%d mode=%x",
+ axi->qbytes, axi->uid, axi->gid, axi->mode);
+ }
+ }
+ audit_log_end(ab);
+ kfree(aux);
+ }
+
for (i = 0; i < context->name_count; i++) {
ab = audit_log_start(context);
if (!ab)
@@ -867,6 +919,7 @@ void audit_syscall_exit(struct task_stru
} else {
audit_free_names(context);
audit_free_files(context);
+ audit_free_aux(context);
audit_zero_context(context, context->state);
tsk->audit_context = context;
}
@@ -1049,3 +1102,26 @@ int audit_notify_watch(struct inode *ino
return 0;
}
+int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode)
+{
+ struct audit_aux_data_ipcctl *ax;
+ struct audit_context *context = current->audit_context;
+
+ if (likely(!context))
+ return 0;
+
+ ax = kmalloc(sizeof(*ax), GFP_KERNEL);
+ if (!ax)
+ return -ENOMEM;
+
+ ax->qbytes = qbytes;
+ ax->uid = uid;
+ ax->gid = gid;
+ ax->mode = mode;
+
+ ax->d.type = AUDIT_AUX_IPCPERM;
+ ax->d.next = context->aux; /* Do we need locking? Can anyone else walk this list */
+ context->aux = ax->d.next; /* while we're mucking about with it? I think not. dwmw2 */
+
+ return 0;
+}
--- linux-2.6.9/ipc/msg.c~ 2004-10-18 22:53:06.000000000 +0100
+++ linux-2.6.9/ipc/msg.c 2005-02-01 17:28:28.155088688 +0000
@@ -24,6 +24,7 @@
#include <linux/list.h>
#include <linux/security.h>
#include <linux/sched.h>
+#include <linux/audit.h>
#include <asm/current.h>
#include <asm/uaccess.h>
#include "util.h"
@@ -424,6 +425,8 @@ asmlinkage long sys_msgctl (int msqid, i
return -EFAULT;
if (copy_msqid_from_user (&setbuf, buf, version))
return -EFAULT;
+ if ((err = audit_ipc_perms(setbuf.qbytes, setbuf.uid, setbuf.gid, setbuf.mode)))
+ return err;
break;
case IPC_RMID:
break;
--- linux-2.6.9/ipc/sem.c~ 2004-10-18 22:53:50.000000000 +0100
+++ linux-2.6.9/ipc/sem.c 2005-02-01 17:28:32.748056160 +0000
@@ -71,6 +71,7 @@
#include <linux/time.h>
#include <linux/smp_lock.h>
#include <linux/security.h>
+#include <linux/audit.h>
#include <asm/uaccess.h>
#include "util.h"
@@ -788,6 +789,8 @@ static int semctl_down(int semid, int se
if(cmd == IPC_SET) {
if(copy_semid_from_user (&setbuf, arg.buf, version))
return -EFAULT;
+ if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode)))
+ return err;
}
sma = sem_lock(semid);
if(sma==NULL)
--- linux-2.6.9/ipc/shm.c~ 2004-10-18 22:54:08.000000000 +0100
+++ linux-2.6.9/ipc/shm.c 2005-02-01 17:28:36.766111032 +0000
@@ -26,6 +26,7 @@
#include <linux/proc_fs.h>
#include <linux/shmem_fs.h>
#include <linux/security.h>
+#include <linux/audit.h>
#include <asm/uaccess.h>
#include "util.h"
@@ -594,6 +595,8 @@ asmlinkage long sys_shmctl (int shmid, i
err = -EFAULT;
goto out;
}
+ if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode)))
+ return err;
down(&shm_ids.sem);
shp = shm_lock(shmid);
err=-EINVAL;
--- linux-2.6.9/include/linux/audit.h~ 2005-01-31 13:22:07.000000000 +0000
+++ linux-2.6.9/include/linux/audit.h 2005-02-01 16:45:38.011083672 +0000
@@ -179,6 +179,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_notify_watch(struct inode *inode, int mask);
+extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode);
#else
#define audit_alloc(t) ({ 0; })
#define audit_free(t) do { ; } while (0)
@@ -189,6 +190,7 @@ extern int audit_notify_watch(struct ino
#define audit_inode(n,i,d) do { ; } while (0)
#define audit_get_loginuid(c) ({ -1; })
#define audit_notify_watch(t,i,m) ({ 0; })
+#define audit_ipc_perms(q, u, g, m) do ({ 0; })
#endif
--
dwmw2
19 years, 10 months