📄 auditsc.c
字号:
* within about 500 bytes (next page boundry) * * why snprintf? an int is up to 12 digits long. if we just assumed when * logging that a[%d]= was going to be 16 characters long we would be wasting * space in every audit message. In one 7500 byte message we can log up to * about 1000 min size arguments. That comes down to about 50% waste of space * if we didn't do the snprintf to find out how long arg_num_len was. */static int audit_log_single_execve_arg(struct audit_context *context, struct audit_buffer **ab, int arg_num, size_t *len_sent, const char __user *p, char *buf){ char arg_num_len_buf[12]; const char __user *tmp_p = p; /* how many digits are in arg_num? 3 is the length of a=\n */ size_t arg_num_len = snprintf(arg_num_len_buf, 12, "%d", arg_num) + 3; size_t len, len_left, to_send; size_t max_execve_audit_len = MAX_EXECVE_AUDIT_LEN; unsigned int i, has_cntl = 0, too_long = 0; int ret; /* strnlen_user includes the null we don't want to send */ len_left = len = strnlen_user(p, MAX_ARG_STRLEN) - 1; /* * We just created this mm, if we can't find the strings * we just copied into it something is _very_ wrong. Similar * for strings that are too long, we should not have created * any. */ if (unlikely((len == -1) || len > MAX_ARG_STRLEN - 1)) { WARN_ON(1); send_sig(SIGKILL, current, 0); return -1; } /* walk the whole argument looking for non-ascii chars */ do { if (len_left > MAX_EXECVE_AUDIT_LEN) to_send = MAX_EXECVE_AUDIT_LEN; else to_send = len_left; ret = copy_from_user(buf, tmp_p, to_send); /* * There is no reason for this copy to be short. We just * copied them here, and the mm hasn't been exposed to user- * space yet. */ if (ret) { WARN_ON(1); send_sig(SIGKILL, current, 0); return -1; } buf[to_send] = '\0'; has_cntl = audit_string_contains_control(buf, to_send); if (has_cntl) { /* * hex messages get logged as 2 bytes, so we can only * send half as much in each message */ max_execve_audit_len = MAX_EXECVE_AUDIT_LEN / 2; break; } len_left -= to_send; tmp_p += to_send; } while (len_left > 0); len_left = len; if (len > max_execve_audit_len) too_long = 1; /* rewalk the argument actually logging the message */ for (i = 0; len_left > 0; i++) { int room_left; if (len_left > max_execve_audit_len) to_send = max_execve_audit_len; else to_send = len_left; /* do we have space left to send this argument in this ab? */ room_left = MAX_EXECVE_AUDIT_LEN - arg_num_len - *len_sent; if (has_cntl) room_left -= (to_send * 2); else room_left -= to_send; if (room_left < 0) { *len_sent = 0; audit_log_end(*ab); *ab = audit_log_start(context, GFP_KERNEL, AUDIT_EXECVE); if (!*ab) return 0; } /* * first record needs to say how long the original string was * so we can be sure nothing was lost. */ if ((i == 0) && (too_long)) audit_log_format(*ab, "a%d_len=%zu ", arg_num, has_cntl ? 2*len : len); /* * normally arguments are small enough to fit and we already * filled buf above when we checked for control characters * so don't bother with another copy_from_user */ if (len >= max_execve_audit_len) ret = copy_from_user(buf, p, to_send); else ret = 0; if (ret) { WARN_ON(1); send_sig(SIGKILL, current, 0); return -1; } buf[to_send] = '\0'; /* actually log it */ audit_log_format(*ab, "a%d", arg_num); if (too_long) audit_log_format(*ab, "[%d]", i); audit_log_format(*ab, "="); if (has_cntl) audit_log_n_hex(*ab, buf, to_send); else audit_log_format(*ab, "\"%s\"", buf); audit_log_format(*ab, "\n"); p += to_send; len_left -= to_send; *len_sent += arg_num_len; if (has_cntl) *len_sent += to_send * 2; else *len_sent += to_send; } /* include the null we didn't log */ return len + 1;}static void audit_log_execve_info(struct audit_context *context, struct audit_buffer **ab, struct audit_aux_data_execve *axi){ int i; size_t len, len_sent = 0; const char __user *p; char *buf; if (axi->mm != current->mm) return; /* execve failed, no additional info */ p = (const char __user *)axi->mm->arg_start; audit_log_format(*ab, "argc=%d ", axi->argc); /* * we need some kernel buffer to hold the userspace args. Just * allocate one big one rather than allocating one of the right size * for every single argument inside audit_log_single_execve_arg() * should be <8k allocation so should be pretty safe. */ buf = kmalloc(MAX_EXECVE_AUDIT_LEN + 1, GFP_KERNEL); if (!buf) { audit_panic("out of memory for argv string\n"); return; } for (i = 0; i < axi->argc; i++) { len = audit_log_single_execve_arg(context, ab, i, &len_sent, p, buf); if (len <= 0) break; p += len; } kfree(buf);}static void audit_log_exit(struct audit_context *context, struct task_struct *tsk){ int i, call_panic = 0; struct audit_buffer *ab; struct audit_aux_data *aux; const char *tty; /* tsk == current */ context->pid = tsk->pid; if (!context->ppid) context->ppid = sys_getppid(); 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) return; /* audit_panic has been called */ audit_log_format(ab, "arch=%x syscall=%d", context->arch, context->major); if (context->personality != PER_LINUX) audit_log_format(ab, " per=%lx", context->personality); if (context->return_valid) 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" " euid=%u suid=%u fsuid=%u" " egid=%u sgid=%u fsgid=%u tty=%s ses=%u", context->argv[0], context->argv[1], context->argv[2], context->argv[3], context->name_count, context->ppid, context->pid, tsk->loginuid, context->uid, context->gid, context->euid, context->suid, context->fsuid, context->egid, context->sgid, context->fsgid, tty, tsk->sessionid); 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) { ab = audit_log_start(context, GFP_KERNEL, aux->type); if (!ab) 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=%#o", axi->uid, axi->gid, axi->mode); if (axi->osid != 0) { char *ctx = NULL; u32 len; if (security_secid_to_secctx( axi->osid, &ctx, &len)) { audit_log_format(ab, " osid=%u", axi->osid); call_panic = 1; } else { audit_log_format(ab, " obj=%s", ctx); security_release_secctx(ctx, len); } } break; } case AUDIT_IPC_SET_PERM: { struct audit_aux_data_ipcctl *axi = (void *)aux; audit_log_format(ab, "qbytes=%lx ouid=%u ogid=%u mode=%#o", axi->qbytes, axi->uid, axi->gid, axi->mode); break; } case AUDIT_EXECVE: { struct audit_aux_data_execve *axi = (void *)aux; audit_log_execve_info(context, &ab, axi); break; } case AUDIT_SOCKETCALL: { struct audit_aux_data_socketcall *axs = (void *)aux; audit_log_format(ab, "nargs=%d", axs->nargs); for (i=0; i<axs->nargs; i++) audit_log_format(ab, " a%d=%lx", i, axs->args[i]); break; } case AUDIT_SOCKADDR: { struct audit_aux_data_sockaddr *axs = (void *)aux; audit_log_format(ab, "saddr="); audit_log_n_hex(ab, axs->a, axs->len); break; } case AUDIT_FD_PAIR: { struct audit_aux_data_fd_pair *axs = (void *)aux; audit_log_format(ab, "fd0=%d fd1=%d", axs->fd[0], axs->fd[1]); break; } } audit_log_end(ab); } for (aux = context->aux_pids; aux; aux = aux->next) { struct audit_aux_data_pids *axs = (void *)aux; for (i = 0; i < axs->pid_count; i++) if (audit_log_pid_context(context, axs->target_pid[i], axs->target_auid[i], axs->target_uid[i], axs->target_sessionid[i], axs->target_sid[i], axs->target_comm[i])) call_panic = 1; } if (context->target_pid && audit_log_pid_context(context, context->target_pid, context->target_auid, context->target_uid, context->target_sessionid, context->target_sid, context->target_comm)) call_panic = 1; if (context->pwd.dentry && context->pwd.mnt) { ab = audit_log_start(context, GFP_KERNEL, AUDIT_CWD); if (ab) { audit_log_d_path(ab, "cwd=", &context->pwd); audit_log_end(ab); } } for (i = 0; i < context->name_count; i++) { struct audit_names *n = &context->names[i]; ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH); 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); break; default: /* log the name's directory component */ audit_log_format(ab, " name="); audit_log_n_untrustedstring(ab, n->name, n->name_len); } } 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 (security_secid_to_secctx( n->osid, &ctx, &len)) { audit_log_format(ab, " osid=%u", n->osid); call_panic = 2; } else { audit_log_format(ab, " obj=%s", ctx); security_release_secctx(ctx, len); } } audit_log_end(ab); } /* Send end of event record to help user space know we are finished */ ab = audit_log_start(context, GFP_KERNEL, AUDIT_EOE); if (ab) 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -