]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'audit/next'
authorStephen Rothwell <sfr@canb.auug.org.au>
Thu, 5 Nov 2015 02:14:09 +0000 (13:14 +1100)
committerStephen Rothwell <sfr@canb.auug.org.au>
Thu, 5 Nov 2015 02:14:09 +0000 (13:14 +1100)
1  2 
kernel/audit.c
kernel/audit.h
kernel/audit_tree.c

diff --combined kernel/audit.c
index 662c007635fb778bef2bca5cc213f8cb23ed364e,4d3cdcd24bcb21b31dd8a89ed4b53b74dcb37c1b..8a056a32ded7d2b4560612af7d84ac317f7a17b3
@@@ -43,7 -43,6 +43,7 @@@
  
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  
 +#include <linux/file.h>
  #include <linux/init.h>
  #include <linux/types.h>
  #include <linux/atomic.h>
@@@ -108,7 -107,6 +108,7 @@@ static u32 audit_rate_limit
   * When set to zero, this means unlimited. */
  static u32    audit_backlog_limit = 64;
  #define AUDIT_BACKLOG_WAIT_TIME (60 * HZ)
 +static u32    audit_backlog_wait_time_master = AUDIT_BACKLOG_WAIT_TIME;
  static u32    audit_backlog_wait_time = AUDIT_BACKLOG_WAIT_TIME;
  static u32    audit_backlog_wait_overflow = 0;
  
@@@ -340,13 -338,13 +340,13 @@@ static int audit_set_backlog_limit(u32 
  static int audit_set_backlog_wait_time(u32 timeout)
  {
        return audit_do_config_change("audit_backlog_wait_time",
 -                                    &audit_backlog_wait_time, timeout);
 +                                    &audit_backlog_wait_time_master, timeout);
  }
  
  static int audit_set_enabled(u32 state)
  {
        int rc;
 -      if (state < AUDIT_OFF || state > AUDIT_LOCKED)
 +      if (state > AUDIT_LOCKED)
                return -EINVAL;
  
        rc =  audit_do_config_change("audit_enabled", &audit_enabled, state);
@@@ -407,16 -405,33 +407,33 @@@ static void audit_printk_skb(struct sk_
  static void kauditd_send_skb(struct sk_buff *skb)
  {
        int err;
+       int attempts = 0;
+ #define AUDITD_RETRIES 5
+ restart:
        /* take a reference in case we can't send it and we want to hold it */
        skb_get(skb);
        err = netlink_unicast(audit_sock, skb, audit_nlk_portid, 0);
        if (err < 0) {
-               BUG_ON(err != -ECONNREFUSED); /* Shouldn't happen */
+               pr_err("netlink_unicast sending to audit_pid=%d returned error: %d\n",
+                      audit_pid, err);
                if (audit_pid) {
-                       pr_err("*NO* daemon at audit_pid=%d\n", audit_pid);
-                       audit_log_lost("auditd disappeared");
-                       audit_pid = 0;
-                       audit_sock = NULL;
+                       if (err == -ECONNREFUSED || err == -EPERM
+                           || ++attempts >= AUDITD_RETRIES) {
+                               char s[32];
+                               snprintf(s, sizeof(s), "audit_pid=%d reset", audit_pid);
+                               audit_log_lost(s);
+                               audit_pid = 0;
+                               audit_sock = NULL;
+                       } else {
+                               pr_warn("re-scheduling(#%d) write to audit_pid=%d\n",
+                                       attempts, audit_pid);
+                               set_current_state(TASK_INTERRUPTIBLE);
+                               schedule();
+                               __set_current_state(TASK_RUNNING);
+                               goto restart;
+                       }
                }
                /* we might get lucky and get this in the next auditd */
                audit_hold_skb(skb);
@@@ -665,7 -680,7 +682,7 @@@ static int audit_netlink_ok(struct sk_b
        case AUDIT_MAKE_EQUIV:
                /* Only support auditd and auditctl in initial pid namespace
                 * for now. */
 -              if ((task_active_pid_ns(current) != &init_pid_ns))
 +              if (task_active_pid_ns(current) != &init_pid_ns)
                        return -EPERM;
  
                if (!netlink_capable(skb, CAP_AUDIT_CONTROL))
        return err;
  }
  
- static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type)
+ static void audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type)
  {
-       int rc = 0;
        uid_t uid = from_kuid(&init_user_ns, current_uid());
        pid_t pid = task_tgid_nr(current);
  
        if (!audit_enabled && msg_type != AUDIT_USER_AVC) {
                *ab = NULL;
-               return rc;
+               return;
        }
  
        *ab = audit_log_start(NULL, GFP_KERNEL, msg_type);
        if (unlikely(!*ab))
-               return rc;
+               return;
        audit_log_format(*ab, "pid=%d uid=%u", pid, uid);
        audit_log_session_info(*ab);
        audit_log_task_context(*ab);
-       return rc;
  }
  
  int is_audit_feature_set(int i)
@@@ -836,7 -848,7 +850,7 @@@ static int audit_receive_msg(struct sk_
                s.lost                  = atomic_read(&audit_lost);
                s.backlog               = skb_queue_len(&audit_skb_queue);
                s.feature_bitmap        = AUDIT_FEATURE_BITMAP_ALL;
 -              s.backlog_wait_time     = audit_backlog_wait_time;
 +              s.backlog_wait_time     = audit_backlog_wait_time_master;
                audit_send_reply(skb, seq, AUDIT_GET, 0, 0, &s, sizeof(s));
                break;
        }
                if (s.mask & AUDIT_STATUS_BACKLOG_WAIT_TIME) {
                        if (sizeof(s) > (size_t)nlh->nlmsg_len)
                                return -EINVAL;
 -                      if (s.backlog_wait_time < 0 ||
 -                          s.backlog_wait_time > 10*AUDIT_BACKLOG_WAIT_TIME)
 +                      if (s.backlog_wait_time > 10*AUDIT_BACKLOG_WAIT_TIME)
                                return -EINVAL;
                        err = audit_set_backlog_wait_time(s.backlog_wait_time);
                        if (err < 0)
@@@ -1386,8 -1399,7 +1400,8 @@@ struct audit_buffer *audit_log_start(st
                return NULL;
        }
  
 -      audit_backlog_wait_time = AUDIT_BACKLOG_WAIT_TIME;
 +      if (!reserve)
 +              audit_backlog_wait_time = audit_backlog_wait_time_master;
  
        ab = audit_buffer_alloc(ctx, gfp_mask, type);
        if (!ab) {
@@@ -1566,14 -1578,14 +1580,14 @@@ void audit_log_n_string(struct audit_bu
   * @string: string to be checked
   * @len: max length of the string to check
   */
int audit_string_contains_control(const char *string, size_t len)
bool audit_string_contains_control(const char *string, size_t len)
  {
        const unsigned char *p;
        for (p = string; p < (const unsigned char *)string + len; p++) {
                if (*p == '"' || *p < 0x21 || *p > 0x7e)
-                       return 1;
+                       return true;
        }
-       return 0;
+       return false;
  }
  
  /**
@@@ -1761,7 -1773,7 +1775,7 @@@ void audit_log_name(struct audit_contex
        } else
                audit_log_format(ab, " name=(null)");
  
 -      if (n->ino != AUDIT_INO_UNSET) {
 +      if (n->ino != AUDIT_INO_UNSET)
                audit_log_format(ab, " inode=%lu"
                                 " dev=%02x:%02x mode=%#ho"
                                 " ouid=%u ogid=%u rdev=%02x:%02x",
                                 from_kgid(&init_user_ns, n->gid),
                                 MAJOR(n->rdev),
                                 MINOR(n->rdev));
 -      }
        if (n->osid != 0) {
                char *ctx = NULL;
                u32 len;
@@@ -1839,29 -1852,11 +1853,29 @@@ error_path
  }
  EXPORT_SYMBOL(audit_log_task_context);
  
 +void audit_log_d_path_exe(struct audit_buffer *ab,
 +                        struct mm_struct *mm)
 +{
 +      struct file *exe_file;
 +
 +      if (!mm)
 +              goto out_null;
 +
 +      exe_file = get_mm_exe_file(mm);
 +      if (!exe_file)
 +              goto out_null;
 +
 +      audit_log_d_path(ab, " exe=", &exe_file->f_path);
 +      fput(exe_file);
 +      return;
 +out_null:
 +      audit_log_format(ab, " exe=(null)");
 +}
 +
  void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk)
  {
        const struct cred *cred;
        char comm[sizeof(tsk->comm)];
 -      struct mm_struct *mm = tsk->mm;
        char *tty;
  
        if (!ab)
        audit_log_format(ab, " comm=");
        audit_log_untrustedstring(ab, get_task_comm(comm, tsk));
  
 -      if (mm) {
 -              down_read(&mm->mmap_sem);
 -              if (mm->exe_file)
 -                      audit_log_d_path(ab, " exe=", &mm->exe_file->f_path);
 -              up_read(&mm->mmap_sem);
 -      } else
 -              audit_log_format(ab, " exe=(null)");
 +      audit_log_d_path_exe(ab, tsk->mm);
        audit_log_task_context(ab);
  }
  EXPORT_SYMBOL(audit_log_task_info);
@@@ -1928,7 -1929,7 +1942,7 @@@ void audit_log_link_denied(const char *
  
        /* Generate AUDIT_PATH record with object. */
        name->type = AUDIT_TYPE_NORMAL;
 -      audit_copy_inode(name, link->dentry, link->dentry->d_inode);
 +      audit_copy_inode(name, link->dentry, d_backing_inode(link->dentry));
        audit_log_name(current->audit_context, name, link, 0, NULL);
  out:
        kfree(name);
diff --combined kernel/audit.h
index dadf86a0e59e5956d16ef741086c56c1fbf77a6c,e47d6ac46b45d3341cef9ea14aa19a054123604f..de6cbb7cf547037d91fd891a403dfd666045c4eb
@@@ -259,9 -259,6 +259,9 @@@ extern struct list_head audit_filter_li
  
  extern struct audit_entry *audit_dupe_rule(struct audit_krule *old);
  
 +extern void audit_log_d_path_exe(struct audit_buffer *ab,
 +                               struct mm_struct *mm);
 +
  /* audit watch functions */
  #ifdef CONFIG_AUDIT_WATCH
  extern void audit_put_watch(struct audit_watch *watch);
@@@ -301,7 -298,7 +301,7 @@@ extern int audit_exe_compare(struct tas
  #ifdef CONFIG_AUDIT_TREE
  extern struct audit_chunk *audit_tree_lookup(const struct inode *);
  extern void audit_put_chunk(struct audit_chunk *);
- extern int audit_tree_match(struct audit_chunk *, struct audit_tree *);
+ extern bool audit_tree_match(struct audit_chunk *, struct audit_tree *);
  extern int audit_make_tree(struct audit_krule *, char *, u32);
  extern int audit_add_tree_rule(struct audit_krule *);
  extern int audit_remove_tree_rule(struct audit_krule *);
diff --combined kernel/audit_tree.c
index 94ecdabda8e6b31f8f2ba25fc66b992e320d9fcb,9acfd9feea861bff2245965044037e66a0b3ba80..5efe9b299a12876242648d41acc1950291b7a166
@@@ -37,7 -37,6 +37,7 @@@ struct audit_chunk 
  
  static LIST_HEAD(tree_list);
  static LIST_HEAD(prune_list);
 +static struct task_struct *prune_thread;
  
  /*
   * One struct chunk is attached to each inode of interest.
@@@ -197,13 -196,13 +197,13 @@@ struct audit_chunk *audit_tree_lookup(c
        return NULL;
  }
  
int audit_tree_match(struct audit_chunk *chunk, struct audit_tree *tree)
bool audit_tree_match(struct audit_chunk *chunk, struct audit_tree *tree)
  {
        int n;
        for (n = 0; n < chunk->count; n++)
                if (chunk->owners[n].owner == tree)
-                       return 1;
-       return 0;
+                       return true;
+       return false;
  }
  
  /* tagging and untagging inodes with trees */
@@@ -579,7 -578,7 +579,7 @@@ int audit_remove_tree_rule(struct audit
  
  static int compare_root(struct vfsmount *mnt, void *arg)
  {
 -      return mnt->mnt_root->d_inode == arg;
 +      return d_backing_inode(mnt->mnt_root) == arg;
  }
  
  void audit_trim_trees(void)
@@@ -651,58 -650,7 +651,58 @@@ void audit_put_tree(struct audit_tree *
  
  static int tag_mount(struct vfsmount *mnt, void *arg)
  {
 -      return tag_chunk(mnt->mnt_root->d_inode, arg);
 +      return tag_chunk(d_backing_inode(mnt->mnt_root), arg);
 +}
 +
 +/*
 + * That gets run when evict_chunk() ends up needing to kill audit_tree.
 + * Runs from a separate thread.
 + */
 +static int prune_tree_thread(void *unused)
 +{
 +      for (;;) {
 +              set_current_state(TASK_INTERRUPTIBLE);
 +              if (list_empty(&prune_list))
 +                      schedule();
 +              __set_current_state(TASK_RUNNING);
 +
 +              mutex_lock(&audit_cmd_mutex);
 +              mutex_lock(&audit_filter_mutex);
 +
 +              while (!list_empty(&prune_list)) {
 +                      struct audit_tree *victim;
 +
 +                      victim = list_entry(prune_list.next,
 +                                      struct audit_tree, list);
 +                      list_del_init(&victim->list);
 +
 +                      mutex_unlock(&audit_filter_mutex);
 +
 +                      prune_one(victim);
 +
 +                      mutex_lock(&audit_filter_mutex);
 +              }
 +
 +              mutex_unlock(&audit_filter_mutex);
 +              mutex_unlock(&audit_cmd_mutex);
 +      }
 +      return 0;
 +}
 +
 +static int audit_launch_prune(void)
 +{
 +      if (prune_thread)
 +              return 0;
 +      prune_thread = kthread_create(prune_tree_thread, NULL,
 +                              "audit_prune_tree");
 +      if (IS_ERR(prune_thread)) {
 +              pr_err("cannot start thread audit_prune_tree");
 +              prune_thread = NULL;
 +              return -ENOMEM;
 +      } else {
 +              wake_up_process(prune_thread);
 +              return 0;
 +      }
  }
  
  /* called with audit_filter_mutex */
@@@ -728,12 -676,6 +728,12 @@@ int audit_add_tree_rule(struct audit_kr
        /* do not set rule->tree yet */
        mutex_unlock(&audit_filter_mutex);
  
 +      if (unlikely(!prune_thread)) {
 +              err = audit_launch_prune();
 +              if (err)
 +                      goto Err;
 +      }
 +
        err = kern_path(tree->pathname, 0, &path);
        if (err)
                goto Err;
@@@ -871,10 -813,36 +871,10 @@@ int audit_tag_tree(char *old, char *new
        return failed;
  }
  
 -/*
 - * That gets run when evict_chunk() ends up needing to kill audit_tree.
 - * Runs from a separate thread.
 - */
 -static int prune_tree_thread(void *unused)
 -{
 -      mutex_lock(&audit_cmd_mutex);
 -      mutex_lock(&audit_filter_mutex);
 -
 -      while (!list_empty(&prune_list)) {
 -              struct audit_tree *victim;
 -
 -              victim = list_entry(prune_list.next, struct audit_tree, list);
 -              list_del_init(&victim->list);
 -
 -              mutex_unlock(&audit_filter_mutex);
 -
 -              prune_one(victim);
 -
 -              mutex_lock(&audit_filter_mutex);
 -      }
 -
 -      mutex_unlock(&audit_filter_mutex);
 -      mutex_unlock(&audit_cmd_mutex);
 -      return 0;
 -}
  
  static void audit_schedule_prune(void)
  {
 -      kthread_run(prune_tree_thread, NULL, "audit_prune_tree");
 +      wake_up_process(prune_thread);
  }
  
  /*
@@@ -941,9 -909,9 +941,9 @@@ static void evict_chunk(struct audit_ch
        for (n = 0; n < chunk->count; n++)
                list_del_init(&chunk->owners[n].list);
        spin_unlock(&hash_lock);
 +      mutex_unlock(&audit_filter_mutex);
        if (need_prune)
                audit_schedule_prune();
 -      mutex_unlock(&audit_filter_mutex);
  }
  
  static int audit_tree_handle_event(struct fsnotify_group *group,