|
|
|
|
@@ -160,6 +160,7 @@ static const struct audit_nfcfgop_tab audit_nfcfgs[] = {
|
|
|
|
|
static int audit_match_perm(struct audit_context *ctx, int mask)
|
|
|
|
|
{
|
|
|
|
|
unsigned n;
|
|
|
|
|
|
|
|
|
|
if (unlikely(!ctx))
|
|
|
|
|
return 0;
|
|
|
|
|
n = ctx->major;
|
|
|
|
|
@@ -231,7 +232,7 @@ static void audit_set_auditable(struct audit_context *ctx)
|
|
|
|
|
{
|
|
|
|
|
if (!ctx->prio) {
|
|
|
|
|
ctx->prio = 1;
|
|
|
|
|
ctx->current_state = AUDIT_RECORD_CONTEXT;
|
|
|
|
|
ctx->current_state = AUDIT_STATE_RECORD;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -239,6 +240,7 @@ static int put_tree_ref(struct audit_context *ctx, struct audit_chunk *chunk)
|
|
|
|
|
{
|
|
|
|
|
struct audit_tree_refs *p = ctx->trees;
|
|
|
|
|
int left = ctx->tree_count;
|
|
|
|
|
|
|
|
|
|
if (likely(left)) {
|
|
|
|
|
p->c[--left] = chunk;
|
|
|
|
|
ctx->tree_count = left;
|
|
|
|
|
@@ -259,6 +261,7 @@ static int put_tree_ref(struct audit_context *ctx, struct audit_chunk *chunk)
|
|
|
|
|
static int grow_tree_refs(struct audit_context *ctx)
|
|
|
|
|
{
|
|
|
|
|
struct audit_tree_refs *p = ctx->trees;
|
|
|
|
|
|
|
|
|
|
ctx->trees = kzalloc(sizeof(struct audit_tree_refs), GFP_KERNEL);
|
|
|
|
|
if (!ctx->trees) {
|
|
|
|
|
ctx->trees = p;
|
|
|
|
|
@@ -277,6 +280,7 @@ static void unroll_tree_refs(struct audit_context *ctx,
|
|
|
|
|
{
|
|
|
|
|
struct audit_tree_refs *q;
|
|
|
|
|
int n;
|
|
|
|
|
|
|
|
|
|
if (!p) {
|
|
|
|
|
/* we started with empty chain */
|
|
|
|
|
p = ctx->first_trees;
|
|
|
|
|
@@ -303,6 +307,7 @@ static void unroll_tree_refs(struct audit_context *ctx,
|
|
|
|
|
static void free_tree_refs(struct audit_context *ctx)
|
|
|
|
|
{
|
|
|
|
|
struct audit_tree_refs *p, *q;
|
|
|
|
|
|
|
|
|
|
for (p = ctx->first_trees; p; p = q) {
|
|
|
|
|
q = p->next;
|
|
|
|
|
kfree(p);
|
|
|
|
|
@@ -313,6 +318,7 @@ static int match_tree_refs(struct audit_context *ctx, struct audit_tree *tree)
|
|
|
|
|
{
|
|
|
|
|
struct audit_tree_refs *p;
|
|
|
|
|
int n;
|
|
|
|
|
|
|
|
|
|
if (!tree)
|
|
|
|
|
return 0;
|
|
|
|
|
/* full ones */
|
|
|
|
|
@@ -337,13 +343,13 @@ static int audit_compare_uid(kuid_t uid,
|
|
|
|
|
{
|
|
|
|
|
struct audit_names *n;
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (name) {
|
|
|
|
|
rc = audit_uid_comparator(uid, f->op, name->uid);
|
|
|
|
|
if (rc)
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (ctx) {
|
|
|
|
|
list_for_each_entry(n, &ctx->names_list, list) {
|
|
|
|
|
rc = audit_uid_comparator(uid, f->op, n->uid);
|
|
|
|
|
@@ -361,13 +367,13 @@ static int audit_compare_gid(kgid_t gid,
|
|
|
|
|
{
|
|
|
|
|
struct audit_names *n;
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (name) {
|
|
|
|
|
rc = audit_gid_comparator(gid, f->op, name->gid);
|
|
|
|
|
if (rc)
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (ctx) {
|
|
|
|
|
list_for_each_entry(n, &ctx->names_list, list) {
|
|
|
|
|
rc = audit_gid_comparator(gid, f->op, n->gid);
|
|
|
|
|
@@ -751,10 +757,10 @@ static int audit_filter_rules(struct task_struct *tsk,
|
|
|
|
|
}
|
|
|
|
|
switch (rule->action) {
|
|
|
|
|
case AUDIT_NEVER:
|
|
|
|
|
*state = AUDIT_DISABLED;
|
|
|
|
|
*state = AUDIT_STATE_DISABLED;
|
|
|
|
|
break;
|
|
|
|
|
case AUDIT_ALWAYS:
|
|
|
|
|
*state = AUDIT_RECORD_CONTEXT;
|
|
|
|
|
*state = AUDIT_STATE_RECORD;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
@@ -773,14 +779,14 @@ static enum audit_state audit_filter_task(struct task_struct *tsk, char **key)
|
|
|
|
|
list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_TASK], list) {
|
|
|
|
|
if (audit_filter_rules(tsk, &e->rule, NULL, NULL,
|
|
|
|
|
&state, true)) {
|
|
|
|
|
if (state == AUDIT_RECORD_CONTEXT)
|
|
|
|
|
if (state == AUDIT_STATE_RECORD)
|
|
|
|
|
*key = kstrdup(e->rule.filterkey, GFP_ATOMIC);
|
|
|
|
|
rcu_read_unlock();
|
|
|
|
|
return state;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
rcu_read_unlock();
|
|
|
|
|
return AUDIT_BUILD_CONTEXT;
|
|
|
|
|
return AUDIT_STATE_BUILD;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int audit_in_mask(const struct audit_krule *rule, unsigned long val)
|
|
|
|
|
@@ -802,7 +808,7 @@ static int audit_in_mask(const struct audit_krule *rule, unsigned long val)
|
|
|
|
|
/* At syscall 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).
|
|
|
|
|
* (i.e., the state is AUDIT_STATE_BUILD).
|
|
|
|
|
*/
|
|
|
|
|
static void audit_filter_syscall(struct task_struct *tsk,
|
|
|
|
|
struct audit_context *ctx)
|
|
|
|
|
@@ -923,7 +929,7 @@ static inline struct audit_context *audit_alloc_context(enum audit_state state)
|
|
|
|
|
if (!context)
|
|
|
|
|
return NULL;
|
|
|
|
|
context->state = state;
|
|
|
|
|
context->prio = state == AUDIT_RECORD_CONTEXT ? ~0ULL : 0;
|
|
|
|
|
context->prio = state == AUDIT_STATE_RECORD ? ~0ULL : 0;
|
|
|
|
|
INIT_LIST_HEAD(&context->killed_trees);
|
|
|
|
|
INIT_LIST_HEAD(&context->names_list);
|
|
|
|
|
context->fds[0] = -1;
|
|
|
|
|
@@ -950,7 +956,7 @@ int audit_alloc(struct task_struct *tsk)
|
|
|
|
|
return 0; /* Return if not auditing. */
|
|
|
|
|
|
|
|
|
|
state = audit_filter_task(tsk, &key);
|
|
|
|
|
if (state == AUDIT_DISABLED) {
|
|
|
|
|
if (state == AUDIT_STATE_DISABLED) {
|
|
|
|
|
clear_task_syscall_work(tsk, SYSCALL_AUDIT);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
@@ -1225,6 +1231,7 @@ static void show_special(struct audit_context *context, int *call_panic)
|
|
|
|
|
switch (context->type) {
|
|
|
|
|
case AUDIT_SOCKETCALL: {
|
|
|
|
|
int nargs = context->socketcall.nargs;
|
|
|
|
|
|
|
|
|
|
audit_log_format(ab, "nargs=%d", nargs);
|
|
|
|
|
for (i = 0; i < nargs; i++)
|
|
|
|
|
audit_log_format(ab, " a%d=%lx", i,
|
|
|
|
|
@@ -1240,6 +1247,7 @@ static void show_special(struct audit_context *context, int *call_panic)
|
|
|
|
|
if (osid) {
|
|
|
|
|
char *ctx = NULL;
|
|
|
|
|
u32 len;
|
|
|
|
|
|
|
|
|
|
if (security_secid_to_secctx(osid, &ctx, &len)) {
|
|
|
|
|
audit_log_format(ab, " osid=%u", osid);
|
|
|
|
|
*call_panic = 1;
|
|
|
|
|
@@ -1289,6 +1297,7 @@ static void show_special(struct audit_context *context, int *call_panic)
|
|
|
|
|
break;
|
|
|
|
|
case AUDIT_MQ_GETSETATTR: {
|
|
|
|
|
struct mq_attr *attr = &context->mq_getsetattr.mqstat;
|
|
|
|
|
|
|
|
|
|
audit_log_format(ab,
|
|
|
|
|
"mqdes=%d mq_flags=0x%lx mq_maxmsg=%ld mq_msgsize=%ld "
|
|
|
|
|
"mq_curmsgs=%ld ",
|
|
|
|
|
@@ -1325,6 +1334,7 @@ static void show_special(struct audit_context *context, int *call_panic)
|
|
|
|
|
static inline int audit_proctitle_rtrim(char *proctitle, int len)
|
|
|
|
|
{
|
|
|
|
|
char *end = proctitle + len - 1;
|
|
|
|
|
|
|
|
|
|
while (end > proctitle && !isprint(*end))
|
|
|
|
|
end--;
|
|
|
|
|
|
|
|
|
|
@@ -1513,6 +1523,7 @@ static void audit_log_exit(void)
|
|
|
|
|
|
|
|
|
|
case AUDIT_BPRM_FCAPS: {
|
|
|
|
|
struct audit_aux_data_bprm_fcaps *axs = (void *)aux;
|
|
|
|
|
|
|
|
|
|
audit_log_format(ab, "fver=%x", axs->fcap_ver);
|
|
|
|
|
audit_log_cap(ab, "fp", &axs->fcap.permitted);
|
|
|
|
|
audit_log_cap(ab, "fi", &axs->fcap.inheritable);
|
|
|
|
|
@@ -1628,7 +1639,7 @@ void __audit_free(struct task_struct *tsk)
|
|
|
|
|
|
|
|
|
|
audit_filter_syscall(tsk, context);
|
|
|
|
|
audit_filter_inodes(tsk, context);
|
|
|
|
|
if (context->current_state == AUDIT_RECORD_CONTEXT)
|
|
|
|
|
if (context->current_state == AUDIT_STATE_RECORD)
|
|
|
|
|
audit_log_exit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1647,7 +1658,7 @@ void __audit_free(struct task_struct *tsk)
|
|
|
|
|
* 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,
|
|
|
|
|
* per-task filter or from the per-syscall filter is AUDIT_STATE_RECORD,
|
|
|
|
|
* 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).
|
|
|
|
|
@@ -1664,11 +1675,11 @@ void __audit_syscall_entry(int major, unsigned long a1, unsigned long a2,
|
|
|
|
|
BUG_ON(context->in_syscall || context->name_count);
|
|
|
|
|
|
|
|
|
|
state = context->state;
|
|
|
|
|
if (state == AUDIT_DISABLED)
|
|
|
|
|
if (state == AUDIT_STATE_DISABLED)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
context->dummy = !audit_n_rules;
|
|
|
|
|
if (!context->dummy && state == AUDIT_BUILD_CONTEXT) {
|
|
|
|
|
if (!context->dummy && state == AUDIT_STATE_BUILD) {
|
|
|
|
|
context->prio = 0;
|
|
|
|
|
if (auditd_test_task(current))
|
|
|
|
|
return;
|
|
|
|
|
@@ -1693,7 +1704,7 @@ void __audit_syscall_entry(int major, unsigned long a1, unsigned long a2,
|
|
|
|
|
* @return_code: return value of the syscall
|
|
|
|
|
*
|
|
|
|
|
* Tear down after system call. If the audit context has been marked as
|
|
|
|
|
* auditable (either because of the AUDIT_RECORD_CONTEXT state from
|
|
|
|
|
* auditable (either because of the AUDIT_STATE_RECORD state from
|
|
|
|
|
* filtering, or because some other part of the kernel wrote an audit
|
|
|
|
|
* message), then write out the syscall information. In call cases,
|
|
|
|
|
* free the names stored from getname().
|
|
|
|
|
@@ -1735,12 +1746,12 @@ void __audit_syscall_exit(int success, long return_code)
|
|
|
|
|
|
|
|
|
|
audit_filter_syscall(current, context);
|
|
|
|
|
audit_filter_inodes(current, context);
|
|
|
|
|
if (context->current_state == AUDIT_RECORD_CONTEXT)
|
|
|
|
|
if (context->current_state == AUDIT_STATE_RECORD)
|
|
|
|
|
audit_log_exit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
context->in_syscall = 0;
|
|
|
|
|
context->prio = context->state == AUDIT_RECORD_CONTEXT ? ~0ULL : 0;
|
|
|
|
|
context->prio = context->state == AUDIT_STATE_RECORD ? ~0ULL : 0;
|
|
|
|
|
|
|
|
|
|
audit_free_module(context);
|
|
|
|
|
audit_free_names(context);
|
|
|
|
|
@@ -1753,7 +1764,7 @@ void __audit_syscall_exit(int success, long return_code)
|
|
|
|
|
context->sockaddr_len = 0;
|
|
|
|
|
context->type = 0;
|
|
|
|
|
context->fds[0] = -1;
|
|
|
|
|
if (context->state != AUDIT_RECORD_CONTEXT) {
|
|
|
|
|
if (context->state != AUDIT_STATE_RECORD) {
|
|
|
|
|
kfree(context->filterkey);
|
|
|
|
|
context->filterkey = NULL;
|
|
|
|
|
}
|
|
|
|
|
@@ -1765,6 +1776,7 @@ static inline void handle_one(const struct inode *inode)
|
|
|
|
|
struct audit_tree_refs *p;
|
|
|
|
|
struct audit_chunk *chunk;
|
|
|
|
|
int count;
|
|
|
|
|
|
|
|
|
|
if (likely(!inode->i_fsnotify_marks))
|
|
|
|
|
return;
|
|
|
|
|
context = audit_context();
|
|
|
|
|
@@ -1806,8 +1818,10 @@ retry:
|
|
|
|
|
seq = read_seqbegin(&rename_lock);
|
|
|
|
|
for(;;) {
|
|
|
|
|
struct inode *inode = d_backing_inode(d);
|
|
|
|
|
|
|
|
|
|
if (inode && unlikely(inode->i_fsnotify_marks)) {
|
|
|
|
|
struct audit_chunk *chunk;
|
|
|
|
|
|
|
|
|
|
chunk = audit_tree_lookup(inode);
|
|
|
|
|
if (chunk) {
|
|
|
|
|
if (unlikely(!put_tree_ref(context, chunk))) {
|
|
|
|
|
@@ -2203,7 +2217,7 @@ int auditsc_get_stamp(struct audit_context *ctx,
|
|
|
|
|
*serial = ctx->serial;
|
|
|
|
|
if (!ctx->prio) {
|
|
|
|
|
ctx->prio = 1;
|
|
|
|
|
ctx->current_state = AUDIT_RECORD_CONTEXT;
|
|
|
|
|
ctx->current_state = AUDIT_STATE_RECORD;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
@@ -2285,6 +2299,7 @@ void __audit_mq_notify(mqd_t mqdes, const struct sigevent *notification)
|
|
|
|
|
void __audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat)
|
|
|
|
|
{
|
|
|
|
|
struct audit_context *context = audit_context();
|
|
|
|
|
|
|
|
|
|
context->mq_getsetattr.mqdes = mqdes;
|
|
|
|
|
context->mq_getsetattr.mqstat = *mqstat;
|
|
|
|
|
context->type = AUDIT_MQ_GETSETATTR;
|
|
|
|
|
@@ -2298,6 +2313,7 @@ void __audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat)
|
|
|
|
|
void __audit_ipc_obj(struct kern_ipc_perm *ipcp)
|
|
|
|
|
{
|
|
|
|
|
struct audit_context *context = audit_context();
|
|
|
|
|
|
|
|
|
|
context->ipc.uid = ipcp->uid;
|
|
|
|
|
context->ipc.gid = ipcp->gid;
|
|
|
|
|
context->ipc.mode = ipcp->mode;
|
|
|
|
|
@@ -2362,6 +2378,7 @@ int __audit_socketcall(int nargs, unsigned long *args)
|
|
|
|
|
void __audit_fd_pair(int fd1, int fd2)
|
|
|
|
|
{
|
|
|
|
|
struct audit_context *context = audit_context();
|
|
|
|
|
|
|
|
|
|
context->fds[0] = fd1;
|
|
|
|
|
context->fds[1] = fd2;
|
|
|
|
|
}
|
|
|
|
|
@@ -2379,6 +2396,7 @@ int __audit_sockaddr(int len, void *a)
|
|
|
|
|
|
|
|
|
|
if (!context->sockaddr) {
|
|
|
|
|
void *p = kmalloc(sizeof(struct sockaddr_storage), GFP_KERNEL);
|
|
|
|
|
|
|
|
|
|
if (!p)
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
context->sockaddr = p;
|
|
|
|
|
@@ -2510,6 +2528,7 @@ int __audit_log_bprm_fcaps(struct linux_binprm *bprm,
|
|
|
|
|
void __audit_log_capset(const struct cred *new, const struct cred *old)
|
|
|
|
|
{
|
|
|
|
|
struct audit_context *context = audit_context();
|
|
|
|
|
|
|
|
|
|
context->capset.pid = task_tgid_nr(current);
|
|
|
|
|
context->capset.cap.effective = new->cap_effective;
|
|
|
|
|
context->capset.cap.inheritable = new->cap_effective;
|
|
|
|
|
@@ -2521,6 +2540,7 @@ void __audit_log_capset(const struct cred *new, const struct cred *old)
|
|
|
|
|
void __audit_mmap_fd(int fd, int flags)
|
|
|
|
|
{
|
|
|
|
|
struct audit_context *context = audit_context();
|
|
|
|
|
|
|
|
|
|
context->mmap.fd = fd;
|
|
|
|
|
context->mmap.flags = flags;
|
|
|
|
|
context->type = AUDIT_MMAP;
|
|
|
|
|
@@ -2686,6 +2706,7 @@ void audit_seccomp_actions_logged(const char *names, const char *old_names,
|
|
|
|
|
struct list_head *audit_killed_trees(void)
|
|
|
|
|
{
|
|
|
|
|
struct audit_context *ctx = audit_context();
|
|
|
|
|
|
|
|
|
|
if (likely(!ctx || !ctx->in_syscall))
|
|
|
|
|
return NULL;
|
|
|
|
|
return &ctx->killed_trees;
|
|
|
|
|
|