Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

audit: add record for multiple task security contexts

Replace the single skb pointer in an audit_buffer with a list of
skb pointers. Add the audit_stamp information to the audit_buffer as
there's no guarantee that there will be an audit_context containing
the stamp associated with the event. At audit_log_end() time create
auxiliary records as have been added to the list. Functions are
created to manage the skb list in the audit_buffer.

Create a new audit record AUDIT_MAC_TASK_CONTEXTS.
An example of the MAC_TASK_CONTEXTS record is:

type=MAC_TASK_CONTEXTS
msg=audit(1600880931.832:113)
subj_apparmor=unconfined
subj_smack=_

When an audit event includes a AUDIT_MAC_TASK_CONTEXTS record the
"subj=" field in other records in the event will be "subj=?".
An AUDIT_MAC_TASK_CONTEXTS record is supplied when the system has
multiple security modules that may make access decisions based on a
subject security context.

Refactor audit_log_task_context(), creating a new audit_log_subj_ctx().
This is used in netlabel auditing to provide multiple subject security
contexts as necessary.

Suggested-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
[PM: subj tweak, audit example readability indents]
Signed-off-by: Paul Moore <paul@paul-moore.com>

authored by

Casey Schaufler and committed by
Paul Moore
eb59d494 a59076f2

+203 -42
+16
include/linux/audit.h
··· 37 37 struct audit_tree; 38 38 struct sk_buff; 39 39 struct kern_ipc_perm; 40 + struct lsm_id; 41 + struct lsm_prop; 40 42 41 43 struct audit_krule { 42 44 u32 pflags; ··· 149 147 #define AUDIT_TTY_ENABLE BIT(0) 150 148 #define AUDIT_TTY_LOG_PASSWD BIT(1) 151 149 150 + /* bit values for audit_cfg_lsm */ 151 + #define AUDIT_CFG_LSM_SECCTX_SUBJECT BIT(0) 152 + 152 153 struct filename; 153 154 154 155 #define AUDIT_OFF 0 ··· 190 185 const char *operation); 191 186 extern void audit_log_lost(const char *message); 192 187 188 + extern int audit_log_subj_ctx(struct audit_buffer *ab, struct lsm_prop *prop); 193 189 extern int audit_log_task_context(struct audit_buffer *ab); 194 190 extern void audit_log_task_info(struct audit_buffer *ab); 195 191 ··· 215 209 extern u32 audit_enabled; 216 210 217 211 extern int audit_signal_info(int sig, struct task_struct *t); 212 + 213 + extern void audit_cfg_lsm(const struct lsm_id *lsmid, int flags); 218 214 219 215 #else /* CONFIG_AUDIT */ 220 216 static inline __printf(4, 5) ··· 253 245 { } 254 246 static inline void audit_log_path_denied(int type, const char *operation) 255 247 { } 248 + static inline int audit_log_subj_ctx(struct audit_buffer *ab, 249 + struct lsm_prop *prop) 250 + { 251 + return 0; 252 + } 256 253 static inline int audit_log_task_context(struct audit_buffer *ab) 257 254 { 258 255 return 0; ··· 281 268 { 282 269 return 0; 283 270 } 271 + 272 + static inline void audit_cfg_lsm(const struct lsm_id *lsmid, int flags) 273 + { } 284 274 285 275 #endif /* CONFIG_AUDIT */ 286 276
+1
include/uapi/linux/audit.h
··· 148 148 #define AUDIT_IPE_POLICY_LOAD 1422 /* IPE policy load */ 149 149 #define AUDIT_LANDLOCK_ACCESS 1423 /* Landlock denial */ 150 150 #define AUDIT_LANDLOCK_DOMAIN 1424 /* Landlock domain status */ 151 + #define AUDIT_MAC_TASK_CONTEXTS 1425 /* Multiple LSM task contexts */ 151 152 152 153 #define AUDIT_FIRST_KERN_ANOM_MSG 1700 153 154 #define AUDIT_LAST_KERN_ANOM_MSG 1799
+176 -34
kernel/audit.c
··· 54 54 #include <net/netlink.h> 55 55 #include <linux/skbuff.h> 56 56 #include <linux/security.h> 57 + #include <linux/lsm_hooks.h> 57 58 #include <linux/freezer.h> 58 59 #include <linux/pid_namespace.h> 59 60 #include <net/netns/generic.h> ··· 81 80 82 81 /* private audit network namespace index */ 83 82 static unsigned int audit_net_id; 83 + 84 + /* Number of modules that provide a security context. 85 + List of lsms that provide a security context */ 86 + static u32 audit_subj_secctx_cnt; 87 + static const struct lsm_id *audit_subj_lsms[MAX_LSM_COUNT]; 84 88 85 89 /** 86 90 * struct audit_net - audit private network namespace data ··· 201 195 * to place it on a transmit queue. Multiple audit_buffers can be in 202 196 * use simultaneously. */ 203 197 struct audit_buffer { 204 - struct sk_buff *skb; /* formatted skb ready to send */ 198 + struct sk_buff *skb; /* the skb for audit_log functions */ 199 + struct sk_buff_head skb_list; /* formatted skbs, ready to send */ 205 200 struct audit_context *ctx; /* NULL or associated context */ 201 + struct audit_stamp stamp; /* audit stamp for these records */ 206 202 gfp_t gfp_mask; 207 203 }; 208 204 ··· 284 276 rcu_read_unlock(); 285 277 286 278 return pid; 279 + } 280 + 281 + /** 282 + * audit_cfg_lsm - Identify a security module as providing a secctx. 283 + * @lsmid: LSM identity 284 + * @flags: which contexts are provided 285 + * 286 + * Description: 287 + * Increments the count of the security modules providing a secctx. 288 + * If the LSM id is already in the list leave it alone. 289 + */ 290 + void audit_cfg_lsm(const struct lsm_id *lsmid, int flags) 291 + { 292 + int i; 293 + 294 + if (flags & AUDIT_CFG_LSM_SECCTX_SUBJECT) { 295 + for (i = 0 ; i < audit_subj_secctx_cnt; i++) 296 + if (audit_subj_lsms[i] == lsmid) 297 + return; 298 + audit_subj_lsms[audit_subj_secctx_cnt++] = lsmid; 299 + } 287 300 } 288 301 289 302 /** ··· 1805 1776 1806 1777 static void audit_buffer_free(struct audit_buffer *ab) 1807 1778 { 1779 + struct sk_buff *skb; 1780 + 1808 1781 if (!ab) 1809 1782 return; 1810 1783 1811 - kfree_skb(ab->skb); 1784 + while ((skb = skb_dequeue(&ab->skb_list))) 1785 + kfree_skb(skb); 1812 1786 kmem_cache_free(audit_buffer_cache, ab); 1813 1787 } 1814 1788 ··· 1827 1795 ab->skb = nlmsg_new(AUDIT_BUFSIZ, gfp_mask); 1828 1796 if (!ab->skb) 1829 1797 goto err; 1798 + 1799 + skb_queue_head_init(&ab->skb_list); 1800 + skb_queue_tail(&ab->skb_list, ab->skb); 1801 + 1830 1802 if (!nlmsg_put(ab->skb, 0, 0, type, 0, 0)) 1831 1803 goto err; 1832 1804 ··· 1896 1860 int type) 1897 1861 { 1898 1862 struct audit_buffer *ab; 1899 - struct audit_stamp stamp; 1900 1863 1901 1864 if (audit_initialized != AUDIT_INITIALIZED) 1902 1865 return NULL; ··· 1950 1915 return NULL; 1951 1916 } 1952 1917 1953 - audit_get_stamp(ab->ctx, &stamp); 1918 + audit_get_stamp(ab->ctx, &ab->stamp); 1954 1919 /* cancel dummy context to enable supporting records */ 1955 1920 if (ctx) 1956 1921 ctx->dummy = 0; 1957 1922 audit_log_format(ab, "audit(%llu.%03lu:%u): ", 1958 - (unsigned long long)stamp.ctime.tv_sec, 1959 - stamp.ctime.tv_nsec/1000000, 1960 - stamp.serial); 1923 + (unsigned long long)ab->stamp.ctime.tv_sec, 1924 + ab->stamp.ctime.tv_nsec/1000000, 1925 + ab->stamp.serial); 1961 1926 1962 1927 return ab; 1963 1928 } ··· 2213 2178 audit_log_format(ab, "(null)"); 2214 2179 } 2215 2180 2216 - int audit_log_task_context(struct audit_buffer *ab) 2181 + /** 2182 + * audit_buffer_aux_new - Add an aux record buffer to the skb list 2183 + * @ab: audit_buffer 2184 + * @type: message type 2185 + * 2186 + * Aux records are allocated and added to the skb list of 2187 + * the "main" record. The ab->skb is reset to point to the 2188 + * aux record on its creation. When the aux record in complete 2189 + * ab->skb has to be reset to point to the "main" record. 2190 + * This allows the audit_log_ functions to be ignorant of 2191 + * which kind of record it is logging to. It also avoids adding 2192 + * special data for aux records. 2193 + * 2194 + * On success ab->skb will point to the new aux record. 2195 + * Returns 0 on success, -ENOMEM should allocation fail. 2196 + */ 2197 + static int audit_buffer_aux_new(struct audit_buffer *ab, int type) 2217 2198 { 2218 - struct lsm_prop prop; 2219 - struct lsm_context ctx; 2220 - int error; 2199 + WARN_ON(ab->skb != skb_peek(&ab->skb_list)); 2221 2200 2222 - security_current_getlsmprop_subj(&prop); 2223 - if (!lsmprop_is_set(&prop)) 2201 + ab->skb = nlmsg_new(AUDIT_BUFSIZ, ab->gfp_mask); 2202 + if (!ab->skb) 2203 + goto err; 2204 + if (!nlmsg_put(ab->skb, 0, 0, type, 0, 0)) 2205 + goto err; 2206 + skb_queue_tail(&ab->skb_list, ab->skb); 2207 + 2208 + audit_log_format(ab, "audit(%llu.%03lu:%u): ", 2209 + (unsigned long long)ab->stamp.ctime.tv_sec, 2210 + ab->stamp.ctime.tv_nsec/1000000, 2211 + ab->stamp.serial); 2212 + 2213 + return 0; 2214 + 2215 + err: 2216 + kfree_skb(ab->skb); 2217 + ab->skb = skb_peek(&ab->skb_list); 2218 + return -ENOMEM; 2219 + } 2220 + 2221 + /** 2222 + * audit_buffer_aux_end - Switch back to the "main" record from an aux record 2223 + * @ab: audit_buffer 2224 + * 2225 + * Restores the "main" audit record to ab->skb. 2226 + */ 2227 + static void audit_buffer_aux_end(struct audit_buffer *ab) 2228 + { 2229 + ab->skb = skb_peek(&ab->skb_list); 2230 + } 2231 + 2232 + /** 2233 + * audit_log_subj_ctx - Add LSM subject information 2234 + * @ab: audit_buffer 2235 + * @prop: LSM subject properties. 2236 + * 2237 + * Add a subj= field and, if necessary, a AUDIT_MAC_TASK_CONTEXTS record. 2238 + */ 2239 + int audit_log_subj_ctx(struct audit_buffer *ab, struct lsm_prop *prop) 2240 + { 2241 + struct lsm_context ctx; 2242 + char *space = ""; 2243 + int error; 2244 + int i; 2245 + 2246 + security_current_getlsmprop_subj(prop); 2247 + if (!lsmprop_is_set(prop)) 2224 2248 return 0; 2225 2249 2226 - error = security_lsmprop_to_secctx(&prop, &ctx, LSM_ID_UNDEF); 2227 - if (error < 0) { 2228 - if (error != -EINVAL) 2229 - goto error_path; 2250 + if (audit_subj_secctx_cnt < 2) { 2251 + error = security_lsmprop_to_secctx(prop, &ctx, LSM_ID_UNDEF); 2252 + if (error < 0) { 2253 + if (error != -EINVAL) 2254 + goto error_path; 2255 + return 0; 2256 + } 2257 + audit_log_format(ab, " subj=%s", ctx.context); 2258 + security_release_secctx(&ctx); 2230 2259 return 0; 2231 2260 } 2261 + /* Multiple LSMs provide contexts. Include an aux record. */ 2262 + audit_log_format(ab, " subj=?"); 2263 + error = audit_buffer_aux_new(ab, AUDIT_MAC_TASK_CONTEXTS); 2264 + if (error) 2265 + goto error_path; 2232 2266 2233 - audit_log_format(ab, " subj=%s", ctx.context); 2234 - security_release_secctx(&ctx); 2267 + for (i = 0; i < audit_subj_secctx_cnt; i++) { 2268 + error = security_lsmprop_to_secctx(prop, &ctx, 2269 + audit_subj_lsms[i]->id); 2270 + if (error < 0) { 2271 + /* 2272 + * Don't print anything. An LSM like BPF could 2273 + * claim to support contexts, but only do so under 2274 + * certain conditions. 2275 + */ 2276 + if (error == -EOPNOTSUPP) 2277 + continue; 2278 + if (error != -EINVAL) 2279 + audit_panic("error in audit_log_subj_ctx"); 2280 + } else { 2281 + audit_log_format(ab, "%ssubj_%s=%s", space, 2282 + audit_subj_lsms[i]->name, ctx.context); 2283 + space = " "; 2284 + security_release_secctx(&ctx); 2285 + } 2286 + } 2287 + audit_buffer_aux_end(ab); 2235 2288 return 0; 2236 2289 2237 2290 error_path: 2238 - audit_panic("error in audit_log_task_context"); 2291 + audit_panic("error in audit_log_subj_ctx"); 2239 2292 return error; 2293 + } 2294 + EXPORT_SYMBOL(audit_log_subj_ctx); 2295 + 2296 + int audit_log_task_context(struct audit_buffer *ab) 2297 + { 2298 + struct lsm_prop prop; 2299 + 2300 + security_current_getlsmprop_subj(&prop); 2301 + return audit_log_subj_ctx(ab, &prop); 2240 2302 } 2241 2303 EXPORT_SYMBOL(audit_log_task_context); 2242 2304 ··· 2544 2412 } 2545 2413 2546 2414 /** 2415 + * __audit_log_end - enqueue one audit record 2416 + * @skb: the buffer to send 2417 + */ 2418 + static void __audit_log_end(struct sk_buff *skb) 2419 + { 2420 + struct nlmsghdr *nlh; 2421 + 2422 + if (audit_rate_check()) { 2423 + /* setup the netlink header, see the comments in 2424 + * kauditd_send_multicast_skb() for length quirks */ 2425 + nlh = nlmsg_hdr(skb); 2426 + nlh->nlmsg_len = skb->len - NLMSG_HDRLEN; 2427 + 2428 + /* queue the netlink packet */ 2429 + skb_queue_tail(&audit_queue, skb); 2430 + } else 2431 + audit_log_lost("rate limit exceeded"); 2432 + } 2433 + 2434 + /** 2547 2435 * audit_log_end - end one audit record 2548 2436 * @ab: the audit_buffer 2549 2437 * ··· 2575 2423 void audit_log_end(struct audit_buffer *ab) 2576 2424 { 2577 2425 struct sk_buff *skb; 2578 - struct nlmsghdr *nlh; 2579 2426 2580 2427 if (!ab) 2581 2428 return; 2582 2429 2583 - if (audit_rate_check()) { 2584 - skb = ab->skb; 2585 - ab->skb = NULL; 2430 + while ((skb = skb_dequeue(&ab->skb_list))) 2431 + __audit_log_end(skb); 2586 2432 2587 - /* setup the netlink header, see the comments in 2588 - * kauditd_send_multicast_skb() for length quirks */ 2589 - nlh = nlmsg_hdr(skb); 2590 - nlh->nlmsg_len = skb->len - NLMSG_HDRLEN; 2591 - 2592 - /* queue the netlink packet and poke the kauditd thread */ 2593 - skb_queue_tail(&audit_queue, skb); 2594 - wake_up_interruptible(&kauditd_wait); 2595 - } else 2596 - audit_log_lost("rate limit exceeded"); 2433 + /* poke the kauditd thread */ 2434 + wake_up_interruptible(&kauditd_wait); 2597 2435 2598 2436 audit_buffer_free(ab); 2599 2437 }
+1 -8
net/netlabel/netlabel_user.c
··· 84 84 struct netlbl_audit *audit_info) 85 85 { 86 86 struct audit_buffer *audit_buf; 87 - struct lsm_context ctx; 88 87 89 88 if (audit_enabled == AUDIT_OFF) 90 89 return NULL; ··· 95 96 audit_log_format(audit_buf, "netlabel: auid=%u ses=%u", 96 97 from_kuid(&init_user_ns, audit_info->loginuid), 97 98 audit_info->sessionid); 98 - 99 - if (lsmprop_is_set(&audit_info->prop) && 100 - security_lsmprop_to_secctx(&audit_info->prop, &ctx, 101 - LSM_ID_UNDEF) > 0) { 102 - audit_log_format(audit_buf, " subj=%s", ctx.context); 103 - security_release_secctx(&ctx); 104 - } 99 + audit_log_subj_ctx(audit_buf, &audit_info->prop); 105 100 106 101 return audit_buf; 107 102 }
+3
security/apparmor/lsm.c
··· 2530 2530 security_add_hooks(apparmor_hooks, ARRAY_SIZE(apparmor_hooks), 2531 2531 &apparmor_lsmid); 2532 2532 2533 + /* Inform the audit system that secctx is used */ 2534 + audit_cfg_lsm(&apparmor_lsmid, AUDIT_CFG_LSM_SECCTX_SUBJECT); 2535 + 2533 2536 /* Report that AppArmor successfully initialized */ 2534 2537 apparmor_initialized = 1; 2535 2538 if (aa_g_profile_mode == APPARMOR_COMPLAIN)
+3
security/selinux/hooks.c
··· 7618 7618 /* Set the security state for the initial task. */ 7619 7619 cred_init_security(); 7620 7620 7621 + /* Inform the audit system that secctx is used */ 7622 + audit_cfg_lsm(&selinux_lsmid, AUDIT_CFG_LSM_SECCTX_SUBJECT); 7623 + 7621 7624 default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC); 7622 7625 if (!default_noexec) 7623 7626 pr_notice("SELinux: virtual memory is executable by default\n");
+3
security/smack/smack_lsm.c
··· 5267 5267 /* initialize the smack_known_list */ 5268 5268 init_smack_known_list(); 5269 5269 5270 + /* Inform the audit system that secctx is used */ 5271 + audit_cfg_lsm(&smack_lsmid, AUDIT_CFG_LSM_SECCTX_SUBJECT); 5272 + 5270 5273 return 0; 5271 5274 } 5272 5275