📄 auditsc.c
字号:
if (!ab) continue; /* audit_panic has been called */ audit_log_format(ab, "item=%d", i); if (n->name) { switch(n->name_len) { case AUDIT_NAME_FULL: /* log the full path */ audit_log_format(ab, " name="); audit_log_untrustedstring(ab, n->name); break; case 0: /* name was specified as a relative path and the * directory component is the cwd */ audit_log_d_path(ab, " name=", context->pwd, context->pwdmnt); break; default: /* log the name's directory component */ audit_log_format(ab, " name="); audit_log_n_untrustedstring(ab, n->name_len, n->name); } } else audit_log_format(ab, " name=(null)"); if (n->ino != (unsigned long)-1) { audit_log_format(ab, " inode=%lu" " dev=%02x:%02x mode=%#o" " ouid=%u ogid=%u rdev=%02x:%02x", n->ino, MAJOR(n->dev), MINOR(n->dev), n->mode, n->uid, n->gid, MAJOR(n->rdev), MINOR(n->rdev)); } if (n->osid != 0) { char *ctx = NULL; u32 len; if (selinux_sid_to_string( n->osid, &ctx, &len)) { audit_log_format(ab, " osid=%u", n->osid); call_panic = 2; } else audit_log_format(ab, " obj=%s", ctx); kfree(ctx); } audit_log_end(ab); } if (call_panic) audit_panic("error converting sid to string");}/** * audit_free - free a per-task audit context * @tsk: task whose audit context block to free * * Called from copy_process and do_exit */void audit_free(struct task_struct *tsk){ struct audit_context *context; context = audit_get_context(tsk, 0, 0); if (likely(!context)) return; /* Check for system calls that do not go through the exit * function (e.g., exit_group), then free context block. * We use GFP_ATOMIC here because we might be doing this * in the context of the idle thread */ /* that can happen only if we are called from do_exit() */ if (context->in_syscall && context->auditable) audit_log_exit(context, tsk); audit_free_context(context);}/** * audit_syscall_entry - fill in an audit record at syscall entry * @tsk: task being audited * @arch: architecture type * @major: major syscall type (function) * @a1: additional syscall register 1 * @a2: additional syscall register 2 * @a3: additional syscall register 3 * @a4: additional syscall register 4 * * Fill in audit context at syscall entry. This only happens if the * audit context was created when the task was created and the state or * filters demand the audit context be built. If the state from the * per-task filter or from the per-syscall filter is AUDIT_RECORD_CONTEXT, * then the record will be written at syscall exit time (otherwise, it * will only be written if another part of the kernel requests that it * be written). */void audit_syscall_entry(int arch, int major, unsigned long a1, unsigned long a2, unsigned long a3, unsigned long a4){ struct task_struct *tsk = current; struct audit_context *context = tsk->audit_context; enum audit_state state; BUG_ON(!context); /* * This happens only on certain architectures that make system * calls in kernel_thread via the entry.S interface, instead of * with direct calls. (If you are porting to a new * architecture, hitting this condition can indicate that you * got the _exit/_leave calls backward in entry.S.) * * i386 no * x86_64 no * ppc64 yes (see arch/powerpc/platforms/iseries/misc.S) * * This also happens with vm86 emulation in a non-nested manner * (entries without exits), so this case must be caught. */ if (context->in_syscall) { struct audit_context *newctx;#if AUDIT_DEBUG printk(KERN_ERR "audit(:%d) pid=%d in syscall=%d;" " entering syscall=%d\n", context->serial, tsk->pid, context->major, major);#endif newctx = audit_alloc_context(context->state); if (newctx) { newctx->previous = context; context = newctx; tsk->audit_context = newctx; } else { /* If we can't alloc a new context, the best we * can do is to leak memory (any pending putname * will be lost). The only other alternative is * to abandon auditing. */ audit_zero_context(context, context->state); } } BUG_ON(context->in_syscall || context->name_count); if (!audit_enabled) return; context->arch = arch; context->major = major; context->argv[0] = a1; context->argv[1] = a2; context->argv[2] = a3; context->argv[3] = a4; state = context->state; context->dummy = !audit_n_rules; if (!context->dummy && (state == AUDIT_SETUP_CONTEXT || state == AUDIT_BUILD_CONTEXT)) state = audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_ENTRY]); if (likely(state == AUDIT_DISABLED)) return; context->serial = 0; context->ctime = CURRENT_TIME; context->in_syscall = 1; context->auditable = !!(state == AUDIT_RECORD_CONTEXT); context->ppid = 0;}/** * audit_syscall_exit - deallocate audit context after a system call * @tsk: task being audited * @valid: success/failure flag * @return_code: syscall return value * * Tear down after system call. If the audit context has been marked as * auditable (either because of the AUDIT_RECORD_CONTEXT state from * filtering, or because some other part of the kernel write an audit * message), then write out the syscall information. In call cases, * free the names stored from getname(). */void audit_syscall_exit(int valid, long return_code){ struct task_struct *tsk = current; struct audit_context *context; context = audit_get_context(tsk, valid, return_code); if (likely(!context)) return; if (context->in_syscall && context->auditable) audit_log_exit(context, tsk); context->in_syscall = 0; context->auditable = 0; if (context->previous) { struct audit_context *new_context = context->previous; context->previous = NULL; audit_free_context(context); tsk->audit_context = new_context; } else { audit_free_names(context); audit_free_aux(context); context->aux = NULL; context->aux_pids = NULL; context->target_pid = 0; context->target_sid = 0; kfree(context->filterkey); context->filterkey = NULL; tsk->audit_context = context; }}/** * audit_getname - add a name to the list * @name: name to add * * Add a name to the list of audit names for this context. * Called from fs/namei.c:getname(). */void __audit_getname(const char *name){ struct audit_context *context = current->audit_context; if (IS_ERR(name) || !name) return; if (!context->in_syscall) {#if AUDIT_DEBUG == 2 printk(KERN_ERR "%s:%d(:%d): ignoring getname(%p)\n", __FILE__, __LINE__, context->serial, name); dump_stack();#endif return; } BUG_ON(context->name_count >= AUDIT_NAMES); context->names[context->name_count].name = name; context->names[context->name_count].name_len = AUDIT_NAME_FULL; context->names[context->name_count].name_put = 1; context->names[context->name_count].ino = (unsigned long)-1; context->names[context->name_count].osid = 0; ++context->name_count; if (!context->pwd) { read_lock(¤t->fs->lock); context->pwd = dget(current->fs->pwd); context->pwdmnt = mntget(current->fs->pwdmnt); read_unlock(¤t->fs->lock); } }/* audit_putname - intercept a putname request * @name: name to intercept and delay for putname * * If we have stored the name from getname in the audit context, * then we delay the putname until syscall exit. * Called from include/linux/fs.h:putname(). */void audit_putname(const char *name){ struct audit_context *context = current->audit_context; BUG_ON(!context); if (!context->in_syscall) {#if AUDIT_DEBUG == 2 printk(KERN_ERR "%s:%d(:%d): __putname(%p)\n", __FILE__, __LINE__, context->serial, name); if (context->name_count) { int i; for (i = 0; i < context->name_count; i++) printk(KERN_ERR "name[%d] = %p = %s\n", i, context->names[i].name, context->names[i].name ?: "(null)"); }#endif __putname(name); }#if AUDIT_DEBUG else { ++context->put_count; if (context->put_count > context->name_count) { printk(KERN_ERR "%s:%d(:%d): major=%d" " in_syscall=%d putname(%p) name_count=%d" " put_count=%d\n", __FILE__, __LINE__, context->serial, context->major, context->in_syscall, name, context->name_count, context->put_count); dump_stack(); } }#endif}static int audit_inc_name_count(struct audit_context *context, const struct inode *inode){ if (context->name_count >= AUDIT_NAMES) { if (inode) printk(KERN_DEBUG "name_count maxed, losing inode data: " "dev=%02x:%02x, inode=%lu", MAJOR(inode->i_sb->s_dev), MINOR(inode->i_sb->s_dev), inode->i_ino); else printk(KERN_DEBUG "name_count maxed, losing inode data"); return 1; } context->name_count++;#if AUDIT_DEBUG context->ino_count++;#endif return 0;}/* Copy inode data into an audit_names. */static void audit_copy_inode(struct audit_names *name, const struct inode *inode){ name->ino = inode->i_ino; name->dev = inode->i_sb->s_dev; name->mode = inode->i_mode; name->uid = inode->i_uid; name->gid = inode->i_gid; name->rdev = inode->i_rdev; selinux_get_inode_sid(inode, &name->osid);}/** * audit_inode - store the inode and device from a lookup * @name: name being audited * @inode: inode being audited * * Called from fs/namei.c:path_lookup(). */void __audit_inode(const char *name, const struct inode *inode){ int idx; struct audit_context *context = current->audit_context; if (!context->in_syscall) return; if (context->name_count && context->names[context->name_count-1].name && context->names[context->name_count-1].name == name) idx = context->name_count - 1; else if (context->name_count > 1 && context->names[context->name_count-2].name && context->names[context->name_count-2].name == name) idx = context->name_count - 2; else { /* FIXME: how much do we care about inodes that have no * associated name? */ if (audit_inc_name_count(context, inode)) return; idx = context->name_count - 1; context->names[idx].name = NULL; } audit_copy_inode(&context->names[idx], inode);}/** * audit_inode_child - collect inode info for created/removed objects * @dname: inode's dentry name * @inode: inode being audited * @parent: inode of dentry parent * * For syscalls that create or remove filesystem objects, audit_inode * can only collect information for the filesystem object's parent. * This call updates the audit context with the child's information. * Syscalls that create a new filesystem object must be hooked after * the object is created. Syscalls that remove a filesystem object * must be hooked prior, in order to capture the target inode during * unsuccessful attempts. */void __audit_inode_child(const char *dname, const struct inode *inode, const struct inode *parent){ int idx; struct audit_context *context = current->audit_context; const char *found_parent = NULL, *found_child = NULL; int dirlen = 0; if (!context->in_syscall) return; /* determine matching parent */ if (!dname) goto add_names; /* parent is more likely, look for it first */ for (idx = 0; idx < context->name_count; idx++) { struct audit_names *n = &context->names[idx]; if (!n->name) continue; if (n->ino == parent->i_ino && !audit_compare_dname_path(dname, n->name, &dirlen)) { n->name_len = dirlen; /* update parent data in place */ found_parent = n->name; goto add_names; } } /* no matching parent, look for matching child */ for (idx = 0; idx < context->name_count; idx++) { struct audit_names *n = &context->names[idx]; if (!n->name) continue; /* strcmp() is the more likely scenario */ if (!strcmp(dname, n->name) || !audit_compare_dname_path(dname, n->name, &dirlen)) { if (inode) audit_copy_inode(n, inode); else n->ino = (unsigned long)-1; found_child = n->name; goto add_names; } }add_names: if (!found_parent) { if (audit_inc_name_count(context, parent)) return; idx = context->name_count - 1; context->names[idx].name = NULL; audit_copy_inode(&context->names[idx], parent); } if (!found_child) { if (audit_inc_name_count(context, inode)) return; idx = context->name_count - 1; /* Re-use the name belonging to the slot for a matching parent * directory. All names for this context are relinquished in * audit_free_names() */ if (found_parent) { context->names[idx].name = found_parent; context->names[idx].name_len = AUDIT_NAME_FULL; /* don't call __putname() */ context->names[idx].name_put = 0; } else { context->names[idx].name = NULL; } if (inode) audit_copy_inode(&context->names[idx], inode); else context->names[idx].ino = (unsigned long)-1; }}/** * auditsc_get_stamp - get local copies of audit_context values * @ctx: audit_context for the task * @t: timespec to store time recorded in the audit_context * @serial: serial value that is recorded in the audit_context * * Also sets the context as auditable. */void auditsc_get_stamp(struct audit_context *ctx, struct timespec *t, unsigned int *serial){ if (!ctx->serial) ctx->serial = audit_serial(); t->tv_sec = ctx->ctime.tv_sec; t->tv_nsec = ctx->ctime.tv_nsec; *serial = ctx->serial; ctx->auditable = 1;}/** * audit_set_loginuid - set a task's audit_context loginuid * @task: task whose audit context is being modified * @loginuid: loginuid value * * Returns 0. * * Called (set) from fs/proc/base.c::proc_loginuid_write(). */int audit_set_loginuid(struct task_struct *task, uid_t loginuid){ struct audit_context *context = task->audit_context; if (context) { /* Only log if audit is enabled */ if (context->in_syscall) { struct audit_buffer *ab; ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_LOGIN); if (ab) { audit_log_format(ab, "login pid=%d uid=%u " "old auid=%u new auid=%u", task->pid, task->uid, context->loginuid, loginuid); audit_log_end(ab); } } context->loginuid = loginuid; } return 0;}/** * audit_get_loginuid - get the loginuid for an audit_context * @ctx: the audit_context * * Returns the context's loginuid or -1 if @ctx is NULL. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -