Merge remote-tracking branch 'audit/next'
authorStephen Rothwell <sfr@canb.auug.org.au>
Tue, 13 Sep 2016 01:46:41 +0000 (11:46 +1000)
committerStephen Rothwell <sfr@canb.auug.org.au>
Tue, 13 Sep 2016 01:46:41 +0000 (11:46 +1000)
1  2 
kernel/audit.c
kernel/auditsc.c
security/lsm_audit.c

diff --combined kernel/audit.c
index a8a91bd2b2a9b68696ca7b9b5916d49891992922,02bde12685bd8da96aa4496226028e05cb13c0f8..f1ca11613379fa2950aa7e33e732d85462f1fb57
@@@ -877,6 -877,12 +877,12 @@@ static int audit_receive_msg(struct sk_
                                return err;
                }
                if (s.mask & AUDIT_STATUS_PID) {
+                       /* NOTE: we are using task_tgid_vnr() below because
+                        *       the s.pid value is relative to the namespace
+                        *       of the caller; at present this doesn't matter
+                        *       much since you can really only run auditd
+                        *       from the initial pid namespace, but something
+                        *       to keep in mind if this changes */
                        int new_pid = s.pid;
                        pid_t requesting_pid = task_tgid_vnr(current);
  
                if (!audit_enabled && msg_type != AUDIT_USER_AVC)
                        return 0;
  
 -              err = audit_filter_user(msg_type);
 +              err = audit_filter(msg_type, AUDIT_FILTER_USER);
                if (err == 1) { /* match or error */
                        err = 0;
                        if (msg_type == AUDIT_USER_TTY) {
@@@ -1379,7 -1385,7 +1385,7 @@@ struct audit_buffer *audit_log_start(st
        if (audit_initialized != AUDIT_INITIALIZED)
                return NULL;
  
 -      if (unlikely(audit_filter_type(type)))
 +      if (unlikely(!audit_filter(type, AUDIT_FILTER_TYPE)))
                return NULL;
  
        if (gfp_mask & __GFP_DIRECT_RECLAIM) {
@@@ -1917,7 -1923,7 +1923,7 @@@ void audit_log_task_info(struct audit_b
                         " euid=%u suid=%u fsuid=%u"
                         " egid=%u sgid=%u fsgid=%u tty=%s ses=%u",
                         task_ppid_nr(tsk),
-                        task_pid_nr(tsk),
+                        task_tgid_nr(tsk),
                         from_kuid(&init_user_ns, audit_get_loginuid(tsk)),
                         from_kuid(&init_user_ns, cred->uid),
                         from_kgid(&init_user_ns, cred->gid),
diff --combined kernel/auditsc.c
index 5abf1dc1f91c578ccea84478c1f7fe53cde27afd,3824b1bbeae1a14a3389caf43d4a53aea67f9c8c..2cd5256dbff72dfbb4716563ff28d2f9e38a018e
@@@ -72,7 -72,6 +72,7 @@@
  #include <linux/compat.h>
  #include <linux/ctype.h>
  #include <linux/string.h>
 +#include <linux/uaccess.h>
  #include <uapi/linux/limits.h>
  
  #include "audit.h"
@@@ -82,8 -81,7 +82,8 @@@
  #define AUDITSC_SUCCESS 1
  #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
  
  /* max length to print of cmdline/proctitle value during audit */
@@@ -457,7 -455,7 +457,7 @@@ static int audit_filter_rules(struct ta
  
                switch (f->type) {
                case AUDIT_PID:
-                       pid = task_pid_nr(tsk);
+                       pid = task_tgid_nr(tsk);
                        result = audit_comparator(pid, f->op, f->val);
                        break;
                case AUDIT_PPID:
                ctx->prio = rule->prio;
        }
        switch (rule->action) {
 -      case AUDIT_NEVER:    *state = AUDIT_DISABLED;       break;
 -      case AUDIT_ALWAYS:   *state = AUDIT_RECORD_CONTEXT; break;
 +      case AUDIT_NEVER:
 +              *state = AUDIT_DISABLED;
 +              break;
 +      case AUDIT_ALWAYS:
 +              *state = AUDIT_RECORD_CONTEXT;
 +              break;
        }
        return 1;
  }
@@@ -993,178 -987,184 +993,178 @@@ static int audit_log_pid_context(struc
        return rc;
  }
  
 -/*
 - * to_send and len_sent accounting are very loose estimates.  We aren't
 - * 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)
 +static void audit_log_execve_info(struct audit_context *context,
 +                                struct audit_buffer **ab)
  {
 -      char arg_num_len_buf[12];
 -      const char __user *tmp_p = p;
 -      /* how many digits are in arg_num? 5 is the length of ' a=""' */
 -      size_t arg_num_len = snprintf(arg_num_len_buf, 12, "%d", arg_num) + 5;
 -      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 (WARN_ON_ONCE(len < 0 || len > MAX_ARG_STRLEN - 1)) {
 -              send_sig(SIGKILL, current, 0);
 -              return -1;
 +      long len_max;
 +      long len_rem;
 +      long len_full;
 +      long len_buf;
 +      long len_abuf;
 +      long len_tmp;
 +      bool require_data;
 +      bool encode;
 +      unsigned int iter;
 +      unsigned int arg;
 +      char *buf_head;
 +      char *buf;
 +      const char __user *p = (const char __user *)current->mm->arg_start;
 +
 +      /* NOTE: this buffer needs to be large enough to hold all the non-arg
 +       *       data we put in the audit record for this argument (see the
 +       *       code below) ... at this point in time 96 is plenty */
 +      char abuf[96];
 +
 +      /* NOTE: we set MAX_EXECVE_AUDIT_LEN to a rather arbitrary limit, the
 +       *       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 {
 -              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;
 -              }
 +              /* NOTE: we don't ever want to trust this value for anything
 +               *       serious, but the audit record format insists we
 +               *       provide an argument length for really long arguments,
 +               *       e.g. > MAX_EXECVE_AUDIT_LEN, so we have no choice but
 +               *       to use strncpy_from_user() to obtain this value for
 +               *       recording in the log, although we don't use it
 +               *       anywhere here to avoid a double-fetch problem */
 +              if (len_full == 0)
 +                      len_full = strnlen_user(p, MAX_ARG_STRLEN) - 1;
 +
 +              /* read more data from userspace */
 +              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);
 +                              goto out;
 +                      } else if (len_tmp == (len_max - len_buf)) {
 +                              /* buffer is not large enough */
 +                              require_data = true;
 +                              /* NOTE: if we are going to span multiple
 +                               *       buffers force the encoding so we stand
 +                               *       a chance at a sane len_full value and
 +                               *       consistent record encoding */
 +                              encode = true;
 +                              len_full = len_full * 2;
 +                              p += len_tmp;
 +                      } else {
 +                              require_data = false;
 +                              if (!encode)
 +                                      encode = audit_string_contains_control(
 +                                                              buf, len_tmp);
 +                              /* try to use a trusted value for len_full */
 +                              if (len_full < len_max)
 +                                      len_full = (encode ?
 +                                                  len_tmp * 2 : len_tmp);
 +                              p += len_tmp + 1;
 +                      }
 +                      len_buf += len_tmp;
 +                      buf_head[len_buf] = '\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;
 +                      /* length of the buffer in the audit record? */
 +                      len_abuf = (encode ? len_buf * 2 : len_buf + 2);
                }
 -              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_string(*ab, buf);
 -
 -              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)
 -{
 -      int i, len;
 -      size_t len_sent = 0;
 -      const char __user *p;
 -      char *buf;
 +              /* write as much as we can to the audit log */
 +              if (len_buf > 0) {
 +                      /* NOTE: some magic numbers here - basically if we
 +                       *       can't fit a reasonable amount of data into the
 +                       *       existing audit buffer, flush it and start with
 +                       *       a new buffer */
 +                      if ((sizeof(abuf) + 8) > len_rem) {
 +                              len_rem = len_max;
 +                              audit_log_end(*ab);
 +                              *ab = audit_log_start(context,
 +                                                    GFP_KERNEL, AUDIT_EXECVE);
 +                              if (!*ab)
 +                                      goto out;
 +                      }
  
 -      p = (const char __user *)current->mm->arg_start;
 +                      /* create the non-arg portion of the arg record */
 +                      len_tmp = 0;
 +                      if (require_data || (iter > 0) ||
 +                          ((len_abuf + sizeof(abuf)) > len_rem)) {
 +                              if (iter == 0) {
 +                                      len_tmp += snprintf(&abuf[len_tmp],
 +                                                      sizeof(abuf) - len_tmp,
 +                                                      " a%d_len=%lu",
 +                                                      arg, len_full);
 +                              }
 +                              len_tmp += snprintf(&abuf[len_tmp],
 +                                                  sizeof(abuf) - len_tmp,
 +                                                  " a%d[%d]=", arg, iter++);
 +                      } else
 +                              len_tmp += snprintf(&abuf[len_tmp],
 +                                                  sizeof(abuf) - len_tmp,
 +                                                  " a%d=", arg);
 +                      WARN_ON(len_tmp >= sizeof(abuf));
 +                      abuf[sizeof(abuf) - 1] = '\0';
 +
 +                      /* log the arg in the audit record */
 +                      audit_log_format(*ab, "%s", abuf);
 +                      len_rem -= len_tmp;
 +                      len_tmp = len_buf;
 +                      if (encode) {
 +                              if (len_abuf > len_rem)
 +                                      len_tmp = len_rem / 2; /* encoding */
 +                              audit_log_n_hex(*ab, buf, len_tmp);
 +                              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;
 +                      }
 +                      len_buf -= len_tmp;
 +                      buf += len_tmp;
 +              }
  
 -      audit_log_format(*ab, "argc=%d", context->execve.argc);
 +              /* ready to move to the next argument? */
 +              if ((len_buf == 0) && !require_data) {
 +                      arg++;
 +                      iter = 0;
 +                      len_full = 0;
 +                      require_data = true;
 +                      encode = false;
 +              }
 +      } while (arg < 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;
 -      }
 +      /* NOTE: the caller handles the final audit_log_end() call */
  
 -      for (i = 0; i < context->execve.argc; i++) {
 -              len = audit_log_single_execve_arg(context, ab, i,
 -                                                &len_sent, p, buf);
 -              if (len <= 0)
 -                      break;
 -              p += len;
 -      }
 -      kfree(buf);
 +out:
 +      kfree(buf_head);
  }
  
  static void show_special(struct audit_context *context, int *call_panic)
@@@ -1425,7 -1425,7 +1425,7 @@@ static void audit_log_exit(struct audit
        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_d_path(ab, "cwd=", &context->pwd);
                        audit_log_end(ab);
                }
        }
@@@ -1993,7 -1993,7 +1993,7 @@@ static void audit_log_set_loginuid(kuid
        loginuid = from_kuid(&init_user_ns, kloginuid),
        tty = audit_get_tty(current);
  
-       audit_log_format(ab, "pid=%d uid=%u", task_pid_nr(current), uid);
+       audit_log_format(ab, "pid=%d uid=%u", task_tgid_nr(current), uid);
        audit_log_task_context(ab);
        audit_log_format(ab, " old-auid=%u auid=%u tty=%s old-ses=%u ses=%u res=%d",
                         oldloginuid, loginuid, tty ? tty_name(tty) : "(none)",
@@@ -2220,7 -2220,7 +2220,7 @@@ void __audit_ptrace(struct task_struct 
  {
        struct audit_context *context = current->audit_context;
  
-       context->target_pid = task_pid_nr(t);
+       context->target_pid = task_tgid_nr(t);
        context->target_auid = audit_get_loginuid(t);
        context->target_uid = task_uid(t);
        context->target_sessionid = audit_get_sessionid(t);
@@@ -2245,7 -2245,7 +2245,7 @@@ int __audit_signal_info(int sig, struc
  
        if (audit_pid && t->tgid == audit_pid) {
                if (sig == SIGTERM || sig == SIGHUP || sig == SIGUSR1 || sig == SIGUSR2) {
-                       audit_sig_pid = task_pid_nr(tsk);
+                       audit_sig_pid = task_tgid_nr(tsk);
                        if (uid_valid(tsk->loginuid))
                                audit_sig_uid = tsk->loginuid;
                        else
@@@ -2345,7 -2345,7 +2345,7 @@@ int __audit_log_bprm_fcaps(struct linux
  void __audit_log_capset(const struct cred *new, const struct cred *old)
  {
        struct audit_context *context = current->audit_context;
-       context->capset.pid = task_pid_nr(current);
+       context->capset.pid = task_tgid_nr(current);
        context->capset.cap.effective   = new->cap_effective;
        context->capset.cap.inheritable = new->cap_effective;
        context->capset.cap.permitted   = new->cap_permitted;
@@@ -2377,7 -2377,7 +2377,7 @@@ static void audit_log_task(struct audit
                         from_kgid(&init_user_ns, gid),
                         sessionid);
        audit_log_task_context(ab);
-       audit_log_format(ab, " pid=%d comm=", task_pid_nr(current));
+       audit_log_format(ab, " pid=%d comm=", task_tgid_nr(current));
        audit_log_untrustedstring(ab, get_task_comm(comm, current));
        audit_log_d_path_exe(ab, current->mm);
  }
diff --combined security/lsm_audit.c
index 9bf851884800b02edd6f022fc4c078f12dd56d46,45d927ab807d82425b470d1e597b786fa91b7259..f560923df57416407b8bf41934223196a0db4df4
@@@ -99,7 -99,7 +99,7 @@@ int ipv4_skb_to_auditdata(struct sk_buf
        }
        return ret;
  }
 -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 +#if IS_ENABLED(CONFIG_IPV6)
  /**
   * ipv6_skb_to_auditdata : fill auditdata from skb
   * @skb : the skb
@@@ -220,7 -220,7 +220,7 @@@ static void dump_common_audit_data(stru
         */
        BUILD_BUG_ON(sizeof(a->u) > sizeof(void *)*2);
  
-       audit_log_format(ab, " pid=%d comm=", task_pid_nr(current));
+       audit_log_format(ab, " pid=%d comm=", task_tgid_nr(current));
        audit_log_untrustedstring(ab, memcpy(comm, current->comm, sizeof(comm)));
  
        switch (a->type) {
                        audit_log_format(ab, " ino=%lu", inode->i_ino);
                }
  
 -              audit_log_format(ab, " ioctlcmd=%hx", a->u.op->cmd);
 +              audit_log_format(ab, " ioctlcmd=0x%hx", a->u.op->cmd);
                break;
        }
        case LSM_AUDIT_DATA_DENTRY: {
        case LSM_AUDIT_DATA_TASK: {
                struct task_struct *tsk = a->u.tsk;
                if (tsk) {
-                       pid_t pid = task_pid_nr(tsk);
+                       pid_t pid = task_tgid_nr(tsk);
                        if (pid) {
                                char comm[sizeof(tsk->comm)];
                                audit_log_format(ab, " opid=%d ocomm=", pid);
This page took 0.036413 seconds and 5 git commands to generate.