[PATCH 0/2] audit string fields interface + consumer
by Amy Griffis
Following are two patches, the first of which provides an interface
for specifying audit rules with string fields. The second patch adds
a new string field AUDIT_WATCH. These patches are an update of the
previous audit interface patches I have posted to this list.
These patches are functionally similar to the previous posts; however,
I believe you will find the organization of the code to be quite
different and much improved. I have updated the interface based on
the feedback I received. I also resolved the issue of differentiating
between inode-based and path-based (or watch-based) filtering by
creating a new field AUDIT_WATCH and adding it to the switch in
audit_filter_rules().
Following is a summary of the interface.
A new struct audit_rule_data and corresponding netlink message types
have been added. Additionally, the SELinux nlmsg_audit_perms[] table
has been updated with the new netlink message types.
The new struct allows userspace to supply one or more string fields
packed in a variable length buffer. The kernel expects the buffer to
be neither null-delimited nor null-terminated.
The length of string data for a given field is provided as its value
element in the array. The kernel provides the buflen element for
convenience on rule listing, to allow userspace to allocate memory for
the buffer without walking the array to tabulate lengths. Buflen is
ignored coming from userspace. Instead, the kernel ensures that the
total of the lengths specified in the value elements do not exceed the
length of the message payload minus sizeof(struct audit_rule_data).
Several routines have been added to auditfilter.c to translate between
the kernel's rule representation and the two userspace rule
representations using structs audit_rule and audit_rule_data.
18 years, 10 months
make vm86 call audit_syscall_exit
by Jason Baron
hi,
The motivation behind the patch below was to address messages in
/var/log/messages such as:
Jan 31 10:54:15 mets kernel: audit(:0): major=252 name_count=0: freeing
multiple contexts (1)
Jan 31 10:54:15 mets kernel: audit(:0): major=113 name_count=0: freeing
multiple contexts (2)
I can reproduce by running 'get-edid' from:
http://john.fremlin.de/programs/linux/read-edid/.
These messages come about in the log b/c the vm86 calls do not exit via
the normal system call exit paths and thus do not call
'audit_syscall_exit'. The next system call will then free the context for
itself and for the vm86 context, thus generating the above messages. This
patch addresses the issue by simply adding a call to 'audit_syscall_exit'
from the vm86 code.
Besides fixing the above error messages the patch also now allows vm86
system calls to become auditable. This is useful since strace does not
appear to properly record the return values from sys_vm86.
I think this patch is also a step in the right direction in terms of
cleaning up some core auditing code. If we can correct any other paths
that do not properly call the audit exit and entries points, then we can
also eliminate the notion of context chaining.
I've tested this patch by verifying that the log messages no longer
appear, and that the audit records for sys_vm86 appear to be correct.
Also, 'read_edid' produces itentical output.
thanks,
-Jason
Signed-off-by: Jason Baron <jbaron(a)redhat.com>
--- linux-2.6/kernel/auditsc.c.bak
+++ linux-2.6/kernel/auditsc.c
@@ -981,11 +981,6 @@ void audit_syscall_entry(struct task_str
if (context && context->in_syscall) {
struct audit_context *newctx;
-#if defined(__NR_vm86) && defined(__NR_vm86old)
- /* vm86 mode should only be entered once */
- if (major == __NR_vm86 || major == __NR_vm86old)
- return;
-#endif
#if AUDIT_DEBUG
printk(KERN_ERR
"audit(:%d) pid=%d in syscall=%d;"
--- linux-2.6/arch/i386/kernel/vm86.c.bak 2006-01-31 12:19:56.000000000 -0500
+++ linux-2.6/arch/i386/kernel/vm86.c 2006-01-31 12:24:52.000000000 -0500
@@ -42,6 +42,7 @@
#include <linux/smp_lock.h>
#include <linux/highmem.h>
#include <linux/ptrace.h>
+#include <linux/audit.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -251,6 +252,7 @@ out:
static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk)
{
struct tss_struct *tss;
+ long eax;
/*
* make sure the vm86() system call doesn't try to do anything silly
*/
@@ -304,13 +306,19 @@ static void do_sys_vm86(struct kernel_vm
tsk->thread.screen_bitmap = info->screen_bitmap;
if (info->flags & VM86_SCREEN_BITMAP)
mark_screen_rdonly(tsk->mm);
+ __asm__ __volatile__("xorl %eax,%eax; movl %eax,%fs; movl %eax,%gs\n\t");
+ __asm__ __volatile__("movl %%eax, %0\n" :"=r"(eax));
+
+ /*call audit_syscall_exit since we do not exit via the normal paths */
+ if (unlikely(current->audit_context))
+ audit_syscall_exit(current, AUDITSC_RESULT(eax), eax);
+
__asm__ __volatile__(
- "xorl %%eax,%%eax; movl %%eax,%%fs; movl %%eax,%%gs\n\t"
"movl %0,%%esp\n\t"
"movl %1,%%ebp\n\t"
"jmp resume_userspace"
: /* no outputs */
- :"r" (&info->regs), "r" (tsk->thread_info) : "ax");
+ :"r" (&info->regs), "r" (tsk->thread_info));
/* we never return here */
}
18 years, 11 months
Best method for obtaining the 'sid' of a task?
by Timothy R. Chavez
Hello,
The audit subsystem would like to collect and record security label
information on a user process emitting audit messages. Due to the
asynchronous nature of netlink, the kernel cannot rely on the pid sent
in the kernel-bound netlink packet because the pid may have already been
recycled and the information recorded to the audit log, incorrect.
Furthermore, we're not permitted to package the security label with the
kernel-bound message itself due to the potential of spoofing. Thus, the
solution seems to be similar to that of login uid, where we package the
sid with the kernel-bound netlink packet at time of delivery when we
know we have the right process (because we are running as that process).
This guarantees that the sid cannot be spoofed and that we're in fact
sending the correct sid. Once the kernel receives this packet, it can
then resolve the sid to the correct security label. One of the pitfalls
of this approach may be that the sid disappears because policy is
reloaded while the packet is in transit. Is this correct? I think, in
terms of an IT security evaluation, we can make the assumption that this
won't be done. Aside from this concern, the question I have is this:
"What is the best way to do this?"
Because I am not exposed to: task_security_struct in net/af_netlink.c, I
cannot simply do a:
if (current->security)
NETLINK_CB(skb).selinux_sid = current->security->sid;
So I did a little digging and I thought perhaps the security hook,
selinux_getprocattr(), could be modified such that I can pass into it
&NETLINK_CB(skb).selinux_sid and obtain the 'sid' in addition to the
context since we're already obtaining the sid there. The disadvantage I
see here, is that it changes the interface. I'm not sure how sensitive
people are to this. Are there any alternative (possibly better)
suggestions?
Thanks.
-tim
18 years, 11 months
audit-1.1.3 and SuSE 10.0 (with FC4 kernel)
by Robert Giles
Hi folks - I'm trying to get the audit tools running on SuSE 10.0...
From the list traffic, it seems that only RHEL4 and FC4 kernels have the
latest patches applied to support the latest auditd, so I retrieved
and built kernel-2.6.14-1.1656_FC4.src.rpm for my system, but I'm still
getting the same "Invalid argument" when I try to do 'auditctl -w file':
(same error message I get with the stock SuSE 10.0 kernel and the SuSE
10.0 pre-packaged audit-1.0.3-2 tools/libraries)
---
linux:/home/rgiles # auditctl -s
AUDIT_STATUS: enabled=1 flag=1 pid=6342 rate_limit=0 backlog_limit=64 lost=0 backlog=0
linux:/home/rgiles # auditctl -w /etc/shadow
Error sending watch insert request (Invalid argument)
---
On startup, I see this from the kernel:
---
audit: initializing netlink socket (disabled)
audit(1138207304.552:1): initialized
---
/var/log/audit/audit.log reads:
---
type=DAEMON_START msg=audit(1138229931.984:4606) auditd start, ver=1.1.3, format=raw, auid=4294967295 res=success, auditd pid=6370
type=CONFIG_CHANGE msg=audit(1138229931.985:5): audit_enabled=1 old=1 by auid=4294967295
---
Any pointers would be greatly appreciated (and I apologize for bothering
y'all with usability questions on what appears to be a kernel devel
list... comp.os.linux.suse is full of LAuS questions, but nothing
pertaining to the built-in kernel auditing that y'all are working on).
-----------------------------------------------------------
Robert Giles Group System Administrator
SPD/ARL:UT (512) 835-3077 � Fax (512) 490-4244
18 years, 11 months
[RFC][PATCH] Audit inotify client
by Amy Griffis
This patch allows audit to operate as an inotify client.
It adds a list of parents, which represent the dentry parents of the
filesystem locations to be watched. When created, a parent registers
an inotify watch on itself. If all the audit rules corresponding to a
parent are removed by the admin, the parent removes its inotify watch
before it is destroyed.
As you will see in audit's inotify event callback
audit_handle_fs_event(), I have not completed the code for updating
the audit rules in the exit filter list based on the information
received from the callback. I am still thinking through some aspects
of the locking model, so I decided to leave the code as printks to
illustrate what should happen. I've played around with some various
filesystem operations, and I believe the printks indicate that audit
is getting the information it needs from inotify in order to make the
right changes to the audit rules.
Again, comments would be appreciated.
diff --git a/kernel/audit.c b/kernel/audit.c
index bdda766..5b1539d 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -55,6 +55,9 @@
#include <net/netlink.h>
#include <linux/skbuff.h>
#include <linux/netlink.h>
+#include <linux/inotify.h>
+
+#include "audit.h"
/* No auditing will take place until audit_initialized != 0.
* (Initialization happens after skb_init is called.) */
@@ -99,6 +102,9 @@ static atomic_t audit_lost = ATOMIC_I
/* The netlink socket. */
static struct sock *audit_sock;
+/* Inotify device. */
+struct inotify_device *audit_idev;
+
/* The audit_freelist is a list of pre-allocated audit buffers (if more
* than AUDIT_MAXFREE are in use, the audit buffer is freed instead of
* being placed on the freelist). */
@@ -564,6 +570,11 @@ static int __init audit_init(void)
audit_initialized = 1;
audit_enabled = audit_default;
audit_log(NULL, GFP_KERNEL, AUDIT_KERNEL, "initialized");
+
+ audit_idev = inotify_init(audit_handle_fs_event);
+ if (IS_ERR(audit_idev))
+ audit_panic("cannot initialize inotify device");
+
return 0;
}
__initcall(audit_init);
diff --git a/kernel/audit.h b/kernel/audit.h
index 5033e1f..26f08d5 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -22,6 +22,8 @@
#include <linux/fs.h>
#include <linux/audit.h>
+struct inotify_event;
+
/* 0 = no checking
1 = put_count checking
2 = verbose put_count checking
@@ -52,10 +54,19 @@ enum audit_state {
};
/* Rule lists */
+struct audit_parent {
+ unsigned long ino; /* associated inode number */
+ u32 wd; /* inotify watch descriptor */
+ struct list_head mlist; /* entry in master_parents */
+ struct list_head watches; /* associated watches */
+};
+
struct audit_watch {
char *path; /* watch insertion path */
struct list_head mlist; /* entry in master_watchlist */
struct list_head rules; /* associated rules */
+ struct list_head wlist; /* entry in audit_parent.watches list*/
+ struct audit_parent *parent; /* associated parent */
};
struct audit_field {
@@ -86,7 +97,9 @@ struct audit_entry {
extern int audit_pid;
extern int audit_comparator(const u32 left, const u32 op, const u32 right);
-
+extern void audit_handle_fs_event(struct inotify_event *event,
+ const char *name, struct inode * inode,
+ void *ptr);
extern void audit_send_reply(int pid, int seq, int type,
int done, int multi,
void *payload, int size);
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 6506084..f2d60a8 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -25,6 +25,7 @@
#include <linux/fs.h>
#include <linux/namei.h>
#include <linux/netlink.h>
+#include <linux/inotify.h>
#include "audit.h"
/* There are three lists of rules -- one to search at task creation
@@ -43,6 +44,13 @@ struct list_head audit_filter_list[AUDIT
};
static LIST_HEAD(master_watchlist);
+static LIST_HEAD(master_parents);
+
+/* Inotify device. */
+extern struct inotify_device *audit_idev;
+
+/* Inotify events we care about. */
+#define AUDIT_FSEVENTS IN_MOVE|IN_CREATE|IN_DELETE|IN_DELETE_SELF|IN_MOVE_SELF
/* Unpack a filter field's string representation from user-space
* buffer. */
@@ -75,7 +83,6 @@ static char *audit_unpack_string(void **
static int audit_to_watch(char *path, struct audit_krule *krule, int fidx)
{
struct audit_field *f = &krule->fields[fidx];
- struct nameidata nd;
struct audit_watch *watch;
if (path[0] != '/' || path[f->val-1] == '/' ||
@@ -83,17 +90,12 @@ static int audit_to_watch(char *path, st
f->op & ~AUDIT_EQUAL)
return -EINVAL;
- if (path_lookup(path, 0, &nd) == 0)
- f->val = nd.dentry->d_inode->i_ino;
- else
- f->val = (unsigned int)-1;
- path_release(&nd);
-
watch = kmalloc(sizeof(*watch), GFP_KERNEL);
if (unlikely(!watch))
return -ENOMEM;
watch->path = path;
krule->watch = watch;
+ f->val = (unsigned int)-1;
return 0;
}
@@ -368,11 +370,94 @@ static inline void audit_free_rule(struc
kfree(e);
}
+static void audit_update_field(struct audit_krule *krule, u32 type, u32 val)
+{
+ int i;
+
+ for (i = 0; i < AUDIT_MAX_FIELDS; i++)
+ if (krule->fields[i].type == type) {
+ krule->fields[i].val = val;
+ return;
+ }
+}
+
+void audit_handle_fs_event(struct inotify_event *event, const char *name,
+ struct inode *inode, void *ptr)
+{
+ struct audit_parent *parent = (struct audit_parent *)ptr;
+
+ if (event->mask & (IN_CREATE)) {
+ printk(KERN_ERR "%s:%d: check inode %lu for watch %s\n",
+ __FILE__, __LINE__, parent->ino, name);
+ printk(KERN_ERR "%s:%d: if found update rules with inode %lu\n",
+ __FILE__, __LINE__, inode->i_ino);
+ } else if (event->mask & (IN_DELETE)) {
+ printk(KERN_ERR "%s:%d: check inode %lu for watch %s\n",
+ __FILE__, __LINE__, parent->ino, name);
+ printk(KERN_ERR "%s:%d: if found update rules with inode -1\n",
+ __FILE__, __LINE__);
+ } else if (event->mask & (IN_MOVED_TO) && inode) {
+ printk(KERN_ERR "%s:%d: check inode %lu for watch %s\n",
+ __FILE__, __LINE__, parent->ino, name);
+ printk(KERN_ERR "%s:%d: if found update rules with inode %lu\n",
+ __FILE__, __LINE__, inode->i_ino);
+ } else if (event->mask & (IN_MOVED_FROM)) {
+ printk(KERN_ERR "%s:%d: check inode %lu for watch %s\n",
+ __FILE__, __LINE__, parent->ino, name);
+ printk(KERN_ERR "%s:%d: if found update rules with inode -1\n",
+ __FILE__, __LINE__);
+ } else if (event->mask & (IN_DELETE_SELF|IN_MOVE_SELF))
+ printk(KERN_ERR
+ "%s:%d: remove all rules w/watches under inode %lu\n",
+ __FILE__, __LINE__, parent->ino);
+}
+
+/* Create a parent entry for this watch, using an existing parent when
+ * possible. */
+static inline int audit_add_parent(struct audit_watch *watch,
+ struct inode *inode)
+{
+ struct audit_parent *p, *parent;
+ int ret = 0;
+
+ list_for_each_entry(p, &master_parents, mlist) {
+ if (p->ino != inode->i_ino)
+ continue;
+
+ list_add(&watch->wlist, &p->watches);
+ watch->parent = p;
+ goto out;
+ }
+
+ parent = kmalloc(sizeof(*parent), GFP_KERNEL);
+ if (unlikely(!parent)) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ INIT_LIST_HEAD(&parent->watches);
+ parent->wd = inotify_add_watch(audit_idev, inode, AUDIT_FSEVENTS,
+ parent);
+ if (parent->wd < 0) {
+ kfree(parent);
+ ret = parent->wd;
+ goto out;
+ }
+ parent->ino = inode->i_ino;
+ list_add(&watch->wlist, &parent->watches);
+ list_add(&parent->mlist, &master_parents);
+ watch->parent = parent;
+
+out:
+ return ret;
+}
+
/* Attach krule's watch to master_watchlist, using existing watches
* when possible. */
-static inline void audit_add_watch(struct audit_krule *krule)
+static inline int audit_add_watch(struct audit_krule *krule)
{
struct audit_watch *w;
+ struct nameidata nd;
+ int ret = 0;
list_for_each_entry(w, &master_watchlist, mlist) {
if (audit_compare_watch(w, krule->watch))
@@ -381,11 +466,28 @@ static inline void audit_add_watch(struc
audit_free_watch(krule->watch);
krule->watch = w;
list_add(&krule->rlist, &w->rules);
- return;
+ goto inode_num;
}
+
+ ret = path_lookup(krule->watch->path, LOOKUP_PARENT, &nd);
+ if (ret)
+ goto out;
INIT_LIST_HEAD(&krule->watch->rules);
list_add(&krule->rlist, &krule->watch->rules);
list_add(&krule->watch->mlist, &master_watchlist);
+
+ ret = audit_add_parent(krule->watch, nd.dentry->d_inode);
+ if (ret)
+ goto out;
+ path_release(&nd);
+
+inode_num:
+ if (path_lookup(krule->watch->path, 0, &nd) == 0)
+ audit_update_field(krule, AUDIT_WATCH,
+ nd.dentry->d_inode->i_ino);
+out:
+ path_release(&nd);
+ return ret;
}
/* Add rule to given filterlist if not a duplicate. Protected by
@@ -394,6 +496,7 @@ static inline int audit_add_rule(struct
struct list_head *list)
{
struct audit_entry *e;
+ int err;
/* Do not use the _rcu iterator here, since this is the only
* addition routine. */
@@ -402,8 +505,11 @@ static inline int audit_add_rule(struct
return -EEXIST;
}
- if (entry->rule.watch)
- audit_add_watch(&entry->rule);
+ if (entry->rule.watch) {
+ err = audit_add_watch(&entry->rule);
+ if (err)
+ return err;
+ }
if (entry->rule.flags & AUDIT_FILTER_PREPEND) {
list_add_rcu(&entry->list, list);
} else {
@@ -413,6 +519,21 @@ static inline int audit_add_rule(struct
return 0;
}
+/* Detach parent from watch, freeing if it has no associated watches. */
+static inline void audit_detach_parent(struct audit_watch *watch)
+{
+ struct audit_parent *parent = watch->parent;
+
+ list_del(&watch->wlist);
+ watch->parent = NULL;
+
+ if (list_empty(&parent->watches)) {
+ list_del(&parent->mlist);
+ inotify_ignore(audit_idev, parent->wd);
+ kfree(parent);
+ }
+}
+
/* Detach watch from krule, freeing if it has no associated rules. */
static inline void audit_detach_watch(struct audit_krule *krule)
{
@@ -423,6 +544,7 @@ static inline void audit_detach_watch(st
if (list_empty(&watch->rules)) {
list_del(&watch->mlist);
+ audit_detach_parent(watch);
audit_free_watch(watch);
}
}
18 years, 11 months
[RFC][PATCH] Inotify kernel API
by Amy Griffis
This is the first of two patches, which when complete should be the
last patches for the baseline filesystem audit functionality.
This patch provides a kernel api for inotify. It was first posted as
an RFC last year:
https://www.redhat.com/archives/linux-audit/2005-August/msg00055.html
I have made some minor changes to address feedback I received and to
provide a little more information in the kernel's event callback. I
found that adding or removing inotify watches from an event callback
is unnecessary for audit's purposes, so I did not make that change.
I also received some feedback regarding making a cleaner separation
between the core inotify code and a kernel and userspace api. I
haven't addressed this yet as it would make for a much larger patch
against inotify, and I would like to discuss it with the inotify dev
before making a lot of changes.
I believe this patch represents the functionality audit requires in
terms of an inotify kernel api. Please have a look and let me know
what you think.
diff --git a/fs/inotify.c b/fs/inotify.c
index 2fecb7a..eec816e 100644
--- a/fs/inotify.c
+++ b/fs/inotify.c
@@ -84,14 +84,18 @@ struct inotify_device {
wait_queue_head_t wq; /* wait queue for i/o */
struct idr idr; /* idr mapping wd -> watch */
struct semaphore sem; /* protects this bad boy */
- struct list_head events; /* list of queued events */
struct list_head watches; /* list of watches */
atomic_t count; /* reference count */
+ u32 last_wd; /* the last wd allocated */
+ /* userland consumer API */
+ struct list_head events; /* list of queued events */
struct user_struct *user; /* user who opened this dev */
unsigned int queue_size; /* size of the queue (bytes) */
unsigned int event_count; /* number of pending events */
unsigned int max_events; /* maximum number of events */
- u32 last_wd; /* the last wd allocated */
+ /* kernel consumer API */
+ void (*callback)(struct inotify_event *, const char *, struct inode *,
+ void *); /* event callback */
};
/*
@@ -123,6 +127,7 @@ struct inotify_watch {
struct inode *inode; /* associated inode */
s32 wd; /* watch descriptor */
u32 mask; /* event mask for this watch */
+ void *callback_arg; /* callback argument - kernel API */
};
#ifdef CONFIG_SYSCTL
@@ -174,8 +179,10 @@ static inline void get_inotify_dev(struc
static inline void put_inotify_dev(struct inotify_device *dev)
{
if (atomic_dec_and_test(&dev->count)) {
- atomic_dec(&dev->user->inotify_devs);
- free_uid(dev->user);
+ if (dev->user) {
+ atomic_dec(&dev->user->inotify_devs);
+ free_uid(dev->user);
+ }
idr_destroy(&dev->idr);
kfree(dev);
}
@@ -343,6 +350,24 @@ static void inotify_dev_event_dequeue(st
}
/*
+ * inotify_callback_event - notify kernel consumers of events
+ */
+static void inotify_callback_event(struct inotify_device *dev,
+ struct inotify_watch *watch,
+ u32 mask, u32 cookie, const char *name,
+ struct inode *inode)
+{
+ struct inotify_event event;
+
+ event.wd = watch->wd;
+ event.mask = mask;
+ event.cookie = cookie;
+ event.len = 0; /* kernel consumers don't need length */
+
+ dev->callback(&event, name, inode, watch->callback_arg);
+}
+
+/*
* inotify_dev_get_wd - returns the next WD for use by the given dev
*
* Callers must hold dev->sem. This function can sleep.
@@ -386,12 +411,13 @@ static int find_inode(const char __user
* Both 'dev' and 'inode' (by way of nameidata) need to be pinned.
*/
static struct inotify_watch *create_watch(struct inotify_device *dev,
- u32 mask, struct inode *inode)
+ u32 mask, struct inode *inode,
+ void *callback_arg)
{
struct inotify_watch *watch;
int ret;
- if (atomic_read(&dev->user->inotify_watches) >=
+ if (dev->user && atomic_read(&dev->user->inotify_watches) >=
inotify_max_user_watches)
return ERR_PTR(-ENOSPC);
@@ -407,6 +433,7 @@ static struct inotify_watch *create_watc
dev->last_wd = watch->wd;
watch->mask = mask;
+ watch->callback_arg = callback_arg;
atomic_set(&watch->count, 0);
INIT_LIST_HEAD(&watch->d_list);
INIT_LIST_HEAD(&watch->i_list);
@@ -424,7 +451,8 @@ static struct inotify_watch *create_watc
/* bump our own count, corresponding to our entry in dev->watches */
get_inotify_watch(watch);
- atomic_inc(&dev->user->inotify_watches);
+ if (dev->user)
+ atomic_inc(&dev->user->inotify_watches);
atomic_inc(&inotify_watches);
return watch;
@@ -457,7 +485,8 @@ static void remove_watch_no_event(struct
list_del(&watch->i_list);
list_del(&watch->d_list);
- atomic_dec(&dev->user->inotify_watches);
+ if (dev->user)
+ atomic_dec(&dev->user->inotify_watches);
atomic_dec(&inotify_watches);
idr_remove(&dev->idr, watch->wd);
put_inotify_watch(watch);
@@ -476,7 +505,10 @@ static void remove_watch_no_event(struct
*/
static void remove_watch(struct inotify_watch *watch,struct inotify_device *dev)
{
- inotify_dev_queue_event(dev, watch, IN_IGNORED, 0, NULL);
+ if (dev->callback)
+ inotify_callback_event(dev, watch, IN_IGNORED, 0, NULL, NULL);
+ else
+ inotify_dev_queue_event(dev, watch, IN_IGNORED, 0, NULL);
remove_watch_no_event(watch, dev);
}
@@ -489,7 +521,190 @@ static inline int inotify_inode_watched(
return !list_empty(&inode->inotify_watches);
}
-/* Kernel API */
+/* Kernel consumer API */
+
+/**
+ * inotify_init - allocates and initializes an inotify device
+ * @callback: kernel consumer's event callback
+ */
+struct inotify_device *inotify_init(void (*callback)(struct inotify_event *,
+ const char *,
+ struct inode *, void *))
+{
+ struct inotify_device *dev;
+
+ dev = kmalloc(sizeof(struct inotify_device), GFP_KERNEL);
+ if (unlikely(!dev))
+ return NULL;
+
+ idr_init(&dev->idr);
+ INIT_LIST_HEAD(&dev->events);
+ INIT_LIST_HEAD(&dev->watches);
+ init_waitqueue_head(&dev->wq);
+ sema_init(&dev->sem, 1);
+ dev->event_count = 0;
+ dev->queue_size = 0;
+ dev->max_events = inotify_max_queued_events;
+ dev->user = NULL; /* set in sys_inotify_init */
+ dev->last_wd = 0;
+ dev->callback = callback;
+ atomic_set(&dev->count, 0);
+ get_inotify_dev(dev);
+
+ return dev;
+}
+EXPORT_SYMBOL_GPL(inotify_init);
+
+/**
+ * inotify_free - clean up and free an inotify device
+ * @dev: inotify device to free
+ */
+int inotify_free(struct inotify_device *dev)
+{
+ /*
+ * Destroy all of the watches on this device. Unfortunately, not very
+ * pretty. We cannot do a simple iteration over the list, because we
+ * do not know the inode until we iterate to the watch. But we need to
+ * hold inode->inotify_sem before dev->sem. The following works.
+ */
+ while (1) {
+ struct inotify_watch *watch;
+ struct list_head *watches;
+ struct inode *inode;
+
+ down(&dev->sem);
+ watches = &dev->watches;
+ if (list_empty(watches)) {
+ up(&dev->sem);
+ break;
+ }
+ watch = list_entry(watches->next, struct inotify_watch, d_list);
+ get_inotify_watch(watch);
+ up(&dev->sem);
+
+ inode = watch->inode;
+ down(&inode->inotify_sem);
+ down(&dev->sem);
+ remove_watch_no_event(watch, dev);
+ up(&dev->sem);
+ up(&inode->inotify_sem);
+ put_inotify_watch(watch);
+ }
+
+ /* destroy all of the events on this device */
+ down(&dev->sem);
+ while (!list_empty(&dev->events))
+ inotify_dev_event_dequeue(dev);
+ up(&dev->sem);
+
+ /* free this device: the put matching the get in inotify_init() */
+ put_inotify_dev(dev);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(inotify_free);
+
+/**
+ * inotify_inotify_add_watch - add a watch to this inotify device
+ * @dev: inotify device
+ * @inode: inode to watch for events
+ * @mask: filesystem event mask
+ * @callback_arg - ptr to data that kernel consumer associates with this watch
+ *
+ * Caller must pin the inode in question, e.g. by calling path_lookup.
+ */
+s32 inotify_add_watch(struct inotify_device *dev, struct inode *inode,
+ u32 mask, void *callback_arg)
+{
+ int mask_add = 0;
+ struct inotify_watch *watch, *old;
+ int ret;
+
+ down(&inode->inotify_sem);
+ down(&dev->sem);
+
+ if (mask & IN_MASK_ADD)
+ mask_add = 1;
+
+ /* don't let user-space set invalid bits: we don't want flags set */
+ mask &= IN_ALL_EVENTS;
+ if (unlikely(!mask)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ * Handle the case of re-adding a watch on an (inode,dev) pair that we
+ * are already watching. We just update the mask and callback_arg and
+ * return its wd.
+ */
+ old = inode_find_dev(inode, dev);
+ if (unlikely(old)) {
+ if (mask_add)
+ old->mask |= mask;
+ else
+ old->mask = mask;
+ old->callback_arg = callback_arg;
+ ret = old->wd;
+ goto out;
+ }
+
+ watch = create_watch(dev, mask, inode, callback_arg);
+ if (unlikely(IS_ERR(watch))) {
+ ret = PTR_ERR(watch);
+ goto out;
+ }
+
+ /* Add the watch to the device's and the inode's list */
+ list_add(&watch->d_list, &dev->watches);
+ list_add(&watch->i_list, &inode->inotify_watches);
+ ret = watch->wd;
+
+out:
+ up(&dev->sem);
+ up(&inode->inotify_sem);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(inotify_add_watch);
+
+/**
+ * inotify_ignore - remove a given wd from this inotify device
+ * @dev: inotify device
+ * @wd: watch descriptor to remove
+ */
+int inotify_ignore(struct inotify_device *dev, s32 wd)
+{
+ struct inotify_watch *watch;
+ struct inode *inode;
+
+ down(&dev->sem);
+ watch = idr_find(&dev->idr, wd);
+ if (unlikely(!watch)) {
+ up(&dev->sem);
+ return -EINVAL;
+ }
+ get_inotify_watch(watch);
+ inode = watch->inode;
+ up(&dev->sem);
+
+ down(&inode->inotify_sem);
+ down(&dev->sem);
+
+ /* make sure that we did not race */
+ watch = idr_find(&dev->idr, wd);
+ if (likely(watch))
+ remove_watch(watch, dev);
+
+ up(&dev->sem);
+ up(&inode->inotify_sem);
+ put_inotify_watch(watch);
+
+ return 0;
+
+}
+EXPORT_SYMBOL_GPL(inotify_ignore);
+
+/* Kernel producer API */
/**
* inotify_inode_queue_event - queue an event to all watches on this inode
@@ -497,9 +712,10 @@ static inline int inotify_inode_watched(
* @mask: event mask describing this event
* @cookie: cookie for synchronization, or zero
* @name: filename, if any
+ * @cinode: child inode, used for events on directories
*/
void inotify_inode_queue_event(struct inode *inode, u32 mask, u32 cookie,
- const char *name)
+ const char *name, struct inode *cinode)
{
struct inotify_watch *watch, *next;
@@ -513,7 +729,12 @@ void inotify_inode_queue_event(struct in
struct inotify_device *dev = watch->dev;
get_inotify_watch(watch);
down(&dev->sem);
- inotify_dev_queue_event(dev, watch, mask, cookie, name);
+ if (dev->callback)
+ inotify_callback_event(dev, watch, mask,
+ cookie, name, cinode);
+ else
+ inotify_dev_queue_event(dev, watch, mask,
+ cookie, name);
if (watch_mask & IN_ONESHOT)
remove_watch_no_event(watch, dev);
up(&dev->sem);
@@ -547,7 +768,8 @@ void inotify_dentry_parent_queue_event(s
if (inotify_inode_watched(inode)) {
dget(parent);
spin_unlock(&dentry->d_lock);
- inotify_inode_queue_event(inode, mask, cookie, name);
+ inotify_inode_queue_event(inode, mask, cookie, name,
+ dentry->d_inode);
dput(parent);
} else
spin_unlock(&dentry->d_lock);
@@ -630,7 +852,12 @@ void inotify_unmount_inodes(struct list_
list_for_each_entry_safe(watch, next_w, watches, i_list) {
struct inotify_device *dev = watch->dev;
down(&dev->sem);
- inotify_dev_queue_event(dev, watch, IN_UNMOUNT,0,NULL);
+ if (dev->callback)
+ inotify_callback_event(dev, watch, IN_UNMOUNT,
+ 0, NULL, NULL);
+ else
+ inotify_dev_queue_event(dev, watch, IN_UNMOUNT,
+ 0, NULL);
remove_watch(watch, dev);
up(&dev->sem);
}
@@ -756,83 +983,7 @@ static ssize_t inotify_read(struct file
static int inotify_release(struct inode *ignored, struct file *file)
{
- struct inotify_device *dev = file->private_data;
-
- /*
- * Destroy all of the watches on this device. Unfortunately, not very
- * pretty. We cannot do a simple iteration over the list, because we
- * do not know the inode until we iterate to the watch. But we need to
- * hold inode->inotify_sem before dev->sem. The following works.
- */
- while (1) {
- struct inotify_watch *watch;
- struct list_head *watches;
- struct inode *inode;
-
- down(&dev->sem);
- watches = &dev->watches;
- if (list_empty(watches)) {
- up(&dev->sem);
- break;
- }
- watch = list_entry(watches->next, struct inotify_watch, d_list);
- get_inotify_watch(watch);
- up(&dev->sem);
-
- inode = watch->inode;
- down(&inode->inotify_sem);
- down(&dev->sem);
- remove_watch_no_event(watch, dev);
- up(&dev->sem);
- up(&inode->inotify_sem);
- put_inotify_watch(watch);
- }
-
- /* destroy all of the events on this device */
- down(&dev->sem);
- while (!list_empty(&dev->events))
- inotify_dev_event_dequeue(dev);
- up(&dev->sem);
-
- /* free this device: the put matching the get in inotify_init() */
- put_inotify_dev(dev);
-
- return 0;
-}
-
-/*
- * inotify_ignore - remove a given wd from this inotify instance.
- *
- * Can sleep.
- */
-static int inotify_ignore(struct inotify_device *dev, s32 wd)
-{
- struct inotify_watch *watch;
- struct inode *inode;
-
- down(&dev->sem);
- watch = idr_find(&dev->idr, wd);
- if (unlikely(!watch)) {
- up(&dev->sem);
- return -EINVAL;
- }
- get_inotify_watch(watch);
- inode = watch->inode;
- up(&dev->sem);
-
- down(&inode->inotify_sem);
- down(&dev->sem);
-
- /* make sure that we did not race */
- watch = idr_find(&dev->idr, wd);
- if (likely(watch))
- remove_watch(watch, dev);
-
- up(&dev->sem);
- up(&inode->inotify_sem);
- put_inotify_watch(watch);
-
- return 0;
+ return inotify_free(file->private_data);
}
static long inotify_ioctl(struct file *file, unsigned int cmd,
@@ -886,12 +1037,15 @@ asmlinkage long sys_inotify_init(void)
goto out_free_uid;
}
- dev = kmalloc(sizeof(struct inotify_device), GFP_KERNEL);
+ dev = inotify_init(NULL);
if (unlikely(!dev)) {
ret = -ENOMEM;
goto out_free_uid;
}
+ dev->user = user;
+ atomic_inc(&user->inotify_devs);
+
filp->f_op = &inotify_fops;
filp->f_vfsmnt = mntget(inotify_mnt);
filp->f_dentry = dget(inotify_mnt->mnt_root);
@@ -900,20 +1054,6 @@ asmlinkage long sys_inotify_init(void)
filp->f_flags = O_RDONLY;
filp->private_data = dev;
- idr_init(&dev->idr);
- INIT_LIST_HEAD(&dev->events);
- INIT_LIST_HEAD(&dev->watches);
- init_waitqueue_head(&dev->wq);
- sema_init(&dev->sem, 1);
- dev->event_count = 0;
- dev->queue_size = 0;
- dev->max_events = inotify_max_queued_events;
- dev->user = user;
- dev->last_wd = 0;
- atomic_set(&dev->count, 0);
-
- get_inotify_dev(dev);
- atomic_inc(&user->inotify_devs);
fd_install(fd, filp);
return fd;
@@ -927,13 +1067,11 @@ out_put_fd:
asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask)
{
- struct inotify_watch *watch, *old;
struct inode *inode;
struct inotify_device *dev;
struct nameidata nd;
struct file *filp;
int ret, fput_needed;
- int mask_add = 0;
unsigned flags = 0;
filp = fget_light(fd, &fput_needed);
@@ -959,46 +1097,7 @@ asmlinkage long sys_inotify_add_watch(in
inode = nd.dentry->d_inode;
dev = filp->private_data;
- down(&inode->inotify_sem);
- down(&dev->sem);
-
- if (mask & IN_MASK_ADD)
- mask_add = 1;
-
- /* don't let user-space set invalid bits: we don't want flags set */
- mask &= IN_ALL_EVENTS;
- if (unlikely(!mask)) {
- ret = -EINVAL;
- goto out;
- }
-
- /*
- * Handle the case of re-adding a watch on an (inode,dev) pair that we
- * are already watching. We just update the mask and return its wd.
- */
- old = inode_find_dev(inode, dev);
- if (unlikely(old)) {
- if (mask_add)
- old->mask |= mask;
- else
- old->mask = mask;
- ret = old->wd;
- goto out;
- }
-
- watch = create_watch(dev, mask, inode);
- if (unlikely(IS_ERR(watch))) {
- ret = PTR_ERR(watch);
- goto out;
- }
-
- /* Add the watch to the device's and the inode's list */
- list_add(&watch->d_list, &dev->watches);
- list_add(&watch->i_list, &inode->inotify_watches);
- ret = watch->wd;
-out:
- up(&dev->sem);
- up(&inode->inotify_sem);
+ ret = inotify_add_watch(dev, inode, mask, NULL);
path_release(&nd);
fput_and_out:
fput_light(filp, fput_needed);
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h
index 94919c3..606b875 100644
--- a/include/linux/fsnotify.h
+++ b/include/linux/fsnotify.h
@@ -35,16 +35,18 @@ static inline void fsnotify_move(struct
if (isdir)
isdir = IN_ISDIR;
- inotify_inode_queue_event(old_dir, IN_MOVED_FROM|isdir,cookie,old_name);
- inotify_inode_queue_event(new_dir, IN_MOVED_TO|isdir, cookie, new_name);
+ inotify_inode_queue_event(old_dir, IN_MOVED_FROM|isdir, cookie,
+ old_name, NULL);
+ inotify_inode_queue_event(new_dir, IN_MOVED_TO|isdir, cookie,
+ new_name, source);
if (target) {
- inotify_inode_queue_event(target, IN_DELETE_SELF, 0, NULL);
+ inotify_inode_queue_event(target, IN_DELETE_SELF, 0, NULL,NULL);
inotify_inode_is_dead(target);
}
if (source) {
- inotify_inode_queue_event(source, IN_MOVE_SELF, 0, NULL);
+ inotify_inode_queue_event(source, IN_MOVE_SELF, 0, NULL, NULL);
}
audit_inode_child(old_name, source, old_dir->i_ino);
audit_inode_child(new_name, target, new_dir->i_ino);
@@ -66,7 +68,7 @@ static inline void fsnotify_nameremove(s
*/
static inline void fsnotify_inoderemove(struct inode *inode)
{
- inotify_inode_queue_event(inode, IN_DELETE_SELF, 0, NULL);
+ inotify_inode_queue_event(inode, IN_DELETE_SELF, 0, NULL, NULL);
inotify_inode_is_dead(inode);
}
@@ -76,7 +78,8 @@ static inline void fsnotify_inoderemove(
static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
{
inode_dir_notify(inode, DN_CREATE);
- inotify_inode_queue_event(inode, IN_CREATE, 0, dentry->d_name.name);
+ inotify_inode_queue_event(inode, IN_CREATE, 0, dentry->d_name.name,
+ dentry->d_inode);
audit_inode_child(dentry->d_name.name, dentry->d_inode, inode->i_ino);
}
@@ -87,7 +90,7 @@ static inline void fsnotify_mkdir(struct
{
inode_dir_notify(inode, DN_CREATE);
inotify_inode_queue_event(inode, IN_CREATE | IN_ISDIR, 0,
- dentry->d_name.name);
+ dentry->d_name.name, dentry->d_inode);
audit_inode_child(dentry->d_name.name, dentry->d_inode, inode->i_ino);
}
@@ -104,7 +107,7 @@ static inline void fsnotify_access(struc
dnotify_parent(dentry, DN_ACCESS);
inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
- inotify_inode_queue_event(inode, mask, 0, NULL);
+ inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
}
/*
@@ -120,7 +123,7 @@ static inline void fsnotify_modify(struc
dnotify_parent(dentry, DN_MODIFY);
inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
- inotify_inode_queue_event(inode, mask, 0, NULL);
+ inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
}
/*
@@ -135,7 +138,7 @@ static inline void fsnotify_open(struct
mask |= IN_ISDIR;
inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
- inotify_inode_queue_event(inode, mask, 0, NULL);
+ inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
}
/*
@@ -153,7 +156,7 @@ static inline void fsnotify_close(struct
mask |= IN_ISDIR;
inotify_dentry_parent_queue_event(dentry, mask, 0, name);
- inotify_inode_queue_event(inode, mask, 0, NULL);
+ inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
}
/*
@@ -168,7 +171,7 @@ static inline void fsnotify_xattr(struct
mask |= IN_ISDIR;
inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
- inotify_inode_queue_event(inode, mask, 0, NULL);
+ inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
}
/*
@@ -215,7 +218,7 @@ static inline void fsnotify_change(struc
if (in_mask) {
if (S_ISDIR(inode->i_mode))
in_mask |= IN_ISDIR;
- inotify_inode_queue_event(inode, in_mask, 0, NULL);
+ inotify_inode_queue_event(inode, in_mask, 0, NULL, NULL);
inotify_dentry_parent_queue_event(dentry, in_mask, 0,
dentry->d_name.name);
}
diff --git a/include/linux/inotify.h b/include/linux/inotify.h
index 267c88b..2a8d1bd 100644
--- a/include/linux/inotify.h
+++ b/include/linux/inotify.h
@@ -14,6 +14,9 @@
*
* When you are watching a directory, you will receive the filename for events
* such as IN_CREATE, IN_DELETE, IN_OPEN, IN_CLOSE, ..., relative to the wd.
+ *
+ * When using inotify from the kernel, len will always be zero. Instead you
+ * should check the path for non-NULL in your callback.
*/
struct inotify_event {
__s32 wd; /* watch descriptor */
@@ -71,8 +74,19 @@ struct inotify_event {
#ifdef CONFIG_INOTIFY
+/* Kernel consumer API */
+
+extern struct inotify_device *inotify_init(void (*)(struct inotify_event *,
+ const char *,
+ struct inode *, void *));
+extern int inotify_free(struct inotify_device *);
+extern __s32 inotify_add_watch(struct inotify_device *, struct inode *, __u32,
+ void *);
+extern int inotify_ignore(struct inotify_device *, __s32);
+
+/* Kernel producer API */
extern void inotify_inode_queue_event(struct inode *, __u32, __u32,
- const char *);
+ const char *, struct inode *);
extern void inotify_dentry_parent_queue_event(struct dentry *, __u32, __u32,
const char *);
extern void inotify_unmount_inodes(struct list_head *);
@@ -81,6 +95,7 @@ extern u32 inotify_get_cookie(void);
#else
+/* Kernel producer API stubs */
static inline void inotify_inode_queue_event(struct inode *inode,
__u32 mask, __u32 cookie,
const char *filename)
18 years, 11 months
[ANN] Linux Event Dispatcher
by Junji Kanemaru
Hi,
I'm pleased to introduce Linux Event Dispatcher version 1.0 beta is
now ready for download.
I thought some people on this list might be interested in this so I'm
posting this. It would be multi-posting. It so, I'm very sorry for bandwidth.
Led is realtime event filtering framework for Linux system that handles any
system events on the fly.
You can register actions to particular events such as access violation and
login failures at realtime with led. The events can be fed from, via syslogd.
auditd, ulogd of netfilter and any other sources too.
This is preliminary release to have people review. The base framework is
pretty much done but plugins. I'd need some help from people out there
to write more plugins.
Any comments and requests are welcome :)
You can download led from: http://www.linuon.com/
[Brief Introduction]
First of all Linux Event Dispatcher, or led for short, is NOT a replacement
for other traditional logging and filtering system. Instead led gets fed events
from them.
The main goal of led is to handle system events realtime and do action for
the events on the fly.
For example you can have filters for critical events from kernel audit system
and setup detailed actions for each event such as avc violation and
unexpected write operation on /var/www/html/index.hml.
You may pick action for each event either shutdown system immediately or
block http port temporarily and recover whole web contents etc. And same
time you can check who did it and ban him/her from host if he/she is on
localhost and report it to you right away...
You would be able to do such things with led.
Normally most of administrators won't realize attack until they get some
error or look into logwatch report email carefully. It might be too late.
You could have restricted setting to take the risk minimum but you can't block
port entirely. As long as you are opening ports to public there's risk so how
fast you can notice error and recover from compromise is the key...
For more info please go to http://www.linuon.com/
Thanks,
-- Junji Kanemaru
Linuon Inc.
Tokyo Japan
18 years, 11 months
bug?: audit filtering on negative values
by Michael C Thompson
Hey all,
I'm not sure if anyone else has seen this, or if its been brought up before
(though I think
not), but I've discovered a problem with trying to have audit filter on
fields with negative
values. I suspect this is due to a difference in kernel space and user
space, given the
results I've seen below, but here are the particulars:
On zSeries and on xSeries, we have noticed that we are incapable (in some
situations) of
filtering messages when the filter value is negative. On zSeries, this
seems to be true for all
fields, while on xSeries, its true if the field is a1,a2,a3.
We have explicity tested -9 and -1, but I believe this code will extend to
all manner of
negative values because seems to be related to the representation of these
values in
the different architectures (32 v 64). I have not tested it on a 32-bit
only platform, if someone
has the ability to that (should take all of 3minutes) that would probably
be useful :)
Below is all of my test information.
Thanks,
Mike
Here are the records we not are seeing (you can trap them without an
special filters):
zSeries:
type=SYSCALL msg=audit(1137516317.334:8619): arch=80000016 syscall=180
success=no exit=-22 a0=ffffffffffffffff a1=ffffffffffffffff
a2=ffffffffffffffff a3=ffffffffffffffff items=0 pid=17427 auid=500 uid=0
gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 comm="pread_attempt"
exe="/rhcc/lspp/tests/LTP/ltp-merged/testcases/audit/filters/pread_attempt"
xSeries:
type=SYSCALL msg=audit(1137489462.885:205387): arch=c000003e syscall=17
success=no exit=-22 a0=ffffffff a1=ffffffffffffffff a2=ffffffffffffffff
a3=ffffffffffffffff items=0 pid=8121 auid=500 uid=0 gid=0 euid=0 suid=0
fsuid=0 egid=0 sgid=0 fsgid=0 comm="a.out"
exe="/tests/LTP/ltp-merged/testcases/audit/syscalls/a.out"
Here are the auditctl commands we are using:
auditctl -a exit,always -S pread -- works always
auditctl -a exit,always -S pread -F a0=-1 -- works only on xSeries, no
message on zSeries
auditctl -a exit,always -S pread -F a1->a3=-1 -- no record on either
auditctl -a exit,always -S pread -F exit=-22 -- no record on zSeries or
xSeries
Here is the code we are running:
#define _XOPEN_SOURCE 500
#include <fcntl.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int fd;
ssize_t read;
size_t size = 5;
char buff[size+1];
off_t offset = 1;
memset(buff,0,size+1);
fd = open("test_file",O_RDONLY);
read = pread(-1, -1, -1, -1);
printf("read: %d from fd: %d\n",read,fd);
printf("Contents: %s\n",buff);
close(fd);
}
18 years, 11 months
Re: devmajor & devminor
by Michael C Thompson
Michael C Thompson/Austin/IBM wrote on 01/18/2006 09:45:17 AM:
> Hey all,
>
> I was looking through the auditctl
Applogies, I sent that note a tad prematurely.
As I was saying, I was looking through the auditctl v1.0.3 man pages, and I
had some questions on some fields auditctl accepts.
What the devmajor and devminor fields actually entail. My guess is hda/hda1
but I am not sure.
Also does the OS personality number (pers) entails?
Thanks,
Mike
18 years, 11 months