📄 auditsc.c
字号:
} } break; case AUDIT_DEVMINOR: if (name) result = audit_comparator(MINOR(name->dev), f->op, f->val); else if (ctx) { for (j = 0; j < ctx->name_count; j++) { if (audit_comparator(MINOR(ctx->names[j].dev), f->op, f->val)) { ++result; break; } } } break; case AUDIT_INODE: if (name) result = (name->ino == f->val); else if (ctx) { for (j = 0; j < ctx->name_count; j++) { if (audit_comparator(ctx->names[j].ino, f->op, f->val)) { ++result; break; } } } break; case AUDIT_WATCH: if (name && rule->watch->ino != (unsigned long)-1) result = (name->dev == rule->watch->dev && name->ino == rule->watch->ino); break; case AUDIT_DIR: if (ctx) result = match_tree_refs(ctx, rule->tree); break; case AUDIT_LOGINUID: result = 0; if (ctx) result = audit_comparator(tsk->loginuid, f->op, f->val); break; case AUDIT_SUBJ_USER: case AUDIT_SUBJ_ROLE: case AUDIT_SUBJ_TYPE: case AUDIT_SUBJ_SEN: case AUDIT_SUBJ_CLR: /* NOTE: this may return negative values indicating a temporary error. We simply treat this as a match for now to avoid losing information that may be wanted. An error message will also be logged upon error */ if (f->lsm_rule) { if (need_sid) { security_task_getsecid(tsk, &sid); need_sid = 0; } result = security_audit_rule_match(sid, f->type, f->op, f->lsm_rule, ctx); } break; case AUDIT_OBJ_USER: case AUDIT_OBJ_ROLE: case AUDIT_OBJ_TYPE: case AUDIT_OBJ_LEV_LOW: case AUDIT_OBJ_LEV_HIGH: /* The above note for AUDIT_SUBJ_USER...AUDIT_SUBJ_CLR also applies here */ if (f->lsm_rule) { /* Find files that match */ if (name) { result = security_audit_rule_match( name->osid, f->type, f->op, f->lsm_rule, ctx); } else if (ctx) { for (j = 0; j < ctx->name_count; j++) { if (security_audit_rule_match( ctx->names[j].osid, f->type, f->op, f->lsm_rule, ctx)) { ++result; break; } } } /* Find ipc objects that match */ if (ctx) { struct audit_aux_data *aux; for (aux = ctx->aux; aux; aux = aux->next) { if (aux->type == AUDIT_IPC) { struct audit_aux_data_ipcctl *axi = (void *)aux; if (security_audit_rule_match(axi->osid, f->type, f->op, f->lsm_rule, ctx)) { ++result; break; } } } } } break; case AUDIT_ARG0: case AUDIT_ARG1: case AUDIT_ARG2: case AUDIT_ARG3: if (ctx) result = audit_comparator(ctx->argv[f->type-AUDIT_ARG0], f->op, f->val); break; case AUDIT_FILTERKEY: /* ignore this field for filtering */ result = 1; break; case AUDIT_PERM: result = audit_match_perm(ctx, f->val); break; case AUDIT_FILETYPE: result = audit_match_filetype(ctx, f->val); break; } if (!result) return 0; } if (rule->filterkey && ctx) ctx->filterkey = kstrdup(rule->filterkey, GFP_ATOMIC); switch (rule->action) { case AUDIT_NEVER: *state = AUDIT_DISABLED; break; case AUDIT_ALWAYS: *state = AUDIT_RECORD_CONTEXT; break; } return 1;}/* At process creation time, we can determine if system-call auditing is * completely disabled for this task. Since we only have the task * structure at this point, we can only check uid and gid. */static enum audit_state audit_filter_task(struct task_struct *tsk){ struct audit_entry *e; enum audit_state state; rcu_read_lock(); list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_TASK], list) { if (audit_filter_rules(tsk, &e->rule, NULL, NULL, &state)) { rcu_read_unlock(); return state; } } rcu_read_unlock(); return AUDIT_BUILD_CONTEXT;}/* At syscall entry and exit time, this filter is called if the * audit_state is not low enough that auditing cannot take place, but is * also not high enough that we already know we have to write an audit * record (i.e., the state is AUDIT_SETUP_CONTEXT or AUDIT_BUILD_CONTEXT). */static enum audit_state audit_filter_syscall(struct task_struct *tsk, struct audit_context *ctx, struct list_head *list){ struct audit_entry *e; enum audit_state state; if (audit_pid && tsk->tgid == audit_pid) return AUDIT_DISABLED; rcu_read_lock(); if (!list_empty(list)) { int word = AUDIT_WORD(ctx->major); int bit = AUDIT_BIT(ctx->major); list_for_each_entry_rcu(e, list, list) { if ((e->rule.mask[word] & bit) == bit && audit_filter_rules(tsk, &e->rule, ctx, NULL, &state)) { rcu_read_unlock(); return state; } } } rcu_read_unlock(); return AUDIT_BUILD_CONTEXT;}/* At syscall exit time, this filter is called if any audit_names[] have been * collected during syscall processing. We only check rules in sublists at hash * buckets applicable to the inode numbers in audit_names[]. * Regarding audit_state, same rules apply as for audit_filter_syscall(). */enum audit_state audit_filter_inodes(struct task_struct *tsk, struct audit_context *ctx){ int i; struct audit_entry *e; enum audit_state state; if (audit_pid && tsk->tgid == audit_pid) return AUDIT_DISABLED; rcu_read_lock(); for (i = 0; i < ctx->name_count; i++) { int word = AUDIT_WORD(ctx->major); int bit = AUDIT_BIT(ctx->major); struct audit_names *n = &ctx->names[i]; int h = audit_hash_ino((u32)n->ino); struct list_head *list = &audit_inode_hash[h]; if (list_empty(list)) continue; list_for_each_entry_rcu(e, list, list) { if ((e->rule.mask[word] & bit) == bit && audit_filter_rules(tsk, &e->rule, ctx, n, &state)) { rcu_read_unlock(); return state; } } } rcu_read_unlock(); return AUDIT_BUILD_CONTEXT;}void audit_set_auditable(struct audit_context *ctx){ ctx->auditable = 1;}static inline struct audit_context *audit_get_context(struct task_struct *tsk, int return_valid, int return_code){ struct audit_context *context = tsk->audit_context; if (likely(!context)) return NULL; context->return_valid = return_valid; /* * we need to fix up the return code in the audit logs if the actual * return codes are later going to be fixed up by the arch specific * signal handlers * * This is actually a test for: * (rc == ERESTARTSYS ) || (rc == ERESTARTNOINTR) || * (rc == ERESTARTNOHAND) || (rc == ERESTART_RESTARTBLOCK) * * but is faster than a bunch of || */ if (unlikely(return_code <= -ERESTARTSYS) && (return_code >= -ERESTART_RESTARTBLOCK) && (return_code != -ENOIOCTLCMD)) context->return_code = -EINTR; else context->return_code = return_code; if (context->in_syscall && !context->dummy && !context->auditable) { enum audit_state state; state = audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_EXIT]); if (state == AUDIT_RECORD_CONTEXT) { context->auditable = 1; goto get_context; } state = audit_filter_inodes(tsk, context); if (state == AUDIT_RECORD_CONTEXT) context->auditable = 1; }get_context: tsk->audit_context = NULL; return context;}static inline void audit_free_names(struct audit_context *context){ int i;#if AUDIT_DEBUG == 2 if (context->auditable ||context->put_count + context->ino_count != context->name_count) { printk(KERN_ERR "%s:%d(:%d): major=%d in_syscall=%d" " name_count=%d put_count=%d" " ino_count=%d [NOT freeing]\n", __FILE__, __LINE__, context->serial, context->major, context->in_syscall, context->name_count, context->put_count, context->ino_count); for (i = 0; i < context->name_count; i++) { printk(KERN_ERR "names[%d] = %p = %s\n", i, context->names[i].name, context->names[i].name ?: "(null)"); } dump_stack(); return; }#endif#if AUDIT_DEBUG context->put_count = 0; context->ino_count = 0;#endif for (i = 0; i < context->name_count; i++) { if (context->names[i].name && context->names[i].name_put) __putname(context->names[i].name); } context->name_count = 0; path_put(&context->pwd); context->pwd.dentry = NULL; context->pwd.mnt = NULL;}static inline void audit_free_aux(struct audit_context *context){ struct audit_aux_data *aux; while ((aux = context->aux)) { context->aux = aux->next; kfree(aux); } while ((aux = context->aux_pids)) { context->aux_pids = aux->next; kfree(aux); }}static inline void audit_zero_context(struct audit_context *context, enum audit_state state){ memset(context, 0, sizeof(*context)); context->state = state;}static inline struct audit_context *audit_alloc_context(enum audit_state state){ struct audit_context *context; if (!(context = kmalloc(sizeof(*context), GFP_KERNEL))) return NULL; audit_zero_context(context, state); return context;}/** * audit_alloc - allocate an audit context block for a task * @tsk: task * * Filter on the task information and allocate a per-task audit context * if necessary. Doing so turns on system call auditing for the * specified task. This is called from copy_process, so no lock is * needed. */int audit_alloc(struct task_struct *tsk){ struct audit_context *context; enum audit_state state; if (likely(!audit_ever_enabled)) return 0; /* Return if not auditing. */ state = audit_filter_task(tsk); if (likely(state == AUDIT_DISABLED)) return 0; if (!(context = audit_alloc_context(state))) { audit_log_lost("out of memory in audit_alloc"); return -ENOMEM; } tsk->audit_context = context; set_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT); return 0;}static inline void audit_free_context(struct audit_context *context){ struct audit_context *previous; int count = 0; do { previous = context->previous; if (previous || (count && count < 10)) { ++count; printk(KERN_ERR "audit(:%d): major=%d name_count=%d:" " freeing multiple contexts (%d)\n", context->serial, context->major, context->name_count, count); } audit_free_names(context); unroll_tree_refs(context, NULL, 0); free_tree_refs(context); audit_free_aux(context); kfree(context->filterkey); kfree(context); context = previous; } while (context); if (count >= 10) printk(KERN_ERR "audit: freed %d contexts\n", count);}void audit_log_task_context(struct audit_buffer *ab){ char *ctx = NULL; unsigned len; int error; u32 sid; security_task_getsecid(current, &sid); if (!sid) return; error = security_secid_to_secctx(sid, &ctx, &len); if (error) { if (error != -EINVAL) goto error_path; return; } audit_log_format(ab, " subj=%s", ctx); security_release_secctx(ctx, len); return;error_path: audit_panic("error in audit_log_task_context"); return;}EXPORT_SYMBOL(audit_log_task_context);static void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk){ char name[sizeof(tsk->comm)]; struct mm_struct *mm = tsk->mm; struct vm_area_struct *vma; /* tsk == current */ get_task_comm(name, tsk); audit_log_format(ab, " comm="); audit_log_untrustedstring(ab, name); if (mm) { down_read(&mm->mmap_sem); vma = mm->mmap; while (vma) { if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) { audit_log_d_path(ab, "exe=", &vma->vm_file->f_path); break; } vma = vma->vm_next; } up_read(&mm->mmap_sem); } audit_log_task_context(ab);}static int audit_log_pid_context(struct audit_context *context, pid_t pid, uid_t auid, uid_t uid, unsigned int sessionid, u32 sid, char *comm){ struct audit_buffer *ab; char *ctx = NULL; u32 len; int rc = 0; ab = audit_log_start(context, GFP_KERNEL, AUDIT_OBJ_PID); if (!ab) return rc; audit_log_format(ab, "opid=%d oauid=%d ouid=%d oses=%d", pid, auid, uid, sessionid); if (security_secid_to_secctx(sid, &ctx, &len)) { audit_log_format(ab, " obj=(none)"); rc = 1; } else { audit_log_format(ab, " obj=%s", ctx); security_release_secctx(ctx, len); } audit_log_format(ab, " ocomm="); audit_log_untrustedstring(ab, comm); audit_log_end(ab); return rc;}/* * to_send and len_sent accounting are very loose estimates. We aren't * really worried about a hard cap to MAX_EXECVE_AUDIT_LEN so much as being
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -