aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorDustin Kirkland <dustin.kirkland@us.ibm.com>2005-11-03 12:15:16 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2006-03-20 14:08:54 -0500
commit8c8570fb8feef2bc166bee75a85748b25cda22d9 (patch)
treeed783d405ea9d5f3d3ccc57fb56c7b7cb2cdfb82 /kernel
parentc8edc80c8b8c397c53f4f659a05b9ea6208029bf (diff)
[PATCH] Capture selinux subject/object context information.
This patch extends existing audit records with subject/object context information. Audit records associated with filesystem inodes, ipc, and tasks now contain SELinux label information in the field "subj" if the item is performing the action, or in "obj" if the item is the receiver of an action. These labels are collected via hooks in SELinux and appended to the appropriate record in the audit code. This additional information is required for Common Criteria Labeled Security Protection Profile (LSPP). [AV: fixed kmalloc flags use] [folded leak fixes] [folded cleanup from akpm (kfree(NULL)] [folded audit_inode_context() leak fix] [folded akpm's fix for audit_ipc_perm() definition in case of !CONFIG_AUDIT] Signed-off-by: Dustin Kirkland <dustin.kirkland@us.ibm.com> Signed-off-by: David Woodhouse <dwmw2@infradead.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/audit.c2
-rw-r--r--kernel/auditsc.c142
2 files changed, 135 insertions, 9 deletions
diff --git a/kernel/audit.c b/kernel/audit.c
index 1c3eb1b12bfc..45c123ef77a7 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -142,7 +142,7 @@ static void audit_set_pid(struct audit_buffer *ab, pid_t pid)
142 nlh->nlmsg_pid = pid; 142 nlh->nlmsg_pid = pid;
143} 143}
144 144
145static void audit_panic(const char *message) 145void audit_panic(const char *message)
146{ 146{
147 switch (audit_failure) 147 switch (audit_failure)
148 { 148 {
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 31917ac730af..4e2256ec7cf3 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -34,6 +34,9 @@
34 * 34 *
35 * Modified by Amy Griffis <amy.griffis@hp.com> to collect additional 35 * Modified by Amy Griffis <amy.griffis@hp.com> to collect additional
36 * filesystem information. 36 * filesystem information.
37 *
38 * Subject and object context labeling support added by <danjones@us.ibm.com>
39 * and <dustin.kirkland@us.ibm.com> for LSPP certification compliance.
37 */ 40 */
38 41
39#include <linux/init.h> 42#include <linux/init.h>
@@ -53,6 +56,7 @@
53#include <linux/netlink.h> 56#include <linux/netlink.h>
54#include <linux/compiler.h> 57#include <linux/compiler.h>
55#include <asm/unistd.h> 58#include <asm/unistd.h>
59#include <linux/security.h>
56 60
57/* 0 = no checking 61/* 0 = no checking
58 1 = put_count checking 62 1 = put_count checking
@@ -109,6 +113,7 @@ struct audit_names {
109 uid_t uid; 113 uid_t uid;
110 gid_t gid; 114 gid_t gid;
111 dev_t rdev; 115 dev_t rdev;
116 char *ctx;
112}; 117};
113 118
114struct audit_aux_data { 119struct audit_aux_data {
@@ -125,6 +130,7 @@ struct audit_aux_data_ipcctl {
125 uid_t uid; 130 uid_t uid;
126 gid_t gid; 131 gid_t gid;
127 mode_t mode; 132 mode_t mode;
133 char *ctx;
128}; 134};
129 135
130struct audit_aux_data_socketcall { 136struct audit_aux_data_socketcall {
@@ -743,10 +749,11 @@ static inline void audit_free_names(struct audit_context *context)
743 context->serial, context->major, context->in_syscall, 749 context->serial, context->major, context->in_syscall,
744 context->name_count, context->put_count, 750 context->name_count, context->put_count,
745 context->ino_count); 751 context->ino_count);
746 for (i = 0; i < context->name_count; i++) 752 for (i = 0; i < context->name_count; i++) {
747 printk(KERN_ERR "names[%d] = %p = %s\n", i, 753 printk(KERN_ERR "names[%d] = %p = %s\n", i,
748 context->names[i].name, 754 context->names[i].name,
749 context->names[i].name ?: "(null)"); 755 context->names[i].name ?: "(null)");
756 }
750 dump_stack(); 757 dump_stack();
751 return; 758 return;
752 } 759 }
@@ -756,9 +763,13 @@ static inline void audit_free_names(struct audit_context *context)
756 context->ino_count = 0; 763 context->ino_count = 0;
757#endif 764#endif
758 765
759 for (i = 0; i < context->name_count; i++) 766 for (i = 0; i < context->name_count; i++) {
767 char *p = context->names[i].ctx;
768 context->names[i].ctx = NULL;
769 kfree(p);
760 if (context->names[i].name) 770 if (context->names[i].name)
761 __putname(context->names[i].name); 771 __putname(context->names[i].name);
772 }
762 context->name_count = 0; 773 context->name_count = 0;
763 if (context->pwd) 774 if (context->pwd)
764 dput(context->pwd); 775 dput(context->pwd);
@@ -778,6 +789,12 @@ static inline void audit_free_aux(struct audit_context *context)
778 dput(axi->dentry); 789 dput(axi->dentry);
779 mntput(axi->mnt); 790 mntput(axi->mnt);
780 } 791 }
792 if ( aux->type == AUDIT_IPC ) {
793 struct audit_aux_data_ipcctl *axi = (void *)aux;
794 if (axi->ctx)
795 kfree(axi->ctx);
796 }
797
781 context->aux = aux->next; 798 context->aux = aux->next;
782 kfree(aux); 799 kfree(aux);
783 } 800 }
@@ -862,7 +879,38 @@ static inline void audit_free_context(struct audit_context *context)
862 printk(KERN_ERR "audit: freed %d contexts\n", count); 879 printk(KERN_ERR "audit: freed %d contexts\n", count);
863} 880}
864 881
865static void audit_log_task_info(struct audit_buffer *ab) 882static void audit_log_task_context(struct audit_buffer *ab, gfp_t gfp_mask)
883{
884 char *ctx = NULL;
885 ssize_t len = 0;
886
887 len = security_getprocattr(current, "current", NULL, 0);
888 if (len < 0) {
889 if (len != -EINVAL)
890 goto error_path;
891 return;
892 }
893
894 ctx = kmalloc(len, gfp_mask);
895 if (!ctx) {
896 goto error_path;
897 return;
898 }
899
900 len = security_getprocattr(current, "current", ctx, len);
901 if (len < 0 )
902 goto error_path;
903
904 audit_log_format(ab, " subj=%s", ctx);
905
906error_path:
907 if (ctx)
908 kfree(ctx);
909 audit_panic("security_getprocattr error in audit_log_task_context");
910 return;
911}
912
913static void audit_log_task_info(struct audit_buffer *ab, gfp_t gfp_mask)
866{ 914{
867 char name[sizeof(current->comm)]; 915 char name[sizeof(current->comm)];
868 struct mm_struct *mm = current->mm; 916 struct mm_struct *mm = current->mm;
@@ -875,6 +923,10 @@ static void audit_log_task_info(struct audit_buffer *ab)
875 if (!mm) 923 if (!mm)
876 return; 924 return;
877 925
926 /*
927 * this is brittle; all callers that pass GFP_ATOMIC will have
928 * NULL current->mm and we won't get here.
929 */
878 down_read(&mm->mmap_sem); 930 down_read(&mm->mmap_sem);
879 vma = mm->mmap; 931 vma = mm->mmap;
880 while (vma) { 932 while (vma) {
@@ -888,6 +940,7 @@ static void audit_log_task_info(struct audit_buffer *ab)
888 vma = vma->vm_next; 940 vma = vma->vm_next;
889 } 941 }
890 up_read(&mm->mmap_sem); 942 up_read(&mm->mmap_sem);
943 audit_log_task_context(ab, gfp_mask);
891} 944}
892 945
893static void audit_log_exit(struct audit_context *context, gfp_t gfp_mask) 946static void audit_log_exit(struct audit_context *context, gfp_t gfp_mask)
@@ -923,7 +976,7 @@ static void audit_log_exit(struct audit_context *context, gfp_t gfp_mask)
923 context->gid, 976 context->gid,
924 context->euid, context->suid, context->fsuid, 977 context->euid, context->suid, context->fsuid,
925 context->egid, context->sgid, context->fsgid); 978 context->egid, context->sgid, context->fsgid);
926 audit_log_task_info(ab); 979 audit_log_task_info(ab, gfp_mask);
927 audit_log_end(ab); 980 audit_log_end(ab);
928 981
929 for (aux = context->aux; aux; aux = aux->next) { 982 for (aux = context->aux; aux; aux = aux->next) {
@@ -936,8 +989,8 @@ static void audit_log_exit(struct audit_context *context, gfp_t gfp_mask)
936 case AUDIT_IPC: { 989 case AUDIT_IPC: {
937 struct audit_aux_data_ipcctl *axi = (void *)aux; 990 struct audit_aux_data_ipcctl *axi = (void *)aux;
938 audit_log_format(ab, 991 audit_log_format(ab,
939 " qbytes=%lx iuid=%u igid=%u mode=%x", 992 " qbytes=%lx iuid=%u igid=%u mode=%x obj=%s",
940 axi->qbytes, axi->uid, axi->gid, axi->mode); 993 axi->qbytes, axi->uid, axi->gid, axi->mode, axi->ctx);
941 break; } 994 break; }
942 995
943 case AUDIT_SOCKETCALL: { 996 case AUDIT_SOCKETCALL: {
@@ -1001,6 +1054,11 @@ static void audit_log_exit(struct audit_context *context, gfp_t gfp_mask)
1001 context->names[i].gid, 1054 context->names[i].gid,
1002 MAJOR(context->names[i].rdev), 1055 MAJOR(context->names[i].rdev),
1003 MINOR(context->names[i].rdev)); 1056 MINOR(context->names[i].rdev));
1057 if (context->names[i].ctx) {
1058 audit_log_format(ab, " obj=%s",
1059 context->names[i].ctx);
1060 }
1061
1004 audit_log_end(ab); 1062 audit_log_end(ab);
1005 } 1063 }
1006} 1064}
@@ -1243,6 +1301,39 @@ void audit_putname(const char *name)
1243#endif 1301#endif
1244} 1302}
1245 1303
1304void audit_inode_context(int idx, const struct inode *inode)
1305{
1306 struct audit_context *context = current->audit_context;
1307 char *ctx = NULL;
1308 int len = 0;
1309
1310 if (!security_inode_xattr_getsuffix())
1311 return;
1312
1313 len = security_inode_getsecurity(inode, (char *)security_inode_xattr_getsuffix(), NULL, 0, 0);
1314 if (len < 0)
1315 goto error_path;
1316
1317 ctx = kmalloc(len, GFP_KERNEL);
1318 if (!ctx)
1319 goto error_path;
1320
1321 len = security_inode_getsecurity(inode, (char *)security_inode_xattr_getsuffix(), ctx, len, 0);
1322 if (len < 0)
1323 goto error_path;
1324
1325 kfree(context->names[idx].ctx);
1326 context->names[idx].ctx = ctx;
1327 return;
1328
1329error_path:
1330 if (ctx)
1331 kfree(ctx);
1332 audit_panic("error in audit_inode_context");
1333 return;
1334}
1335
1336
1246/** 1337/**
1247 * audit_inode - store the inode and device from a lookup 1338 * audit_inode - store the inode and device from a lookup
1248 * @name: name being audited 1339 * @name: name being audited
@@ -1282,6 +1373,7 @@ void __audit_inode(const char *name, const struct inode *inode, unsigned flags)
1282 context->names[idx].uid = inode->i_uid; 1373 context->names[idx].uid = inode->i_uid;
1283 context->names[idx].gid = inode->i_gid; 1374 context->names[idx].gid = inode->i_gid;
1284 context->names[idx].rdev = inode->i_rdev; 1375 context->names[idx].rdev = inode->i_rdev;
1376 audit_inode_context(idx, inode);
1285 if ((flags & LOOKUP_PARENT) && (strcmp(name, "/") != 0) && 1377 if ((flags & LOOKUP_PARENT) && (strcmp(name, "/") != 0) &&
1286 (strcmp(name, ".") != 0)) { 1378 (strcmp(name, ".") != 0)) {
1287 context->names[idx].ino = (unsigned long)-1; 1379 context->names[idx].ino = (unsigned long)-1;
@@ -1363,6 +1455,7 @@ update_context:
1363 context->names[idx].uid = inode->i_uid; 1455 context->names[idx].uid = inode->i_uid;
1364 context->names[idx].gid = inode->i_gid; 1456 context->names[idx].gid = inode->i_gid;
1365 context->names[idx].rdev = inode->i_rdev; 1457 context->names[idx].rdev = inode->i_rdev;
1458 audit_inode_context(idx, inode);
1366 } 1459 }
1367} 1460}
1368 1461
@@ -1423,6 +1516,38 @@ uid_t audit_get_loginuid(struct audit_context *ctx)
1423 return ctx ? ctx->loginuid : -1; 1516 return ctx ? ctx->loginuid : -1;
1424} 1517}
1425 1518
1519static char *audit_ipc_context(struct kern_ipc_perm *ipcp)
1520{
1521 struct audit_context *context = current->audit_context;
1522 char *ctx = NULL;
1523 int len = 0;
1524
1525 if (likely(!context))
1526 return NULL;
1527
1528 len = security_ipc_getsecurity(ipcp, NULL, 0);
1529 if (len == -EOPNOTSUPP)
1530 goto ret;
1531 if (len < 0)
1532 goto error_path;
1533
1534 ctx = kmalloc(len, GFP_ATOMIC);
1535 if (!ctx)
1536 goto error_path;
1537
1538 len = security_ipc_getsecurity(ipcp, ctx, len);
1539 if (len < 0)
1540 goto error_path;
1541
1542 return ctx;
1543
1544error_path:
1545 kfree(ctx);
1546 audit_panic("error in audit_ipc_context");
1547ret:
1548 return NULL;
1549}
1550
1426/** 1551/**
1427 * audit_ipc_perms - record audit data for ipc 1552 * audit_ipc_perms - record audit data for ipc
1428 * @qbytes: msgq bytes 1553 * @qbytes: msgq bytes
@@ -1432,7 +1557,7 @@ uid_t audit_get_loginuid(struct audit_context *ctx)
1432 * 1557 *
1433 * Returns 0 for success or NULL context or < 0 on error. 1558 * Returns 0 for success or NULL context or < 0 on error.
1434 */ 1559 */
1435int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode) 1560int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp)
1436{ 1561{
1437 struct audit_aux_data_ipcctl *ax; 1562 struct audit_aux_data_ipcctl *ax;
1438 struct audit_context *context = current->audit_context; 1563 struct audit_context *context = current->audit_context;
@@ -1440,7 +1565,7 @@ int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode)
1440 if (likely(!context)) 1565 if (likely(!context))
1441 return 0; 1566 return 0;
1442 1567
1443 ax = kmalloc(sizeof(*ax), GFP_KERNEL); 1568 ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
1444 if (!ax) 1569 if (!ax)
1445 return -ENOMEM; 1570 return -ENOMEM;
1446 1571
@@ -1448,6 +1573,7 @@ int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode)
1448 ax->uid = uid; 1573 ax->uid = uid;
1449 ax->gid = gid; 1574 ax->gid = gid;
1450 ax->mode = mode; 1575 ax->mode = mode;
1576 ax->ctx = audit_ipc_context(ipcp);
1451 1577
1452 ax->d.type = AUDIT_IPC; 1578 ax->d.type = AUDIT_IPC;
1453 ax->d.next = context->aux; 1579 ax->d.next = context->aux;