SELinux: flush the avc before disabling SELinux
[safe/jmp/linux-2.6] / security / smack / smackfs.c
index 856c8a2..f83a809 100644 (file)
@@ -41,6 +41,7 @@ enum smk_inos {
        SMK_AMBIENT     = 7,    /* internet ambient label */
        SMK_NETLBLADDR  = 8,    /* single label hosts */
        SMK_ONLYCAP     = 9,    /* the only "capable" label */
+       SMK_LOGGING     = 10,   /* logging */
 };
 
 /*
@@ -86,6 +87,9 @@ LIST_HEAD(smack_rule_list);
 
 static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
 
+const char *smack_cipso_option = SMACK_CIPSO_OPTION;
+
+
 #define        SEQ_READ_FINISHED       1
 
 /*
@@ -565,6 +569,11 @@ static ssize_t smk_write_cipso(struct file *file, const char __user *buf,
                goto unlockedout;
        }
 
+       /* labels cannot begin with a '-' */
+       if (data[0] == '-') {
+               rc = -EINVAL;
+               goto unlockedout;
+       }
        data[count] = '\0';
        rule = data;
        /*
@@ -726,8 +735,8 @@ static void smk_netlbladdr_insert(struct smk_netlbladdr *new)
                return;
        }
 
-       m = list_entry(rcu_dereference(smk_netlbladdr_list.next),
-                        struct smk_netlbladdr, list);
+       m = list_entry_rcu(smk_netlbladdr_list.next,
+                          struct smk_netlbladdr, list);
 
        /* the comparison '>' is a bit hacky, but works */
        if (new->smk_mask.s_addr > m->smk_mask.s_addr) {
@@ -740,8 +749,8 @@ static void smk_netlbladdr_insert(struct smk_netlbladdr *new)
                        list_add_rcu(&new->list, &m->list);
                        return;
                }
-               m_next = list_entry(rcu_dereference(m->list.next),
-                                struct smk_netlbladdr, list);
+               m_next = list_entry_rcu(m->list.next,
+                                       struct smk_netlbladdr, list);
                if (new->smk_mask.s_addr > m_next->smk_mask.s_addr) {
                        list_add_rcu(&new->list, &m->list);
                        return;
@@ -767,7 +776,7 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
        struct sockaddr_in newname;
        char smack[SMK_LABELLEN];
        char *sp;
-       char data[SMK_NETLBLADDRMAX];
+       char data[SMK_NETLBLADDRMAX + 1];
        char *host = (char *)&newname.sin_addr.s_addr;
        int rc;
        struct netlbl_audit audit_info;
@@ -808,9 +817,18 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
        if (m > BEBITS)
                return -EINVAL;
 
-       sp = smk_import(smack, 0);
-       if (sp == NULL)
-               return -EINVAL;
+       /* if smack begins with '-', its an option, don't import it */
+       if (smack[0] != '-') {
+               sp = smk_import(smack, 0);
+               if (sp == NULL)
+                       return -EINVAL;
+       } else {
+               /* check known options */
+               if (strcmp(smack, smack_cipso_option) == 0)
+                       sp = (char *)smack_cipso_option;
+               else
+                       return -EINVAL;
+       }
 
        for (temp_mask = 0; m > 0; m--) {
                temp_mask |= mask_bits;
@@ -849,18 +867,23 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
                        smk_netlbladdr_insert(skp);
                }
        } else {
-               rc = netlbl_cfg_unlbl_static_del(&init_net, NULL,
-                       &skp->smk_host.sin_addr, &skp->smk_mask,
-                       PF_INET, &audit_info);
+               /* we delete the unlabeled entry, only if the previous label
+                * wasnt the special CIPSO option */
+               if (skp->smk_label != smack_cipso_option)
+                       rc = netlbl_cfg_unlbl_static_del(&init_net, NULL,
+                                       &skp->smk_host.sin_addr, &skp->smk_mask,
+                                       PF_INET, &audit_info);
+               else
+                       rc = 0;
                skp->smk_label = sp;
        }
 
        /*
         * Now tell netlabel about the single label nature of
         * this host so that incoming packets get labeled.
+        * but only if we didn't get the special CIPSO option
         */
-
-       if (rc == 0)
+       if (rc == 0 && sp != smack_cipso_option)
                rc = netlbl_cfg_unlbl_static_add(&init_net, NULL,
                        &skp->smk_host.sin_addr, &skp->smk_mask, PF_INET,
                        smack_to_secid(skp->smk_label), &audit_info);
@@ -1170,6 +1193,69 @@ static const struct file_operations smk_onlycap_ops = {
 };
 
 /**
+ * smk_read_logging - read() for /smack/logging
+ * @filp: file pointer, not actually used
+ * @buf: where to put the result
+ * @cn: maximum to send along
+ * @ppos: where to start
+ *
+ * Returns number of bytes read or error code, as appropriate
+ */
+static ssize_t smk_read_logging(struct file *filp, char __user *buf,
+                               size_t count, loff_t *ppos)
+{
+       char temp[32];
+       ssize_t rc;
+
+       if (*ppos != 0)
+               return 0;
+
+       sprintf(temp, "%d\n", log_policy);
+       rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
+       return rc;
+}
+
+/**
+ * smk_write_logging - write() for /smack/logging
+ * @file: file pointer, not actually used
+ * @buf: where to get the data from
+ * @count: bytes sent
+ * @ppos: where to start
+ *
+ * Returns number of bytes written or error code, as appropriate
+ */
+static ssize_t smk_write_logging(struct file *file, const char __user *buf,
+                               size_t count, loff_t *ppos)
+{
+       char temp[32];
+       int i;
+
+       if (!capable(CAP_MAC_ADMIN))
+               return -EPERM;
+
+       if (count >= sizeof(temp) || count == 0)
+               return -EINVAL;
+
+       if (copy_from_user(temp, buf, count) != 0)
+               return -EFAULT;
+
+       temp[count] = '\0';
+
+       if (sscanf(temp, "%d", &i) != 1)
+               return -EINVAL;
+       if (i < 0 || i > 3)
+               return -EINVAL;
+       log_policy = i;
+       return count;
+}
+
+
+
+static const struct file_operations smk_logging_ops = {
+       .read           = smk_read_logging,
+       .write          = smk_write_logging,
+};
+/**
  * smk_fill_super - fill the /smackfs superblock
  * @sb: the empty superblock
  * @data: unused
@@ -1199,6 +1285,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
                        {"netlabel", &smk_netlbladdr_ops, S_IRUGO|S_IWUSR},
                [SMK_ONLYCAP]   =
                        {"onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR},
+               [SMK_LOGGING]   =
+                       {"logging", &smk_logging_ops, S_IRUGO|S_IWUSR},
                /* last one */ {""}
        };