Documentation: add binding description of Rockchip PCIe controller
[firefly-linux-kernel-4.4.55.git] / kernel / auditfilter.c
index 6bd4a90d1991cdf84e5d14fa187af4a3b3f390f9..b8ff9e193753614072d55b98b0bb46e2a8534880 100644 (file)
@@ -19,6 +19,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/audit.h>
 #include <linux/kthread.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/security.h>
+#include <net/net_namespace.h>
+#include <net/sock.h>
 #include "audit.h"
 
 /*
  * Locking model:
  *
  * audit_filter_mutex:
- *             Synchronizes writes and blocking reads of audit's filterlist
- *             data.  Rcu is used to traverse the filterlist and access
- *             contents of structs audit_entry, audit_watch and opaque
- *             LSM rules during filtering.  If modified, these structures
- *             must be copied and replace their counterparts in the filterlist.
- *             An audit_parent struct is not accessed during filtering, so may
- *             be written directly provided audit_filter_mutex is held.
+ *             Synchronizes writes and blocking reads of audit's filterlist
+ *             data.  Rcu is used to traverse the filterlist and access
+ *             contents of structs audit_entry, audit_watch and opaque
+ *             LSM rules during filtering.  If modified, these structures
+ *             must be copied and replace their counterparts in the filterlist.
+ *             An audit_parent struct is not accessed during filtering, so may
+ *             be written directly provided audit_filter_mutex is held.
  */
 
 /* Audit filter lists, defined in <linux/audit.h> */
@@ -67,6 +71,24 @@ static struct list_head audit_rules_list[AUDIT_NR_FILTERS] = {
 
 DEFINE_MUTEX(audit_filter_mutex);
 
+static void audit_free_lsm_field(struct audit_field *f)
+{
+       switch (f->type) {
+       case AUDIT_SUBJ_USER:
+       case AUDIT_SUBJ_ROLE:
+       case AUDIT_SUBJ_TYPE:
+       case AUDIT_SUBJ_SEN:
+       case AUDIT_SUBJ_CLR:
+       case AUDIT_OBJ_USER:
+       case AUDIT_OBJ_ROLE:
+       case AUDIT_OBJ_TYPE:
+       case AUDIT_OBJ_LEV_LOW:
+       case AUDIT_OBJ_LEV_HIGH:
+               kfree(f->lsm_str);
+               security_audit_rule_free(f->lsm_rule);
+       }
+}
+
 static inline void audit_free_rule(struct audit_entry *e)
 {
        int i;
@@ -76,11 +98,8 @@ static inline void audit_free_rule(struct audit_entry *e)
        if (erule->watch)
                audit_put_watch(erule->watch);
        if (erule->fields)
-               for (i = 0; i < erule->field_count; i++) {
-                       struct audit_field *f = &erule->fields[i];
-                       kfree(f->lsm_str);
-                       security_audit_rule_free(f->lsm_rule);
-               }
+               for (i = 0; i < erule->field_count; i++)
+                       audit_free_lsm_field(&erule->fields[i]);
        kfree(erule->fields);
        kfree(erule->filterkey);
        kfree(e);
@@ -102,7 +121,7 @@ static inline struct audit_entry *audit_init_entry(u32 field_count)
        if (unlikely(!entry))
                return NULL;
 
-       fields = kzalloc(sizeof(*fields) * field_count, GFP_KERNEL);
+       fields = kcalloc(field_count, sizeof(*fields), GFP_KERNEL);
        if (unlikely(!fields)) {
                kfree(entry);
                return NULL;
@@ -144,7 +163,7 @@ static inline int audit_to_inode(struct audit_krule *krule,
                                 struct audit_field *f)
 {
        if (krule->listnr != AUDIT_FILTER_EXIT ||
-           krule->watch || krule->inode_f || krule->tree ||
+           krule->inode_f || krule->watch || krule->tree ||
            (f->op != Audit_equal && f->op != Audit_not_equal))
                return -EINVAL;
 
@@ -156,7 +175,7 @@ static __u32 *classes[AUDIT_SYSCALL_CLASSES];
 
 int __init audit_register_class(int class, unsigned *list)
 {
-       __u32 *p = kzalloc(AUDIT_BITMASK_SIZE * sizeof(__u32), GFP_KERNEL);
+       __u32 *p = kcalloc(AUDIT_BITMASK_SIZE, sizeof(__u32), GFP_KERNEL);
        if (!p)
                return -ENOMEM;
        while (*list != ~0U) {
@@ -224,7 +243,7 @@ static int audit_match_signal(struct audit_entry *entry)
 #endif
 
 /* Common user-space to kernel rule translation. */
-static inline struct audit_entry *audit_to_entry_common(struct audit_rule *rule)
+static inline struct audit_entry *audit_to_entry_common(struct audit_rule_data *rule)
 {
        unsigned listnr;
        struct audit_entry *entry;
@@ -247,7 +266,7 @@ static inline struct audit_entry *audit_to_entry_common(struct audit_rule *rule)
                ;
        }
        if (unlikely(rule->action == AUDIT_POSSIBLE)) {
-               printk(KERN_ERR "AUDIT_POSSIBLE is deprecated\n");
+               pr_err("AUDIT_POSSIBLE is deprecated\n");
                goto exit_err;
        }
        if (rule->action != AUDIT_NEVER && rule->action != AUDIT_ALWAYS)
@@ -343,6 +362,7 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f)
        case AUDIT_DEVMINOR:
        case AUDIT_EXIT:
        case AUDIT_SUCCESS:
+       case AUDIT_INODE:
                /* bit ops are only useful on syscall args */
                if (f->op == Audit_bitmask || f->op == Audit_bittest)
                        return -EINVAL;
@@ -385,6 +405,12 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f)
                if (f->val > AUDIT_MAX_FIELD_COMPARE)
                        return -EINVAL;
                break;
+       case AUDIT_EXE:
+               if (f->op != Audit_equal)
+                       return -EINVAL;
+               if (entry->rule.listnr != AUDIT_FILTER_EXIT)
+                       return -EINVAL;
+               break;
        };
        return 0;
 }
@@ -399,13 +425,13 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
        size_t remain = datasz - sizeof(struct audit_rule_data);
        int i;
        char *str;
+       struct audit_fsnotify_mark *audit_mark;
 
-       entry = audit_to_entry_common((struct audit_rule *)data);
+       entry = audit_to_entry_common(data);
        if (IS_ERR(entry))
                goto exit_nofree;
 
        bufp = data->buf;
-       entry->rule.vers_ops = 2;
        for (i = 0; i < data->field_count; i++) {
                struct audit_field *f = &entry->rule.fields[i];
 
@@ -417,15 +443,12 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
 
                f->type = data->fields[i];
                f->val = data->values[i];
-               f->uid = INVALID_UID;
-               f->gid = INVALID_GID;
-               f->lsm_str = NULL;
-               f->lsm_rule = NULL;
 
                /* Support legacy tests for a valid loginuid */
-               if ((f->type == AUDIT_LOGINUID) && (f->val == 4294967295)) {
+               if ((f->type == AUDIT_LOGINUID) && (f->val == AUDIT_UID_UNSET)) {
                        f->type = AUDIT_LOGINUID_SET;
                        f->val = 0;
+                       entry->rule.pflags |= AUDIT_LOGINUID_LEGACY;
                }
 
                err = audit_field_valid(entry, f);
@@ -476,8 +499,8 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
                        /* Keep currently invalid fields around in case they
                         * become valid after a policy reload. */
                        if (err == -EINVAL) {
-                               printk(KERN_WARNING "audit rule for LSM "
-                                      "\'%s\' is invalid\n",  str);
+                               pr_warn("audit rule for LSM \'%s\' is invalid\n",
+                                       str);
                                err = 0;
                        }
                        if (err) {
@@ -523,6 +546,24 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
                        entry->rule.buflen += f->val;
                        entry->rule.filterkey = str;
                        break;
+               case AUDIT_EXE:
+                       if (entry->rule.exe || f->val > PATH_MAX)
+                               goto exit_free;
+                       str = audit_unpack_string(&bufp, &remain, f->val);
+                       if (IS_ERR(str)) {
+                               err = PTR_ERR(str);
+                               goto exit_free;
+                       }
+                       entry->rule.buflen += f->val;
+
+                       audit_mark = audit_alloc_mark(&entry->rule, str, f->val);
+                       if (IS_ERR(audit_mark)) {
+                               kfree(str);
+                               err = PTR_ERR(audit_mark);
+                               goto exit_free;
+                       }
+                       entry->rule.exe = audit_mark;
+                       break;
                }
        }
 
@@ -533,10 +574,10 @@ exit_nofree:
        return entry;
 
 exit_free:
-       if (entry->rule.watch)
-               audit_put_watch(entry->rule.watch); /* matches initial get */
        if (entry->rule.tree)
                audit_put_tree(entry->rule.tree); /* that's the temporary one */
+       if (entry->rule.exe)
+               audit_remove_mark(entry->rule.exe); /* that's the template one */
        audit_free_rule(entry);
        return ERR_PTR(err);
 }
@@ -601,6 +642,17 @@ static struct audit_rule_data *audit_krule_to_data(struct audit_krule *krule)
                        data->buflen += data->values[i] =
                                audit_pack_string(&bufp, krule->filterkey);
                        break;
+               case AUDIT_EXE:
+                       data->buflen += data->values[i] =
+                               audit_pack_string(&bufp, audit_mark_path(krule->exe));
+                       break;
+               case AUDIT_LOGINUID_SET:
+                       if (krule->pflags & AUDIT_LOGINUID_LEGACY && !f->val) {
+                               data->fields[i] = AUDIT_LOGINUID;
+                               data->values[i] = AUDIT_UID_UNSET;
+                               break;
+                       }
+                       /* fallthrough if set */
                default:
                        data->values[i] = f->val;
                }
@@ -617,6 +669,7 @@ static int audit_compare_rule(struct audit_krule *a, struct audit_krule *b)
        int i;
 
        if (a->flags != b->flags ||
+           a->pflags != b->pflags ||
            a->listnr != b->listnr ||
            a->action != b->action ||
            a->field_count != b->field_count)
@@ -656,6 +709,12 @@ static int audit_compare_rule(struct audit_krule *a, struct audit_krule *b)
                        if (strcmp(a->filterkey, b->filterkey))
                                return 1;
                        break;
+               case AUDIT_EXE:
+                       /* both paths exist based on above type compare */
+                       if (strcmp(audit_mark_path(a->exe),
+                                  audit_mark_path(b->exe)))
+                               return 1;
+                       break;
                case AUDIT_UID:
                case AUDIT_EUID:
                case AUDIT_SUID:
@@ -706,8 +765,8 @@ static inline int audit_dupe_lsm_field(struct audit_field *df,
        /* Keep currently invalid fields around in case they
         * become valid after a policy reload. */
        if (ret == -EINVAL) {
-               printk(KERN_WARNING "audit rule for LSM \'%s\' is "
-                      "invalid\n", df->lsm_str);
+               pr_warn("audit rule for LSM \'%s\' is invalid\n",
+                       df->lsm_str);
                ret = 0;
        }
 
@@ -733,8 +792,8 @@ struct audit_entry *audit_dupe_rule(struct audit_krule *old)
                return ERR_PTR(-ENOMEM);
 
        new = &entry->rule;
-       new->vers_ops = old->vers_ops;
        new->flags = old->flags;
+       new->pflags = old->pflags;
        new->listnr = old->listnr;
        new->action = old->action;
        for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
@@ -777,8 +836,14 @@ struct audit_entry *audit_dupe_rule(struct audit_krule *old)
                                err = -ENOMEM;
                        else
                                new->filterkey = fk;
+                       break;
+               case AUDIT_EXE:
+                       err = audit_dupe_exe(new, old);
+                       break;
                }
                if (err) {
+                       if (new->exe)
+                               audit_remove_mark(new->exe);
                        audit_free_rule(entry);
                        return ERR_PTR(err);
                }
@@ -839,7 +904,7 @@ static inline int audit_add_rule(struct audit_entry *entry)
        struct audit_watch *watch = entry->rule.watch;
        struct audit_tree *tree = entry->rule.tree;
        struct list_head *list;
-       int err;
+       int err = 0;
 #ifdef CONFIG_AUDITSYSCALL
        int dont_count = 0;
 
@@ -857,7 +922,7 @@ static inline int audit_add_rule(struct audit_entry *entry)
                /* normally audit_add_tree_rule() will free it on failure */
                if (tree)
                        audit_put_tree(tree);
-               goto error;
+               return err;
        }
 
        if (watch) {
@@ -865,14 +930,20 @@ static inline int audit_add_rule(struct audit_entry *entry)
                err = audit_add_watch(&entry->rule, &list);
                if (err) {
                        mutex_unlock(&audit_filter_mutex);
-                       goto error;
+                       /*
+                        * normally audit_add_tree_rule() will free it
+                        * on failure
+                        */
+                       if (tree)
+                               audit_put_tree(tree);
+                       return err;
                }
        }
        if (tree) {
                err = audit_add_tree_rule(&entry->rule);
                if (err) {
                        mutex_unlock(&audit_filter_mutex);
-                       goto error;
+                       return err;
                }
        }
 
@@ -903,19 +974,13 @@ static inline int audit_add_rule(struct audit_entry *entry)
 #endif
        mutex_unlock(&audit_filter_mutex);
 
-       return 0;
-
-error:
-       if (watch)
-               audit_put_watch(watch); /* tmp watch, matches initial get */
        return err;
 }
 
 /* Remove an existing rule from filterlist. */
-static inline int audit_del_rule(struct audit_entry *entry)
+int audit_del_rule(struct audit_entry *entry)
 {
        struct audit_entry  *e;
-       struct audit_watch *watch = entry->rule.watch;
        struct audit_tree *tree = entry->rule.tree;
        struct list_head *list;
        int ret = 0;
@@ -931,7 +996,6 @@ static inline int audit_del_rule(struct audit_entry *entry)
        mutex_lock(&audit_filter_mutex);
        e = audit_find_rule(entry, &list);
        if (!e) {
-               mutex_unlock(&audit_filter_mutex);
                ret = -ENOENT;
                goto out;
        }
@@ -942,9 +1006,8 @@ static inline int audit_del_rule(struct audit_entry *entry)
        if (e->rule.tree)
                audit_remove_tree_rule(&e->rule);
 
-       list_del_rcu(&e->list);
-       list_del(&e->rule.list);
-       call_rcu(&e->rcu, audit_free_rule_rcu);
+       if (e->rule.exe)
+               audit_remove_mark_rule(&e->rule);
 
 #ifdef CONFIG_AUDITSYSCALL
        if (!dont_count)
@@ -953,11 +1016,14 @@ static inline int audit_del_rule(struct audit_entry *entry)
        if (!audit_match_signal(entry))
                audit_signals--;
 #endif
-       mutex_unlock(&audit_filter_mutex);
+
+       list_del_rcu(&e->list);
+       list_del(&e->rule.list);
+       call_rcu(&e->rcu, audit_free_rule_rcu);
 
 out:
-       if (watch)
-               audit_put_watch(watch); /* match initial get */
+       mutex_unlock(&audit_filter_mutex);
+
        if (tree)
                audit_put_tree(tree);   /* that's the temporary one */
 
@@ -965,7 +1031,7 @@ out:
 }
 
 /* List rules using struct audit_rule_data. */
-static void audit_list_rules(int pid, int seq, struct sk_buff_head *q)
+static void audit_list_rules(__u32 portid, int seq, struct sk_buff_head *q)
 {
        struct sk_buff *skb;
        struct audit_krule *r;
@@ -980,14 +1046,15 @@ static void audit_list_rules(int pid, int seq, struct sk_buff_head *q)
                        data = audit_krule_to_data(r);
                        if (unlikely(!data))
                                break;
-                       skb = audit_make_reply(pid, seq, AUDIT_LIST_RULES, 0, 1,
-                                        data, sizeof(*data) + data->buflen);
+                       skb = audit_make_reply(portid, seq, AUDIT_LIST_RULES,
+                                              0, 1, data,
+                                              sizeof(*data) + data->buflen);
                        if (skb)
                                skb_queue_tail(q, skb);
                        kfree(data);
                }
        }
-       skb = audit_make_reply(pid, seq, AUDIT_LIST_RULES, 1, 1, NULL, 0);
+       skb = audit_make_reply(portid, seq, AUDIT_LIST_RULES, 1, 1, NULL, 0);
        if (skb)
                skb_queue_tail(q, skb);
 }
@@ -997,7 +1064,7 @@ static void audit_log_rule_change(char *action, struct audit_krule *rule, int re
 {
        struct audit_buffer *ab;
        uid_t loginuid = from_kuid(&init_user_ns, audit_get_loginuid(current));
-       u32 sessionid = audit_get_sessionid(current);
+       unsigned int sessionid = audit_get_sessionid(current);
 
        if (!audit_enabled)
                return;
@@ -1015,66 +1082,81 @@ static void audit_log_rule_change(char *action, struct audit_krule *rule, int re
 }
 
 /**
- * audit_receive_filter - apply all rules to the specified message type
+ * audit_rule_change - apply all rules to the specified message type
  * @type: audit message type
- * @pid: target pid for netlink audit messages
+ * @portid: target port id for netlink audit messages
  * @seq: netlink audit message sequence (serial) number
  * @data: payload data
  * @datasz: size of payload data
  */
-int audit_receive_filter(int type, int pid, int seq, void *data, size_t datasz)
+int audit_rule_change(int type, __u32 portid, int seq, void *data,
+                       size_t datasz)
 {
-       struct task_struct *tsk;
-       struct audit_netlink_list *dest;
        int err = 0;
        struct audit_entry *entry;
 
-       switch (type) {
-       case AUDIT_LIST_RULES:
-               /* We can't just spew out the rules here because we might fill
-                * the available socket buffer space and deadlock waiting for
-                * auditctl to read from it... which isn't ever going to
-                * happen if we're actually running in the context of auditctl
-                * trying to _send_ the stuff */
-
-               dest = kmalloc(sizeof(struct audit_netlink_list), GFP_KERNEL);
-               if (!dest)
-                       return -ENOMEM;
-               dest->pid = pid;
-               skb_queue_head_init(&dest->q);
-
-               mutex_lock(&audit_filter_mutex);
-               audit_list_rules(pid, seq, &dest->q);
-               mutex_unlock(&audit_filter_mutex);
+       entry = audit_data_to_entry(data, datasz);
+       if (IS_ERR(entry))
+               return PTR_ERR(entry);
 
-               tsk = kthread_run(audit_send_list, dest, "audit_send_list");
-               if (IS_ERR(tsk)) {
-                       skb_queue_purge(&dest->q);
-                       kfree(dest);
-                       err = PTR_ERR(tsk);
-               }
-               break;
+       switch (type) {
        case AUDIT_ADD_RULE:
-               entry = audit_data_to_entry(data, datasz);
-               if (IS_ERR(entry))
-                       return PTR_ERR(entry);
-
                err = audit_add_rule(entry);
-               audit_log_rule_change("add rule", &entry->rule, !err);
-               if (err)
-                       audit_free_rule(entry);
+               audit_log_rule_change("add_rule", &entry->rule, !err);
                break;
        case AUDIT_DEL_RULE:
-               entry = audit_data_to_entry(data, datasz);
-               if (IS_ERR(entry))
-                       return PTR_ERR(entry);
-
                err = audit_del_rule(entry);
-               audit_log_rule_change("remove rule", &entry->rule, !err);
-               audit_free_rule(entry);
+               audit_log_rule_change("remove_rule", &entry->rule, !err);
                break;
        default:
-               return -EINVAL;
+               err = -EINVAL;
+               WARN_ON(1);
+       }
+
+       if (err || type == AUDIT_DEL_RULE) {
+               if (entry->rule.exe)
+                       audit_remove_mark(entry->rule.exe);
+               audit_free_rule(entry);
+       }
+
+       return err;
+}
+
+/**
+ * audit_list_rules_send - list the audit rules
+ * @request_skb: skb of request we are replying to (used to target the reply)
+ * @seq: netlink audit message sequence (serial) number
+ */
+int audit_list_rules_send(struct sk_buff *request_skb, int seq)
+{
+       u32 portid = NETLINK_CB(request_skb).portid;
+       struct net *net = sock_net(NETLINK_CB(request_skb).sk);
+       struct task_struct *tsk;
+       struct audit_netlink_list *dest;
+       int err = 0;
+
+       /* We can't just spew out the rules here because we might fill
+        * the available socket buffer space and deadlock waiting for
+        * auditctl to read from it... which isn't ever going to
+        * happen if we're actually running in the context of auditctl
+        * trying to _send_ the stuff */
+
+       dest = kmalloc(sizeof(struct audit_netlink_list), GFP_KERNEL);
+       if (!dest)
+               return -ENOMEM;
+       dest->net = get_net(net);
+       dest->portid = portid;
+       skb_queue_head_init(&dest->q);
+
+       mutex_lock(&audit_filter_mutex);
+       audit_list_rules(portid, seq, &dest->q);
+       mutex_unlock(&audit_filter_mutex);
+
+       tsk = kthread_run(audit_send_list, dest, "audit_send_list");
+       if (IS_ERR(tsk)) {
+               skb_queue_purge(&dest->q);
+               kfree(dest);
+               err = PTR_ERR(tsk);
        }
 
        return err;
@@ -1215,12 +1297,14 @@ static int audit_filter_user_rules(struct audit_krule *rule, int type,
 
        for (i = 0; i < rule->field_count; i++) {
                struct audit_field *f = &rule->fields[i];
+               pid_t pid;
                int result = 0;
                u32 sid;
 
                switch (f->type) {
                case AUDIT_PID:
-                       result = audit_comparator(task_pid_vnr(current), f->op, f->val);
+                       pid = task_pid_nr(current);
+                       result = audit_comparator(pid, f->op, f->val);
                        break;
                case AUDIT_UID:
                        result = audit_uid_comparator(current_uid(), f->op, f->uid);
@@ -1269,19 +1353,22 @@ int audit_filter_user(int type)
 {
        enum audit_state state = AUDIT_DISABLED;
        struct audit_entry *e;
-       int ret = 1;
+       int rc, ret;
+
+       ret = 1; /* Audit by default */
 
        rcu_read_lock();
        list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_USER], list) {
-               if (audit_filter_user_rules(&e->rule, type, &state)) {
-                       if (state == AUDIT_DISABLED)
+               rc = audit_filter_user_rules(&e->rule, type, &state);
+               if (rc) {
+                       if (rc > 0 && state == AUDIT_DISABLED)
                                ret = 0;
                        break;
                }
        }
        rcu_read_unlock();
 
-       return ret; /* Audit by default */
+       return ret;
 }
 
 int audit_filter_type(int type)
@@ -1322,6 +1409,8 @@ static int update_lsm_rule(struct audit_krule *r)
                return 0;
 
        nentry = audit_dupe_rule(r);
+       if (entry->rule.exe)
+               audit_remove_mark(entry->rule.exe);
        if (IS_ERR(nentry)) {
                /* save the first error encountered for the
                 * return value */