Loading kernel/auditsc.c +164 −168 Original line number Original line Diff line number Diff line Loading @@ -73,6 +73,7 @@ #include <linux/compat.h> #include <linux/compat.h> #include <linux/ctype.h> #include <linux/ctype.h> #include <linux/string.h> #include <linux/string.h> #include <linux/uaccess.h> #include <uapi/linux/limits.h> #include <uapi/linux/limits.h> #include "audit.h" #include "audit.h" Loading @@ -82,7 +83,8 @@ #define AUDITSC_SUCCESS 1 #define AUDITSC_SUCCESS 1 #define AUDITSC_FAILURE 2 #define AUDITSC_FAILURE 2 /* no execve audit message should be longer than this (userspace limits) */ /* no execve audit message should be longer than this (userspace limits), * see the note near the top of audit_log_execve_info() about this value */ #define MAX_EXECVE_AUDIT_LEN 7500 #define MAX_EXECVE_AUDIT_LEN 7500 /* max length to print of cmdline/proctitle value during audit */ /* max length to print of cmdline/proctitle value during audit */ Loading Loading @@ -988,184 +990,178 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid, return rc; return rc; } } /* static void audit_log_execve_info(struct audit_context *context, * to_send and len_sent accounting are very loose estimates. We aren't struct audit_buffer **ab) * really worried about a hard cap to MAX_EXECVE_AUDIT_LEN so much as being * within about 500 bytes (next page boundary) * * 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]; long len_max; const char __user *tmp_p = p; long len_rem; /* how many digits are in arg_num? 5 is the length of ' a=""' */ long len_full; size_t arg_num_len = snprintf(arg_num_len_buf, 12, "%d", arg_num) + 5; long len_buf; size_t len, len_left, to_send; long len_abuf; size_t max_execve_audit_len = MAX_EXECVE_AUDIT_LEN; long len_tmp; unsigned int i, has_cntl = 0, too_long = 0; bool require_data; int ret; bool encode; unsigned int iter; /* strnlen_user includes the null we don't want to send */ unsigned int arg; len_left = len = strnlen_user(p, MAX_ARG_STRLEN) - 1; char *buf_head; char *buf; /* const char __user *p = (const char __user *)current->mm->arg_start; * We just created this mm, if we can't find the strings * we just copied into it something is _very_ wrong. Similar /* NOTE: this buffer needs to be large enough to hold all the non-arg * for strings that are too long, we should not have created * data we put in the audit record for this argument (see the * any. * code below) ... at this point in time 96 is plenty */ */ char abuf[96]; if (WARN_ON_ONCE(len < 0 || len > MAX_ARG_STRLEN - 1)) { send_sig(SIGKILL, current, 0); /* NOTE: we set MAX_EXECVE_AUDIT_LEN to a rather arbitrary limit, the return -1; * current value of 7500 is not as important as the fact that it * is less than 8k, a setting of 7500 gives us plenty of wiggle * room if we go over a little bit in the logging below */ WARN_ON_ONCE(MAX_EXECVE_AUDIT_LEN > 7500); len_max = MAX_EXECVE_AUDIT_LEN; /* scratch buffer to hold the userspace args */ buf_head = kmalloc(MAX_EXECVE_AUDIT_LEN + 1, GFP_KERNEL); if (!buf_head) { audit_panic("out of memory for argv string"); return; } } buf = buf_head; /* walk the whole argument looking for non-ascii chars */ audit_log_format(*ab, "argc=%d", context->execve.argc); len_rem = len_max; len_buf = 0; len_full = 0; require_data = true; encode = false; iter = 0; arg = 0; do { do { if (len_left > MAX_EXECVE_AUDIT_LEN) /* NOTE: we don't ever want to trust this value for anything to_send = MAX_EXECVE_AUDIT_LEN; * serious, but the audit record format insists we else * provide an argument length for really long arguments, to_send = len_left; * e.g. > MAX_EXECVE_AUDIT_LEN, so we have no choice but ret = copy_from_user(buf, tmp_p, to_send); * to use strncpy_from_user() to obtain this value for /* * recording in the log, although we don't use it * There is no reason for this copy to be short. We just * anywhere here to avoid a double-fetch problem */ * copied them here, and the mm hasn't been exposed to user- if (len_full == 0) * space yet. len_full = strnlen_user(p, MAX_ARG_STRLEN) - 1; */ if (ret) { /* read more data from userspace */ WARN_ON(1); if (require_data) { /* can we make more room in the buffer? */ if (buf != buf_head) { memmove(buf_head, buf, len_buf); buf = buf_head; } /* fetch as much as we can of the argument */ len_tmp = strncpy_from_user(&buf_head[len_buf], p, len_max - len_buf); if (len_tmp == -EFAULT) { /* unable to copy from userspace */ send_sig(SIGKILL, current, 0); send_sig(SIGKILL, current, 0); return -1; goto out; } } else if (len_tmp == (len_max - len_buf)) { buf[to_send] = '\0'; /* buffer is not large enough */ has_cntl = audit_string_contains_control(buf, to_send); require_data = true; if (has_cntl) { /* NOTE: if we are going to span multiple /* * buffers force the encoding so we stand * hex messages get logged as 2 bytes, so we can only * a chance at a sane len_full value and * send half as much in each message * consistent record encoding */ */ encode = true; max_execve_audit_len = MAX_EXECVE_AUDIT_LEN / 2; len_full = len_full * 2; break; p += len_tmp; } } else { len_left -= to_send; require_data = false; tmp_p += to_send; if (!encode) } while (len_left > 0); encode = audit_string_contains_control( buf, len_tmp); len_left = len; /* try to use a trusted value for len_full */ if (len_full < len_max) if (len > max_execve_audit_len) len_full = (encode ? too_long = 1; len_tmp * 2 : len_tmp); p += len_tmp + 1; /* rewalk the argument actually logging the message */ } for (i = 0; len_left > 0; i++) { len_buf += len_tmp; int room_left; buf_head[len_buf] = '\0'; if (len_left > max_execve_audit_len) /* length of the buffer in the audit record? */ to_send = max_execve_audit_len; len_abuf = (encode ? len_buf * 2 : len_buf + 2); else } to_send = len_left; /* write as much as we can to the audit log */ /* do we have space left to send this argument in this ab? */ if (len_buf > 0) { room_left = MAX_EXECVE_AUDIT_LEN - arg_num_len - *len_sent; /* NOTE: some magic numbers here - basically if we if (has_cntl) * can't fit a reasonable amount of data into the room_left -= (to_send * 2); * existing audit buffer, flush it and start with else * a new buffer */ room_left -= to_send; if ((sizeof(abuf) + 8) > len_rem) { if (room_left < 0) { len_rem = len_max; *len_sent = 0; audit_log_end(*ab); audit_log_end(*ab); *ab = audit_log_start(context, GFP_KERNEL, AUDIT_EXECVE); *ab = audit_log_start(context, GFP_KERNEL, AUDIT_EXECVE); if (!*ab) if (!*ab) return 0; goto out; } } /* /* create the non-arg portion of the arg record */ * first record needs to say how long the original string was len_tmp = 0; * so we can be sure nothing was lost. if (require_data || (iter > 0) || */ ((len_abuf + sizeof(abuf)) > len_rem)) { if ((i == 0) && (too_long)) if (iter == 0) { audit_log_format(*ab, " a%d_len=%zu", arg_num, len_tmp += snprintf(&abuf[len_tmp], has_cntl ? 2*len : len); sizeof(abuf) - len_tmp, " a%d_len=%lu", /* arg, len_full); * 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'; len_tmp += snprintf(&abuf[len_tmp], sizeof(abuf) - len_tmp, /* actually log it */ " a%d[%d]=", arg, iter++); audit_log_format(*ab, " a%d", arg_num); } else if (too_long) len_tmp += snprintf(&abuf[len_tmp], audit_log_format(*ab, "[%d]", i); sizeof(abuf) - len_tmp, audit_log_format(*ab, "="); " a%d=", arg); if (has_cntl) WARN_ON(len_tmp >= sizeof(abuf)); audit_log_n_hex(*ab, buf, to_send); abuf[sizeof(abuf) - 1] = '\0'; else audit_log_string(*ab, buf); /* log the arg in the audit record */ audit_log_format(*ab, "%s", abuf); p += to_send; len_rem -= len_tmp; len_left -= to_send; len_tmp = len_buf; *len_sent += arg_num_len; if (encode) { if (has_cntl) if (len_abuf > len_rem) *len_sent += to_send * 2; len_tmp = len_rem / 2; /* encoding */ else audit_log_n_hex(*ab, buf, len_tmp); *len_sent += to_send; len_rem -= len_tmp * 2; len_abuf -= len_tmp * 2; } else { if (len_abuf > len_rem) len_tmp = len_rem - 2; /* quotes */ audit_log_n_string(*ab, buf, len_tmp); len_rem -= len_tmp + 2; /* don't subtract the "2" because we still need * to add quotes to the remaining string */ len_abuf -= len_tmp; } } /* include the null we didn't log */ len_buf -= len_tmp; return len + 1; buf += len_tmp; } } static void audit_log_execve_info(struct audit_context *context, /* ready to move to the next argument? */ struct audit_buffer **ab) if ((len_buf == 0) && !require_data) { { arg++; int i, len; iter = 0; size_t len_sent = 0; len_full = 0; const char __user *p; require_data = true; char *buf; encode = false; p = (const char __user *)current->mm->arg_start; audit_log_format(*ab, "argc=%d", context->execve.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"); return; } } } while (arg < context->execve.argc); for (i = 0; i < context->execve.argc; i++) { /* NOTE: the caller handles the final audit_log_end() call */ len = audit_log_single_execve_arg(context, ab, i, &len_sent, p, buf); out: if (len <= 0) kfree(buf_head); break; p += len; } kfree(buf); } } static void show_special(struct audit_context *context, int *call_panic) static void show_special(struct audit_context *context, int *call_panic) Loading Loading
kernel/auditsc.c +164 −168 Original line number Original line Diff line number Diff line Loading @@ -73,6 +73,7 @@ #include <linux/compat.h> #include <linux/compat.h> #include <linux/ctype.h> #include <linux/ctype.h> #include <linux/string.h> #include <linux/string.h> #include <linux/uaccess.h> #include <uapi/linux/limits.h> #include <uapi/linux/limits.h> #include "audit.h" #include "audit.h" Loading @@ -82,7 +83,8 @@ #define AUDITSC_SUCCESS 1 #define AUDITSC_SUCCESS 1 #define AUDITSC_FAILURE 2 #define AUDITSC_FAILURE 2 /* no execve audit message should be longer than this (userspace limits) */ /* no execve audit message should be longer than this (userspace limits), * see the note near the top of audit_log_execve_info() about this value */ #define MAX_EXECVE_AUDIT_LEN 7500 #define MAX_EXECVE_AUDIT_LEN 7500 /* max length to print of cmdline/proctitle value during audit */ /* max length to print of cmdline/proctitle value during audit */ Loading Loading @@ -988,184 +990,178 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid, return rc; return rc; } } /* static void audit_log_execve_info(struct audit_context *context, * to_send and len_sent accounting are very loose estimates. We aren't struct audit_buffer **ab) * really worried about a hard cap to MAX_EXECVE_AUDIT_LEN so much as being * within about 500 bytes (next page boundary) * * 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]; long len_max; const char __user *tmp_p = p; long len_rem; /* how many digits are in arg_num? 5 is the length of ' a=""' */ long len_full; size_t arg_num_len = snprintf(arg_num_len_buf, 12, "%d", arg_num) + 5; long len_buf; size_t len, len_left, to_send; long len_abuf; size_t max_execve_audit_len = MAX_EXECVE_AUDIT_LEN; long len_tmp; unsigned int i, has_cntl = 0, too_long = 0; bool require_data; int ret; bool encode; unsigned int iter; /* strnlen_user includes the null we don't want to send */ unsigned int arg; len_left = len = strnlen_user(p, MAX_ARG_STRLEN) - 1; char *buf_head; char *buf; /* const char __user *p = (const char __user *)current->mm->arg_start; * We just created this mm, if we can't find the strings * we just copied into it something is _very_ wrong. Similar /* NOTE: this buffer needs to be large enough to hold all the non-arg * for strings that are too long, we should not have created * data we put in the audit record for this argument (see the * any. * code below) ... at this point in time 96 is plenty */ */ char abuf[96]; if (WARN_ON_ONCE(len < 0 || len > MAX_ARG_STRLEN - 1)) { send_sig(SIGKILL, current, 0); /* NOTE: we set MAX_EXECVE_AUDIT_LEN to a rather arbitrary limit, the return -1; * current value of 7500 is not as important as the fact that it * is less than 8k, a setting of 7500 gives us plenty of wiggle * room if we go over a little bit in the logging below */ WARN_ON_ONCE(MAX_EXECVE_AUDIT_LEN > 7500); len_max = MAX_EXECVE_AUDIT_LEN; /* scratch buffer to hold the userspace args */ buf_head = kmalloc(MAX_EXECVE_AUDIT_LEN + 1, GFP_KERNEL); if (!buf_head) { audit_panic("out of memory for argv string"); return; } } buf = buf_head; /* walk the whole argument looking for non-ascii chars */ audit_log_format(*ab, "argc=%d", context->execve.argc); len_rem = len_max; len_buf = 0; len_full = 0; require_data = true; encode = false; iter = 0; arg = 0; do { do { if (len_left > MAX_EXECVE_AUDIT_LEN) /* NOTE: we don't ever want to trust this value for anything to_send = MAX_EXECVE_AUDIT_LEN; * serious, but the audit record format insists we else * provide an argument length for really long arguments, to_send = len_left; * e.g. > MAX_EXECVE_AUDIT_LEN, so we have no choice but ret = copy_from_user(buf, tmp_p, to_send); * to use strncpy_from_user() to obtain this value for /* * recording in the log, although we don't use it * There is no reason for this copy to be short. We just * anywhere here to avoid a double-fetch problem */ * copied them here, and the mm hasn't been exposed to user- if (len_full == 0) * space yet. len_full = strnlen_user(p, MAX_ARG_STRLEN) - 1; */ if (ret) { /* read more data from userspace */ WARN_ON(1); if (require_data) { /* can we make more room in the buffer? */ if (buf != buf_head) { memmove(buf_head, buf, len_buf); buf = buf_head; } /* fetch as much as we can of the argument */ len_tmp = strncpy_from_user(&buf_head[len_buf], p, len_max - len_buf); if (len_tmp == -EFAULT) { /* unable to copy from userspace */ send_sig(SIGKILL, current, 0); send_sig(SIGKILL, current, 0); return -1; goto out; } } else if (len_tmp == (len_max - len_buf)) { buf[to_send] = '\0'; /* buffer is not large enough */ has_cntl = audit_string_contains_control(buf, to_send); require_data = true; if (has_cntl) { /* NOTE: if we are going to span multiple /* * buffers force the encoding so we stand * hex messages get logged as 2 bytes, so we can only * a chance at a sane len_full value and * send half as much in each message * consistent record encoding */ */ encode = true; max_execve_audit_len = MAX_EXECVE_AUDIT_LEN / 2; len_full = len_full * 2; break; p += len_tmp; } } else { len_left -= to_send; require_data = false; tmp_p += to_send; if (!encode) } while (len_left > 0); encode = audit_string_contains_control( buf, len_tmp); len_left = len; /* try to use a trusted value for len_full */ if (len_full < len_max) if (len > max_execve_audit_len) len_full = (encode ? too_long = 1; len_tmp * 2 : len_tmp); p += len_tmp + 1; /* rewalk the argument actually logging the message */ } for (i = 0; len_left > 0; i++) { len_buf += len_tmp; int room_left; buf_head[len_buf] = '\0'; if (len_left > max_execve_audit_len) /* length of the buffer in the audit record? */ to_send = max_execve_audit_len; len_abuf = (encode ? len_buf * 2 : len_buf + 2); else } to_send = len_left; /* write as much as we can to the audit log */ /* do we have space left to send this argument in this ab? */ if (len_buf > 0) { room_left = MAX_EXECVE_AUDIT_LEN - arg_num_len - *len_sent; /* NOTE: some magic numbers here - basically if we if (has_cntl) * can't fit a reasonable amount of data into the room_left -= (to_send * 2); * existing audit buffer, flush it and start with else * a new buffer */ room_left -= to_send; if ((sizeof(abuf) + 8) > len_rem) { if (room_left < 0) { len_rem = len_max; *len_sent = 0; audit_log_end(*ab); audit_log_end(*ab); *ab = audit_log_start(context, GFP_KERNEL, AUDIT_EXECVE); *ab = audit_log_start(context, GFP_KERNEL, AUDIT_EXECVE); if (!*ab) if (!*ab) return 0; goto out; } } /* /* create the non-arg portion of the arg record */ * first record needs to say how long the original string was len_tmp = 0; * so we can be sure nothing was lost. if (require_data || (iter > 0) || */ ((len_abuf + sizeof(abuf)) > len_rem)) { if ((i == 0) && (too_long)) if (iter == 0) { audit_log_format(*ab, " a%d_len=%zu", arg_num, len_tmp += snprintf(&abuf[len_tmp], has_cntl ? 2*len : len); sizeof(abuf) - len_tmp, " a%d_len=%lu", /* arg, len_full); * 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'; len_tmp += snprintf(&abuf[len_tmp], sizeof(abuf) - len_tmp, /* actually log it */ " a%d[%d]=", arg, iter++); audit_log_format(*ab, " a%d", arg_num); } else if (too_long) len_tmp += snprintf(&abuf[len_tmp], audit_log_format(*ab, "[%d]", i); sizeof(abuf) - len_tmp, audit_log_format(*ab, "="); " a%d=", arg); if (has_cntl) WARN_ON(len_tmp >= sizeof(abuf)); audit_log_n_hex(*ab, buf, to_send); abuf[sizeof(abuf) - 1] = '\0'; else audit_log_string(*ab, buf); /* log the arg in the audit record */ audit_log_format(*ab, "%s", abuf); p += to_send; len_rem -= len_tmp; len_left -= to_send; len_tmp = len_buf; *len_sent += arg_num_len; if (encode) { if (has_cntl) if (len_abuf > len_rem) *len_sent += to_send * 2; len_tmp = len_rem / 2; /* encoding */ else audit_log_n_hex(*ab, buf, len_tmp); *len_sent += to_send; len_rem -= len_tmp * 2; len_abuf -= len_tmp * 2; } else { if (len_abuf > len_rem) len_tmp = len_rem - 2; /* quotes */ audit_log_n_string(*ab, buf, len_tmp); len_rem -= len_tmp + 2; /* don't subtract the "2" because we still need * to add quotes to the remaining string */ len_abuf -= len_tmp; } } /* include the null we didn't log */ len_buf -= len_tmp; return len + 1; buf += len_tmp; } } static void audit_log_execve_info(struct audit_context *context, /* ready to move to the next argument? */ struct audit_buffer **ab) if ((len_buf == 0) && !require_data) { { arg++; int i, len; iter = 0; size_t len_sent = 0; len_full = 0; const char __user *p; require_data = true; char *buf; encode = false; p = (const char __user *)current->mm->arg_start; audit_log_format(*ab, "argc=%d", context->execve.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"); return; } } } while (arg < context->execve.argc); for (i = 0; i < context->execve.argc; i++) { /* NOTE: the caller handles the final audit_log_end() call */ len = audit_log_single_execve_arg(context, ab, i, &len_sent, p, buf); out: if (len <= 0) kfree(buf_head); break; p += len; } kfree(buf); } } static void show_special(struct audit_context *context, int *call_panic) static void show_special(struct audit_context *context, int *call_panic) Loading