Pull audit updates from Paul Moore: "Add some additional audit logging to capture the openat2() syscall open_how struct info. Previous variations of the open()/openat() syscalls allowed audit admins to inspect the syscall args to get the information contained in the new open_how struct used in openat2()" * tag 'audit-pr-20211101' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/audit: audit: return early if the filter rule has a lower priority audit: add OPENAT2 record to list "how" info audit: add support for the openat2 syscall audit: replace magic audit syscall class numbers with macros lsm_audit: avoid overloading the "key" audit field audit: Convert to SPDX identifier audit: rename struct node to struct audit_node to prevent future name collisions
Showing the changes to kernel (3 of 23 files). Show all
Unified · Split
| @@ -14,6 +14,7 @@ · 13 unmodified lines | ||
| 14 | 14 | #include <linux/skbuff.h> |
| 15 | 15 | #include <uapi/linux/mqueue.h> |
| 16 | 16 | #include <linux/tty.h> |
| 17 | +#include <uapi/linux/openat2.h> // struct open_how | |
| 17 | 18 | |
| 18 | 19 | /* AUDIT_NAMES is the number of slots we reserve in the audit_context |
| 19 | 20 | * for saving names from getname(). If we get more names we will allocate |
| @@ -193,6 +194,7 @@ struct audit_context { · 173 unmodified lines | ||
| 193 | 194 | int fd; |
| 194 | 195 | int flags; |
| 195 | 196 | } mmap; |
| 197 | + struct open_how openat2; | |
| 196 | 198 | struct { |
| 197 | 199 | int argc; |
| 198 | 200 | } execve; |
| @@ -30,7 +30,7 @@ struct audit_chunk { · 29 unmodified lines | ||
| 30 | 30 | int count; |
| 31 | 31 | atomic_long_t refs; |
| 32 | 32 | struct rcu_head head; |
| 33 | − struct node { | |
| 33 | + struct audit_node { | |
| 34 | 34 | struct list_head list; |
| 35 | 35 | struct audit_tree *owner; |
| 36 | 36 | unsigned index; /* index; upper bit indicates 'will prune' */ |
| @@ -269,7 +269,7 @@ bool audit_tree_match(struct audit_chunk *chunk, struct audit_tree *tree) · 232 unmodified lines | ||
| 269 | 269 | |
| 270 | 270 | /* tagging and untagging inodes with trees */ |
| 271 | 271 | |
| 272 | −static struct audit_chunk *find_chunk(struct node *p) | |
| 272 | +static struct audit_chunk *find_chunk(struct audit_node *p) | |
| 273 | 273 | { |
| 274 | 274 | int index = p->index & ~(1U<<31); |
| 275 | 275 | p -= index; |
| @@ -322,7 +322,7 @@ static void replace_chunk(struct audit_chunk *new, struct audit_chunk *old) · 46 unmodified lines | ||
| 322 | 322 | list_replace_rcu(&old->hash, &new->hash); |
| 323 | 323 | } |
| 324 | 324 | |
| 325 | −static void remove_chunk_node(struct audit_chunk *chunk, struct node *p) | |
| 325 | +static void remove_chunk_node(struct audit_chunk *chunk, struct audit_node *p) | |
| 326 | 326 | { |
| 327 | 327 | struct audit_tree *owner = p->owner; |
| 328 | 328 | |
| @@ -459,7 +459,7 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree) · 130 unmodified lines | ||
| 459 | 459 | { |
| 460 | 460 | struct fsnotify_mark *mark; |
| 461 | 461 | struct audit_chunk *chunk, *old; |
| 462 | − struct node *p; | |
| 462 | + struct audit_node *p; | |
| 463 | 463 | int n; |
| 464 | 464 | |
| 465 | 465 | mutex_lock(&audit_tree_group->mark_mutex); |
| @@ -570,11 +570,11 @@ static void prune_tree_chunks(struct audit_tree *victim, bool tagged) · 104 unmodified lines | ||
| 570 | 570 | { |
| 571 | 571 | spin_lock(&hash_lock); |
| 572 | 572 | while (!list_empty(&victim->chunks)) { |
| 573 | − struct node *p; | |
| 573 | + struct audit_node *p; | |
| 574 | 574 | struct audit_chunk *chunk; |
| 575 | 575 | struct fsnotify_mark *mark; |
| 576 | 576 | |
| 577 | − p = list_first_entry(&victim->chunks, struct node, list); | |
| 577 | + p = list_first_entry(&victim->chunks, struct audit_node, list); | |
| 578 | 578 | /* have we run out of marked? */ |
| 579 | 579 | if (tagged && !(p->index & (1U<<31))) |
| 580 | 580 | break; |
| @@ -616,7 +616,7 @@ static void trim_marked(struct audit_tree *tree) · 35 unmodified lines | ||
| 616 | 616 | } |
| 617 | 617 | /* reorder */ |
| 618 | 618 | for (p = tree->chunks.next; p != &tree->chunks; p = q) { |
| 619 | − struct node *node = list_entry(p, struct node, list); | |
| 619 | + struct audit_node *node = list_entry(p, struct audit_node, list); | |
| 620 | 620 | q = p->next; |
| 621 | 621 | if (node->index & (1U<<31)) { |
| 622 | 622 | list_del_init(p); |
| @@ -684,7 +684,7 @@ void audit_trim_trees(void) · 61 unmodified lines | ||
| 684 | 684 | struct audit_tree *tree; |
| 685 | 685 | struct path path; |
| 686 | 686 | struct vfsmount *root_mnt; |
| 687 | − struct node *node; | |
| 687 | + struct audit_node *node; | |
| 688 | 688 | int err; |
| 689 | 689 | |
| 690 | 690 | tree = container_of(cursor.next, struct audit_tree, list); |
| @@ -840,7 +840,7 @@ int audit_add_tree_rule(struct audit_krule *rule) · 149 unmodified lines | ||
| 840 | 840 | drop_collected_mounts(mnt); |
| 841 | 841 | |
| 842 | 842 | if (!err) { |
| 843 | − struct node *node; | |
| 843 | + struct audit_node *node; | |
| 844 | 844 | spin_lock(&hash_lock); |
| 845 | 845 | list_for_each_entry(node, &tree->chunks, list) |
| 846 | 846 | node->index &= ~(1U<<31); |
| @@ -939,7 +939,7 @@ int audit_tag_tree(char *old, char *new) · 92 unmodified lines | ||
| 939 | 939 | mutex_unlock(&audit_filter_mutex); |
| 940 | 940 | |
| 941 | 941 | if (!failed) { |
| 942 | − struct node *node; | |
| 942 | + struct audit_node *node; | |
| 943 | 943 | spin_lock(&hash_lock); |
| 944 | 944 | list_for_each_entry(node, &tree->chunks, list) |
| 945 | 945 | node->index &= ~(1U<<31); |
| @@ -1,3 +1,4 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later | |
| 1 | 2 | /* auditsc.c -- System-call auditing support |
| 2 | 3 | * Handles all system-call specific auditing features. |
| 3 | 4 | * |
| @@ -6,20 +7,6 @@ · 2 unmodified lines | ||
| 6 | 7 | * Copyright (C) 2005, 2006 IBM Corporation |
| 7 | 8 | * All Rights Reserved. |
| 8 | 9 | * |
| 9 | − * This program is free software; you can redistribute it and/or modify | |
| 10 | − * it under the terms of the GNU General Public License as published by | |
| 11 | − * the Free Software Foundation; either version 2 of the License, or | |
| 12 | − * (at your option) any later version. | |
| 13 | − * | |
| 14 | − * This program is distributed in the hope that it will be useful, | |
| 15 | − * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 16 | − * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 17 | − * GNU General Public License for more details. | |
| 18 | − * | |
| 19 | − * You should have received a copy of the GNU General Public License | |
| 20 | − * along with this program; if not, write to the Free Software | |
| 21 | − * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| 22 | − * | |
| 23 | 10 | * Written by Rickard E. (Rik) Faith <faith@redhat.com> |
| 24 | 11 | * |
| 25 | 12 | * Many of the ideas implemented here are from Stephen C. Tweedie, |
| @@ -76,6 +63,7 @@ · 50 unmodified lines | ||
| 76 | 63 | #include <linux/fsnotify_backend.h> |
| 77 | 64 | #include <uapi/linux/limits.h> |
| 78 | 65 | #include <uapi/linux/netfilter/nf_tables.h> |
| 66 | +#include <uapi/linux/openat2.h> // struct open_how | |
| 79 | 67 | |
| 80 | 68 | #include "audit.h" |
| 81 | 69 | |
| @@ -166,7 +154,7 @@ static int audit_match_perm(struct audit_context *ctx, int mask) · 84 unmodified lines | ||
| 166 | 154 | n = ctx->major; |
| 167 | 155 | |
| 168 | 156 | switch (audit_classify_syscall(ctx->arch, n)) { |
| 169 | − case 0: /* native */ | |
| 157 | + case AUDITSC_NATIVE: | |
| 170 | 158 | if ((mask & AUDIT_PERM_WRITE) && |
| 171 | 159 | audit_match_class(AUDIT_CLASS_WRITE, n)) |
| 172 | 160 | return 1; |
| @@ -177,7 +165,7 @@ static int audit_match_perm(struct audit_context *ctx, int mask) · 4 unmodified lines | ||
| 177 | 165 | audit_match_class(AUDIT_CLASS_CHATTR, n)) |
| 178 | 166 | return 1; |
| 179 | 167 | return 0; |
| 180 | − case 1: /* 32bit on biarch */ | |
| 168 | + case AUDITSC_COMPAT: /* 32bit on biarch */ | |
| 181 | 169 | if ((mask & AUDIT_PERM_WRITE) && |
| 182 | 170 | audit_match_class(AUDIT_CLASS_WRITE_32, n)) |
| 183 | 171 | return 1; |
| @@ -188,14 +176,16 @@ static int audit_match_perm(struct audit_context *ctx, int mask) · 4 unmodified lines | ||
| 188 | 176 | audit_match_class(AUDIT_CLASS_CHATTR_32, n)) |
| 189 | 177 | return 1; |
| 190 | 178 | return 0; |
| 191 | − case 2: /* open */ | |
| 179 | + case AUDITSC_OPEN: | |
| 192 | 180 | return mask & ACC_MODE(ctx->argv[1]); |
| 193 | − case 3: /* openat */ | |
| 181 | + case AUDITSC_OPENAT: | |
| 194 | 182 | return mask & ACC_MODE(ctx->argv[2]); |
| 195 | − case 4: /* socketcall */ | |
| 183 | + case AUDITSC_SOCKETCALL: | |
| 196 | 184 | return ((mask & AUDIT_PERM_WRITE) && ctx->argv[0] == SYS_BIND); |
| 197 | − case 5: /* execve */ | |
| 185 | + case AUDITSC_EXECVE: | |
| 198 | 186 | return mask & AUDIT_PERM_EXEC; |
| 187 | + case AUDITSC_OPENAT2: | |
| 188 | + return mask & ACC_MODE((u32)((struct open_how *)ctx->argv[2])->flags); | |
| 199 | 189 | default: |
| 200 | 190 | return 0; |
| 201 | 191 | } |
| @@ -480,6 +470,9 @@ static int audit_filter_rules(struct task_struct *tsk, · 278 unmodified lines | ||
| 480 | 470 | u32 sid; |
| 481 | 471 | unsigned int sessionid; |
| 482 | 472 | |
| 473 | + if (ctx && rule->prio <= ctx->prio) | |
| 474 | + return 0; | |
| 475 | + | |
| 483 | 476 | cred = rcu_dereference_check(tsk->cred, tsk == current || task_creation); |
| 484 | 477 | |
| 485 | 478 | for (i = 0; i < rule->field_count; i++) { |
| @@ -747,8 +740,6 @@ static int audit_filter_rules(struct task_struct *tsk, · 261 unmodified lines | ||
| 747 | 740 | } |
| 748 | 741 | |
| 749 | 742 | if (ctx) { |
| 750 | − if (rule->prio <= ctx->prio) | |
| 751 | − return 0; | |
| 752 | 743 | if (rule->filterkey) { |
| 753 | 744 | kfree(ctx->filterkey); |
| 754 | 745 | ctx->filterkey = kstrdup(rule->filterkey, GFP_ATOMIC); |
| @@ -1437,6 +1428,12 @@ static void show_special(struct audit_context *context, int *call_panic) · 682 unmodified lines | ||
| 1437 | 1428 | audit_log_format(ab, "fd=%d flags=0x%x", context->mmap.fd, |
| 1438 | 1429 | context->mmap.flags); |
| 1439 | 1430 | break; |
| 1431 | + case AUDIT_OPENAT2: | |
| 1432 | + audit_log_format(ab, "oflag=0%llo mode=0%llo resolve=0x%llx", | |
| 1433 | + context->openat2.flags, | |
| 1434 | + context->openat2.mode, | |
| 1435 | + context->openat2.resolve); | |
| 1436 | + break; | |
| 1440 | 1437 | case AUDIT_EXECVE: |
| 1441 | 1438 | audit_log_execve_info(context, &ab); |
| 1442 | 1439 | break; |
| @@ -2815,6 +2812,16 @@ void __audit_mmap_fd(int fd, int flags) · 1372 unmodified lines | ||
| 2815 | 2812 | context->type = AUDIT_MMAP; |
| 2816 | 2813 | } |
| 2817 | 2814 | |
| 2815 | +void __audit_openat2_how(struct open_how *how) | |
| 2816 | +{ | |
| 2817 | + struct audit_context *context = audit_context(); | |
| 2818 | + | |
| 2819 | + context->openat2.flags = how->flags; | |
| 2820 | + context->openat2.mode = how->mode; | |
| 2821 | + context->openat2.resolve = how->resolve; | |
| 2822 | + context->type = AUDIT_OPENAT2; | |
| 2823 | +} | |
| 2824 | + | |
| 2818 | 2825 | void __audit_log_kern_module(char *name) |
| 2819 | 2826 | { |
| 2820 | 2827 | struct audit_context *context = audit_context(); |