diff options
Diffstat (limited to 'kernel/audit.c')
-rw-r--r-- | kernel/audit.c | 267 |
1 files changed, 109 insertions, 158 deletions
diff --git a/kernel/audit.c b/kernel/audit.c index 632d36059556..c89ea48c70a6 100644 --- a/kernel/audit.c +++ b/kernel/audit.c | |||
@@ -396,10 +396,10 @@ static int audit_log_config_change(char *function_name, u32 new, u32 old, | |||
396 | struct audit_buffer *ab; | 396 | struct audit_buffer *ab; |
397 | int rc = 0; | 397 | int rc = 0; |
398 | 398 | ||
399 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); | 399 | ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_CONFIG_CHANGE); |
400 | if (unlikely(!ab)) | 400 | if (unlikely(!ab)) |
401 | return rc; | 401 | return rc; |
402 | audit_log_format(ab, "%s=%u old=%u ", function_name, new, old); | 402 | audit_log_format(ab, "op=set %s=%u old=%u ", function_name, new, old); |
403 | audit_log_session_info(ab); | 403 | audit_log_session_info(ab); |
404 | rc = audit_log_task_context(ab); | 404 | rc = audit_log_task_context(ab); |
405 | if (rc) | 405 | if (rc) |
@@ -1053,7 +1053,8 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type) | |||
1053 | return err; | 1053 | return err; |
1054 | } | 1054 | } |
1055 | 1055 | ||
1056 | static void audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type) | 1056 | static void audit_log_common_recv_msg(struct audit_context *context, |
1057 | struct audit_buffer **ab, u16 msg_type) | ||
1057 | { | 1058 | { |
1058 | uid_t uid = from_kuid(&init_user_ns, current_uid()); | 1059 | uid_t uid = from_kuid(&init_user_ns, current_uid()); |
1059 | pid_t pid = task_tgid_nr(current); | 1060 | pid_t pid = task_tgid_nr(current); |
@@ -1063,7 +1064,7 @@ static void audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type) | |||
1063 | return; | 1064 | return; |
1064 | } | 1065 | } |
1065 | 1066 | ||
1066 | *ab = audit_log_start(NULL, GFP_KERNEL, msg_type); | 1067 | *ab = audit_log_start(context, GFP_KERNEL, msg_type); |
1067 | if (unlikely(!*ab)) | 1068 | if (unlikely(!*ab)) |
1068 | return; | 1069 | return; |
1069 | audit_log_format(*ab, "pid=%d uid=%u ", pid, uid); | 1070 | audit_log_format(*ab, "pid=%d uid=%u ", pid, uid); |
@@ -1071,6 +1072,12 @@ static void audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type) | |||
1071 | audit_log_task_context(*ab); | 1072 | audit_log_task_context(*ab); |
1072 | } | 1073 | } |
1073 | 1074 | ||
1075 | static inline void audit_log_user_recv_msg(struct audit_buffer **ab, | ||
1076 | u16 msg_type) | ||
1077 | { | ||
1078 | audit_log_common_recv_msg(NULL, ab, msg_type); | ||
1079 | } | ||
1080 | |||
1074 | int is_audit_feature_set(int i) | 1081 | int is_audit_feature_set(int i) |
1075 | { | 1082 | { |
1076 | return af.features & AUDIT_FEATURE_TO_MASK(i); | 1083 | return af.features & AUDIT_FEATURE_TO_MASK(i); |
@@ -1338,7 +1345,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
1338 | if (err) | 1345 | if (err) |
1339 | break; | 1346 | break; |
1340 | } | 1347 | } |
1341 | audit_log_common_recv_msg(&ab, msg_type); | 1348 | audit_log_user_recv_msg(&ab, msg_type); |
1342 | if (msg_type != AUDIT_USER_TTY) | 1349 | if (msg_type != AUDIT_USER_TTY) |
1343 | audit_log_format(ab, " msg='%.*s'", | 1350 | audit_log_format(ab, " msg='%.*s'", |
1344 | AUDIT_MESSAGE_TEXT_MAX, | 1351 | AUDIT_MESSAGE_TEXT_MAX, |
@@ -1361,8 +1368,12 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
1361 | if (nlmsg_len(nlh) < sizeof(struct audit_rule_data)) | 1368 | if (nlmsg_len(nlh) < sizeof(struct audit_rule_data)) |
1362 | return -EINVAL; | 1369 | return -EINVAL; |
1363 | if (audit_enabled == AUDIT_LOCKED) { | 1370 | if (audit_enabled == AUDIT_LOCKED) { |
1364 | audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE); | 1371 | audit_log_common_recv_msg(audit_context(), &ab, |
1365 | audit_log_format(ab, " audit_enabled=%d res=0", audit_enabled); | 1372 | AUDIT_CONFIG_CHANGE); |
1373 | audit_log_format(ab, " op=%s audit_enabled=%d res=0", | ||
1374 | msg_type == AUDIT_ADD_RULE ? | ||
1375 | "add_rule" : "remove_rule", | ||
1376 | audit_enabled); | ||
1366 | audit_log_end(ab); | 1377 | audit_log_end(ab); |
1367 | return -EPERM; | 1378 | return -EPERM; |
1368 | } | 1379 | } |
@@ -1373,7 +1384,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
1373 | break; | 1384 | break; |
1374 | case AUDIT_TRIM: | 1385 | case AUDIT_TRIM: |
1375 | audit_trim_trees(); | 1386 | audit_trim_trees(); |
1376 | audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE); | 1387 | audit_log_common_recv_msg(audit_context(), &ab, |
1388 | AUDIT_CONFIG_CHANGE); | ||
1377 | audit_log_format(ab, " op=trim res=1"); | 1389 | audit_log_format(ab, " op=trim res=1"); |
1378 | audit_log_end(ab); | 1390 | audit_log_end(ab); |
1379 | break; | 1391 | break; |
@@ -1403,8 +1415,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
1403 | /* OK, here comes... */ | 1415 | /* OK, here comes... */ |
1404 | err = audit_tag_tree(old, new); | 1416 | err = audit_tag_tree(old, new); |
1405 | 1417 | ||
1406 | audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE); | 1418 | audit_log_common_recv_msg(audit_context(), &ab, |
1407 | 1419 | AUDIT_CONFIG_CHANGE); | |
1408 | audit_log_format(ab, " op=make_equiv old="); | 1420 | audit_log_format(ab, " op=make_equiv old="); |
1409 | audit_log_untrustedstring(ab, old); | 1421 | audit_log_untrustedstring(ab, old); |
1410 | audit_log_format(ab, " new="); | 1422 | audit_log_format(ab, " new="); |
@@ -1471,7 +1483,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
1471 | old.enabled = t & AUDIT_TTY_ENABLE; | 1483 | old.enabled = t & AUDIT_TTY_ENABLE; |
1472 | old.log_passwd = !!(t & AUDIT_TTY_LOG_PASSWD); | 1484 | old.log_passwd = !!(t & AUDIT_TTY_LOG_PASSWD); |
1473 | 1485 | ||
1474 | audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE); | 1486 | audit_log_common_recv_msg(audit_context(), &ab, |
1487 | AUDIT_CONFIG_CHANGE); | ||
1475 | audit_log_format(ab, " op=tty_set old-enabled=%d new-enabled=%d" | 1488 | audit_log_format(ab, " op=tty_set old-enabled=%d new-enabled=%d" |
1476 | " old-log_passwd=%d new-log_passwd=%d res=%d", | 1489 | " old-log_passwd=%d new-log_passwd=%d res=%d", |
1477 | old.enabled, s.enabled, old.log_passwd, | 1490 | old.enabled, s.enabled, old.log_passwd, |
@@ -2054,153 +2067,6 @@ void audit_log_key(struct audit_buffer *ab, char *key) | |||
2054 | audit_log_format(ab, "(null)"); | 2067 | audit_log_format(ab, "(null)"); |
2055 | } | 2068 | } |
2056 | 2069 | ||
2057 | void audit_log_cap(struct audit_buffer *ab, char *prefix, kernel_cap_t *cap) | ||
2058 | { | ||
2059 | int i; | ||
2060 | |||
2061 | if (cap_isclear(*cap)) { | ||
2062 | audit_log_format(ab, " %s=0", prefix); | ||
2063 | return; | ||
2064 | } | ||
2065 | audit_log_format(ab, " %s=", prefix); | ||
2066 | CAP_FOR_EACH_U32(i) | ||
2067 | audit_log_format(ab, "%08x", cap->cap[CAP_LAST_U32 - i]); | ||
2068 | } | ||
2069 | |||
2070 | static void audit_log_fcaps(struct audit_buffer *ab, struct audit_names *name) | ||
2071 | { | ||
2072 | audit_log_cap(ab, "cap_fp", &name->fcap.permitted); | ||
2073 | audit_log_cap(ab, "cap_fi", &name->fcap.inheritable); | ||
2074 | audit_log_format(ab, " cap_fe=%d cap_fver=%x", | ||
2075 | name->fcap.fE, name->fcap_ver); | ||
2076 | } | ||
2077 | |||
2078 | static inline int audit_copy_fcaps(struct audit_names *name, | ||
2079 | const struct dentry *dentry) | ||
2080 | { | ||
2081 | struct cpu_vfs_cap_data caps; | ||
2082 | int rc; | ||
2083 | |||
2084 | if (!dentry) | ||
2085 | return 0; | ||
2086 | |||
2087 | rc = get_vfs_caps_from_disk(dentry, &caps); | ||
2088 | if (rc) | ||
2089 | return rc; | ||
2090 | |||
2091 | name->fcap.permitted = caps.permitted; | ||
2092 | name->fcap.inheritable = caps.inheritable; | ||
2093 | name->fcap.fE = !!(caps.magic_etc & VFS_CAP_FLAGS_EFFECTIVE); | ||
2094 | name->fcap_ver = (caps.magic_etc & VFS_CAP_REVISION_MASK) >> | ||
2095 | VFS_CAP_REVISION_SHIFT; | ||
2096 | |||
2097 | return 0; | ||
2098 | } | ||
2099 | |||
2100 | /* Copy inode data into an audit_names. */ | ||
2101 | void audit_copy_inode(struct audit_names *name, const struct dentry *dentry, | ||
2102 | struct inode *inode) | ||
2103 | { | ||
2104 | name->ino = inode->i_ino; | ||
2105 | name->dev = inode->i_sb->s_dev; | ||
2106 | name->mode = inode->i_mode; | ||
2107 | name->uid = inode->i_uid; | ||
2108 | name->gid = inode->i_gid; | ||
2109 | name->rdev = inode->i_rdev; | ||
2110 | security_inode_getsecid(inode, &name->osid); | ||
2111 | audit_copy_fcaps(name, dentry); | ||
2112 | } | ||
2113 | |||
2114 | /** | ||
2115 | * audit_log_name - produce AUDIT_PATH record from struct audit_names | ||
2116 | * @context: audit_context for the task | ||
2117 | * @n: audit_names structure with reportable details | ||
2118 | * @path: optional path to report instead of audit_names->name | ||
2119 | * @record_num: record number to report when handling a list of names | ||
2120 | * @call_panic: optional pointer to int that will be updated if secid fails | ||
2121 | */ | ||
2122 | void audit_log_name(struct audit_context *context, struct audit_names *n, | ||
2123 | const struct path *path, int record_num, int *call_panic) | ||
2124 | { | ||
2125 | struct audit_buffer *ab; | ||
2126 | ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH); | ||
2127 | if (!ab) | ||
2128 | return; | ||
2129 | |||
2130 | audit_log_format(ab, "item=%d", record_num); | ||
2131 | |||
2132 | if (path) | ||
2133 | audit_log_d_path(ab, " name=", path); | ||
2134 | else if (n->name) { | ||
2135 | switch (n->name_len) { | ||
2136 | case AUDIT_NAME_FULL: | ||
2137 | /* log the full path */ | ||
2138 | audit_log_format(ab, " name="); | ||
2139 | audit_log_untrustedstring(ab, n->name->name); | ||
2140 | break; | ||
2141 | case 0: | ||
2142 | /* name was specified as a relative path and the | ||
2143 | * directory component is the cwd */ | ||
2144 | audit_log_d_path(ab, " name=", &context->pwd); | ||
2145 | break; | ||
2146 | default: | ||
2147 | /* log the name's directory component */ | ||
2148 | audit_log_format(ab, " name="); | ||
2149 | audit_log_n_untrustedstring(ab, n->name->name, | ||
2150 | n->name_len); | ||
2151 | } | ||
2152 | } else | ||
2153 | audit_log_format(ab, " name=(null)"); | ||
2154 | |||
2155 | if (n->ino != AUDIT_INO_UNSET) | ||
2156 | audit_log_format(ab, " inode=%lu" | ||
2157 | " dev=%02x:%02x mode=%#ho" | ||
2158 | " ouid=%u ogid=%u rdev=%02x:%02x", | ||
2159 | n->ino, | ||
2160 | MAJOR(n->dev), | ||
2161 | MINOR(n->dev), | ||
2162 | n->mode, | ||
2163 | from_kuid(&init_user_ns, n->uid), | ||
2164 | from_kgid(&init_user_ns, n->gid), | ||
2165 | MAJOR(n->rdev), | ||
2166 | MINOR(n->rdev)); | ||
2167 | if (n->osid != 0) { | ||
2168 | char *ctx = NULL; | ||
2169 | u32 len; | ||
2170 | if (security_secid_to_secctx( | ||
2171 | n->osid, &ctx, &len)) { | ||
2172 | audit_log_format(ab, " osid=%u", n->osid); | ||
2173 | if (call_panic) | ||
2174 | *call_panic = 2; | ||
2175 | } else { | ||
2176 | audit_log_format(ab, " obj=%s", ctx); | ||
2177 | security_release_secctx(ctx, len); | ||
2178 | } | ||
2179 | } | ||
2180 | |||
2181 | /* log the audit_names record type */ | ||
2182 | switch(n->type) { | ||
2183 | case AUDIT_TYPE_NORMAL: | ||
2184 | audit_log_format(ab, " nametype=NORMAL"); | ||
2185 | break; | ||
2186 | case AUDIT_TYPE_PARENT: | ||
2187 | audit_log_format(ab, " nametype=PARENT"); | ||
2188 | break; | ||
2189 | case AUDIT_TYPE_CHILD_DELETE: | ||
2190 | audit_log_format(ab, " nametype=DELETE"); | ||
2191 | break; | ||
2192 | case AUDIT_TYPE_CHILD_CREATE: | ||
2193 | audit_log_format(ab, " nametype=CREATE"); | ||
2194 | break; | ||
2195 | default: | ||
2196 | audit_log_format(ab, " nametype=UNKNOWN"); | ||
2197 | break; | ||
2198 | } | ||
2199 | |||
2200 | audit_log_fcaps(ab, n); | ||
2201 | audit_log_end(ab); | ||
2202 | } | ||
2203 | |||
2204 | int audit_log_task_context(struct audit_buffer *ab) | 2070 | int audit_log_task_context(struct audit_buffer *ab) |
2205 | { | 2071 | { |
2206 | char *ctx = NULL; | 2072 | char *ctx = NULL; |
@@ -2322,6 +2188,91 @@ void audit_log_link_denied(const char *operation) | |||
2322 | audit_log_end(ab); | 2188 | audit_log_end(ab); |
2323 | } | 2189 | } |
2324 | 2190 | ||
2191 | /* global counter which is incremented every time something logs in */ | ||
2192 | static atomic_t session_id = ATOMIC_INIT(0); | ||
2193 | |||
2194 | static int audit_set_loginuid_perm(kuid_t loginuid) | ||
2195 | { | ||
2196 | /* if we are unset, we don't need privs */ | ||
2197 | if (!audit_loginuid_set(current)) | ||
2198 | return 0; | ||
2199 | /* if AUDIT_FEATURE_LOGINUID_IMMUTABLE means never ever allow a change*/ | ||
2200 | if (is_audit_feature_set(AUDIT_FEATURE_LOGINUID_IMMUTABLE)) | ||
2201 | return -EPERM; | ||
2202 | /* it is set, you need permission */ | ||
2203 | if (!capable(CAP_AUDIT_CONTROL)) | ||
2204 | return -EPERM; | ||
2205 | /* reject if this is not an unset and we don't allow that */ | ||
2206 | if (is_audit_feature_set(AUDIT_FEATURE_ONLY_UNSET_LOGINUID) | ||
2207 | && uid_valid(loginuid)) | ||
2208 | return -EPERM; | ||
2209 | return 0; | ||
2210 | } | ||
2211 | |||
2212 | static void audit_log_set_loginuid(kuid_t koldloginuid, kuid_t kloginuid, | ||
2213 | unsigned int oldsessionid, | ||
2214 | unsigned int sessionid, int rc) | ||
2215 | { | ||
2216 | struct audit_buffer *ab; | ||
2217 | uid_t uid, oldloginuid, loginuid; | ||
2218 | struct tty_struct *tty; | ||
2219 | |||
2220 | if (!audit_enabled) | ||
2221 | return; | ||
2222 | |||
2223 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_LOGIN); | ||
2224 | if (!ab) | ||
2225 | return; | ||
2226 | |||
2227 | uid = from_kuid(&init_user_ns, task_uid(current)); | ||
2228 | oldloginuid = from_kuid(&init_user_ns, koldloginuid); | ||
2229 | loginuid = from_kuid(&init_user_ns, kloginuid), | ||
2230 | tty = audit_get_tty(); | ||
2231 | |||
2232 | audit_log_format(ab, "pid=%d uid=%u", task_tgid_nr(current), uid); | ||
2233 | audit_log_task_context(ab); | ||
2234 | audit_log_format(ab, " old-auid=%u auid=%u tty=%s old-ses=%u ses=%u res=%d", | ||
2235 | oldloginuid, loginuid, tty ? tty_name(tty) : "(none)", | ||
2236 | oldsessionid, sessionid, !rc); | ||
2237 | audit_put_tty(tty); | ||
2238 | audit_log_end(ab); | ||
2239 | } | ||
2240 | |||
2241 | /** | ||
2242 | * audit_set_loginuid - set current task's loginuid | ||
2243 | * @loginuid: loginuid value | ||
2244 | * | ||
2245 | * Returns 0. | ||
2246 | * | ||
2247 | * Called (set) from fs/proc/base.c::proc_loginuid_write(). | ||
2248 | */ | ||
2249 | int audit_set_loginuid(kuid_t loginuid) | ||
2250 | { | ||
2251 | unsigned int oldsessionid, sessionid = AUDIT_SID_UNSET; | ||
2252 | kuid_t oldloginuid; | ||
2253 | int rc; | ||
2254 | |||
2255 | oldloginuid = audit_get_loginuid(current); | ||
2256 | oldsessionid = audit_get_sessionid(current); | ||
2257 | |||
2258 | rc = audit_set_loginuid_perm(loginuid); | ||
2259 | if (rc) | ||
2260 | goto out; | ||
2261 | |||
2262 | /* are we setting or clearing? */ | ||
2263 | if (uid_valid(loginuid)) { | ||
2264 | sessionid = (unsigned int)atomic_inc_return(&session_id); | ||
2265 | if (unlikely(sessionid == AUDIT_SID_UNSET)) | ||
2266 | sessionid = (unsigned int)atomic_inc_return(&session_id); | ||
2267 | } | ||
2268 | |||
2269 | current->sessionid = sessionid; | ||
2270 | current->loginuid = loginuid; | ||
2271 | out: | ||
2272 | audit_log_set_loginuid(oldloginuid, loginuid, oldsessionid, sessionid, rc); | ||
2273 | return rc; | ||
2274 | } | ||
2275 | |||
2325 | /** | 2276 | /** |
2326 | * audit_log_end - end one audit record | 2277 | * audit_log_end - end one audit record |
2327 | * @ab: the audit_buffer | 2278 | * @ab: the audit_buffer |