Re: [PATCH 2/2] filesystem auditing: augment audit_inode
by Dustin Kirkland
On 10/21/05, Amy Griffis <amy.griffis(a)hp.com> wrote:
> On Thu, Oct 20, 2005 at 10:04:09AM -0500, Timothy R. Chavez wrote:
> > > Not too many comments on my first cursory glance.
>
> Thanks for taking a look.
Amy-
I looked through the patch as well and I didn't see anything that jumped
out at me as problematic. Plus, your copyright notice and changelog
entry reminded me to revisit my patch and slap in equivalent notes :)
Thanks,
:-Dustin
19 years
Re: LSPP audit enablement: example audit records with subj/obj labels
by Dustin Kirkland
On 10/20/05, Linda Knippers <linda.knippers(a)hp.com> wrote:
> > At this point, the subj/obj label is simply appended onto the end of the
> > existing audit record for the associated subject or object. Steve has
> > mentioned that this will get more complicated when a given subject acts
> > on multiple objects (though I haven't found a good way to test this
> > behavior yet).
>
> In most cases where there are multiple objects, wouldn't each have its
> own record (like the PATH record) so it would be clear which object the
> label is for?
That's my guess right now, Linda. I'm looking forward to seeing what
happens once Amy & Tim's fs watch code and my code are merged so that I
can test it out and see what it looks like. There's a distinct
possibility that it'll just work cleanly as you suggested.
> > If there are strong feelings one way or another, let's please
> > discuss them now.
>
> I used to think the information should be separate but I don't think
> so anymore.
Thanks, I'm happy that at least someone else likes it this way. :-D
I guess we have to remember that the ausearch et al. tools could be
augmented to sew together auxiliary records if they were separated. But
doing it this way greatly simplifies that aspect of the work to be done.
If this is intuitive and effect for LSPP compliance, I would lean toward
doing it this way and maintaining a list of future work items that
perhaps includes separating these labels out as aux records at some
point later.
:-Dustin
19 years
[PATCH 2/2] filesystem auditing: augment audit_inode
by Amy Griffis
Collect more inode information during syscall processing.
NOTE: This patch makes some changes to the output of AUDIT_PATH
records. In the case of the name field, the record will show
"name=(null)" if there is no name field (e.g. in an fchown call). I
did this because it seemed it would make more sense to someone looking
at the records.
I also added a "parent" field to distinguish between the inode number
and the parent inode number. This allowed me to remove the "flags"
field. In some cases, such as syscall failures, inode information may
not be present in the audit context. I took the liberty to not emit
fields with undefined values. I don't know if this is the right
approach. I think the real solution is to move to a binary record
format and leave this decision for a userspace tool.
diff --git a/fs/namei.c b/fs/namei.c
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1046,8 +1046,7 @@ int fastcall path_lookup(const char *nam
current->total_link_count = 0;
retval = link_path_walk(name, nd);
out:
- if (unlikely(current->audit_context
- && nd && nd->dentry && nd->dentry->d_inode))
+ if (nd && nd->dentry && nd->dentry->d_inode)
audit_inode(name, nd->dentry->d_inode, flags);
return retval;
}
@@ -1192,6 +1191,7 @@ static inline int may_delete(struct inod
return -ENOENT;
BUG_ON(victim->d_parent->d_inode != dir);
+ audit_inode_child(victim->d_name.name, victim->d_inode, dir->i_ino);
error = permission(dir,MAY_WRITE | MAY_EXEC, NULL);
if (error)
diff --git a/fs/open.c b/fs/open.c
--- a/fs/open.c
+++ b/fs/open.c
@@ -25,6 +25,7 @@
#include <linux/pagemap.h>
#include <linux/syscalls.h>
#include <linux/rcupdate.h>
+#include <linux/audit.h>
#include <asm/unistd.h>
@@ -609,6 +610,8 @@ asmlinkage long sys_fchmod(unsigned int
dentry = file->f_dentry;
inode = dentry->d_inode;
+ audit_inode(NULL, inode, 0);
+
err = -EROFS;
if (IS_RDONLY(inode))
goto out_putf;
@@ -732,7 +735,10 @@ asmlinkage long sys_fchown(unsigned int
file = fget(fd);
if (file) {
- error = chown_common(file->f_dentry, user, group);
+ struct dentry * dentry;
+ dentry = file->f_dentry;
+ audit_inode(NULL, dentry->d_inode, 0);
+ error = chown_common(dentry, user, group);
fput(file);
}
return error;
diff --git a/fs/xattr.c b/fs/xattr.c
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -17,6 +17,7 @@
#include <linux/syscalls.h>
#include <linux/module.h>
#include <linux/fsnotify.h>
+#include <linux/audit.h>
#include <asm/uaccess.h>
/*
@@ -114,12 +115,15 @@ sys_fsetxattr(int fd, char __user *name,
size_t size, int flags)
{
struct file *f;
+ struct dentry *dentry;
int error = -EBADF;
f = fget(fd);
if (!f)
return error;
- error = setxattr(f->f_dentry, name, value, size, flags);
+ dentry = f->f_dentry;
+ audit_inode(NULL, dentry->d_inode, 0);
+ error = setxattr(dentry, name, value, size, flags);
fput(f);
return error;
}
@@ -364,12 +368,15 @@ asmlinkage long
sys_fremovexattr(int fd, char __user *name)
{
struct file *f;
+ struct dentry *dentry;
int error = -EBADF;
f = fget(fd);
if (!f)
return error;
- error = removexattr(f->f_dentry, name);
+ dentry = f->f_dentry;
+ audit_inode(NULL, dentry->d_inode, 0);
+ error = removexattr(dentry, name);
fput(f);
return error;
}
diff --git a/include/linux/audit.h b/include/linux/audit.h
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -222,7 +222,20 @@ extern void audit_syscall_entry(struct t
extern void audit_syscall_exit(struct task_struct *task, int failed, long return_code);
extern void audit_getname(const char *name);
extern void audit_putname(const char *name);
-extern void audit_inode(const char *name, const struct inode *inode, unsigned flags);
+extern void __audit_inode(const char *name, const struct inode *inode, unsigned flags);
+extern void __audit_inode_child(const char *dname, const struct inode *inode,
+ unsigned long pino);
+static inline void audit_inode(const char *name, const struct inode *inode,
+ unsigned flags) {
+ if (unlikely(current->audit_context))
+ __audit_inode(name, inode, flags);
+}
+static inline void audit_inode_child(const char *dname,
+ const struct inode *inode,
+ unsigned long pino) {
+ if (unlikely(current->audit_context))
+ __audit_inode_child(dname, inode, pino);
+}
/* Private API (for audit.c only) */
extern int audit_receive_filter(int type, int pid, int uid, int seq,
@@ -245,7 +258,10 @@ extern int audit_filter_user(struct netl
#define audit_syscall_exit(t,f,r) do { ; } while (0)
#define audit_getname(n) do { ; } while (0)
#define audit_putname(n) do { ; } while (0)
+#define __audit_inode(n,i,f) do { ; } while (0)
+#define __audit_inode_child(d,i,p) do { ; } while (0)
#define audit_inode(n,i,f) do { ; } while (0)
+#define audit_inode_child(d,i,p) do { ; } while (0)
#define audit_receive_filter(t,p,u,s,d,l) ({ -EOPNOTSUPP; })
#define auditsc_get_stamp(c,t,s) do { BUG(); } while (0)
#define audit_get_loginuid(c) ({ -1; })
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h
--- a/include/linux/fsnotify.h
+++ b/include/linux/fsnotify.h
@@ -15,6 +15,7 @@
#include <linux/dnotify.h>
#include <linux/inotify.h>
+#include <linux/audit.h>
/*
* fsnotify_move - file old_name at old_dir was moved to new_name at new_dir
@@ -45,6 +46,8 @@ static inline void fsnotify_move(struct
if (source) {
inotify_inode_queue_event(source, IN_MOVE_SELF, 0, NULL);
}
+ audit_inode_child(old_name, source, old_dir->i_ino);
+ audit_inode_child(new_name, target, new_dir->i_ino);
}
/*
@@ -74,6 +77,7 @@ static inline void fsnotify_create(struc
{
inode_dir_notify(inode, DN_CREATE);
inotify_inode_queue_event(inode, IN_CREATE, 0, dentry->d_name.name);
+ audit_inode_child(dentry->d_name.name, dentry->d_inode, inode->i_ino);
}
/*
@@ -84,6 +88,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);
+ audit_inode_child(dentry->d_name.name, dentry->d_inode, inode->i_ino);
}
/*
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -2,6 +2,7 @@
* Handles all system-call specific auditing features.
*
* Copyright 2003-2004 Red Hat Inc., Durham, North Carolina.
+ * Copyright 2005 Hewlett-Packard Development Company, L.P.
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -27,11 +28,15 @@
* this file -- see entry.S) is based on a GPL'd patch written by
* okir(a)suse.de and Copyright 2003 SuSE Linux AG.
*
+ * Modified by Amy Griffis <amy.griffis(a)hp.com> to collect additional
+ * filesystem information.
*/
#include <linux/init.h>
#include <asm/atomic.h>
#include <asm/types.h>
+#include <linux/fs.h>
+#include <linux/namei.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/mount.h>
@@ -93,12 +98,12 @@ enum audit_state {
struct audit_names {
const char *name;
unsigned long ino;
+ unsigned long pino;
dev_t dev;
umode_t mode;
uid_t uid;
gid_t gid;
dev_t rdev;
- unsigned flags;
};
struct audit_aux_data {
@@ -479,7 +484,9 @@ static int audit_filter_rules(struct tas
case AUDIT_INODE:
if (ctx) {
for (j = 0; j < ctx->name_count; j++) {
- if (ctx->names[j].ino == value) {
+ if ((ctx->names[j].ino == value) ||
+ (ctx->names[j].pino == value))
+ {
++result;
break;
}
@@ -663,17 +670,17 @@ static inline void audit_free_names(stru
#if AUDIT_DEBUG == 2
if (context->auditable
||context->put_count + context->ino_count != context->name_count) {
- printk(KERN_ERR "audit.c:%d(:%d): major=%d in_syscall=%d"
+ printk(KERN_ERR "%s:%d(:%d): major=%d in_syscall=%d"
" name_count=%d put_count=%d"
" ino_count=%d [NOT freeing]\n",
- __LINE__,
+ __FILE__, __LINE__,
context->serial, context->major, context->in_syscall,
context->name_count, context->put_count,
context->ino_count);
for (i = 0; i < context->name_count; i++)
printk(KERN_ERR "names[%d] = %p = %s\n", i,
context->names[i].name,
- context->names[i].name);
+ context->names[i].name ?: "(null)");
dump_stack();
return;
}
@@ -899,27 +906,34 @@ static void audit_log_exit(struct audit_
}
}
for (i = 0; i < context->name_count; i++) {
+ unsigned long ino = context->names[i].ino;
+ unsigned long pino = context->names[i].pino;
+
ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH);
if (!ab)
continue; /* audit_panic has been called */
audit_log_format(ab, "item=%d", i);
- if (context->names[i].name) {
- audit_log_format(ab, " name=");
+
+ audit_log_format(ab, " name=");
+ if (context->names[i].name)
audit_log_untrustedstring(ab, context->names[i].name);
- }
- audit_log_format(ab, " flags=%x\n", context->names[i].flags);
-
- if (context->names[i].ino != (unsigned long)-1)
- audit_log_format(ab, " inode=%lu dev=%02x:%02x mode=%#o"
- " ouid=%u ogid=%u rdev=%02x:%02x",
- context->names[i].ino,
- MAJOR(context->names[i].dev),
- MINOR(context->names[i].dev),
- context->names[i].mode,
- context->names[i].uid,
- context->names[i].gid,
- MAJOR(context->names[i].rdev),
+ else
+ audit_log_format(ab, "(null)");
+
+ if (pino != (unsigned long)-1)
+ audit_log_format(ab, " parent=%lu", pino);
+ if (ino != (unsigned long)-1)
+ audit_log_format(ab, " inode=%lu", ino);
+ if ((pino != (unsigned long)-1) || (ino != (unsigned long)-1))
+ audit_log_format(ab, " dev=%02x:%02x mode=%#o"
+ " ouid=%u ogid=%u rdev=%02x:%02x",
+ MAJOR(context->names[i].dev),
+ MINOR(context->names[i].dev),
+ context->names[i].mode,
+ context->names[i].uid,
+ context->names[i].gid,
+ MAJOR(context->names[i].rdev),
MINOR(context->names[i].rdev));
audit_log_end(ab);
}
@@ -1146,7 +1160,7 @@ void audit_putname(const char *name)
for (i = 0; i < context->name_count; i++)
printk(KERN_ERR "name[%d] = %p = %s\n", i,
context->names[i].name,
- context->names[i].name);
+ context->names[i].name ?: "(null)");
}
#endif
__putname(name);
@@ -1174,9 +1188,10 @@ void audit_putname(const char *name)
* @inode: inode being audited
* @flags: lookup flags (as used in path_lookup())
*
- * Called from fs/namei.c:path_lookup().
+ * Hooking path_lookup() catches most cases. Syscalls operating on
+ * file descriptors must be separately hooked.
*/
-void audit_inode(const char *name, const struct inode *inode, unsigned flags)
+void __audit_inode(const char *name, const struct inode *inode, unsigned flags)
{
int idx;
struct audit_context *context = current->audit_context;
@@ -1202,13 +1217,93 @@ void audit_inode(const char *name, const
++context->ino_count;
#endif
}
- context->names[idx].flags = flags;
- context->names[idx].ino = inode->i_ino;
context->names[idx].dev = inode->i_sb->s_dev;
context->names[idx].mode = inode->i_mode;
context->names[idx].uid = inode->i_uid;
context->names[idx].gid = inode->i_gid;
context->names[idx].rdev = inode->i_rdev;
+ if ((flags & LOOKUP_PARENT) && (strcmp(name, "/") != 0) &&
+ (strcmp(name, ".") != 0)) {
+ context->names[idx].ino = (unsigned long)-1;
+ context->names[idx].pino = inode->i_ino;
+ } else {
+ context->names[idx].ino = inode->i_ino;
+ context->names[idx].pino = (unsigned long)-1;
+ }
+}
+
+/**
+ * audit_inode_child - collect inode info for created/removed objects
+ * @dname: inode's dentry name
+ * @inode: inode being audited
+ * @pino: inode number of dentry parent
+ *
+ * For syscalls that create or remove filesystem objects, audit_inode
+ * can only collect information for the filesystem object's parent.
+ * This call updates the audit context with the child's information.
+ * Syscalls that create a new filesystem object must be hooked after
+ * the object is created. Syscalls that remove a filesystem object
+ * must be hooked prior, in order to capture the target inode during
+ * unsuccessful attempts.
+ */
+void __audit_inode_child(const char *dname, const struct inode *inode,
+ unsigned long pino)
+{
+ int idx;
+ struct audit_context *context = current->audit_context;
+
+ if (!context->in_syscall)
+ return;
+
+ /* determine matching parent */
+ if (dname)
+ for (idx = 0; idx < context->name_count; idx++)
+ if (context->names[idx].pino == pino) {
+ const char *n;
+ const char *name = context->names[idx].name;
+ int dlen = strlen(dname);
+ int nlen = name ? strlen(name) : 0;
+
+ if (nlen < dlen)
+ continue;
+
+ /* disregard trailing slashes */
+ n = name + nlen - 1;
+ while ((*n == '/') && (n > name))
+ n--;
+
+ /* find last path component */
+ n = n - dlen + 1;
+ if (n < name)
+ continue;
+ else if (n > name) {
+ if (*--n != '/')
+ continue;
+ else
+ n++;
+ }
+
+ if (strncmp(n, dname, dlen) == 0)
+ goto update_context;
+ }
+
+ /* catch-all in case match not found */
+ idx = context->name_count++;
+ context->names[idx].name = NULL;
+ context->names[idx].pino = pino;
+#if AUDIT_DEBUG
+ context->ino_count++;
+#endif
+
+update_context:
+ if (inode) {
+ context->names[idx].ino = inode->i_ino;
+ context->names[idx].dev = inode->i_sb->s_dev;
+ context->names[idx].mode = inode->i_mode;
+ context->names[idx].uid = inode->i_uid;
+ context->names[idx].gid = inode->i_gid;
+ context->names[idx].rdev = inode->i_rdev;
+ }
}
/**
19 years
LSPP audit enablement: example audit records with subj/obj labels
by Dustin Kirkland
I expect that most people have only looked at the code of the
subject/object labeling patch, and have not actually patched a kernel,
compiled, and tested it.
Thus, I'm pasting below a few snippets of the audit logs so that you can
get an idea of what these labels look like, and how they're falling into
place.
At this point, the subj/obj label is simply appended onto the end of the
existing audit record for the associated subject or object. Steve has
mentioned that this will get more complicated when a given subject acts
on multiple objects (though I haven't found a good way to test this
behavior yet).
Alternatively, the subj/obj label could exist as an auxiliary record and
refer back to the owning record. This could work as well, but this is
not how my patch is currently written. It's a little more complicated
than what I have in place now, though probably doable without too much
trouble. If there are strong feelings one way or another, let's please
discuss them now.
Examples follow.
--
This is the /var/log/audit/audit.log output of a watch on chmod
(auditctl -a exit,always -S chmod). Note the specified subject context
attached to the syscall record (subj). Also note the specified object
context attached to the path record (obj).
type=SYSCALL msg=audit(1129732019.179:29): arch=40000003 syscall=15
success=yes exit=0 a0=80528a8 a1=1ed a2=805153c a3=8053a68 items=1
pid=3110 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0
fsgid=0 comm="chmod" exe="/bin/chmod" subj=root:system_r:unconfined_t
type=CWD msg=audit(1129732019.179:29): cwd="/tmp"
type=PATH msg=audit(1129732019.179:29): item=0 name="dustin" flags=1
inode=1638928 dev=fd:00 mode=0100777 ouid=500 ogid=500 rdev=00:00
obj=root:object_r:tmp_t
And this is the /var/log/audit/audit.log output of a watch on ipc calls
(auditctl -a exit,always -S ipc). I created a little test program that
creates, sets, and removes a semaphore (which is where there are several
records here). Note the subj field in the syscall record, and the obj
field in the IPC record.
type=SYSCALL msg=audit(1129732008.219:26): arch=40000003 syscall=117
success=yes exit=0 a0=3 a1=0 a2=0 a3=101 items=0 pid=3107
auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0
comm="a.out" exe="/tmp/a.out" subj=root:system_r:unconfined_t
type=IPC msg=audit(1129732008.219:26): qbytes=0 iuid=2332033043
igid=4294966419 mode=ffff obj=system_u:system_r:unconfined_t
type=SYSCALL msg=audit(1129732008.219:27): arch=40000003 syscall=117
success=yes exit=98306 a0=2 a1=0 a2=1 a3=1ff items=0 pid=3107
auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0
comm="a.out" exe="/tmp/a.out" subj=root:system_r:unconfined_t
type=SYSCALL msg=audit(1129732008.219:28): arch=40000003 syscall=117
success=yes exit=0 a0=3 a1=18002 a2=0 a3=100 items=0 pid=3107
auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0
comm="a.out" exe="/tmp/a.out" subj=root:system_r:unconfined_t
:-Dustin
19 years
Re: [PATCH] LSPP audit enablement: storing selinux ocontext and scontext
by Dustin Kirkland
Ok, sorry for the repeated posting of the patch. I'm trying to keep it
in sync with the feedback I'm receiving.
Steve Grubb asked that I remove the parts of the patch that defined the
LSPP message types, as he just posted a patch that did just that.
I'm complying and posting an updated patch here.
Thanks,
:-Dustin
diff -urpN linux-2.6.14-rc4/include/linux/audit.h
linux-2.6.14-rc4-context_labels/include/linux/audit.h
--- linux-2.6.14-rc4/include/linux/audit.h 2005-10-19 09:40:27.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/include/linux/audit.h 2005-10-20 13:46:27.000000000 -0500
@@ -232,12 +232,14 @@ extern void auditsc_get_stamp(struct aud
struct timespec *t, unsigned int *serial);
extern int audit_set_loginuid(struct task_struct *task, uid_t loginuid);
extern uid_t audit_get_loginuid(struct audit_context *ctx);
-extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode);
+extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp);
extern int audit_socketcall(int nargs, unsigned long *args);
extern int audit_sockaddr(int len, void *addr);
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);
+char *audit_ipc_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 +257,8 @@ 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; })
+#define audit_ipc_context(i) do { ; } while (0)
+#define audit_set_macxattr(n) do { ; } while (0)
#endif
#ifdef CONFIG_AUDIT
@@ -283,6 +287,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 +298,7 @@ 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)
+#define audit_panic(m) do { ; } while (0)
#endif
#endif
#endif
diff -urpN linux-2.6.14-rc4/include/linux/security.h linux-2.6.14-rc4-context_labels/include/linux/security.h
--- linux-2.6.14-rc4/include/linux/security.h 2005-10-19 09:40:28.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/include/linux/security.h 2005-10-19 06:52:20.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:
@@ -1091,6 +1096,7 @@ struct security_operations {
int (*inode_getxattr) (struct dentry *dentry, char *name);
int (*inode_listxattr) (struct dentry *dentry);
int (*inode_removexattr) (struct dentry *dentry, char *name);
+ char *(*inode_xattr_getsuffix) (void);
int (*inode_getsecurity)(struct inode *inode, const char *name, void *buffer, size_t size);
int (*inode_setsecurity)(struct inode *inode, const char *name, const void *value, size_t size, int flags);
int (*inode_listsecurity)(struct inode *inode, char *buffer, size_t buffer_size);
@@ -1140,6 +1146,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);
@@ -1580,6 +1587,11 @@ static inline int security_inode_removex
return security_ops->inode_removexattr (dentry, name);
}
+static inline const char *security_inode_xattr_getsuffix(void)
+{
+ return security_ops->inode_xattr_getsuffix();
+}
+
static inline int security_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size)
{
if (unlikely (IS_PRIVATE (inode)))
@@ -1775,6 +1787,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);
@@ -2222,6 +2239,11 @@ static inline int security_inode_removex
return cap_inode_removexattr(dentry, name);
}
+static inline const char *security_inode_xattr_getsuffix (void)
+{
+ return NULL ;
+}
+
static inline int security_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size)
{
return -EOPNOTSUPP;
@@ -2405,6 +2427,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 -urpN linux-2.6.14-rc4/ipc/msg.c linux-2.6.14-rc4-context_labels/ipc/msg.c
--- linux-2.6.14-rc4/ipc/msg.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/ipc/msg.c 2005-10-19 06:52:20.000000000 -0500
@@ -428,8 +428,6 @@ 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;
@@ -460,6 +458,9 @@ asmlinkage long sys_msgctl (int msqid, i
switch (cmd) {
case IPC_SET:
{
+ if ((err = audit_ipc_perms(setbuf.qbytes, setbuf.uid, setbuf.gid, setbuf.mode, ipcp)))
+ goto out_unlock_up;
+
err = -EPERM;
if (setbuf.qbytes > msg_ctlmnb && !capable(CAP_SYS_RESOURCE))
goto out_unlock_up;
diff -urpN linux-2.6.14-rc4/ipc/sem.c linux-2.6.14-rc4-context_labels/ipc/sem.c
--- linux-2.6.14-rc4/ipc/sem.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/ipc/sem.c 2005-10-19 06:52:20.000000000 -0500
@@ -806,8 +806,6 @@ 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)
@@ -818,7 +816,6 @@ static int semctl_down(int semid, int se
goto out_unlock;
}
ipcp = &sma->sem_perm;
-
if (current->euid != ipcp->cuid &&
current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) {
err=-EPERM;
@@ -835,6 +832,8 @@ static int semctl_down(int semid, int se
err = 0;
break;
case IPC_SET:
+ if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode, ipcp)))
+ goto out_unlock;
ipcp->uid = setbuf.uid;
ipcp->gid = setbuf.gid;
ipcp->mode = (ipcp->mode & ~S_IRWXUGO)
diff -urpN linux-2.6.14-rc4/ipc/shm.c linux-2.6.14-rc4-context_labels/ipc/shm.c
--- linux-2.6.14-rc4/ipc/shm.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/ipc/shm.c 2005-10-19 06:52:20.000000000 -0500
@@ -604,13 +604,13 @@ 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;
if(shp==NULL)
goto out_up;
+ if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode, &(shp->shm_perm))))
+ goto out_unlock_up;
err = shm_checkid(shp,shmid);
if(err)
goto out_unlock_up;
diff -urpN linux-2.6.14-rc4/ipc/util.c linux-2.6.14-rc4-context_labels/ipc/util.c
--- linux-2.6.14-rc4/ipc/util.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/ipc/util.c 2005-10-19 10:51:12.000000000 -0500
@@ -26,6 +26,7 @@
#include <linux/workqueue.h>
#include <linux/seq_file.h>
#include <linux/proc_fs.h>
+#include <linux/audit.h>
#include <asm/unistd.h>
@@ -466,6 +467,7 @@ 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_context(ipcp);
requested_mode = (flag >> 6) | (flag >> 3) | flag;
granted_mode = ipcp->mode;
if (current->euid == ipcp->cuid || current->euid == ipcp->uid)
diff -urpN linux-2.6.14-rc4/kernel/audit.c linux-2.6.14-rc4-context_labels/kernel/audit.c
--- linux-2.6.14-rc4/kernel/audit.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/kernel/audit.c 2005-10-19 06:52:20.000000000 -0500
@@ -142,7 +142,7 @@ static void audit_set_pid(struct audit_b
nlh->nlmsg_pid = pid;
}
-static void audit_panic(const char *message)
+void audit_panic(const char *message)
{
switch (audit_failure)
{
diff -urpN linux-2.6.14-rc4/kernel/auditsc.c linux-2.6.14-rc4-context_labels/kernel/auditsc.c
--- linux-2.6.14-rc4/kernel/auditsc.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/kernel/auditsc.c 2005-10-20 11:10:24.000000000 -0500
@@ -2,6 +2,7 @@
* Handles all system-call specific auditing features.
*
* Copyright 2003-2004 Red Hat Inc., Durham, North Carolina.
+ * Copyright (C) IBM Corporation, 2005
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -27,6 +28,9 @@
* this file -- see entry.S) is based on a GPL'd patch written by
* okir(a)suse.de and Copyright 2003 SuSE Linux AG.
*
+ * Subject and object context labeling support added by <danjones(a)us.ibm.com>
+ * and <dustin.kirkland(a)us.ibm.com> for LSPP certification compliance.
+ *
*/
#include <linux/init.h>
@@ -43,6 +47,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 +104,7 @@ struct audit_names {
gid_t gid;
dev_t rdev;
unsigned flags;
+ char *ctx;
};
struct audit_aux_data {
@@ -115,6 +121,7 @@ struct audit_aux_data_ipcctl {
uid_t uid;
gid_t gid;
mode_t mode;
+ char *ctx;
};
struct audit_aux_data_socketcall {
@@ -661,10 +668,12 @@ static inline void audit_free_names(stru
context->serial, context->major, context->in_syscall,
context->name_count, context->put_count,
context->ino_count);
- for (i = 0; i < context->name_count; i++)
+ for (i = 0; i < context->name_count; i++) {
printk(KERN_ERR "names[%d] = %p = %s\n", i,
context->names[i].name,
context->names[i].name);
+ kfree(context->names[i].ctx);
+ }
dump_stack();
return;
}
@@ -696,6 +705,12 @@ static inline void audit_free_aux(struct
dput(axi->dentry);
mntput(axi->mnt);
}
+ if ( aux->type == AUDIT_IPC ) {
+ struct audit_aux_data_ipcctl *axi = (void *)aux;
+ if (axi->ctx)
+ kfree(axi->ctx);
+ }
+
context->aux = aux->next;
kfree(aux);
}
@@ -775,6 +790,37 @@ static inline void audit_free_context(st
printk(KERN_ERR "audit: freed %d contexts\n", count);
}
+static void audit_log_task_context(struct audit_buffer *ab)
+{
+ char *ctx = NULL;
+ ssize_t len = 0;
+
+ len = security_getprocattr(current, "current", NULL, 0);
+ if (len < 0) {
+ if (len != -EINVAL)
+ goto error_path;
+ return;
+ }
+
+ ctx = kmalloc(len, GFP_KERNEL);
+ if (!ctx) {
+ goto error_path;
+ return;
+ }
+
+ len = security_getprocattr(current, "current", ctx, len);
+ if (len < 0 )
+ goto error_path;
+
+ audit_log_format(ab, " subj=%s", ctx);
+
+error_path:
+ if (ctx)
+ kfree(ctx);
+ audit_panic("security_getprocattr error in audit_log_task_context");
+ return;
+}
+
static void audit_log_task_info(struct audit_buffer *ab)
{
char name[sizeof(current->comm)];
@@ -801,6 +847,7 @@ static void audit_log_task_info(struct a
vma = vma->vm_next;
}
up_read(&mm->mmap_sem);
+ audit_log_task_context(ab);
}
static void audit_log_exit(struct audit_context *context, unsigned int gfp_mask)
@@ -849,8 +896,8 @@ static void audit_log_exit(struct audit_
case AUDIT_IPC: {
struct audit_aux_data_ipcctl *axi = (void *)aux;
audit_log_format(ab,
- " qbytes=%lx iuid=%u igid=%u mode=%x",
- axi->qbytes, axi->uid, axi->gid, axi->mode);
+ " qbytes=%lx iuid=%u igid=%u mode=%x obj=%s",
+ axi->qbytes, axi->uid, axi->gid, axi->mode, axi->ctx);
break; }
case AUDIT_SOCKETCALL: {
@@ -907,6 +954,11 @@ 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].ctx) {
+ audit_log_format(ab, " obj=%s",
+ context->names[i].ctx);
+ }
+
audit_log_end(ab);
}
}
@@ -1122,6 +1174,37 @@ void audit_putname(const char *name)
#endif
}
+void audit_inode_context(int idx, const struct inode *inode)
+{
+ struct audit_context *context = current->audit_context;
+ char *ctx = NULL;
+ int len = 0;
+
+ if (!security_inode_xattr_getsuffix())
+ return;
+
+ len = security_inode_getsecurity(inode, (char *)security_inode_xattr_getsuffix(), NULL, 0);
+ if (len < 0)
+ goto error_path;
+
+ ctx = kmalloc(len, GFP_KERNEL);
+ if (!ctx)
+ goto error_path;
+
+ len = security_inode_getsecurity(inode, (char *)security_inode_xattr_getsuffix(), ctx, len);
+ if (len < 0)
+ goto error_path;
+
+ context->names[idx].ctx = ctx;
+ return;
+
+error_path:
+ if (ctx)
+ kfree(ctx);
+ audit_panic("error in audit_inode_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)
@@ -1157,6 +1240,7 @@ 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_context(idx, inode);
}
void auditsc_get_stamp(struct audit_context *ctx,
@@ -1193,7 +1277,7 @@ uid_t audit_get_loginuid(struct audit_co
return ctx ? ctx->loginuid : -1;
}
-int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode)
+int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp)
{
struct audit_aux_data_ipcctl *ax;
struct audit_context *context = current->audit_context;
@@ -1201,7 +1285,7 @@ int audit_ipc_perms(unsigned long qbytes
if (likely(!context))
return 0;
- ax = kmalloc(sizeof(*ax), GFP_KERNEL);
+ ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
if (!ax)
return -ENOMEM;
@@ -1209,6 +1293,7 @@ int audit_ipc_perms(unsigned long qbytes
ax->uid = uid;
ax->gid = gid;
ax->mode = mode;
+ ax->ctx = audit_ipc_context(ipcp);
ax->d.type = AUDIT_IPC;
ax->d.next = context->aux;
@@ -1216,6 +1301,36 @@ int audit_ipc_perms(unsigned long qbytes
return 0;
}
+char *audit_ipc_context(struct kern_ipc_perm *ipcp)
+{
+ struct audit_context *context = current->audit_context;
+ char *ctx = NULL;
+ int len = 0;
+
+ if (likely(!context))
+ return NULL;
+
+ len = security_ipc_getsecurity(ipcp, NULL, 0);
+ if (len < 0)
+ goto error_path;
+
+ ctx = kmalloc(len, GFP_ATOMIC);
+ if (!ctx)
+ goto error_path;
+
+ len = security_ipc_getsecurity(ipcp, ctx, len);
+ if (len < 0)
+ goto error_path;
+
+ return ctx;
+
+error_path:
+ if (ctx)
+ kfree(ctx);
+ audit_panic("error in audit_ipc_context");
+ return NULL;
+}
+
int audit_socketcall(int nargs, unsigned long *args)
{
struct audit_aux_data_socketcall *ax;
diff -urpN linux-2.6.14-rc4/security/dummy.c linux-2.6.14-rc4-context_labels/security/dummy.c
--- linux-2.6.14-rc4/security/dummy.c 2005-10-19 09:40:31.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/security/dummy.c 2005-10-19 06:52:20.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 -urpN linux-2.6.14-rc4/security/selinux/hooks.c linux-2.6.14-rc4-context_labels/security/selinux/hooks.c
--- linux-2.6.14-rc4/security/selinux/hooks.c 2005-10-19 09:40:31.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/security/selinux/hooks.c 2005-10-19 06:52:20.000000000 -0500
@@ -116,6 +116,32 @@ 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;
+
+ rc = security_sid_to_context(sid, &context, &len);
+ if (rc)
+ return rc;
+
+ if (!buffer || !size)
+ goto getsecurity_exit;
+
+ if (size < len) {
+ len = -ERANGE;
+ goto getsecurity_exit;
+ }
+ 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)
@@ -2247,33 +2273,21 @@ static int selinux_inode_removexattr (st
return -EACCES;
}
+static const char *selinux_inode_xattr_getsuffix(void)
+{
+ return XATTR_SELINUX_SUFFIX;
+}
+
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,
@@ -4045,6 +4059,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)
{
@@ -4086,8 +4107,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) {
@@ -4096,9 +4116,6 @@ static int selinux_getprocattr(struct ta
return error;
}
- if (!size)
- return -ERANGE;
-
tsec = p->security;
if (!strcmp(name, "current"))
@@ -4115,16 +4132,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,
@@ -4282,6 +4290,7 @@ static struct security_operations selinu
.inode_getxattr = selinux_inode_getxattr,
.inode_listxattr = selinux_inode_listxattr,
.inode_removexattr = selinux_inode_removexattr,
+ .inode_xattr_getsuffix = selinux_inode_xattr_getsuffix,
.inode_getsecurity = selinux_inode_getsecurity,
.inode_setsecurity = selinux_inode_setsecurity,
.inode_listsecurity = selinux_inode_listsecurity,
@@ -4319,6 +4328,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,
19 years
Re: [PATCH] LSPP audit enablement: storing selinux ocontext and scontext
by Dustin Kirkland
With copyright and changelog statements.
diff -uprN linux-2.6.14-rc4/include/linux/audit.h
linux-2.6.14-rc4-context_labels/include/linux/audit.h
--- linux-2.6.14-rc4/include/linux/audit.h 2005-10-19 09:40:27.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/include/linux/audit.h 2005-10-19 10:51:34.000000000 -0500
@@ -33,7 +33,8 @@
* 1200 - 1299 messages internal to the audit daemon
* 1300 - 1399 audit event messages
* 1400 - 1499 SE Linux use
- * 1500 - 1999 future use
+ * 1500 - 1599 labeled security messages (LSPP)
+ * 1600 - 1999 future use
* 2000 is for otherwise unclassified kernel audit messages
*
* Messages from 1000-1199 are bi-directional. 1200-1299 are exclusively user
@@ -232,12 +233,14 @@ extern void auditsc_get_stamp(struct aud
struct timespec *t, unsigned int *serial);
extern int audit_set_loginuid(struct task_struct *task, uid_t loginuid);
extern uid_t audit_get_loginuid(struct audit_context *ctx);
-extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode);
+extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp);
extern int audit_socketcall(int nargs, unsigned long *args);
extern int audit_sockaddr(int len, void *addr);
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);
+char *audit_ipc_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,8 @@ 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; })
+#define audit_ipc_context(i) do { ; } while (0)
+#define audit_set_macxattr(n) do { ; } while (0)
#endif
#ifdef CONFIG_AUDIT
@@ -283,6 +288,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 +299,7 @@ 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)
+#define audit_panic(m) do { ; } while (0)
#endif
#endif
#endif
diff -uprN linux-2.6.14-rc4/include/linux/security.h linux-2.6.14-rc4-context_labels/include/linux/security.h
--- linux-2.6.14-rc4/include/linux/security.h 2005-10-19 09:40:28.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/include/linux/security.h 2005-10-19 06:52:20.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:
@@ -1091,6 +1096,7 @@ struct security_operations {
int (*inode_getxattr) (struct dentry *dentry, char *name);
int (*inode_listxattr) (struct dentry *dentry);
int (*inode_removexattr) (struct dentry *dentry, char *name);
+ char *(*inode_xattr_getsuffix) (void);
int (*inode_getsecurity)(struct inode *inode, const char *name, void *buffer, size_t size);
int (*inode_setsecurity)(struct inode *inode, const char *name, const void *value, size_t size, int flags);
int (*inode_listsecurity)(struct inode *inode, char *buffer, size_t buffer_size);
@@ -1140,6 +1146,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);
@@ -1580,6 +1587,11 @@ static inline int security_inode_removex
return security_ops->inode_removexattr (dentry, name);
}
+static inline const char *security_inode_xattr_getsuffix(void)
+{
+ return security_ops->inode_xattr_getsuffix();
+}
+
static inline int security_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size)
{
if (unlikely (IS_PRIVATE (inode)))
@@ -1775,6 +1787,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);
@@ -2222,6 +2239,11 @@ static inline int security_inode_removex
return cap_inode_removexattr(dentry, name);
}
+static inline const char *security_inode_xattr_getsuffix (void)
+{
+ return NULL ;
+}
+
static inline int security_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size)
{
return -EOPNOTSUPP;
@@ -2405,6 +2427,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.14-rc4/ipc/msg.c linux-2.6.14-rc4-context_labels/ipc/msg.c
--- linux-2.6.14-rc4/ipc/msg.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/ipc/msg.c 2005-10-19 06:52:20.000000000 -0500
@@ -428,8 +428,6 @@ 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;
@@ -460,6 +458,9 @@ asmlinkage long sys_msgctl (int msqid, i
switch (cmd) {
case IPC_SET:
{
+ if ((err = audit_ipc_perms(setbuf.qbytes, setbuf.uid, setbuf.gid, setbuf.mode, ipcp)))
+ goto out_unlock_up;
+
err = -EPERM;
if (setbuf.qbytes > msg_ctlmnb && !capable(CAP_SYS_RESOURCE))
goto out_unlock_up;
diff -uprN linux-2.6.14-rc4/ipc/sem.c linux-2.6.14-rc4-context_labels/ipc/sem.c
--- linux-2.6.14-rc4/ipc/sem.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/ipc/sem.c 2005-10-19 06:52:20.000000000 -0500
@@ -806,8 +806,6 @@ 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)
@@ -818,7 +816,6 @@ static int semctl_down(int semid, int se
goto out_unlock;
}
ipcp = &sma->sem_perm;
-
if (current->euid != ipcp->cuid &&
current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) {
err=-EPERM;
@@ -835,6 +832,8 @@ static int semctl_down(int semid, int se
err = 0;
break;
case IPC_SET:
+ if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode, ipcp)))
+ goto out_unlock;
ipcp->uid = setbuf.uid;
ipcp->gid = setbuf.gid;
ipcp->mode = (ipcp->mode & ~S_IRWXUGO)
diff -uprN linux-2.6.14-rc4/ipc/shm.c linux-2.6.14-rc4-context_labels/ipc/shm.c
--- linux-2.6.14-rc4/ipc/shm.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/ipc/shm.c 2005-10-19 06:52:20.000000000 -0500
@@ -604,13 +604,13 @@ 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;
if(shp==NULL)
goto out_up;
+ if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode, &(shp->shm_perm))))
+ goto out_unlock_up;
err = shm_checkid(shp,shmid);
if(err)
goto out_unlock_up;
diff -uprN linux-2.6.14-rc4/ipc/util.c linux-2.6.14-rc4-context_labels/ipc/util.c
--- linux-2.6.14-rc4/ipc/util.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/ipc/util.c 2005-10-19 10:51:12.000000000 -0500
@@ -26,6 +26,7 @@
#include <linux/workqueue.h>
#include <linux/seq_file.h>
#include <linux/proc_fs.h>
+#include <linux/audit.h>
#include <asm/unistd.h>
@@ -466,6 +467,7 @@ 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_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.14-rc4/kernel/audit.c linux-2.6.14-rc4-context_labels/kernel/audit.c
--- linux-2.6.14-rc4/kernel/audit.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/kernel/audit.c 2005-10-19 06:52:20.000000000 -0500
@@ -142,7 +142,7 @@ static void audit_set_pid(struct audit_b
nlh->nlmsg_pid = pid;
}
-static void audit_panic(const char *message)
+void audit_panic(const char *message)
{
switch (audit_failure)
{
diff -uprN linux-2.6.14-rc4/kernel/auditsc.c linux-2.6.14-rc4-context_labels/kernel/auditsc.c
--- linux-2.6.14-rc4/kernel/auditsc.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/kernel/auditsc.c 2005-10-20 11:10:24.000000000 -0500
@@ -2,6 +2,7 @@
* Handles all system-call specific auditing features.
*
* Copyright 2003-2004 Red Hat Inc., Durham, North Carolina.
+ * Copyright (C) IBM Corporation, 2005
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -27,6 +28,9 @@
* this file -- see entry.S) is based on a GPL'd patch written by
* okir(a)suse.de and Copyright 2003 SuSE Linux AG.
*
+ * Subject and object context labeling support added by <danjones(a)us.ibm.com>
+ * and <dustin.kirkland(a)us.ibm.com> for LSPP certification compliance.
+ *
*/
#include <linux/init.h>
@@ -43,6 +47,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 +104,7 @@ struct audit_names {
gid_t gid;
dev_t rdev;
unsigned flags;
+ char *ctx;
};
struct audit_aux_data {
@@ -115,6 +121,7 @@ struct audit_aux_data_ipcctl {
uid_t uid;
gid_t gid;
mode_t mode;
+ char *ctx;
};
struct audit_aux_data_socketcall {
@@ -661,10 +668,12 @@ static inline void audit_free_names(stru
context->serial, context->major, context->in_syscall,
context->name_count, context->put_count,
context->ino_count);
- for (i = 0; i < context->name_count; i++)
+ for (i = 0; i < context->name_count; i++) {
printk(KERN_ERR "names[%d] = %p = %s\n", i,
context->names[i].name,
context->names[i].name);
+ kfree(context->names[i].ctx);
+ }
dump_stack();
return;
}
@@ -696,6 +705,12 @@ static inline void audit_free_aux(struct
dput(axi->dentry);
mntput(axi->mnt);
}
+ if ( aux->type == AUDIT_IPC ) {
+ struct audit_aux_data_ipcctl *axi = (void *)aux;
+ if (axi->ctx)
+ kfree(axi->ctx);
+ }
+
context->aux = aux->next;
kfree(aux);
}
@@ -775,6 +790,37 @@ static inline void audit_free_context(st
printk(KERN_ERR "audit: freed %d contexts\n", count);
}
+static void audit_log_task_context(struct audit_buffer *ab)
+{
+ char *ctx = NULL;
+ ssize_t len = 0;
+
+ len = security_getprocattr(current, "current", NULL, 0);
+ if (len < 0) {
+ if (len != -EINVAL)
+ goto error_path;
+ return;
+ }
+
+ ctx = kmalloc(len, GFP_KERNEL);
+ if (!ctx) {
+ goto error_path;
+ return;
+ }
+
+ len = security_getprocattr(current, "current", ctx, len);
+ if (len < 0 )
+ goto error_path;
+
+ audit_log_format(ab, " subj=%s", ctx);
+
+error_path:
+ if (ctx)
+ kfree(ctx);
+ audit_panic("security_getprocattr error in audit_log_task_context");
+ return;
+}
+
static void audit_log_task_info(struct audit_buffer *ab)
{
char name[sizeof(current->comm)];
@@ -801,6 +847,7 @@ static void audit_log_task_info(struct a
vma = vma->vm_next;
}
up_read(&mm->mmap_sem);
+ audit_log_task_context(ab);
}
static void audit_log_exit(struct audit_context *context, unsigned int gfp_mask)
@@ -849,8 +896,8 @@ static void audit_log_exit(struct audit_
case AUDIT_IPC: {
struct audit_aux_data_ipcctl *axi = (void *)aux;
audit_log_format(ab,
- " qbytes=%lx iuid=%u igid=%u mode=%x",
- axi->qbytes, axi->uid, axi->gid, axi->mode);
+ " qbytes=%lx iuid=%u igid=%u mode=%x obj=%s",
+ axi->qbytes, axi->uid, axi->gid, axi->mode, axi->ctx);
break; }
case AUDIT_SOCKETCALL: {
@@ -907,6 +954,11 @@ 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].ctx) {
+ audit_log_format(ab, " obj=%s",
+ context->names[i].ctx);
+ }
+
audit_log_end(ab);
}
}
@@ -1122,6 +1174,37 @@ void audit_putname(const char *name)
#endif
}
+void audit_inode_context(int idx, const struct inode *inode)
+{
+ struct audit_context *context = current->audit_context;
+ char *ctx = NULL;
+ int len = 0;
+
+ if (!security_inode_xattr_getsuffix())
+ return;
+
+ len = security_inode_getsecurity(inode, (char *)security_inode_xattr_getsuffix(), NULL, 0);
+ if (len < 0)
+ goto error_path;
+
+ ctx = kmalloc(len, GFP_KERNEL);
+ if (!ctx)
+ goto error_path;
+
+ len = security_inode_getsecurity(inode, (char *)security_inode_xattr_getsuffix(), ctx, len);
+ if (len < 0)
+ goto error_path;
+
+ context->names[idx].ctx = ctx;
+ return;
+
+error_path:
+ if (ctx)
+ kfree(ctx);
+ audit_panic("error in audit_inode_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)
@@ -1157,6 +1240,7 @@ 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_context(idx, inode);
}
void auditsc_get_stamp(struct audit_context *ctx,
@@ -1193,7 +1277,7 @@ uid_t audit_get_loginuid(struct audit_co
return ctx ? ctx->loginuid : -1;
}
-int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode)
+int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp)
{
struct audit_aux_data_ipcctl *ax;
struct audit_context *context = current->audit_context;
@@ -1201,7 +1285,7 @@ int audit_ipc_perms(unsigned long qbytes
if (likely(!context))
return 0;
- ax = kmalloc(sizeof(*ax), GFP_KERNEL);
+ ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
if (!ax)
return -ENOMEM;
@@ -1209,6 +1293,7 @@ int audit_ipc_perms(unsigned long qbytes
ax->uid = uid;
ax->gid = gid;
ax->mode = mode;
+ ax->ctx = audit_ipc_context(ipcp);
ax->d.type = AUDIT_IPC;
ax->d.next = context->aux;
@@ -1216,6 +1301,36 @@ int audit_ipc_perms(unsigned long qbytes
return 0;
}
+char *audit_ipc_context(struct kern_ipc_perm *ipcp)
+{
+ struct audit_context *context = current->audit_context;
+ char *ctx = NULL;
+ int len = 0;
+
+ if (likely(!context))
+ return NULL;
+
+ len = security_ipc_getsecurity(ipcp, NULL, 0);
+ if (len < 0)
+ goto error_path;
+
+ ctx = kmalloc(len, GFP_ATOMIC);
+ if (!ctx)
+ goto error_path;
+
+ len = security_ipc_getsecurity(ipcp, ctx, len);
+ if (len < 0)
+ goto error_path;
+
+ return ctx;
+
+error_path:
+ if (ctx)
+ kfree(ctx);
+ audit_panic("error in audit_ipc_context");
+ return NULL;
+}
+
int audit_socketcall(int nargs, unsigned long *args)
{
struct audit_aux_data_socketcall *ax;
diff -uprN linux-2.6.14-rc4/security/dummy.c linux-2.6.14-rc4-context_labels/security/dummy.c
--- linux-2.6.14-rc4/security/dummy.c 2005-10-19 09:40:31.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/security/dummy.c 2005-10-19 06:52:20.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.14-rc4/security/selinux/hooks.c linux-2.6.14-rc4-context_labels/security/selinux/hooks.c
--- linux-2.6.14-rc4/security/selinux/hooks.c 2005-10-19 09:40:31.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/security/selinux/hooks.c 2005-10-19 06:52:20.000000000 -0500
@@ -116,6 +116,32 @@ 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;
+
+ rc = security_sid_to_context(sid, &context, &len);
+ if (rc)
+ return rc;
+
+ if (!buffer || !size)
+ goto getsecurity_exit;
+
+ if (size < len) {
+ len = -ERANGE;
+ goto getsecurity_exit;
+ }
+ 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)
@@ -2247,33 +2273,21 @@ static int selinux_inode_removexattr (st
return -EACCES;
}
+static const char *selinux_inode_xattr_getsuffix(void)
+{
+ return XATTR_SELINUX_SUFFIX;
+}
+
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,
@@ -4045,6 +4059,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)
{
@@ -4086,8 +4107,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) {
@@ -4096,9 +4116,6 @@ static int selinux_getprocattr(struct ta
return error;
}
- if (!size)
- return -ERANGE;
-
tsec = p->security;
if (!strcmp(name, "current"))
@@ -4115,16 +4132,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,
@@ -4282,6 +4290,7 @@ static struct security_operations selinu
.inode_getxattr = selinux_inode_getxattr,
.inode_listxattr = selinux_inode_listxattr,
.inode_removexattr = selinux_inode_removexattr,
+ .inode_xattr_getsuffix = selinux_inode_xattr_getsuffix,
.inode_getsecurity = selinux_inode_getsecurity,
.inode_setsecurity = selinux_inode_setsecurity,
.inode_listsecurity = selinux_inode_listsecurity,
@@ -4319,6 +4328,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,
19 years
Re: [PATCH 0/2] filesystem auditing: augment audit_inode
by Dustin Kirkland
On 10/19/05, Amy Griffis <amy.griffis(a)hp.com> wrote:
> 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.
Thanks, Amy.
> 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.
Just out of curiosity, why is that? Are you suggesting that these inode
auditing patches should be in a separate tree than the subj/obj labeling
patches that I submitted?
:-Dustin
19 years
audit 1.0.7 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:
- Updated reports
- Add new message types
- Bug fixes
There are numerous fixups throughout the code. This release introduces a lot
of new user space message types for future application usage.
Please let me know if there are any problems with this release.
Thanks,
-Steve
19 years
Re: [PATCH] LSPP audit enablement: storing selinux ocontext and scontext
by Dustin Kirkland
On 10/13/05, Amy Griffis <amy.griffis(a)hp.com> wrote:
> On Fri, Oct 07, 2005 at 01:24:13PM -0500, Dustin Kirkland wrote:
> > Some have suggested propagating errno's up to the calling syscalls.
> > This rippled into other unforeseen places in my efforts to accomplish
> > this and I never found a clean implementation.
>
> Okay, I can take a look at improving the error handling when I get a
> chance.
Would be appreciated. Especially if you can base your work off of this
work that I've already started ;)
> > > I'd prefer not to add another aux struct just to hold ipc security
> > > context. I don't see any reason why this couldn't be added to
> > > audit_aux_data_ipcctl below.
> >
> > Well, audit_aux_data_security_context is a little more generic than
> > audit_aux_data_ipcctl (which is ipc-specific). I tend to disagree with
> > this suggestion, as the security_context information should be across
> > objects besides just ipc.
>
> I can't think of a reason to make it generic other than to save
> space. Since the other aux data structs are already allocated
> dynamically, this approach is actually taking more space as well as
> introducing the overhead of having to walk more elements in the aux
> list.
Ok, I've come around to your point of view. Now, the context is char
*ctx within the audit_aux_data_ipc structure.
This may not be the final word, however. I can see reasons for both
approaches, with the context labels simply appended onto existing
records, or with context labels being auxiliary records connected to
existing records. The implementation in this patch, though, behaves as
you suggest, adding the context data to the char *ctx in the data
structure and simply appending subj=... or obj=... to the rest of the
audit record.
> > > Also, the security_context_len field is unused.
> >
> > That's true. It's easily enough removed. But as is, it's simply
> > mimmicing the definition of audit_aux_sockaddr. I'm ambivalent about
> > this change. I'm leaving as is, since it mirrors previous struct
> > definitions. If the consensus is to eliminate it, I'm not opposed...
>
> I don't see why we would want to add an unused field just to look
> like another structure.
Ok, I've removed it.
> > Following the standard set forth by the rest of this file, it seems
> > that the preferred manner in which to create an extension to an
> > audit record is to create a structure as above to hold the new data.
>
> You added a security_context field to audit_names. So adding a
> comparable field to audit_aux_data_ipcctl makes sense.
Agreed. Done.
> By the way, have you run into any issues with allocating memory during
> path_lookup?
No, none yet.
> Thanks. Just make sure to clarify that this patch is for collecting
> security label context for inodes and ipc only, and I'll be happy. :-)
You are correct. There is still work to be done to audit the subj/obj
labels for sockets. I should be very clear about that ;)
--
A couple of other comments...
- There's still work to be done if the audit_panic()'s are to be
replaced with mechanisms to propagate up errno's to the launching
syscalls. Amy said in her previous email that she might look into this.
I will as well, but this bothers me less than it bothers other people,
so I'm hoping those offended by the audit_panic()'s within this patch
might post patches that demonstrate their preferred approaches.
- This patch reduced some of the verbage required for several functions
and variables. In several places, "security_context" was replaced with
"context", such as
s/audit_ipc_security_context/audit_ipc_context/g
s/audit_log_task_security_context/audit_log_task_context/g
s/audit_aux_data_security_context/audit_aux_data_context/g
s/audit_inode_security_context/audit_inode_context/g
Additionally, the audit_names data structure uses char *ctx instead of
char *security_context now (which fits in more with gid,rdev,flags,
etc).
- I also ported this patch forward to the 2.6.14-rc4 kernel such that
David might be able to more easily apply it to his tree.
Please let me know if anyone is offended by these unrequested changes.
If this seems good enough to start testing, I'd like to see David merge
into his try by the end of the week. Thanks!
Updated patch attached.
:-Dustin
diff -uprN linux-2.6.14-rc4/include/linux/audit.h
linux-2.6.14-rc4-context_labels/include/linux/audit.h
--- linux-2.6.14-rc4/include/linux/audit.h 2005-10-19 09:40:27.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/include/linux/audit.h 2005-10-19 10:51:34.000000000 -0500
@@ -33,7 +33,8 @@
* 1200 - 1299 messages internal to the audit daemon
* 1300 - 1399 audit event messages
* 1400 - 1499 SE Linux use
- * 1500 - 1999 future use
+ * 1500 - 1599 labeled security messages (LSPP)
+ * 1600 - 1999 future use
* 2000 is for otherwise unclassified kernel audit messages
*
* Messages from 1000-1199 are bi-directional. 1200-1299 are exclusively user
@@ -232,12 +233,14 @@ extern void auditsc_get_stamp(struct aud
struct timespec *t, unsigned int *serial);
extern int audit_set_loginuid(struct task_struct *task, uid_t loginuid);
extern uid_t audit_get_loginuid(struct audit_context *ctx);
-extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode);
+extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp);
extern int audit_socketcall(int nargs, unsigned long *args);
extern int audit_sockaddr(int len, void *addr);
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);
+char *audit_ipc_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,8 @@ 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; })
+#define audit_ipc_context(i) do { ; } while (0)
+#define audit_set_macxattr(n) do { ; } while (0)
#endif
#ifdef CONFIG_AUDIT
@@ -283,6 +288,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 +299,7 @@ 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)
+#define audit_panic(m) do { ; } while (0)
#endif
#endif
#endif
diff -uprN linux-2.6.14-rc4/include/linux/security.h linux-2.6.14-rc4-context_labels/include/linux/security.h
--- linux-2.6.14-rc4/include/linux/security.h 2005-10-19 09:40:28.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/include/linux/security.h 2005-10-19 06:52:20.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:
@@ -1091,6 +1096,7 @@ struct security_operations {
int (*inode_getxattr) (struct dentry *dentry, char *name);
int (*inode_listxattr) (struct dentry *dentry);
int (*inode_removexattr) (struct dentry *dentry, char *name);
+ char *(*inode_xattr_getsuffix) (void);
int (*inode_getsecurity)(struct inode *inode, const char *name, void *buffer, size_t size);
int (*inode_setsecurity)(struct inode *inode, const char *name, const void *value, size_t size, int flags);
int (*inode_listsecurity)(struct inode *inode, char *buffer, size_t buffer_size);
@@ -1140,6 +1146,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);
@@ -1580,6 +1587,11 @@ static inline int security_inode_removex
return security_ops->inode_removexattr (dentry, name);
}
+static inline const char *security_inode_xattr_getsuffix(void)
+{
+ return security_ops->inode_xattr_getsuffix();
+}
+
static inline int security_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size)
{
if (unlikely (IS_PRIVATE (inode)))
@@ -1775,6 +1787,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);
@@ -2222,6 +2239,11 @@ static inline int security_inode_removex
return cap_inode_removexattr(dentry, name);
}
+static inline const char *security_inode_xattr_getsuffix (void)
+{
+ return NULL ;
+}
+
static inline int security_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size)
{
return -EOPNOTSUPP;
@@ -2405,6 +2427,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.14-rc4/ipc/msg.c linux-2.6.14-rc4-context_labels/ipc/msg.c
--- linux-2.6.14-rc4/ipc/msg.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/ipc/msg.c 2005-10-19 06:52:20.000000000 -0500
@@ -428,8 +428,6 @@ 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;
@@ -460,6 +458,9 @@ asmlinkage long sys_msgctl (int msqid, i
switch (cmd) {
case IPC_SET:
{
+ if ((err = audit_ipc_perms(setbuf.qbytes, setbuf.uid, setbuf.gid, setbuf.mode, ipcp)))
+ goto out_unlock_up;
+
err = -EPERM;
if (setbuf.qbytes > msg_ctlmnb && !capable(CAP_SYS_RESOURCE))
goto out_unlock_up;
diff -uprN linux-2.6.14-rc4/ipc/sem.c linux-2.6.14-rc4-context_labels/ipc/sem.c
--- linux-2.6.14-rc4/ipc/sem.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/ipc/sem.c 2005-10-19 06:52:20.000000000 -0500
@@ -806,8 +806,6 @@ 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)
@@ -818,7 +816,6 @@ static int semctl_down(int semid, int se
goto out_unlock;
}
ipcp = &sma->sem_perm;
-
if (current->euid != ipcp->cuid &&
current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) {
err=-EPERM;
@@ -835,6 +832,8 @@ static int semctl_down(int semid, int se
err = 0;
break;
case IPC_SET:
+ if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode, ipcp)))
+ goto out_unlock;
ipcp->uid = setbuf.uid;
ipcp->gid = setbuf.gid;
ipcp->mode = (ipcp->mode & ~S_IRWXUGO)
diff -uprN linux-2.6.14-rc4/ipc/shm.c linux-2.6.14-rc4-context_labels/ipc/shm.c
--- linux-2.6.14-rc4/ipc/shm.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/ipc/shm.c 2005-10-19 06:52:20.000000000 -0500
@@ -604,13 +604,13 @@ 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;
if(shp==NULL)
goto out_up;
+ if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode, &(shp->shm_perm))))
+ goto out_unlock_up;
err = shm_checkid(shp,shmid);
if(err)
goto out_unlock_up;
diff -uprN linux-2.6.14-rc4/ipc/util.c linux-2.6.14-rc4-context_labels/ipc/util.c
--- linux-2.6.14-rc4/ipc/util.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/ipc/util.c 2005-10-19 10:51:12.000000000 -0500
@@ -26,6 +26,7 @@
#include <linux/workqueue.h>
#include <linux/seq_file.h>
#include <linux/proc_fs.h>
+#include <linux/audit.h>
#include <asm/unistd.h>
@@ -466,6 +467,7 @@ 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_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.14-rc4/kernel/audit.c linux-2.6.14-rc4-context_labels/kernel/audit.c
--- linux-2.6.14-rc4/kernel/audit.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/kernel/audit.c 2005-10-19 06:52:20.000000000 -0500
@@ -142,7 +142,7 @@ static void audit_set_pid(struct audit_b
nlh->nlmsg_pid = pid;
}
-static void audit_panic(const char *message)
+void audit_panic(const char *message)
{
switch (audit_failure)
{
diff -uprN linux-2.6.14-rc4/kernel/auditsc.c linux-2.6.14-rc4-context_labels/kernel/auditsc.c
--- linux-2.6.14-rc4/kernel/auditsc.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/kernel/auditsc.c 2005-10-19 11:19:39.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 *ctx;
};
struct audit_aux_data {
@@ -115,6 +117,7 @@ struct audit_aux_data_ipcctl {
uid_t uid;
gid_t gid;
mode_t mode;
+ char *ctx;
};
struct audit_aux_data_socketcall {
@@ -661,10 +664,12 @@ static inline void audit_free_names(stru
context->serial, context->major, context->in_syscall,
context->name_count, context->put_count,
context->ino_count);
- for (i = 0; i < context->name_count; i++)
+ for (i = 0; i < context->name_count; i++) {
printk(KERN_ERR "names[%d] = %p = %s\n", i,
context->names[i].name,
context->names[i].name);
+ kfree(context->names[i].ctx);
+ }
dump_stack();
return;
}
@@ -696,6 +701,12 @@ static inline void audit_free_aux(struct
dput(axi->dentry);
mntput(axi->mnt);
}
+ if ( aux->type == AUDIT_IPC ) {
+ struct audit_aux_data_ipcctl *axi = (void *)aux;
+ if (axi->ctx)
+ kfree(axi->ctx);
+ }
+
context->aux = aux->next;
kfree(aux);
}
@@ -775,6 +786,37 @@ static inline void audit_free_context(st
printk(KERN_ERR "audit: freed %d contexts\n", count);
}
+static void audit_log_task_context(struct audit_buffer *ab)
+{
+ char *ctx = NULL;
+ ssize_t len = 0;
+
+ len = security_getprocattr(current, "current", NULL, 0);
+ if (len < 0) {
+ if (len != -EINVAL)
+ goto error_path;
+ return;
+ }
+
+ ctx = kmalloc(len, GFP_KERNEL);
+ if (!ctx) {
+ goto error_path;
+ return;
+ }
+
+ len = security_getprocattr(current, "current", ctx, len);
+ if (len < 0 )
+ goto error_path;
+
+ audit_log_format(ab, " subj=%s", ctx);
+
+error_path:
+ if (ctx)
+ kfree(ctx);
+ audit_panic("security_getprocattr error in audit_log_task_context");
+ return;
+}
+
static void audit_log_task_info(struct audit_buffer *ab)
{
char name[sizeof(current->comm)];
@@ -801,6 +843,7 @@ static void audit_log_task_info(struct a
vma = vma->vm_next;
}
up_read(&mm->mmap_sem);
+ audit_log_task_context(ab);
}
static void audit_log_exit(struct audit_context *context, unsigned int gfp_mask)
@@ -849,8 +892,8 @@ static void audit_log_exit(struct audit_
case AUDIT_IPC: {
struct audit_aux_data_ipcctl *axi = (void *)aux;
audit_log_format(ab,
- " qbytes=%lx iuid=%u igid=%u mode=%x",
- axi->qbytes, axi->uid, axi->gid, axi->mode);
+ " qbytes=%lx iuid=%u igid=%u mode=%x obj=%s",
+ axi->qbytes, axi->uid, axi->gid, axi->mode, axi->ctx);
break; }
case AUDIT_SOCKETCALL: {
@@ -907,6 +950,11 @@ 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].ctx) {
+ audit_log_format(ab, " obj=%s",
+ context->names[i].ctx);
+ }
+
audit_log_end(ab);
}
}
@@ -1122,6 +1170,37 @@ void audit_putname(const char *name)
#endif
}
+void audit_inode_context(int idx, const struct inode *inode)
+{
+ struct audit_context *context = current->audit_context;
+ char *ctx = NULL;
+ int len = 0;
+
+ if (!security_inode_xattr_getsuffix())
+ return;
+
+ len = security_inode_getsecurity(inode, (char *)security_inode_xattr_getsuffix(), NULL, 0);
+ if (len < 0)
+ goto error_path;
+
+ ctx = kmalloc(len, GFP_KERNEL);
+ if (!ctx)
+ goto error_path;
+
+ len = security_inode_getsecurity(inode, (char *)security_inode_xattr_getsuffix(), ctx, len);
+ if (len < 0)
+ goto error_path;
+
+ context->names[idx].ctx = ctx;
+ return;
+
+error_path:
+ if (ctx)
+ kfree(ctx);
+ audit_panic("error in audit_inode_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)
@@ -1157,6 +1236,7 @@ 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_context(idx, inode);
}
void auditsc_get_stamp(struct audit_context *ctx,
@@ -1193,7 +1273,7 @@ uid_t audit_get_loginuid(struct audit_co
return ctx ? ctx->loginuid : -1;
}
-int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode)
+int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp)
{
struct audit_aux_data_ipcctl *ax;
struct audit_context *context = current->audit_context;
@@ -1201,7 +1281,7 @@ int audit_ipc_perms(unsigned long qbytes
if (likely(!context))
return 0;
- ax = kmalloc(sizeof(*ax), GFP_KERNEL);
+ ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
if (!ax)
return -ENOMEM;
@@ -1209,6 +1289,7 @@ int audit_ipc_perms(unsigned long qbytes
ax->uid = uid;
ax->gid = gid;
ax->mode = mode;
+ ax->ctx = audit_ipc_context(ipcp);
ax->d.type = AUDIT_IPC;
ax->d.next = context->aux;
@@ -1216,6 +1297,36 @@ int audit_ipc_perms(unsigned long qbytes
return 0;
}
+char *audit_ipc_context(struct kern_ipc_perm *ipcp)
+{
+ struct audit_context *context = current->audit_context;
+ char *ctx = NULL;
+ int len = 0;
+
+ if (likely(!context))
+ return NULL;
+
+ len = security_ipc_getsecurity(ipcp, NULL, 0);
+ if (len < 0)
+ goto error_path;
+
+ ctx = kmalloc(len, GFP_ATOMIC);
+ if (!ctx)
+ goto error_path;
+
+ len = security_ipc_getsecurity(ipcp, ctx, len);
+ if (len < 0)
+ goto error_path;
+
+ return ctx;
+
+error_path:
+ if (ctx)
+ kfree(ctx);
+ audit_panic("error in audit_ipc_context");
+ return NULL;
+}
+
int audit_socketcall(int nargs, unsigned long *args)
{
struct audit_aux_data_socketcall *ax;
diff -uprN linux-2.6.14-rc4/security/dummy.c linux-2.6.14-rc4-context_labels/security/dummy.c
--- linux-2.6.14-rc4/security/dummy.c 2005-10-19 09:40:31.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/security/dummy.c 2005-10-19 06:52:20.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.14-rc4/security/selinux/hooks.c linux-2.6.14-rc4-context_labels/security/selinux/hooks.c
--- linux-2.6.14-rc4/security/selinux/hooks.c 2005-10-19 09:40:31.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/security/selinux/hooks.c 2005-10-19 06:52:20.000000000 -0500
@@ -116,6 +116,32 @@ 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;
+
+ rc = security_sid_to_context(sid, &context, &len);
+ if (rc)
+ return rc;
+
+ if (!buffer || !size)
+ goto getsecurity_exit;
+
+ if (size < len) {
+ len = -ERANGE;
+ goto getsecurity_exit;
+ }
+ 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)
@@ -2247,33 +2273,21 @@ static int selinux_inode_removexattr (st
return -EACCES;
}
+static const char *selinux_inode_xattr_getsuffix(void)
+{
+ return XATTR_SELINUX_SUFFIX;
+}
+
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,
@@ -4045,6 +4059,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)
{
@@ -4086,8 +4107,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) {
@@ -4096,9 +4116,6 @@ static int selinux_getprocattr(struct ta
return error;
}
- if (!size)
- return -ERANGE;
-
tsec = p->security;
if (!strcmp(name, "current"))
@@ -4115,16 +4132,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,
@@ -4282,6 +4290,7 @@ static struct security_operations selinu
.inode_getxattr = selinux_inode_getxattr,
.inode_listxattr = selinux_inode_listxattr,
.inode_removexattr = selinux_inode_removexattr,
+ .inode_xattr_getsuffix = selinux_inode_xattr_getsuffix,
.inode_getsecurity = selinux_inode_getsecurity,
.inode_setsecurity = selinux_inode_setsecurity,
.inode_listsecurity = selinux_inode_listsecurity,
@@ -4319,6 +4328,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,
19 years