diff options
Diffstat (limited to 'kernel/auditsc.c')
-rw-r--r-- | kernel/auditsc.c | 142 |
1 files changed, 134 insertions, 8 deletions
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 | ||
114 | struct audit_aux_data { | 119 | struct 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 | ||
130 | struct audit_aux_data_socketcall { | 136 | struct 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 | ||
865 | static void audit_log_task_info(struct audit_buffer *ab) | 882 | static 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 | |||
906 | error_path: | ||
907 | if (ctx) | ||
908 | kfree(ctx); | ||
909 | audit_panic("security_getprocattr error in audit_log_task_context"); | ||
910 | return; | ||
911 | } | ||
912 | |||
913 | static 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 | ||
893 | static void audit_log_exit(struct audit_context *context, gfp_t gfp_mask) | 946 | static 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 | ||
1304 | void 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 | |||
1329 | error_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 | ||
1519 | static 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 | |||
1544 | error_path: | ||
1545 | kfree(ctx); | ||
1546 | audit_panic("error in audit_ipc_context"); | ||
1547 | ret: | ||
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 | */ |
1435 | int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode) | 1560 | int 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; |