[PATCH 1/2] filesystem auditing: augment audit_inode
by Amy Griffis
Modify the arguments to fsnotify_create and fsnotify_mkdir so they
can be used by audit.
diff --git a/fs/namei.c b/fs/namei.c
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1317,7 +1317,7 @@ int vfs_create(struct inode *dir, struct
DQUOT_INIT(dir);
error = dir->i_op->create(dir, dentry, mode, nd);
if (!error)
- fsnotify_create(dir, dentry->d_name.name);
+ fsnotify_create(dir, dentry);
return error;
}
@@ -1634,7 +1634,7 @@ int vfs_mknod(struct inode *dir, struct
DQUOT_INIT(dir);
error = dir->i_op->mknod(dir, dentry, mode, dev);
if (!error)
- fsnotify_create(dir, dentry->d_name.name);
+ fsnotify_create(dir, dentry);
return error;
}
@@ -1705,7 +1705,7 @@ int vfs_mkdir(struct inode *dir, struct
DQUOT_INIT(dir);
error = dir->i_op->mkdir(dir, dentry, mode);
if (!error)
- fsnotify_mkdir(dir, dentry->d_name.name);
+ fsnotify_mkdir(dir, dentry);
return error;
}
@@ -1942,7 +1942,7 @@ int vfs_symlink(struct inode *dir, struc
DQUOT_INIT(dir);
error = dir->i_op->symlink(dir, dentry, oldname);
if (!error)
- fsnotify_create(dir, dentry->d_name.name);
+ fsnotify_create(dir, dentry);
return error;
}
@@ -2013,7 +2013,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)
- fsnotify_create(dir, new_dentry->d_name.name);
+ fsnotify_create(dir, new_dentry);
return error;
}
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h
--- a/include/linux/fsnotify.h
+++ b/include/linux/fsnotify.h
@@ -70,19 +70,20 @@ static inline void fsnotify_inoderemove(
/*
* fsnotify_create - 'name' was linked in
*/
-static inline void fsnotify_create(struct inode *inode, const char *name)
+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, name);
+ inotify_inode_queue_event(inode, IN_CREATE, 0, dentry->d_name.name);
}
/*
* fsnotify_mkdir - directory 'name' was created
*/
-static inline void fsnotify_mkdir(struct inode *inode, const char *name)
+static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
{
inode_dir_notify(inode, DN_CREATE);
- inotify_inode_queue_event(inode, IN_CREATE | IN_ISDIR, 0, name);
+ inotify_inode_queue_event(inode, IN_CREATE | IN_ISDIR, 0,
+ dentry->d_name.name);
}
/*
19 years
[PATCH 0/2] filesystem auditing: augment audit_inode
by Amy Griffis
Hello,
The following two patches augment the collection of inode info during
syscall processing. They represent part of the functionality that was
provided by the auditfs patch included in RHEL4.
Specifically, they:
- Collect information for target inodes created or removed during
syscalls. Previous code only collects information for the target
inode's parent.
- Add the audit_inode() hook to syscalls that operate on a file
descriptor (e.g. fchown), enabling audit to do inode filtering for
these calls.
- Modify filtering code to check audit context for either an inode #
or a parent inode # matching a given rule.
- Modify logging to provide inode # for both parent and child.
- Protect debug info from NULL audit_names.name.
Please let me know if you have any comments. I'll note a concern of
my own in a following email.
I've done a fair amount of testing with these patches, and think it
would be good if we could start providing a test kernel for filesystem
auditing patches. I think this should be separate from an audit-lspp
test kernel.
I based these patches off David's git tree, although the patch against
fsnotify should really be sent to the Inotify developers. Any
thoughts on where these patches should live? Could we have multiple
branches in David's audit git tree?
Thanks,
Amy
19 years
[PATCH] LSPP audit enablement: storing selinux ocontext and scontext
by Dustin Kirkland
The attached patch contains functionality specified by the labeled
security protection profile--basically appending object context and
subject context labels to audit records.
This code was originally written by Dan Jones against a 2.6.9 kernel
tree. I have ported it forward to the 2.6.13-rc3-mm1 tree and tested
it.
I expect at least one section of this code to generate some animated
discussion. This code utilizes "static inline" function definitions
rather than "#define" macros, as per Documentation/SubmittingPatches
lines 328-372 and Documentation/CodingStyle line 358. This is
inconsistent with the rest of the code in include/linux/audit.h, so I
suspect someone will have to give, in the interest of consistency.
Please advise.
Additionally, we've arbitrarily defined AUDIT_SECURITY_CONTEXT = 1350.
We expect this to change to whatever the appropriate value might be.
Signed-off-by: Dustin Kirkland <dustin.kirkland(a)us.ibm.com>
diff -uprN linux-2.6.13-rc3-mm1/include/linux/audit.h
linux-2.6.13-rc3-mm1-lspp_audit/include/linux/audit.h
--- linux-2.6.13-rc3-mm1/include/linux/audit.h 2005-07-18 15:20:34.000000000 -0500
+++ linux-2.6.13-rc3-mm1-lspp_audit/include/linux/audit.h 2005-07-19 11:33:37.000000000 -0500
@@ -68,6 +68,7 @@
#define AUDIT_CONFIG_CHANGE 1305 /* Audit system configuration change */
#define AUDIT_SOCKADDR 1306 /* sockaddr copied as syscall arg */
#define AUDIT_CWD 1307 /* Current working directory */
+#define AUDIT_SECURITY_CONTEXT 1350 /* security context */
#define AUDIT_AVC 1400 /* SE Linux avc denial or grant */
#define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */
@@ -238,6 +239,8 @@ extern int audit_sockaddr(int len, void
extern int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt);
extern void audit_signal_info(int sig, struct task_struct *t);
extern int audit_filter_user(struct netlink_skb_parms *cb, int type);
+extern int audit_ipc_security_context(struct kern_ipc_perm *ipcp);
+extern int audit_set_macxattr(const char *name);
#else
#define audit_alloc(t) ({ 0; })
#define audit_free(t) do { ; } while (0)
@@ -255,6 +258,14 @@ extern int audit_filter_user(struct netl
#define audit_avc_path(dentry, mnt) ({ 0; })
#define audit_signal_info(s,t) do { ; } while (0)
#define audit_filter_user(cb,t) ({ 1; })
+static inline int audit_ipc_security_context(struct kern_ipc_perm *ipcp)
+{
+ return 0;
+}
+static inline int audit_set_macxattr(const char *name)
+{
+ return 0;
+}
#endif
#ifdef CONFIG_AUDIT
@@ -283,6 +294,7 @@ extern void audit_send_reply(int pi
int done, int multi,
void *payload, int size);
extern void audit_log_lost(const char *message);
+extern void audit_panic(const char *message);
extern struct semaphore audit_netlink_sem;
#else
#define audit_log(c,g,t,f,...) do { ; } while (0)
@@ -293,6 +305,10 @@ extern struct semaphore audit_netlink_se
#define audit_log_hex(a,b,l) do { ; } while (0)
#define audit_log_untrustedstring(a,s) do { ; } while (0)
#define audit_log_d_path(b,p,d,v) do { ; } while (0)
+static inline void audit_panic(const char *message)
+{
+ return;
+}
#endif
#endif
#endif
diff -uprN linux-2.6.13-rc3-mm1/include/linux/security.h linux-2.6.13-rc3-mm1-lspp_audit/include/linux/security.h
--- linux-2.6.13-rc3-mm1/include/linux/security.h 2005-07-18 15:20:35.000000000 -0500
+++ linux-2.6.13-rc3-mm1-lspp_audit/include/linux/security.h 2005-07-18 16:35:02.000000000 -0500
@@ -792,6 +792,11 @@ struct swap_info_struct;
* @ipcp contains the kernel IPC permission structure
* @flag contains the desired (requested) permission set
* Return 0 if permission is granted.
+ * @ipc_getsecurity:
+ * Copy the security label associated with the ipc object into
+ * @buffer. @buffer may be NULL to request the size of the buffer
+ * required. @size indicates the size of @buffer in bytes. Return
+ * number of bytes used/required on success.
*
* Security hooks for individual messages held in System V IPC message queues
* @msg_msg_alloc_security:
@@ -1140,6 +1145,7 @@ struct security_operations {
void (*task_to_inode)(struct task_struct *p, struct inode *inode);
int (*ipc_permission) (struct kern_ipc_perm * ipcp, short flag);
+ int (*ipc_getsecurity)(struct kern_ipc_perm *ipcp, void *buffer, size_t size);
int (*msg_msg_alloc_security) (struct msg_msg * msg);
void (*msg_msg_free_security) (struct msg_msg * msg);
@@ -1775,6 +1781,11 @@ static inline int security_ipc_permissio
return security_ops->ipc_permission (ipcp, flag);
}
+static inline int security_ipc_getsecurity(struct kern_ipc_perm *ipcp, void *buffer, size_t size)
+{
+ return security_ops->ipc_getsecurity(ipcp, buffer, size);
+}
+
static inline int security_msg_msg_alloc (struct msg_msg * msg)
{
return security_ops->msg_msg_alloc_security (msg);
@@ -2405,6 +2416,11 @@ static inline int security_ipc_permissio
return 0;
}
+static inline int security_ipc_getsecurity(struct kern_ipc_perm *ipcp, void *buffer, size_t size)
+{
+ return -EOPNOTSUPP;
+}
+
static inline int security_msg_msg_alloc (struct msg_msg * msg)
{
return 0;
diff -uprN linux-2.6.13-rc3-mm1/ipc/msg.c linux-2.6.13-rc3-mm1-lspp_audit/ipc/msg.c
--- linux-2.6.13-rc3-mm1/ipc/msg.c 2005-06-17 14:48:29.000000000 -0500
+++ linux-2.6.13-rc3-mm1-lspp_audit/ipc/msg.c 2005-07-18 16:35:02.000000000 -0500
@@ -441,6 +441,13 @@ asmlinkage long sys_msgctl (int msqid, i
if (msq == NULL)
goto out_up;
+ ipcp = &msq->q_perm;
+
+ if (cmd == IPC_SET) {
+ if ((err = audit_ipc_security_context(ipcp)))
+ goto out_unlock_up;
+ }
+
err = -EIDRM;
if (msg_checkid(msq,msqid))
goto out_unlock_up;
diff -uprN linux-2.6.13-rc3-mm1/ipc/sem.c linux-2.6.13-rc3-mm1-lspp_audit/ipc/sem.c
--- linux-2.6.13-rc3-mm1/ipc/sem.c 2005-07-18 15:20:05.000000000 -0500
+++ linux-2.6.13-rc3-mm1-lspp_audit/ipc/sem.c 2005-07-18 16:35:02.000000000 -0500
@@ -811,12 +811,18 @@ static int semctl_down(int semid, int se
if(sma==NULL)
return -EINVAL;
+ ipcp = &sma->sem_perm;
+
+ if(cmd == IPC_SET) {
+ if ((err = audit_ipc_security_context(ipcp)))
+ goto out_unlock;
+ }
+
if (sem_checkid(sma,semid)) {
err=-EIDRM;
goto out_unlock;
}
- ipcp = &sma->sem_perm;
-
+
if (current->euid != ipcp->cuid &&
current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) {
err=-EPERM;
diff -uprN linux-2.6.13-rc3-mm1/ipc/shm.c linux-2.6.13-rc3-mm1-lspp_audit/ipc/shm.c
--- linux-2.6.13-rc3-mm1/ipc/shm.c 2005-06-17 14:48:29.000000000 -0500
+++ linux-2.6.13-rc3-mm1-lspp_audit/ipc/shm.c 2005-07-18 16:35:02.000000000 -0500
@@ -610,6 +610,9 @@ asmlinkage long sys_shmctl (int shmid, i
err=-EINVAL;
if(shp==NULL)
goto out_up;
+ err = audit_ipc_security_context(&(shp->shm_perm));
+ if(err)
+ goto out_unlock_up;
err = shm_checkid(shp,shmid);
if(err)
goto out_unlock_up;
diff -uprN linux-2.6.13-rc3-mm1/ipc/util.c linux-2.6.13-rc3-mm1-lspp_audit/ipc/util.c
--- linux-2.6.13-rc3-mm1/ipc/util.c 2005-06-17 14:48:29.000000000 -0500
+++ linux-2.6.13-rc3-mm1-lspp_audit/ipc/util.c 2005-07-18 16:35:02.000000000 -0500
@@ -24,6 +24,7 @@
#include <linux/security.h>
#include <linux/rcupdate.h>
#include <linux/workqueue.h>
+#include <linux/audit.h>
#include <asm/unistd.h>
@@ -420,6 +421,8 @@ int ipcperms (struct kern_ipc_perm *ipcp
{ /* flag will most probably be 0 or S_...UGO from <linux/stat.h> */
int requested_mode, granted_mode;
+ audit_ipc_security_context(ipcp);
+
requested_mode = (flag >> 6) | (flag >> 3) | flag;
granted_mode = ipcp->mode;
if (current->euid == ipcp->cuid || current->euid == ipcp->uid)
diff -uprN linux-2.6.13-rc3-mm1/kernel/audit.c linux-2.6.13-rc3-mm1-lspp_audit/kernel/audit.c
--- linux-2.6.13-rc3-mm1/kernel/audit.c 2005-07-18 15:20:35.000000000 -0500
+++ linux-2.6.13-rc3-mm1-lspp_audit/kernel/audit.c 2005-07-18 16:35:02.000000000 -0500
@@ -147,7 +147,7 @@ struct audit_entry {
struct audit_rule rule;
};
-static void audit_panic(const char *message)
+void audit_panic(const char *message)
{
switch (audit_failure)
{
@@ -896,3 +896,4 @@ void audit_log(struct audit_context *ctx
audit_log_end(ab);
}
}
+
diff -uprN linux-2.6.13-rc3-mm1/kernel/auditsc.c linux-2.6.13-rc3-mm1-lspp_audit/kernel/auditsc.c
--- linux-2.6.13-rc3-mm1/kernel/auditsc.c 2005-07-18 15:20:35.000000000 -0500
+++ linux-2.6.13-rc3-mm1-lspp_audit/kernel/auditsc.c 2005-07-19 11:50:15.000000000 -0500
@@ -43,6 +43,7 @@
#include <linux/netlink.h>
#include <linux/compiler.h>
#include <asm/unistd.h>
+#include <linux/security.h>
/* 0 = no checking
1 = put_count checking
@@ -99,6 +100,7 @@ struct audit_names {
gid_t gid;
dev_t rdev;
unsigned flags;
+ char *security_context;
};
struct audit_aux_data {
@@ -108,6 +110,12 @@ struct audit_aux_data {
#define AUDIT_AUX_IPCPERM 0
+struct audit_aux_data_security_context {
+ struct audit_aux_data d;
+ char *security_context;
+ size_t security_context_len;
+};
+
struct audit_aux_data_ipcctl {
struct audit_aux_data d;
struct ipc_perm p;
@@ -167,6 +175,8 @@ struct audit_context {
#endif
};
+static const char *audit_macxattr;
+
/* Public API */
/* There are three lists of rules -- one to search at task creation
* time, one to search at syscall entry time, and another to search at
@@ -650,9 +660,11 @@ static inline void audit_free_names(stru
context->ino_count = 0;
#endif
- for (i = 0; i < context->name_count; i++)
+ for (i = 0; i < context->name_count; i++) {
if (context->names[i].name)
__putname(context->names[i].name);
+ kfree(context->names[i].security_context);
+ }
context->name_count = 0;
if (context->pwd)
dput(context->pwd);
@@ -751,6 +763,37 @@ static inline void audit_free_context(st
printk(KERN_ERR "audit: freed %d contexts\n", count);
}
+static void audit_log_task_security_context(struct audit_buffer *ab)
+{
+ char *security_context;
+ ssize_t len = 0;
+
+ len = security_getprocattr(current, "current", NULL, 0);
+ if (len < 0) {
+ if (len != -EINVAL)
+ audit_panic("security_getprocattr error in audit_log_task_security_context");
+ return;
+ }
+
+ security_context = kmalloc(len, GFP_KERNEL);
+ if (!security_context) {
+ audit_panic("memory allocation error in audit_log_task_security_context");
+ return;
+ }
+
+ len = security_getprocattr(current, "current", security_context, len);
+ if (len < 0 ) {
+ audit_panic("security_getprocattr error in audit_log_task_security_context");
+ goto out;
+ }
+
+ audit_log_format(ab, " scontext=%s", security_context);
+
+out:
+ kfree(security_context);
+ return;
+}
+
static void audit_log_task_info(struct audit_buffer *ab)
{
char name[sizeof(current->comm)];
@@ -777,6 +820,7 @@ static void audit_log_task_info(struct a
vma = vma->vm_next;
}
up_read(&mm->mmap_sem);
+ audit_log_task_security_context(ab);
}
static void audit_log_exit(struct audit_context *context, unsigned int gfp_mask)
@@ -848,6 +892,11 @@ static void audit_log_exit(struct audit_
struct audit_aux_data_path *axi = (void *)aux;
audit_log_d_path(ab, "path=", axi->dentry, axi->mnt);
break; }
+ case AUDIT_SECURITY_CONTEXT: {
+ struct audit_aux_data_security_context *axi = (void *)aux;
+ audit_log_format(ab, " ocontext=%s", axi->security_context);
+ kfree(axi->security_context);
+ break; }
}
audit_log_end(ab);
@@ -883,6 +932,10 @@ static void audit_log_exit(struct audit_
context->names[i].gid,
MAJOR(context->names[i].rdev),
MINOR(context->names[i].rdev));
+ if (context->names[i].security_context) {
+ audit_log_format(ab, " ocontext=%s",
+ context->names[i].security_context);
+ }
audit_log_end(ab);
}
}
@@ -1098,6 +1151,37 @@ void audit_putname(const char *name)
#endif
}
+void audit_inode_security_context(int idx, const struct inode *inode)
+{
+ struct audit_context *context = current->audit_context;
+ int len = 0;
+
+ if (!audit_macxattr)
+ return;
+
+ len = security_inode_getsecurity((struct inode *)inode, audit_macxattr, NULL, 0);
+ if (len < 0) {
+ if (len != -EOPNOTSUPP)
+ audit_panic("security_inode_getsecurity error in audit_inode_security_context");
+ return;
+ }
+
+ context->names[idx].security_context = kmalloc(len, GFP_KERNEL);
+ if (!(context->names[idx].security_context)) {
+ audit_panic("memory allocation error in audit_inode_security_context");
+ return;
+ }
+
+ len = security_inode_getsecurity((struct inode *)inode, audit_macxattr,
+ context->names[idx].security_context, len);
+ if (len < 0) {
+ kfree(context->names[idx].security_context);
+ audit_panic("security_inode_getsecurity error in audit_inode_security_context");
+ }
+
+ return;
+}
+
/* Store the inode and device from a lookup. Called from
* fs/namei.c:path_lookup(). */
void audit_inode(const char *name, const struct inode *inode, unsigned flags)
@@ -1133,6 +1217,8 @@ void audit_inode(const char *name, const
context->names[idx].uid = inode->i_uid;
context->names[idx].gid = inode->i_gid;
context->names[idx].rdev = inode->i_rdev;
+
+ audit_inode_security_context(idx, inode);
}
void auditsc_get_stamp(struct audit_context *ctx,
@@ -1270,3 +1356,63 @@ void audit_signal_info(int sig, struct t
}
}
+int audit_ipc_security_context(struct kern_ipc_perm *ipcp)
+{
+ struct audit_aux_data_security_context *ax;
+ struct audit_context *context = current->audit_context;
+ int len = 0;
+
+ if (likely(!context))
+ return 0;
+
+ ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
+ if (!ax) {
+ audit_panic("memory allocation error in audit_ipc_security_context");
+ return -ENOMEM;
+ }
+
+ len = security_ipc_getsecurity(ipcp, NULL, 0);
+ if (len < 0) {
+ if (len != -EOPNOTSUPP)
+ audit_panic("security_ipc_getsecurity error in audit_ipc_security_context");
+ return len;
+ }
+
+ ax->security_context = kmalloc(len, GFP_ATOMIC);
+ if (!ax->security_context) {
+ audit_panic("memory allocation error in audit_ipc_security_context");
+ kfree(ax);
+ return -ENOMEM;
+ }
+
+ len = security_ipc_getsecurity(ipcp, ax->security_context, len);
+ if (len < 0) {
+ audit_panic("security_ipc_getsecurity error in audit_ipc_security_context");
+ kfree(ax->security_context);
+ kfree(ax);
+ return len;
+ }
+
+ ax->security_context_len = len;
+
+ ax->d.type = AUDIT_SECURITY_CONTEXT;
+ ax->d.next = context->aux;
+ context->aux = (void *)ax;
+ return 0;
+}
+
+/* Set the security XATTR name. This is needed for audit functions
+ * to obtain the security context of file system objects. */
+int audit_set_macxattr(const char *name)
+{
+ size_t len = strlen(name)+1;
+
+ if (audit_macxattr)
+ return -EINVAL;
+
+ audit_macxattr = kmalloc(len, GFP_KERNEL);
+ if (!audit_macxattr)
+ return -ENOMEM;
+ memcpy((void *)audit_macxattr, (const void *)name, len);
+ return 0;
+}
diff -uprN linux-2.6.13-rc3-mm1/security/dummy.c linux-2.6.13-rc3-mm1-lspp_audit/security/dummy.c
--- linux-2.6.13-rc3-mm1/security/dummy.c 2005-07-18 15:20:36.000000000 -0500
+++ linux-2.6.13-rc3-mm1-lspp_audit/security/dummy.c 2005-07-18 16:35:02.000000000 -0500
@@ -557,6 +557,11 @@ static int dummy_ipc_permission (struct
return 0;
}
+static int dummy_ipc_getsecurity(struct kern_ipc_perm *ipcp, void *buffer, size_t size)
+{
+ return -EOPNOTSUPP;
+}
+
static int dummy_msg_msg_alloc_security (struct msg_msg *msg)
{
return 0;
@@ -907,6 +912,7 @@ void security_fixup_ops (struct security
set_to_dummy_if_null(ops, task_reparent_to_init);
set_to_dummy_if_null(ops, task_to_inode);
set_to_dummy_if_null(ops, ipc_permission);
+ set_to_dummy_if_null(ops, ipc_getsecurity);
set_to_dummy_if_null(ops, msg_msg_alloc_security);
set_to_dummy_if_null(ops, msg_msg_free_security);
set_to_dummy_if_null(ops, msg_queue_alloc_security);
diff -uprN linux-2.6.13-rc3-mm1/security/selinux/hooks.c linux-2.6.13-rc3-mm1-lspp_audit/security/selinux/hooks.c
--- linux-2.6.13-rc3-mm1/security/selinux/hooks.c 2005-07-18 15:20:36.000000000 -0500
+++ linux-2.6.13-rc3-mm1-lspp_audit/security/selinux/hooks.c 2005-07-19 10:56:44.000000000 -0500
@@ -116,6 +116,35 @@ static struct security_operations *secon
static LIST_HEAD(superblock_security_head);
static DEFINE_SPINLOCK(sb_security_lock);
+/* Return security context for a given sid or just the context
+ length if the buffer is null or length is 0 */
+static int selinux_getsecurity(u32 sid, void *buffer, size_t size)
+{
+ char *context;
+ unsigned len;
+ int rc;
+
+ if (buffer && !size)
+ return -ERANGE;
+
+ rc = security_sid_to_context(sid, &context, &len);
+ if (rc)
+ return rc;
+
+ if (!buffer || !size)
+ goto getsecurity_exit;
+
+ if (size < len) {
+ kfree(context);
+ return -ERANGE;
+ }
+ memcpy(buffer, context, len);
+
+getsecurity_exit:
+ kfree(context);
+ return len;
+}
+
/* Allocate and free functions for each kind of security blob. */
static int task_alloc_security(struct task_struct *task)
@@ -2232,30 +2261,13 @@ static int selinux_inode_removexattr (st
static int selinux_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size)
{
struct inode_security_struct *isec = inode->i_security;
- char *context;
- unsigned len;
- int rc;
/* Permission check handled by selinux_inode_getxattr hook.*/
if (strcmp(name, XATTR_SELINUX_SUFFIX))
return -EOPNOTSUPP;
- rc = security_sid_to_context(isec->sid, &context, &len);
- if (rc)
- return rc;
-
- if (!buffer || !size) {
- kfree(context);
- return len;
- }
- if (size < len) {
- kfree(context);
- return -ERANGE;
- }
- memcpy(buffer, context, len);
- kfree(context);
- return len;
+ return(selinux_getsecurity(isec->sid, buffer, size));
}
static int selinux_inode_setsecurity(struct inode *inode, const char *name,
@@ -3360,6 +3372,13 @@ out:
return err;
}
+static int selinux_socket_getsecurity(struct socket *sock, void *buffer, size_t size)
+{
+ struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
+
+ return(selinux_getsecurity(isec->sid, buffer, size));
+}
+
static int selinux_sk_alloc_security(struct sock *sk, int family, int priority)
{
return sk_alloc_security(sk, family, priority);
@@ -4025,6 +4044,13 @@ static int selinux_ipc_permission(struct
return ipc_has_perm(ipcp, av);
}
+static int selinux_ipc_getsecurity(struct kern_ipc_perm *ipcp, void *buffer, size_t size)
+{
+ struct ipc_security_struct *isec = ipcp->security;
+
+ return(selinux_getsecurity(isec->sid, buffer, size));
+}
+
/* module stacking operations */
static int selinux_register_security (const char *name, struct security_operations *ops)
{
@@ -4066,8 +4092,7 @@ static int selinux_getprocattr(struct ta
char *name, void *value, size_t size)
{
struct task_security_struct *tsec;
- u32 sid, len;
- char *context;
+ u32 sid;
int error;
if (current != p) {
@@ -4076,9 +4101,6 @@ static int selinux_getprocattr(struct ta
return error;
}
- if (!size)
- return -ERANGE;
-
tsec = p->security;
if (!strcmp(name, "current"))
@@ -4095,16 +4117,7 @@ static int selinux_getprocattr(struct ta
if (!sid)
return 0;
- error = security_sid_to_context(sid, &context, &len);
- if (error)
- return error;
- if (len > size) {
- kfree(context);
- return -ERANGE;
- }
- memcpy(value, context, len);
- kfree(context);
- return len;
+ return(selinux_getsecurity(sid, value, size));
}
static int selinux_setprocattr(struct task_struct *p,
@@ -4299,6 +4312,7 @@ static struct security_operations selinu
.task_to_inode = selinux_task_to_inode,
.ipc_permission = selinux_ipc_permission,
+ .ipc_getsecurity = selinux_ipc_getsecurity,
.msg_msg_alloc_security = selinux_msg_msg_alloc_security,
.msg_msg_free_security = selinux_msg_msg_free_security,
@@ -4379,6 +4393,10 @@ static __init int selinux_init(void)
if (register_security (&selinux_ops))
panic("SELinux: Unable to register with kernel.\n");
+ if (audit_set_macxattr(XATTR_SELINUX_SUFFIX)) {
+ printk(KERN_WARNING "SELinux: Unable to register xattr name with audit.\n");
+ }
+
if (selinux_enforcing) {
printk(KERN_INFO "SELinux: Starting in enforcing mode\n");
} else {
19 years
Selective Audit; filtering on message type; integration of operators
by Dustin Kirkland
RBACPP FAU_SEL.1 Selective Audit
The TSF shall be able to include or exclude auditable events from the
set of audited events based on the following attributes:
(a) Object identity, user identity, subject identity, host identity, and
***event type***
I'm currently working on a design for a patch to the audit userspace and
kernel subsystem that provides this functionality. Additionally, I'm
conducting this work in conjunction with trying to provide extended
support for operators (such as > and <), as these would be useful in
this context.
To give credit where due, Steve Grubb and I have discussed a some of
these items in off hand conversations recently. I'm collecting those
thoughts and others here for review.
--
USER_SPACE
From a user-experience perspective, we're trying to enable a user to
exclude messages of a certain type (or ranges of messages of particular
types). If you're unclear what types of messages are currently defined,
see include/linux/audit.h. Given extended support for ranges and
comparative operators, this should be extensible to other audit record
keys, such the user, subject, etc.
I'm suggesting the ability to add new rules via auditctl to a new list,
perhaps called "exclude". The proposed interface would look like:
Exclude messages of a specific type:
auditctl -a exclude,always -F "type=AUDIT_IPC"
Exclude messages within range:
auditctl -a exclude,always -F "type=AUDIT_SYSCALL..AUDIT_CWD"
Exclude messages using auditctl helper terms (ALL_DAEMON interpreted by
auditctl to be a range of 1200-1299 as specified in the audit.h header):
auditctl -a exclude,always -F "type=ALL_DAEMON"
Use multiple rules to exclude audit system command messages:
auditctl -a exclude,always -F "type<1100"
Also, the same form should be usable for other parameters as well, such
as uid, pid, etc.
auditctl -a exclude,always -F "uid<500"
auditctl -a exclude,always -F "pid=464"
I have written the code necessary to create an ordered, compressed list
of ranges of numbers that the kernel could very efficiently filter on.
Given some arbitrary number of ranges (as small as a singularity and as
large as the enumerated space), the code creates a list of upper and
lower bounds, however few are necessary to properly express the list of
ranges. For instance, given the user input ranges:
10-20, 5, 15-25, 23, 50
The algorithm will produce an optimized list:
5,5
10,25
50,50
This is a key, inexpensive operation to perform in user space that is
potentially a valuable gain kernel space. Memory requirements are
minimized, matches are found quickly, and the traversal is aborted as
soon as a range greater than the current value is encountered.
Note that I've also written the code necessary to remove individual
elements or ranges from an existing range, such that given our previous
range: (5, 10-25, 50), one chooses to remove 7, 13, 40-60 would result
in: (5, 10-12, 14-25). This is needed for the user's ability to prune
and modify existing rules.
--
KERNEL_SPACE
The kernel piece of this is pretty straightforward, actually... Near
the very top of audit_log_start(), we basically do something like:
if (unlikely(audit_exclude_type(type)))
return NULL;
Where audit_exclude_type() traverses our list of ranges looking for a
match, returning 1 if is to be excluded, 0 if no matches found.
Remember, this is ordered such that we can end the traversal as soon as
possible.
--
NETLINK
I'm nearly ready to post a patch, but I'm waiting on some consensus on
Steve's previous thread (New operators for rules). As of this posting,
there's no consensus yet on how we go about passing these values to/from
the kernel/userspace.
I'm trying to work within struct audit_rule.
struct audit_rule { /* for AUDIT_LIST, AUDIT_ADD, and AUDIT_DEL */
uint32_t flags; /* AUDIT_PER_{TASK,CALL}, AUDIT_PREPEND */
uint32_t action; /* AUDIT_NEVER, AUDIT_POSSIBLE, AUDIT_ALWAYS */
uint32_t field_count;
uint32_t mask[AUDIT_BITMASK_SIZE];
uint32_t fields[AUDIT_MAX_FIELDS];
uint32_t values[AUDIT_MAX_FIELDS];
};
There have been several propositions so far (utilize upper bits of
flags; utilize matching fields[]/values[] entries; hack in a zero-sized
array). If you have opinions on the conveyance of said operators,
please post to aforementioned thread.
Other comments on the design here proposed?
:-Dustin
19 years
audit 1.0.6 released
by Steve Grubb
Hello,
I've just released a new version of the audit daemon. It can be downloaded
from http://people.redhat.com/sgrubb/audit It will also be in rawhide
tomorrow. The Changelog is:
- in aureport, add column labels to reports
- added watch report to aureport
- added interpreting mode to aureport
- added user space avc standard message to libaudit
- aureport & ausearch now use builtin log locations when bad config file
- add email alert to low disk space warning actions in auditd
This release improves aureport, though its still not finished. It also
introduces email alerts for audit daemon low disk space notification.
Let me know if there are any problems with this release.
-Steve
19 years
Re: LSPP Requirement Specifically for Auditing
by Dustin Kirkland
On 10/3/05, Steve Grubb <sgrubb(a)redhat.com> wrote:
> I've been doing an analysis of what all we need to do to get the audit system
> up to par for LSPP. The actual work list for all of LSPP is bigger, I am
> extracting just the ones that are aimed primarily at the audit system. This
> is the essential requirements:
Hey Steve-
Thanks for doing this work. For the of completeness, can you reference
the section of the LSPP/RBAC specification where each of these came
from? Just looking at a few these, I'm a little confused where the
requirement comes from.
> 10.0 Postfix
> 10.1 Add loginuid code to set it when delivering local mail
Also, I'm pretty sure that we removed Postfix from the Security Target.
:-Dustin
19 years
Re: FYI: 2.6.13.3 Memory leak, names_cache
by Dustin Kirkland
On 10/7/05, Steve Grubb <sgrubb(a)redhat.com> wrote:
> On Friday 07 October 2005 12:49, Timothy R. Chavez wrote:
> > Shouldn't this type of message be CCed to this list?
>
> Offhand, I don't see the correlation between names_cache and audit
system.
Talked to Steve about this on IRC... For everyone else, read the rest
of the thread and you'll see that this was caused by audit syscall code.
:-Dustin
19 years
New operators for rules
by Steve Grubb
Hello,
Dustin and I were talking about how to represent some new operators for
writing audit rules. I am interested in seeing >, <, and range added at a
minimum. The question came up as to how to fit this into the existing
audit_rule structure. This is what we currently have:
struct audit_rule { /* for AUDIT_LIST, AUDIT_ADD, and AUDIT_DEL */
__u32 flags; /* AUDIT_PER_{TASK,CALL}, AUDIT_PREPEND */
__u32 action; /* AUDIT_NEVER, AUDIT_POSSIBLE, AUDIT_ALWAYS */
__u32 field_count;
__u32 mask[AUDIT_BITMASK_SIZE];
__u32 fields[AUDIT_MAX_FIELDS];
__u32 values[AUDIT_MAX_FIELDS];
};
The fields member currently uses the msb to determine whether its = or !=.
#define AUDIT_NEGATE 0x80000000
I was wondering if we should go ahead and map the other operators into the
other high bits. We are currently only using the lower 4 bits of the u32 word
so we have plenty of room. We have to do this in a way that is backward
compatible for old kernels. Any ideas? Any preferred bit patterns?
Also, we have the issue of needing to send 2 values for a range operator. How
should we make the kernel understand this? Or should we create a new message
type for adding, listing, and deleting rules that we can expand the idea of
operators for and use the current one for legacy compatibility?
Need some ideas from the kernel hackers....
-Steve
19 years
Re: Selective Audit; filtering on message type; integration of operators
by Dustin Kirkland
On 10/6/05, Amy Griffis <amy.griffis(a)hp.com> wrote:
> On Thu, Sep 29, 2005 at 03:00:31PM -0500, Dustin Kirkland wrote:
> > I'm suggesting the ability to add new rules via auditctl to a new list,
> > perhaps called "exclude". The proposed interface would look like:
> >
> > Exclude messages of a specific type:
> > auditctl -a exclude,always -F "type=AUDIT_IPC"
>
> I don't think the exclude list should be a filter list, for a couple
> of reasons. The filter rules are designed to represent particular
> system events. Audit message types don't have anything to do with
> what's going on in the system. Additionally, you are only making use
> of one of the three possible actions (always). The others don't make
> any sense in this context. This is a good indication that this
> feature is not what the filter lists were designed for.
So your vote would be for something more like:
auditctl -E "type=AUDIT_IPC"
auditctl -E "uid>500"
I think I like that ^
Steve: What do you think about this? I know you and I talked about
doing it this way earlier and you pointed me toward the filter list
input methodology...
> > KERNEL_SPACE
> >
> > The kernel piece of this is pretty straightforward, actually... Near
> > the very top of audit_log_start(), we basically do something like:
> > if (unlikely(audit_exclude_type(type)))
> > return NULL;
> >
> > Where audit_exclude_type() traverses our list of ranges looking for
> > a match, returning 1 if is to be excluded, 0 if no matches found.
> > Remember, this is ordered such that we can end the traversal as soon
> > as possible.
>
> The cleanest implementation would be a bitmask of all audit message
> types. Checking the bitmask would require a single operation to
> determine whether or not to generate the log message. You could also
> define additional constants to represent groups of messages, which
> would remove the need to support ranges.
Agreed that it would be simplest. But it's neither scalable nor
flexible. 32-bits or 64-bits just won't support very many different
types of messages. There's been some discussion on this list about
increasing the message blocks from the current 100 to something much
larger to allow particular vendors to create message types of their own.
:-Dustin
19 years