diff options
-rw-r--r-- | include/linux/capability.h | 5 | ||||
-rw-r--r-- | kernel/auditsc.c | 82 |
2 files changed, 82 insertions, 5 deletions
diff --git a/include/linux/capability.h b/include/linux/capability.h index d567af247ed8..0f1950181102 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h | |||
@@ -53,6 +53,7 @@ typedef struct __user_cap_data_struct { | |||
53 | #define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX | 53 | #define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX |
54 | 54 | ||
55 | #define VFS_CAP_REVISION_MASK 0xFF000000 | 55 | #define VFS_CAP_REVISION_MASK 0xFF000000 |
56 | #define VFS_CAP_REVISION_SHIFT 24 | ||
56 | #define VFS_CAP_FLAGS_MASK ~VFS_CAP_REVISION_MASK | 57 | #define VFS_CAP_FLAGS_MASK ~VFS_CAP_REVISION_MASK |
57 | #define VFS_CAP_FLAGS_EFFECTIVE 0x000001 | 58 | #define VFS_CAP_FLAGS_EFFECTIVE 0x000001 |
58 | 59 | ||
@@ -534,6 +535,10 @@ kernel_cap_t cap_set_effective(const kernel_cap_t pE_new); | |||
534 | 535 | ||
535 | extern int capable(int cap); | 536 | extern int capable(int cap); |
536 | 537 | ||
538 | /* audit system wants to get cap info from files as well */ | ||
539 | struct dentry; | ||
540 | extern int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps); | ||
541 | |||
537 | #endif /* __KERNEL__ */ | 542 | #endif /* __KERNEL__ */ |
538 | 543 | ||
539 | #endif /* !_LINUX_CAPABILITY_H */ | 544 | #endif /* !_LINUX_CAPABILITY_H */ |
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index cf5bc2f5f9c3..de7e9bcba9ae 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
@@ -65,6 +65,7 @@ | |||
65 | #include <linux/highmem.h> | 65 | #include <linux/highmem.h> |
66 | #include <linux/syscalls.h> | 66 | #include <linux/syscalls.h> |
67 | #include <linux/inotify.h> | 67 | #include <linux/inotify.h> |
68 | #include <linux/capability.h> | ||
68 | 69 | ||
69 | #include "audit.h" | 70 | #include "audit.h" |
70 | 71 | ||
@@ -84,6 +85,15 @@ int audit_n_rules; | |||
84 | /* determines whether we collect data for signals sent */ | 85 | /* determines whether we collect data for signals sent */ |
85 | int audit_signals; | 86 | int audit_signals; |
86 | 87 | ||
88 | struct audit_cap_data { | ||
89 | kernel_cap_t permitted; | ||
90 | kernel_cap_t inheritable; | ||
91 | union { | ||
92 | unsigned int fE; /* effective bit of a file capability */ | ||
93 | kernel_cap_t effective; /* effective set of a process */ | ||
94 | }; | ||
95 | }; | ||
96 | |||
87 | /* When fs/namei.c:getname() is called, we store the pointer in name and | 97 | /* When fs/namei.c:getname() is called, we store the pointer in name and |
88 | * we don't let putname() free it (instead we free all of the saved | 98 | * we don't let putname() free it (instead we free all of the saved |
89 | * pointers at syscall exit time). | 99 | * pointers at syscall exit time). |
@@ -100,6 +110,8 @@ struct audit_names { | |||
100 | gid_t gid; | 110 | gid_t gid; |
101 | dev_t rdev; | 111 | dev_t rdev; |
102 | u32 osid; | 112 | u32 osid; |
113 | struct audit_cap_data fcap; | ||
114 | unsigned int fcap_ver; | ||
103 | }; | 115 | }; |
104 | 116 | ||
105 | struct audit_aux_data { | 117 | struct audit_aux_data { |
@@ -1171,6 +1183,35 @@ static void audit_log_execve_info(struct audit_context *context, | |||
1171 | kfree(buf); | 1183 | kfree(buf); |
1172 | } | 1184 | } |
1173 | 1185 | ||
1186 | static void audit_log_cap(struct audit_buffer *ab, char *prefix, kernel_cap_t *cap) | ||
1187 | { | ||
1188 | int i; | ||
1189 | |||
1190 | audit_log_format(ab, " %s=", prefix); | ||
1191 | CAP_FOR_EACH_U32(i) { | ||
1192 | audit_log_format(ab, "%08x", cap->cap[(_KERNEL_CAPABILITY_U32S-1) - i]); | ||
1193 | } | ||
1194 | } | ||
1195 | |||
1196 | static void audit_log_fcaps(struct audit_buffer *ab, struct audit_names *name) | ||
1197 | { | ||
1198 | kernel_cap_t *perm = &name->fcap.permitted; | ||
1199 | kernel_cap_t *inh = &name->fcap.inheritable; | ||
1200 | int log = 0; | ||
1201 | |||
1202 | if (!cap_isclear(*perm)) { | ||
1203 | audit_log_cap(ab, "cap_fp", perm); | ||
1204 | log = 1; | ||
1205 | } | ||
1206 | if (!cap_isclear(*inh)) { | ||
1207 | audit_log_cap(ab, "cap_fi", inh); | ||
1208 | log = 1; | ||
1209 | } | ||
1210 | |||
1211 | if (log) | ||
1212 | audit_log_format(ab, " cap_fe=%d cap_fver=%x", name->fcap.fE, name->fcap_ver); | ||
1213 | } | ||
1214 | |||
1174 | static void audit_log_exit(struct audit_context *context, struct task_struct *tsk) | 1215 | static void audit_log_exit(struct audit_context *context, struct task_struct *tsk) |
1175 | { | 1216 | { |
1176 | int i, call_panic = 0; | 1217 | int i, call_panic = 0; |
@@ -1421,6 +1462,8 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
1421 | } | 1462 | } |
1422 | } | 1463 | } |
1423 | 1464 | ||
1465 | audit_log_fcaps(ab, n); | ||
1466 | |||
1424 | audit_log_end(ab); | 1467 | audit_log_end(ab); |
1425 | } | 1468 | } |
1426 | 1469 | ||
@@ -1787,8 +1830,36 @@ static int audit_inc_name_count(struct audit_context *context, | |||
1787 | return 0; | 1830 | return 0; |
1788 | } | 1831 | } |
1789 | 1832 | ||
1833 | |||
1834 | static inline int audit_copy_fcaps(struct audit_names *name, const struct dentry *dentry) | ||
1835 | { | ||
1836 | struct cpu_vfs_cap_data caps; | ||
1837 | int rc; | ||
1838 | |||
1839 | memset(&name->fcap.permitted, 0, sizeof(kernel_cap_t)); | ||
1840 | memset(&name->fcap.inheritable, 0, sizeof(kernel_cap_t)); | ||
1841 | name->fcap.fE = 0; | ||
1842 | name->fcap_ver = 0; | ||
1843 | |||
1844 | if (!dentry) | ||
1845 | return 0; | ||
1846 | |||
1847 | rc = get_vfs_caps_from_disk(dentry, &caps); | ||
1848 | if (rc) | ||
1849 | return rc; | ||
1850 | |||
1851 | name->fcap.permitted = caps.permitted; | ||
1852 | name->fcap.inheritable = caps.inheritable; | ||
1853 | name->fcap.fE = !!(caps.magic_etc & VFS_CAP_FLAGS_EFFECTIVE); | ||
1854 | name->fcap_ver = (caps.magic_etc & VFS_CAP_REVISION_MASK) >> VFS_CAP_REVISION_SHIFT; | ||
1855 | |||
1856 | return 0; | ||
1857 | } | ||
1858 | |||
1859 | |||
1790 | /* Copy inode data into an audit_names. */ | 1860 | /* Copy inode data into an audit_names. */ |
1791 | static void audit_copy_inode(struct audit_names *name, const struct inode *inode) | 1861 | static void audit_copy_inode(struct audit_names *name, const struct dentry *dentry, |
1862 | const struct inode *inode) | ||
1792 | { | 1863 | { |
1793 | name->ino = inode->i_ino; | 1864 | name->ino = inode->i_ino; |
1794 | name->dev = inode->i_sb->s_dev; | 1865 | name->dev = inode->i_sb->s_dev; |
@@ -1797,6 +1868,7 @@ static void audit_copy_inode(struct audit_names *name, const struct inode *inode | |||
1797 | name->gid = inode->i_gid; | 1868 | name->gid = inode->i_gid; |
1798 | name->rdev = inode->i_rdev; | 1869 | name->rdev = inode->i_rdev; |
1799 | security_inode_getsecid(inode, &name->osid); | 1870 | security_inode_getsecid(inode, &name->osid); |
1871 | audit_copy_fcaps(name, dentry); | ||
1800 | } | 1872 | } |
1801 | 1873 | ||
1802 | /** | 1874 | /** |
@@ -1831,7 +1903,7 @@ void __audit_inode(const char *name, const struct dentry *dentry) | |||
1831 | context->names[idx].name = NULL; | 1903 | context->names[idx].name = NULL; |
1832 | } | 1904 | } |
1833 | handle_path(dentry); | 1905 | handle_path(dentry); |
1834 | audit_copy_inode(&context->names[idx], inode); | 1906 | audit_copy_inode(&context->names[idx], dentry, inode); |
1835 | } | 1907 | } |
1836 | 1908 | ||
1837 | /** | 1909 | /** |
@@ -1892,7 +1964,7 @@ void __audit_inode_child(const char *dname, const struct dentry *dentry, | |||
1892 | if (!strcmp(dname, n->name) || | 1964 | if (!strcmp(dname, n->name) || |
1893 | !audit_compare_dname_path(dname, n->name, &dirlen)) { | 1965 | !audit_compare_dname_path(dname, n->name, &dirlen)) { |
1894 | if (inode) | 1966 | if (inode) |
1895 | audit_copy_inode(n, inode); | 1967 | audit_copy_inode(n, NULL, inode); |
1896 | else | 1968 | else |
1897 | n->ino = (unsigned long)-1; | 1969 | n->ino = (unsigned long)-1; |
1898 | found_child = n->name; | 1970 | found_child = n->name; |
@@ -1906,7 +1978,7 @@ add_names: | |||
1906 | return; | 1978 | return; |
1907 | idx = context->name_count - 1; | 1979 | idx = context->name_count - 1; |
1908 | context->names[idx].name = NULL; | 1980 | context->names[idx].name = NULL; |
1909 | audit_copy_inode(&context->names[idx], parent); | 1981 | audit_copy_inode(&context->names[idx], NULL, parent); |
1910 | } | 1982 | } |
1911 | 1983 | ||
1912 | if (!found_child) { | 1984 | if (!found_child) { |
@@ -1927,7 +1999,7 @@ add_names: | |||
1927 | } | 1999 | } |
1928 | 2000 | ||
1929 | if (inode) | 2001 | if (inode) |
1930 | audit_copy_inode(&context->names[idx], inode); | 2002 | audit_copy_inode(&context->names[idx], NULL, inode); |
1931 | else | 2003 | else |
1932 | context->names[idx].ino = (unsigned long)-1; | 2004 | context->names[idx].ino = (unsigned long)-1; |
1933 | } | 2005 | } |