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,