X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=kernel%2Fauditsc.c;h=1c03a4ed1b27fb8b6f4276b3305ed10907f8f4c3;hb=9464c7cf61b9433057924c36e6e02f303a00e768;hp=8fab061dfc39a4f41c0825f52a73692b3c37629b;hpb=41689045f6a3cbe0550e1d34e9cc20d2e8c432ba;p=linux-2.6.git diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 8fab061df..1c03a4ed1 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -3,7 +3,7 @@ * * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina. * Copyright 2005 Hewlett-Packard Development Company, L.P. - * Copyright (C) 2005, 2006 IBM Corporation + * Copyright (C) 2005 IBM Corporation * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify @@ -29,9 +29,6 @@ * this file -- see entry.S) is based on a GPL'd patch written by * okir@suse.de and Copyright 2003 SuSE Linux AG. * - * POSIX message queue support added by George Wilson , - * 2006. - * * The support of additional filter rules compares (>, <, >=, <=) was * added by Dustin Kirkland , 2005. * @@ -52,7 +49,6 @@ #include #include #include -#include #include #include #include @@ -63,8 +59,6 @@ #include #include #include -#include -#include #include "audit.h" @@ -82,12 +76,6 @@ extern int audit_enabled; * path_lookup. */ #define AUDIT_NAMES_RESERVED 7 -/* Indicates that audit should log the full pathname. */ -#define AUDIT_NAME_FULL -1 - -/* number of audit rules */ -int audit_n_rules; - /* When fs/namei.c:getname() is called, we store the pointer in name and * we don't let putname() free it (instead we free all of the saved * pointers at syscall exit time). @@ -95,9 +83,8 @@ int audit_n_rules; * Further, in fs/namei.c:path_lookup() we store the inode and device. */ struct audit_names { const char *name; - int name_len; /* number of name's characters to log */ - unsigned name_put; /* call __putname() for this name */ unsigned long ino; + unsigned long pino; dev_t dev; umode_t mode; uid_t uid; @@ -113,33 +100,6 @@ struct audit_aux_data { #define AUDIT_AUX_IPCPERM 0 -struct audit_aux_data_mq_open { - struct audit_aux_data d; - int oflag; - mode_t mode; - struct mq_attr attr; -}; - -struct audit_aux_data_mq_sendrecv { - struct audit_aux_data d; - mqd_t mqdes; - size_t msg_len; - unsigned int msg_prio; - struct timespec abs_timeout; -}; - -struct audit_aux_data_mq_notify { - struct audit_aux_data d; - mqd_t mqdes; - struct sigevent notification; -}; - -struct audit_aux_data_mq_getsetattr { - struct audit_aux_data d; - mqd_t mqdes; - struct mq_attr mqstat; -}; - struct audit_aux_data_ipcctl { struct audit_aux_data d; struct ipc_perm p; @@ -150,13 +110,6 @@ struct audit_aux_data_ipcctl { u32 osid; }; -struct audit_aux_data_execve { - struct audit_aux_data d; - int argc; - int envc; - char mem[0]; -}; - struct audit_aux_data_socketcall { struct audit_aux_data d; int nargs; @@ -177,7 +130,6 @@ struct audit_aux_data_path { /* The per-task audit context. */ struct audit_context { - int dummy; /* must be the first element */ int in_syscall; /* 1 if task is in a syscall */ enum audit_state state; unsigned int serial; /* serial number for record */ @@ -190,14 +142,13 @@ struct audit_context { int auditable; /* 1 if record should be written */ int name_count; struct audit_names names[AUDIT_NAMES]; - char * filterkey; /* key for rule that triggered record */ struct dentry * pwd; struct vfsmount * pwdmnt; struct audit_context *previous; /* For nested syscalls */ struct audit_aux_data *aux; /* Save things to print about task_struct */ - pid_t pid, ppid; + pid_t pid; uid_t uid, euid, suid, fsuid; gid_t gid, egid, sgid, fsgid; unsigned long personality; @@ -209,61 +160,12 @@ struct audit_context { #endif }; -#define ACC_MODE(x) ("\004\002\006\006"[(x)&O_ACCMODE]) -static inline int open_arg(int flags, int mask) -{ - int n = ACC_MODE(flags); - if (flags & (O_TRUNC | O_CREAT)) - n |= AUDIT_PERM_WRITE; - return n & mask; -} - -static int audit_match_perm(struct audit_context *ctx, int mask) -{ - unsigned n = ctx->major; - switch (audit_classify_syscall(ctx->arch, n)) { - case 0: /* native */ - if ((mask & AUDIT_PERM_WRITE) && - audit_match_class(AUDIT_CLASS_WRITE, n)) - return 1; - if ((mask & AUDIT_PERM_READ) && - audit_match_class(AUDIT_CLASS_READ, n)) - return 1; - if ((mask & AUDIT_PERM_ATTR) && - audit_match_class(AUDIT_CLASS_CHATTR, n)) - return 1; - return 0; - case 1: /* 32bit on biarch */ - if ((mask & AUDIT_PERM_WRITE) && - audit_match_class(AUDIT_CLASS_WRITE_32, n)) - return 1; - if ((mask & AUDIT_PERM_READ) && - audit_match_class(AUDIT_CLASS_READ_32, n)) - return 1; - if ((mask & AUDIT_PERM_ATTR) && - audit_match_class(AUDIT_CLASS_CHATTR_32, n)) - return 1; - return 0; - case 2: /* open */ - return mask & ACC_MODE(ctx->argv[1]); - case 3: /* openat */ - return mask & ACC_MODE(ctx->argv[2]); - case 4: /* socketcall */ - return ((mask & AUDIT_PERM_WRITE) && ctx->argv[0] == SYS_BIND); - case 5: /* execve */ - return mask & AUDIT_PERM_EXEC; - default: - return 0; - } -} -/* Determine if any context name data matches a rule's watch data */ /* Compare a task_struct with an audit_rule. Return 1 on match, 0 * otherwise. */ static int audit_filter_rules(struct task_struct *tsk, struct audit_krule *rule, struct audit_context *ctx, - struct audit_names *name, enum audit_state *state) { int i, j, need_sid = 1; @@ -277,10 +179,6 @@ static int audit_filter_rules(struct task_struct *tsk, case AUDIT_PID: result = audit_comparator(tsk->pid, f->op, f->val); break; - case AUDIT_PPID: - if (ctx) - result = audit_comparator(ctx->ppid, f->op, f->val); - break; case AUDIT_UID: result = audit_comparator(tsk->uid, f->op, f->val); break; @@ -326,10 +224,7 @@ static int audit_filter_rules(struct task_struct *tsk, } break; case AUDIT_DEVMAJOR: - if (name) - result = audit_comparator(MAJOR(name->dev), - f->op, f->val); - else if (ctx) { + if (ctx) { for (j = 0; j < ctx->name_count; j++) { if (audit_comparator(MAJOR(ctx->names[j].dev), f->op, f->val)) { ++result; @@ -339,10 +234,7 @@ static int audit_filter_rules(struct task_struct *tsk, } break; case AUDIT_DEVMINOR: - if (name) - result = audit_comparator(MINOR(name->dev), - f->op, f->val); - else if (ctx) { + if (ctx) { for (j = 0; j < ctx->name_count; j++) { if (audit_comparator(MINOR(ctx->names[j].dev), f->op, f->val)) { ++result; @@ -352,32 +244,26 @@ static int audit_filter_rules(struct task_struct *tsk, } break; case AUDIT_INODE: - if (name) - result = (name->ino == f->val); - else if (ctx) { + if (ctx) { for (j = 0; j < ctx->name_count; j++) { - if (audit_comparator(ctx->names[j].ino, f->op, f->val)) { + if (audit_comparator(ctx->names[j].ino, f->op, f->val) || + audit_comparator(ctx->names[j].pino, 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_LOGINUID: result = 0; if (ctx) result = audit_comparator(ctx->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: + case AUDIT_SE_USER: + case AUDIT_SE_ROLE: + case AUDIT_SE_TYPE: + case AUDIT_SE_SEN: + case AUDIT_SE_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 @@ -394,46 +280,6 @@ static int audit_filter_rules(struct task_struct *tsk, 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->se_rule) { - /* Find files that match */ - if (name) { - result = selinux_audit_rule_match( - name->osid, f->type, f->op, - f->se_rule, ctx); - } else if (ctx) { - for (j = 0; j < ctx->name_count; j++) { - if (selinux_audit_rule_match( - ctx->names[j].osid, - f->type, f->op, - f->se_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 (selinux_audit_rule_match(axi->osid, f->type, f->op, f->se_rule, ctx)) { - ++result; - break; - } - } - } - } - } - break; case AUDIT_ARG0: case AUDIT_ARG1: case AUDIT_ARG2: @@ -441,22 +287,14 @@ static int audit_filter_rules(struct task_struct *tsk, 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; } if (!result) return 0; } - if (rule->filterkey) - ctx->filterkey = kstrdup(rule->filterkey, GFP_ATOMIC); switch (rule->action) { case AUDIT_NEVER: *state = AUDIT_DISABLED; break; + case AUDIT_POSSIBLE: *state = AUDIT_BUILD_CONTEXT; break; case AUDIT_ALWAYS: *state = AUDIT_RECORD_CONTEXT; break; } return 1; @@ -473,7 +311,7 @@ static enum audit_state audit_filter_task(struct task_struct *tsk) 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)) { + if (audit_filter_rules(tsk, &e->rule, NULL, &state)) { rcu_read_unlock(); return state; } @@ -503,9 +341,8 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk, 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)) { + if ((e->rule.mask[word] & bit) == bit + && audit_filter_rules(tsk, &e->rule, ctx, &state)) { rcu_read_unlock(); return state; } @@ -515,49 +352,6 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk, 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) @@ -569,23 +363,23 @@ static inline struct audit_context *audit_get_context(struct task_struct *tsk, context->return_valid = return_valid; context->return_code = return_code; - if (context->in_syscall && !context->dummy && !context->auditable) { + if (context->in_syscall && !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: - + context->pid = tsk->pid; + context->uid = tsk->uid; + context->gid = tsk->gid; + context->euid = tsk->euid; + context->suid = tsk->suid; + context->fsuid = tsk->fsuid; + context->egid = tsk->egid; + context->sgid = tsk->sgid; + context->fsgid = tsk->fsgid; + context->personality = tsk->personality; tsk->audit_context = NULL; return context; } @@ -619,7 +413,7 @@ static inline void audit_free_names(struct audit_context *context) #endif for (i = 0; i < context->name_count; i++) { - if (context->names[i].name && context->names[i].name_put) + if (context->names[i].name) __putname(context->names[i].name); } context->name_count = 0; @@ -719,7 +513,6 @@ static inline void audit_free_context(struct audit_context *context) } audit_free_names(context); audit_free_aux(context); - kfree(context->filterkey); kfree(context); context = previous; } while (context); @@ -751,7 +544,8 @@ static void audit_log_task_context(struct audit_buffer *ab) return; error_path: - kfree(ctx); + if (ctx) + kfree(ctx); audit_panic("error in audit_log_task_context"); return; } @@ -794,17 +588,6 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts const char *tty; /* tsk == current */ - context->pid = tsk->pid; - context->ppid = sys_getppid(); /* sic. tsk == current in all cases */ - context->uid = tsk->uid; - context->gid = tsk->gid; - context->euid = tsk->euid; - context->suid = tsk->suid; - context->fsuid = tsk->fsuid; - context->egid = tsk->egid; - context->sgid = tsk->sgid; - context->fsgid = tsk->fsgid; - context->personality = tsk->personality; ab = audit_log_start(context, GFP_KERNEL, AUDIT_SYSCALL); if (!ab) @@ -817,17 +600,13 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts audit_log_format(ab, " success=%s exit=%ld", (context->return_valid==AUDITSC_SUCCESS)?"yes":"no", context->return_code); - - mutex_lock(&tty_mutex); - read_lock(&tasklist_lock); if (tsk->signal && tsk->signal->tty && tsk->signal->tty->name) tty = tsk->signal->tty->name; else tty = "(none)"; - read_unlock(&tasklist_lock); audit_log_format(ab, " a0=%lx a1=%lx a2=%lx a3=%lx items=%d" - " ppid=%d pid=%d auid=%u uid=%u gid=%u" + " pid=%d auid=%u uid=%u gid=%u" " euid=%u suid=%u fsuid=%u" " egid=%u sgid=%u fsgid=%u tty=%s", context->argv[0], @@ -835,22 +614,13 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts context->argv[2], context->argv[3], context->name_count, - context->ppid, context->pid, context->loginuid, context->uid, context->gid, context->euid, context->suid, context->fsuid, context->egid, context->sgid, context->fsgid, tty); - - mutex_unlock(&tty_mutex); - audit_log_task_info(ab, tsk); - if (context->filterkey) { - audit_log_format(ab, " key="); - audit_log_untrustedstring(ab, context->filterkey); - } else - audit_log_format(ab, " key=(null)"); audit_log_end(ab); for (aux = context->aux; aux; aux = aux->next) { @@ -860,48 +630,11 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts continue; /* audit_panic has been called */ switch (aux->type) { - case AUDIT_MQ_OPEN: { - struct audit_aux_data_mq_open *axi = (void *)aux; - audit_log_format(ab, - "oflag=0x%x mode=%#o mq_flags=0x%lx mq_maxmsg=%ld " - "mq_msgsize=%ld mq_curmsgs=%ld", - axi->oflag, axi->mode, axi->attr.mq_flags, - axi->attr.mq_maxmsg, axi->attr.mq_msgsize, - axi->attr.mq_curmsgs); - break; } - - case AUDIT_MQ_SENDRECV: { - struct audit_aux_data_mq_sendrecv *axi = (void *)aux; - audit_log_format(ab, - "mqdes=%d msg_len=%zd msg_prio=%u " - "abs_timeout_sec=%ld abs_timeout_nsec=%ld", - axi->mqdes, axi->msg_len, axi->msg_prio, - axi->abs_timeout.tv_sec, axi->abs_timeout.tv_nsec); - break; } - - case AUDIT_MQ_NOTIFY: { - struct audit_aux_data_mq_notify *axi = (void *)aux; - audit_log_format(ab, - "mqdes=%d sigev_signo=%d", - axi->mqdes, - axi->notification.sigev_signo); - break; } - - case AUDIT_MQ_GETSETATTR: { - struct audit_aux_data_mq_getsetattr *axi = (void *)aux; - audit_log_format(ab, - "mqdes=%d mq_flags=0x%lx mq_maxmsg=%ld mq_msgsize=%ld " - "mq_curmsgs=%ld ", - axi->mqdes, - axi->mqstat.mq_flags, axi->mqstat.mq_maxmsg, - axi->mqstat.mq_msgsize, axi->mqstat.mq_curmsgs); - break; } - case AUDIT_IPC: { struct audit_aux_data_ipcctl *axi = (void *)aux; audit_log_format(ab, - "ouid=%u ogid=%u mode=%x", - axi->uid, axi->gid, axi->mode); + " qbytes=%lx iuid=%u igid=%u mode=%x", + axi->qbytes, axi->uid, axi->gid, axi->mode); if (axi->osid != 0) { char *ctx = NULL; u32 len; @@ -919,18 +652,19 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts case AUDIT_IPC_SET_PERM: { struct audit_aux_data_ipcctl *axi = (void *)aux; audit_log_format(ab, - "qbytes=%lx ouid=%u ogid=%u mode=%x", + " new qbytes=%lx new iuid=%u new igid=%u new mode=%x", axi->qbytes, axi->uid, axi->gid, axi->mode); - break; } - - case AUDIT_EXECVE: { - struct audit_aux_data_execve *axi = (void *)aux; - int i; - const char *p; - for (i = 0, p = axi->mem; i < axi->argc; i++) { - audit_log_format(ab, "a%d=", i); - p = audit_log_untrustedstring(ab, p); - audit_log_format(ab, "\n"); + if (axi->osid != 0) { + char *ctx = NULL; + u32 len; + if (selinux_ctxid_to_string( + axi->osid, &ctx, &len)) { + audit_log_format(ab, " osid=%u", + axi->osid); + call_panic = 1; + } else + audit_log_format(ab, " obj=%s", ctx); + kfree(ctx); } break; } @@ -966,7 +700,8 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts } } for (i = 0; i < context->name_count; i++) { - struct audit_names *n = &context->names[i]; + unsigned long ino = context->names[i].ino; + unsigned long pino = context->names[i].pino; ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH); if (!ab) @@ -974,47 +709,33 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts 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) { + audit_log_format(ab, " name="); + if (context->names[i].name) + audit_log_untrustedstring(ab, context->names[i].name); + else + audit_log_format(ab, "(null)"); + + if (pino != (unsigned long)-1) + audit_log_format(ab, " parent=%lu", pino); + if (ino != (unsigned long)-1) + audit_log_format(ab, " inode=%lu", ino); + if ((pino != (unsigned long)-1) || (ino != (unsigned long)-1)) + audit_log_format(ab, " dev=%02x:%02x mode=%#o" + " ouid=%u ogid=%u rdev=%02x:%02x", + MAJOR(context->names[i].dev), + MINOR(context->names[i].dev), + context->names[i].mode, + context->names[i].uid, + context->names[i].gid, + MAJOR(context->names[i].rdev), + MINOR(context->names[i].rdev)); + if (context->names[i].osid != 0) { char *ctx = NULL; u32 len; if (selinux_ctxid_to_string( - n->osid, &ctx, &len)) { - audit_log_format(ab, " osid=%u", n->osid); + context->names[i].osid, &ctx, &len)) { + audit_log_format(ab, " osid=%u", + context->names[i].osid); call_panic = 2; } else audit_log_format(ab, " obj=%s", ctx); @@ -1129,8 +850,7 @@ void audit_syscall_entry(int arch, int major, context->argv[3] = a4; state = context->state; - context->dummy = !audit_n_rules; - if (!context->dummy && (state == AUDIT_SETUP_CONTEXT || state == AUDIT_BUILD_CONTEXT)) + if (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; @@ -1177,8 +897,6 @@ void audit_syscall_exit(int valid, long return_code) } else { audit_free_names(context); audit_free_aux(context); - kfree(context->filterkey); - context->filterkey = NULL; tsk->audit_context = context; } } @@ -1190,11 +908,11 @@ void audit_syscall_exit(int valid, long return_code) * Add a name to the list of audit names for this context. * Called from fs/namei.c:getname(). */ -void __audit_getname(const char *name) +void audit_getname(const char *name) { struct audit_context *context = current->audit_context; - if (IS_ERR(name) || !name) + if (!context || IS_ERR(name) || !name) return; if (!context->in_syscall) { @@ -1207,8 +925,6 @@ void __audit_getname(const char *name) } 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->name_count; if (!context->pwd) { @@ -1263,26 +979,23 @@ void audit_putname(const char *name) #endif } -/* Copy inode data into an audit_names. */ -static void audit_copy_inode(struct audit_names *name, const struct inode *inode) +static void audit_inode_context(int idx, 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); + struct audit_context *context = current->audit_context; + + selinux_get_inode_sid(inode, &context->names[idx].osid); } + /** * audit_inode - store the inode and device from a lookup * @name: name being audited * @inode: inode being audited + * @flags: lookup flags (as used in path_lookup()) * * Called from fs/namei.c:path_lookup(). */ -void __audit_inode(const char *name, const struct inode *inode) +void __audit_inode(const char *name, const struct inode *inode, unsigned flags) { int idx; struct audit_context *context = current->audit_context; @@ -1302,28 +1015,33 @@ void __audit_inode(const char *name, const struct inode *inode) * associated name? */ if (context->name_count >= AUDIT_NAMES - AUDIT_NAMES_RESERVED) return; - idx = context->name_count; - if (context->name_count == (AUDIT_NAMES - 1)) { - printk(KERN_DEBUG - "name_count maxed and losing entry [%d]=%s\n", - context->name_count, - context->names[context->name_count].name ?: - "(null)"); - } else - context->name_count++; + idx = context->name_count++; context->names[idx].name = NULL; #if AUDIT_DEBUG ++context->ino_count; #endif } - audit_copy_inode(&context->names[idx], inode); + context->names[idx].dev = inode->i_sb->s_dev; + context->names[idx].mode = inode->i_mode; + context->names[idx].uid = inode->i_uid; + context->names[idx].gid = inode->i_gid; + context->names[idx].rdev = inode->i_rdev; + audit_inode_context(idx, inode); + if ((flags & LOOKUP_PARENT) && (strcmp(name, "/") != 0) && + (strcmp(name, ".") != 0)) { + context->names[idx].ino = (unsigned long)-1; + context->names[idx].pino = inode->i_ino; + } else { + context->names[idx].ino = inode->i_ino; + context->names[idx].pino = (unsigned long)-1; + } } /** * audit_inode_child - collect inode info for created/removed objects * @dname: inode's dentry name * @inode: inode being audited - * @parent: inode of dentry parent + * @pino: inode number of dentry parent * * For syscalls that create or remove filesystem objects, audit_inode * can only collect information for the filesystem object's parent. @@ -1334,103 +1052,66 @@ void __audit_inode(const char *name, const struct inode *inode) * unsuccessful attempts. */ void __audit_inode_child(const char *dname, const struct inode *inode, - const struct inode *parent) + unsigned long pino) { int idx; struct audit_context *context = current->audit_context; - const char *found_name = NULL; - int dirlen = 0; if (!context->in_syscall) return; /* determine matching parent */ - if (!dname) - goto update_context; - for (idx = 0; idx < context->name_count; idx++) - if (context->names[idx].ino == parent->i_ino) { - const char *name = context->names[idx].name; - - if (!name) - continue; - - if (audit_compare_dname_path(dname, name, &dirlen) == 0) { - context->names[idx].name_len = dirlen; - found_name = name; - break; + if (dname) + for (idx = 0; idx < context->name_count; idx++) + if (context->names[idx].pino == pino) { + const char *n; + const char *name = context->names[idx].name; + int dlen = strlen(dname); + int nlen = name ? strlen(name) : 0; + + if (nlen < dlen) + continue; + + /* disregard trailing slashes */ + n = name + nlen - 1; + while ((*n == '/') && (n > name)) + n--; + + /* find last path component */ + n = n - dlen + 1; + if (n < name) + continue; + else if (n > name) { + if (*--n != '/') + continue; + else + n++; + } + + if (strncmp(n, dname, dlen) == 0) + goto update_context; } - } -update_context: - idx = context->name_count; - if (context->name_count == (AUDIT_NAMES - 1)) { - printk(KERN_DEBUG "name_count maxed and losing entry [%d]=%s\n", - context->name_count, - context->names[context->name_count].name ?: "(null)"); - } else - context->name_count++; + /* catch-all in case match not found */ + idx = context->name_count++; + context->names[idx].name = NULL; + context->names[idx].pino = pino; #if AUDIT_DEBUG context->ino_count++; #endif - /* Re-use the name belonging to the slot for a matching parent directory. - * All names for this context are relinquished in audit_free_names() */ - context->names[idx].name = found_name; - context->names[idx].name_len = AUDIT_NAME_FULL; - context->names[idx].name_put = 0; /* don't call __putname() */ - - if (!inode) - context->names[idx].ino = (unsigned long)-1; - else - audit_copy_inode(&context->names[idx], inode); - - /* A parent was not found in audit_names, so copy the inode data for the - * provided parent. */ - if (!found_name) { - idx = context->name_count; - if (context->name_count == (AUDIT_NAMES - 1)) { - printk(KERN_DEBUG - "name_count maxed and losing entry [%d]=%s\n", - context->name_count, - context->names[context->name_count].name ?: - "(null)"); - } else - context->name_count++; -#if AUDIT_DEBUG - context->ino_count++; -#endif - audit_copy_inode(&context->names[idx], parent); - } -} -/** - * audit_inode_update - update inode info for last collected name - * @inode: inode being audited - * - * When open() is called on an existing object with the O_CREAT flag, the inode - * data audit initially collects is incorrect. This additional hook ensures - * audit has the inode data for the actual object to be opened. - */ -void __audit_inode_update(const struct inode *inode) -{ - struct audit_context *context = current->audit_context; - int idx; - - if (!context->in_syscall || !inode) - return; - - if (context->name_count == 0) { - context->name_count++; -#if AUDIT_DEBUG - context->ino_count++; -#endif +update_context: + if (inode) { + context->names[idx].ino = inode->i_ino; + context->names[idx].dev = inode->i_sb->s_dev; + context->names[idx].mode = inode->i_mode; + context->names[idx].uid = inode->i_uid; + context->names[idx].gid = inode->i_gid; + context->names[idx].rdev = inode->i_rdev; + audit_inode_context(idx, inode); } - idx = context->name_count - 1; - - audit_copy_inode(&context->names[idx], inode); } -EXPORT_SYMBOL_GPL(__audit_inode_child); - /** * auditsc_get_stamp - get local copies of audit_context values * @ctx: audit_context for the task @@ -1461,23 +1142,18 @@ void auditsc_get_stamp(struct audit_context *ctx, */ 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); - } + if (task->audit_context) { + 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, + task->audit_context->loginuid, loginuid); + audit_log_end(ab); } - context->loginuid = loginuid; + task->audit_context->loginuid = loginuid; } return 0; } @@ -1493,221 +1169,20 @@ uid_t audit_get_loginuid(struct audit_context *ctx) return ctx ? ctx->loginuid : -1; } -/** - * __audit_mq_open - record audit data for a POSIX MQ open - * @oflag: open flag - * @mode: mode bits - * @u_attr: queue attributes - * - * Returns 0 for success or NULL context or < 0 on error. - */ -int __audit_mq_open(int oflag, mode_t mode, struct mq_attr __user *u_attr) -{ - struct audit_aux_data_mq_open *ax; - struct audit_context *context = current->audit_context; - - if (!audit_enabled) - return 0; - - if (likely(!context)) - return 0; - - ax = kmalloc(sizeof(*ax), GFP_ATOMIC); - if (!ax) - return -ENOMEM; - - if (u_attr != NULL) { - if (copy_from_user(&ax->attr, u_attr, sizeof(ax->attr))) { - kfree(ax); - return -EFAULT; - } - } else - memset(&ax->attr, 0, sizeof(ax->attr)); - - ax->oflag = oflag; - ax->mode = mode; - - ax->d.type = AUDIT_MQ_OPEN; - ax->d.next = context->aux; - context->aux = (void *)ax; - return 0; -} - -/** - * __audit_mq_timedsend - record audit data for a POSIX MQ timed send - * @mqdes: MQ descriptor - * @msg_len: Message length - * @msg_prio: Message priority - * @u_abs_timeout: Message timeout in absolute time - * - * Returns 0 for success or NULL context or < 0 on error. - */ -int __audit_mq_timedsend(mqd_t mqdes, size_t msg_len, unsigned int msg_prio, - const struct timespec __user *u_abs_timeout) -{ - struct audit_aux_data_mq_sendrecv *ax; - struct audit_context *context = current->audit_context; - - if (!audit_enabled) - return 0; - - if (likely(!context)) - return 0; - - ax = kmalloc(sizeof(*ax), GFP_ATOMIC); - if (!ax) - return -ENOMEM; - - if (u_abs_timeout != NULL) { - if (copy_from_user(&ax->abs_timeout, u_abs_timeout, sizeof(ax->abs_timeout))) { - kfree(ax); - return -EFAULT; - } - } else - memset(&ax->abs_timeout, 0, sizeof(ax->abs_timeout)); - - ax->mqdes = mqdes; - ax->msg_len = msg_len; - ax->msg_prio = msg_prio; - - ax->d.type = AUDIT_MQ_SENDRECV; - ax->d.next = context->aux; - context->aux = (void *)ax; - return 0; -} - -/** - * __audit_mq_timedreceive - record audit data for a POSIX MQ timed receive - * @mqdes: MQ descriptor - * @msg_len: Message length - * @u_msg_prio: Message priority - * @u_abs_timeout: Message timeout in absolute time - * - * Returns 0 for success or NULL context or < 0 on error. - */ -int __audit_mq_timedreceive(mqd_t mqdes, size_t msg_len, - unsigned int __user *u_msg_prio, - const struct timespec __user *u_abs_timeout) -{ - struct audit_aux_data_mq_sendrecv *ax; - struct audit_context *context = current->audit_context; - - if (!audit_enabled) - return 0; - - if (likely(!context)) - return 0; - - ax = kmalloc(sizeof(*ax), GFP_ATOMIC); - if (!ax) - return -ENOMEM; - - if (u_msg_prio != NULL) { - if (get_user(ax->msg_prio, u_msg_prio)) { - kfree(ax); - return -EFAULT; - } - } else - ax->msg_prio = 0; - - if (u_abs_timeout != NULL) { - if (copy_from_user(&ax->abs_timeout, u_abs_timeout, sizeof(ax->abs_timeout))) { - kfree(ax); - return -EFAULT; - } - } else - memset(&ax->abs_timeout, 0, sizeof(ax->abs_timeout)); - - ax->mqdes = mqdes; - ax->msg_len = msg_len; - - ax->d.type = AUDIT_MQ_SENDRECV; - ax->d.next = context->aux; - context->aux = (void *)ax; - return 0; -} - -/** - * __audit_mq_notify - record audit data for a POSIX MQ notify - * @mqdes: MQ descriptor - * @u_notification: Notification event - * - * Returns 0 for success or NULL context or < 0 on error. - */ - -int __audit_mq_notify(mqd_t mqdes, const struct sigevent __user *u_notification) -{ - struct audit_aux_data_mq_notify *ax; - struct audit_context *context = current->audit_context; - - if (!audit_enabled) - return 0; - - if (likely(!context)) - return 0; - - ax = kmalloc(sizeof(*ax), GFP_ATOMIC); - if (!ax) - return -ENOMEM; - - if (u_notification != NULL) { - if (copy_from_user(&ax->notification, u_notification, sizeof(ax->notification))) { - kfree(ax); - return -EFAULT; - } - } else - memset(&ax->notification, 0, sizeof(ax->notification)); - - ax->mqdes = mqdes; - - ax->d.type = AUDIT_MQ_NOTIFY; - ax->d.next = context->aux; - context->aux = (void *)ax; - return 0; -} - -/** - * __audit_mq_getsetattr - record audit data for a POSIX MQ get/set attribute - * @mqdes: MQ descriptor - * @mqstat: MQ flags - * - * Returns 0 for success or NULL context or < 0 on error. - */ -int __audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat) -{ - struct audit_aux_data_mq_getsetattr *ax; - struct audit_context *context = current->audit_context; - - if (!audit_enabled) - return 0; - - if (likely(!context)) - return 0; - - ax = kmalloc(sizeof(*ax), GFP_ATOMIC); - if (!ax) - return -ENOMEM; - - ax->mqdes = mqdes; - ax->mqstat = *mqstat; - - ax->d.type = AUDIT_MQ_GETSETATTR; - ax->d.next = context->aux; - context->aux = (void *)ax; - return 0; -} - /** * audit_ipc_obj - record audit data for ipc object * @ipcp: ipc permissions * * Returns 0 for success or NULL context or < 0 on error. */ -int __audit_ipc_obj(struct kern_ipc_perm *ipcp) +int audit_ipc_obj(struct kern_ipc_perm *ipcp) { struct audit_aux_data_ipcctl *ax; struct audit_context *context = current->audit_context; + if (likely(!context)) + return 0; + ax = kmalloc(sizeof(*ax), GFP_ATOMIC); if (!ax) return -ENOMEM; @@ -1732,11 +1207,14 @@ int __audit_ipc_obj(struct kern_ipc_perm *ipcp) * * Returns 0 for success or NULL context or < 0 on error. */ -int __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode) +int audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp) { struct audit_aux_data_ipcctl *ax; struct audit_context *context = current->audit_context; + if (likely(!context)) + return 0; + ax = kmalloc(sizeof(*ax), GFP_ATOMIC); if (!ax) return -ENOMEM; @@ -1745,6 +1223,7 @@ int __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode ax->uid = uid; ax->gid = gid; ax->mode = mode; + selinux_get_ipc_sid(ipcp, &ax->osid); ax->d.type = AUDIT_IPC_SET_PERM; ax->d.next = context->aux; @@ -1752,39 +1231,6 @@ int __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode return 0; } -int audit_bprm(struct linux_binprm *bprm) -{ - struct audit_aux_data_execve *ax; - struct audit_context *context = current->audit_context; - unsigned long p, next; - void *to; - - if (likely(!audit_enabled || !context || context->dummy)) - return 0; - - ax = kmalloc(sizeof(*ax) + PAGE_SIZE * MAX_ARG_PAGES - bprm->p, - GFP_KERNEL); - if (!ax) - return -ENOMEM; - - ax->argc = bprm->argc; - ax->envc = bprm->envc; - for (p = bprm->p, to = ax->mem; p < MAX_ARG_PAGES*PAGE_SIZE; p = next) { - struct page *page = bprm->page[p / PAGE_SIZE]; - void *kaddr = kmap(page); - next = (p + PAGE_SIZE) & ~(PAGE_SIZE - 1); - memcpy(to, kaddr + (p & (PAGE_SIZE - 1)), next - p); - to += next - p; - kunmap(page); - } - - ax->d.type = AUDIT_EXECVE; - ax->d.next = context->aux; - context->aux = (void *)ax; - return 0; -} - - /** * audit_socketcall - record audit data for sys_socketcall * @nargs: number of args @@ -1797,7 +1243,7 @@ int audit_socketcall(int nargs, unsigned long *args) struct audit_aux_data_socketcall *ax; struct audit_context *context = current->audit_context; - if (likely(!context || context->dummy)) + if (likely(!context)) return 0; ax = kmalloc(sizeof(*ax) + nargs * sizeof(unsigned long), GFP_KERNEL); @@ -1825,7 +1271,7 @@ int audit_sockaddr(int len, void *a) struct audit_aux_data_sockaddr *ax; struct audit_context *context = current->audit_context; - if (likely(!context || context->dummy)) + if (likely(!context)) return 0; ax = kmalloc(sizeof(*ax) + len, GFP_KERNEL); @@ -1879,20 +1325,19 @@ int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt) * If the audit subsystem is being terminated, record the task (pid) * and uid that is doing that. */ -void __audit_signal_info(int sig, struct task_struct *t) +void audit_signal_info(int sig, struct task_struct *t) { extern pid_t audit_sig_pid; extern uid_t audit_sig_uid; - extern u32 audit_sig_sid; - - if (sig == SIGTERM || sig == SIGHUP || sig == SIGUSR1) { - struct task_struct *tsk = current; - struct audit_context *ctx = tsk->audit_context; - audit_sig_pid = tsk->pid; - if (ctx) - audit_sig_uid = ctx->loginuid; - else - audit_sig_uid = tsk->uid; - selinux_get_task_sid(tsk, &audit_sig_sid); + + if (unlikely(audit_pid && t->tgid == audit_pid)) { + if (sig == SIGTERM || sig == SIGHUP) { + struct audit_context *ctx = current->audit_context; + audit_sig_pid = current->pid; + if (ctx) + audit_sig_uid = ctx->loginuid; + else + audit_sig_uid = current->uid; + } } }