[Title] Patch Smack_backport_3.0.9_to_2.6.36.patch & smack-recursive-transmute-201202...
authordon.hong <don.hong@samsung.com>
Thu, 29 Mar 2012 09:16:29 +0000 (18:16 +0900)
committerdon.hong <don.hong@samsung.com>
Thu, 29 Mar 2012 10:50:17 +0000 (19:50 +0900)
[Type] Enahncement
[Module]
[Priority]
[CQ#]
[Redmine#]
[Problem]
[Cause]
[Solution]
[TestCase]

Change-Id: Id7a345fddf1756704151f4fdbca1fcca3cedc1cf

include/linux/xattr.h
security/smack/smack.h
security/smack/smack_access.c
security/smack/smack_lsm.c
security/smack/smackfs.c

index 5c84af8c5f6fd7014439570a8d958f9b83eadecb..24d1ad09e2457f775ec8c1f46bdec860d1020e3f 100644 (file)
 #define XATTR_CREATE   0x1     /* set value, fail if attr already exists */
 #define XATTR_REPLACE  0x2     /* set value, fail if attr does not exist */
 
+#define XATTR_SMACK_SUFFIX "SMACK64"
+#define XATTR_SMACK_IPIN "SMACK64IPIN"
+#define XATTR_SMACK_IPOUT "SMACK64IPOUT"
+#define XATTR_SMACK_EXEC "SMACK64EXEC"
+#define XATTR_SMACK_TRANSMUTE "SMACK64TRANSMUTE"
+#define XATTR_SMACK_MMAP "SMACK64MMAP"
+#define XATTR_NAME_SMACK XATTR_SECURITY_PREFIX XATTR_SMACK_SUFFIX
+#define XATTR_NAME_SMACKIPIN   XATTR_SECURITY_PREFIX XATTR_SMACK_IPIN
+#define XATTR_NAME_SMACKIPOUT  XATTR_SECURITY_PREFIX XATTR_SMACK_IPOUT
+#define XATTR_NAME_SMACKEXEC   XATTR_SECURITY_PREFIX XATTR_SMACK_EXEC
+#define XATTR_NAME_SMACKTRANSMUTE XATTR_SECURITY_PREFIX XATTR_SMACK_TRANSMUTE
+#define XATTR_NAME_SMACKMMAP XATTR_SECURITY_PREFIX XATTR_SMACK_MMAP
+
 #ifdef  __KERNEL__
 
 #include <linux/types.h>
index 4fd80a37ca93fdbd19e97fda3e8f45d831fadebb..fab873a8dad5bf087ae8f59ad549eab9e987a0c8 100644 (file)
@@ -66,6 +66,7 @@ struct task_smack {
 
 #define        SMK_INODE_INSTANT       0x01    /* inode is instantiated */
 #define        SMK_INODE_TRANSMUTE     0x02    /* directory is transmuting */
+#define        SMK_INODE_CHANGED       0x04    /* smack was transmuted */
 
 /*
  * A label access rule.
@@ -139,19 +140,6 @@ struct smack_known {
 #define SMK_FSHAT      "smackfshat="
 #define SMK_FSROOT     "smackfsroot="
 
-#define        XATTR_SMACK_SUFFIX      "SMACK64"
-#define        XATTR_SMACK_IPIN        "SMACK64IPIN"
-#define        XATTR_SMACK_IPOUT       "SMACK64IPOUT"
-#define        XATTR_SMACK_EXEC        "SMACK64EXEC"
-#define        XATTR_SMACK_TRANSMUTE   "SMACK64TRANSMUTE"
-#define        XATTR_SMACK_MMAP        "SMACK64MMAP"
-#define        XATTR_NAME_SMACK        XATTR_SECURITY_PREFIX   XATTR_SMACK_SUFFIX
-#define        XATTR_NAME_SMACKIPIN    XATTR_SECURITY_PREFIX   XATTR_SMACK_IPIN
-#define        XATTR_NAME_SMACKIPOUT   XATTR_SECURITY_PREFIX   XATTR_SMACK_IPOUT
-#define        XATTR_NAME_SMACKEXEC    XATTR_SECURITY_PREFIX   XATTR_SMACK_EXEC
-#define        XATTR_NAME_SMACKTRANSMUTE XATTR_SECURITY_PREFIX XATTR_SMACK_TRANSMUTE
-#define        XATTR_NAME_SMACKMMAP    XATTR_SECURITY_PREFIX   XATTR_SMACK_MMAP
-
 #define SMACK_CIPSO_OPTION     "-CIPSO"
 
 /*
@@ -169,7 +157,6 @@ struct smack_known {
 
 /*
  * smackfs magic number
- * smackfs macic number
  */
 #define SMACK_MAGIC    0x43415d53 /* "SMAC" */
 
@@ -195,9 +182,9 @@ struct smack_known {
 #define MAY_NOT                0
 
 /*
- * Number of access types used by Smack (rwxa)
+ * Number of access types used by Smack (rwxat)
  */
-#define SMK_NUM_ACCESS_TYPE 4
+#define SMK_NUM_ACCESS_TYPE 5
 
 /*
  * Smack audit data; is empty if CONFIG_AUDIT not set
@@ -222,6 +209,7 @@ int smk_curacc(char *, u32, struct smk_audit_info *);
 int smack_to_cipso(const char *, struct smack_cipso *);
 char *smack_from_cipso(u32, char *);
 char *smack_from_secid(const u32);
+void smk_parse_smack(const char *string, int len, char *smack);
 char *smk_import(const char *, int);
 struct smack_known *smk_import_entry(const char *, int);
 struct smack_known *smk_find_entry(const char *);
index a885f628f56ece6d96c58020e0a2e285aa330452..cc7cb6edba081acaab825c1e6a93fb078234bcf3 100644 (file)
@@ -353,17 +353,13 @@ struct smack_known *smk_find_entry(const char *string)
 }
 
 /**
- * smk_import_entry - import a label, return the list entry
- * @string: a text string that might be a Smack label
+ * smk_parse_smack - parse smack label from a text string
+ * @string: a text string that might contain a Smack label
  * @len: the maximum size, or zero if it is NULL terminated.
- *
- * Returns a pointer to the entry in the label list that
- * matches the passed string, adding it if necessary.
+ * @smack: parsed smack label, or NULL if parse error
  */
-struct smack_known *smk_import_entry(const char *string, int len)
+void smk_parse_smack(const char *string, int len, char *smack)
 {
-       struct smack_known *skp;
-       char smack[SMK_LABELLEN];
        int found;
        int i;
 
@@ -381,7 +377,22 @@ struct smack_known *smk_import_entry(const char *string, int len)
                } else
                        smack[i] = string[i];
        }
+}
+
+/**
+ * smk_import_entry - import a label, return the list entry
+ * @string: a text string that might be a Smack label
+ * @len: the maximum size, or zero if it is NULL terminated.
+ *
+ * Returns a pointer to the entry in the label list that
+ * matches the passed string, adding it if necessary.
+ */
+struct smack_known *smk_import_entry(const char *string, int len)
+{
+       struct smack_known *skp;
+       char smack[SMK_LABELLEN];
 
+       smk_parse_smack(string, len, smack);
        if (smack[0] == '\0')
                return NULL;
 
index c0a5cdd80bb4265b413c23e6323805ad6209a3fc..92ff6267ad4b8ac1f17e21ef4004c4f376fffa9d 100644 (file)
@@ -5,12 +5,13 @@
  *
  *  Authors:
  *     Casey Schaufler <casey@schaufler-ca.com>
- *     Jarkko Sakkinen <ext-jarkko.2.sakkinen@nokia.com>
+ *     Jarkko Sakkinen <jarkko.sakkinen@intel.com>
  *
  *  Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com>
  *  Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
  *                Paul Moore <paul@paul-moore.com>
  *  Copyright (C) 2010 Nokia Corporation
+ *  Copyright (C) 2011 Intel Corporation.
  *
  *     This program is free software; you can redistribute it and/or modify
  *     it under the terms of the GNU General Public License version 2,
@@ -34,6 +35,7 @@
 #include <linux/audit.h>
 #include <linux/magic.h>
 #include <linux/dcache.h>
+#include <linux/personality.h>
 #include "smack.h"
 
 #define task_security(task)    (task_cred_xxx((task), security))
@@ -441,11 +443,17 @@ static int smack_sb_umount(struct vfsmount *mnt, int flags)
  * BPRM hooks
  */
 
+/**
+ * smack_bprm_set_creds - set creds for exec
+ * @bprm: the exec information
+ *
+ * Returns 0 if it gets a blob, -ENOMEM otherwise
+ */
 static int smack_bprm_set_creds(struct linux_binprm *bprm)
 {
-       struct task_smack *tsp = bprm->cred->security;
+       struct inode *inode = bprm->file->f_path.dentry->d_inode;
+       struct task_smack *bsp = bprm->cred->security;
        struct inode_smack *isp;
-       struct dentry *dp;
        int rc;
 
        rc = cap_bprm_set_creds(bprm);
@@ -455,20 +463,48 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm)
        if (bprm->cred_prepared)
                return 0;
 
-       if (bprm->file == NULL || bprm->file->f_dentry == NULL)
+       isp = inode->i_security;
+       if (isp->smk_task == NULL || isp->smk_task == bsp->smk_task)
                return 0;
 
-       dp = bprm->file->f_dentry;
+       if (bprm->unsafe)
+               return -EPERM;
 
-       if (dp->d_inode == NULL)
-               return 0;
+       bsp->smk_task = isp->smk_task;
+       bprm->per_clear |= PER_CLEAR_ON_SETID;
 
-       isp = dp->d_inode->i_security;
+       return 0;
+}
 
-       if (isp->smk_task != NULL)
-               tsp->smk_task = isp->smk_task;
+/**
+ * smack_bprm_committing_creds - Prepare to install the new credentials
+ * from bprm.
+ *
+ * @bprm: binprm for exec
+ */
+static void smack_bprm_committing_creds(struct linux_binprm *bprm)
+{
+       struct task_smack *bsp = bprm->cred->security;
 
-       return 0;
+       if (bsp->smk_task != bsp->smk_forked)
+               current->pdeath_signal = 0;
+}
+
+/**
+ * smack_bprm_secureexec - Return the decision to use secureexec.
+ * @bprm: binprm for exec
+ *
+ * Returns 0 on success.
+ */
+static int smack_bprm_secureexec(struct linux_binprm *bprm)
+{
+       struct task_smack *tsp = current_security();
+       int ret = cap_bprm_secureexec(bprm);
+
+       if (!ret && (tsp->smk_task != tsp->smk_forked))
+               ret = 1;
+
+       return ret;
 }
 
 /*
@@ -517,6 +553,7 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
 
 {
        struct smack_known *skp;
+       struct inode_smack *issp = inode->i_security;
        char *csp = smk_of_current();
        char *isp = smk_of_inode(inode);
        char *dsp = smk_of_inode(dir);
@@ -538,10 +575,13 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
                 * If the access rule allows transmutation and
                 * the directory requests transmutation then
                 * by all means transmute.
+                * Mark the inode as changed.
                 */
                if (may > 0 && ((may & MAY_TRANSMUTE) != 0) &&
-                   smk_inode_transmutable(dir))
-                       isp = dsp;
+                   smk_inode_transmutable(dir)) {
+                               isp = dsp;
+                               issp->smk_flags |= SMK_INODE_CHANGED;
+               }
 
                *value = kstrdup(isp, GFP_KERNEL);
                if (*value == NULL)
@@ -687,6 +727,7 @@ static int smack_inode_rename(struct inode *old_inode,
  * smack_inode_permission - Smack version of permission()
  * @inode: the inode in question
  * @mask: the access requested
+ * @flags: special case
  *
  * This is the important Smack hook.
  *
@@ -703,6 +744,10 @@ static int smack_inode_permission(struct inode *inode, int mask)
        if (mask == 0)
                return 0;
 
+       /* May be droppable after audit
+       if (flags & IPERM_FLAG_RCU)
+               return -ECHILD;*/
+
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
        smk_ad_setfield_u_fs_inode(&ad, inode);
        return smk_curacc(smk_of_inode(inode), mask, &ad);
@@ -857,7 +902,7 @@ static int smack_inode_getxattr(struct dentry *dentry, const char *name)
        return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad);
 }
 
-/*
+/**
  * smack_inode_removexattr - Smack check on removexattr
  * @dentry: the object
  * @name: name of the attribute
@@ -2508,6 +2553,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
        char *final;
        char trattr[TRANS_TRUE_SIZE];
        int transflag = 0;
+       int rc;
        struct dentry *dp;
 
        if (inode == NULL)
@@ -2626,15 +2672,36 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
                 */
                dp = dget(opt_dentry);
                fetched = smk_fetch(XATTR_NAME_SMACK, inode, dp);
-               if (fetched != NULL) {
+               if (fetched != NULL)
                        final = fetched;
-                       if (S_ISDIR(inode->i_mode)) {
-                               trattr[0] = '\0';
-                               inode->i_op->getxattr(dp,
+
+               /*
+                * Transmuting directory
+                */
+               if (S_ISDIR(inode->i_mode)) {
+                       /*
+                        * If there is a transmute attribute on the
+                        * directory mark the inode.
+                        */
+                       rc = inode->i_op->getxattr(dp,
+                               XATTR_NAME_SMACKTRANSMUTE, trattr,
+                               TRANS_TRUE_SIZE);
+                       if (rc >= 0 &&
+                           strncmp(trattr, TRANS_TRUE, TRANS_TRUE_SIZE) == 0)
+                               transflag = SMK_INODE_TRANSMUTE;
+                       /*
+                        * If this is a new directory and the label was
+                        * transmuted when the inode was initialized
+                        * set the transmute attribute on the directory
+                        * and mark the inode.
+                        */
+                       if (isp->smk_flags & SMK_INODE_CHANGED) {
+                               isp->smk_flags &= ~SMK_INODE_CHANGED;
+                               rc = inode->i_op->setxattr(dp,
                                        XATTR_NAME_SMACKTRANSMUTE,
-                                       trattr, TRANS_TRUE_SIZE);
-                               if (strncmp(trattr, TRANS_TRUE,
-                                           TRANS_TRUE_SIZE) == 0)
+                                       TRANS_TRUE, TRANS_TRUE_SIZE,
+                                       0);
+                               if (rc >= 0)
                                        transflag = SMK_INODE_TRANSMUTE;
                        }
                }
@@ -3449,6 +3516,8 @@ struct security_operations smack_ops = {
        .sb_umount =                    smack_sb_umount,
 
        .bprm_set_creds =               smack_bprm_set_creds,
+       .bprm_committing_creds =        smack_bprm_committing_creds,
+       .bprm_secureexec =              smack_bprm_secureexec,
 
        .inode_alloc_security =         smack_inode_alloc_security,
        .inode_free_security =          smack_inode_free_security,
index 5b4f1659bda768574f411f9ebd2c50a473590394..34bb5fa85ed218b062f5ffc7ed67420da0110af8 100644 (file)
@@ -194,19 +194,37 @@ static int smk_set_access(struct smack_rule *srp, struct list_head *rule_list,
 }
 
 /**
- * smk_parse_rule - parse subject, object and access type
+ * smk_parse_rule - parse Smack rule from load string
  * @data: string to be parsed whose size is SMK_LOADLEN
- * @rule: parsed entities are stored in here
+ * @rule: Smack rule
+ * @import: if non-zero, import labels
  */
-static int smk_parse_rule(const char *data, struct smack_rule *rule)
+static int smk_parse_rule(const char *data, struct smack_rule *rule, int import)
 {
-       rule->smk_subject = smk_import(data, 0);
-       if (rule->smk_subject == NULL)
-               return -1;
+       char smack[SMK_LABELLEN];
+       struct smack_known *skp;
 
-       rule->smk_object = smk_import(data + SMK_LABELLEN, 0);
-       if (rule->smk_object == NULL)
-               return -1;
+       if (import) {
+               rule->smk_subject = smk_import(data, 0);
+               if (rule->smk_subject == NULL)
+                       return -1;
+
+               rule->smk_object = smk_import(data + SMK_LABELLEN, 0);
+               if (rule->smk_object == NULL)
+                       return -1;
+       } else {
+               smk_parse_smack(data, 0, smack);
+               skp = smk_find_entry(smack);
+               if (skp == NULL)
+                       return -1;
+               rule->smk_subject = skp->smk_known;
+
+               smk_parse_smack(data + SMK_LABELLEN, 0, smack);
+               skp = smk_find_entry(smack);
+               if (skp == NULL)
+                       return -1;
+               rule->smk_object = skp->smk_known;
+       }
 
        rule->smk_access = 0;
 
@@ -330,7 +348,7 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf,
                goto out;
        }
 
-       if (smk_parse_rule(data, rule))
+       if (smk_parse_rule(data, rule, 1))
                goto out_free_rule;
 
        if (rule_list == NULL) {
@@ -342,10 +360,12 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf,
 
        rc = count;
        /*
+        * If this is "load" as opposed to "load-self" and a new rule
+        * it needs to get added for reporting.
         * smk_set_access returns true if there was already a rule
         * for the subject/object pair, and false if it was new.
         */
-       if (!smk_set_access(rule, rule_list, rule_lock)) {
+       if (load && !smk_set_access(rule, rule_list, rule_lock)) {
                smlp = kzalloc(sizeof(*smlp), GFP_KERNEL);
                if (smlp != NULL) {
                        smlp->smk_rule = rule;
@@ -364,10 +384,11 @@ out:
 
 
 /*
- * Seq_file read operations for /smack/load
+ * Core logic for smackfs seq list operations.
  */
 
-static void *load_seq_start(struct seq_file *s, loff_t *pos)
+static void *smk_seq_start(struct seq_file *s, loff_t *pos,
+                               struct list_head *head)
 {
        struct list_head *list;
 
@@ -375,7 +396,7 @@ static void *load_seq_start(struct seq_file *s, loff_t *pos)
         * This is 0 the first time through.
         */
        if (s->index == 0)
-               s->private = &smack_rule_list;
+               s->private = head;
 
        if (s->private == NULL)
                return NULL;
@@ -389,11 +410,12 @@ static void *load_seq_start(struct seq_file *s, loff_t *pos)
        return list;
 }
 
-static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos)
+static void *smk_seq_next(struct seq_file *s, void *v, loff_t *pos,
+                               struct list_head *head)
 {
        struct list_head *list = v;
 
-       if (list_is_last(list, &smack_rule_list)) {
+       if (list_is_last(list, head)) {
                s->private = NULL;
                return NULL;
        }
@@ -401,6 +423,25 @@ static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos)
        return list->next;
 }
 
+static void smk_seq_stop(struct seq_file *s, void *v)
+{
+       /* No-op */
+}
+
+/*
+ * Seq_file read operations for /smack/load
+ */
+
+static void *load_seq_start(struct seq_file *s, loff_t *pos)
+{
+       return smk_seq_start(s, pos, &smack_rule_list);
+}
+
+static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+       return smk_seq_next(s, v, pos, &smack_rule_list);
+}
+
 static int load_seq_show(struct seq_file *s, void *v)
 {
        struct list_head *list = v;
@@ -431,16 +472,11 @@ static int load_seq_show(struct seq_file *s, void *v)
        return 0;
 }
 
-static void load_seq_stop(struct seq_file *s, void *v)
-{
-       /* No-op */
-}
-
 static const struct seq_operations load_seq_ops = {
        .start = load_seq_start,
        .next  = load_seq_next,
        .show  = load_seq_show,
-       .stop  = load_seq_stop,
+       .stop  = smk_seq_stop,
 };
 
 /**
@@ -475,10 +511,6 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
        if (!capable(CAP_MAC_ADMIN))
                return -EPERM;
 
-/*
-       return smk_write_load_list(file, buf, count, ppos, &smack_rule_list,
-                                       &smack_list_lock);
-*/
        return smk_write_load_list(file, buf, count, ppos, NULL, NULL);
 }
 
@@ -563,28 +595,12 @@ static void smk_unlbl_ambient(char *oldambient)
 
 static void *cipso_seq_start(struct seq_file *s, loff_t *pos)
 {
-       if (*pos == SEQ_READ_FINISHED)
-               return NULL;
-       if (list_empty(&smack_known_list))
-               return NULL;
-
-       return smack_known_list.next;
+       return smk_seq_start(s, pos, &smack_known_list);
 }
 
 static void *cipso_seq_next(struct seq_file *s, void *v, loff_t *pos)
 {
-       struct list_head  *list = v;
-
-       /*
-        * labels with no associated cipso value wont be printed
-        * in cipso_seq_show
-        */
-       if (list_is_last(list, &smack_known_list)) {
-               *pos = SEQ_READ_FINISHED;
-               return NULL;
-       }
-
-       return list->next;
+       return smk_seq_next(s, v, pos, &smack_known_list);
 }
 
 /*
@@ -623,16 +639,11 @@ static int cipso_seq_show(struct seq_file *s, void *v)
        return 0;
 }
 
-static void cipso_seq_stop(struct seq_file *s, void *v)
-{
-       /* No-op */
-}
-
 static const struct seq_operations cipso_seq_ops = {
        .start = cipso_seq_start,
-       .stop  = cipso_seq_stop,
        .next  = cipso_seq_next,
        .show  = cipso_seq_show,
+       .stop  = smk_seq_stop,
 };
 
 /**
@@ -777,23 +788,12 @@ static const struct file_operations smk_cipso_ops = {
 
 static void *netlbladdr_seq_start(struct seq_file *s, loff_t *pos)
 {
-       if (*pos == SEQ_READ_FINISHED)
-               return NULL;
-       if (list_empty(&smk_netlbladdr_list))
-               return NULL;
-       return smk_netlbladdr_list.next;
+       return smk_seq_start(s, pos, &smk_netlbladdr_list);
 }
 
 static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos)
 {
-       struct list_head *list = v;
-
-       if (list_is_last(list, &smk_netlbladdr_list)) {
-               *pos = SEQ_READ_FINISHED;
-               return NULL;
-       }
-
-       return list->next;
+       return smk_seq_next(s, v, pos, &smk_netlbladdr_list);
 }
 #define BEBITS (sizeof(__be32) * 8)
 
@@ -817,16 +817,11 @@ static int netlbladdr_seq_show(struct seq_file *s, void *v)
        return 0;
 }
 
-static void netlbladdr_seq_stop(struct seq_file *s, void *v)
-{
-       /* No-op */
-}
-
 static const struct seq_operations netlbladdr_seq_ops = {
        .start = netlbladdr_seq_start,
-       .stop  = netlbladdr_seq_stop,
        .next  = netlbladdr_seq_next,
        .show  = netlbladdr_seq_show,
+       .stop  = smk_seq_stop,
 };
 
 /**
@@ -1394,23 +1389,14 @@ static void *load_self_seq_start(struct seq_file *s, loff_t *pos)
 {
        struct task_smack *tsp = current_security();
 
-       if (*pos == SEQ_READ_FINISHED)
-               return NULL;
-       if (list_empty(&tsp->smk_rules))
-               return NULL;
-       return tsp->smk_rules.next;
+       return smk_seq_start(s, pos, &tsp->smk_rules);
 }
 
 static void *load_self_seq_next(struct seq_file *s, void *v, loff_t *pos)
 {
        struct task_smack *tsp = current_security();
-       struct list_head *list = v;
 
-       if (list_is_last(list, &tsp->smk_rules)) {
-               *pos = SEQ_READ_FINISHED;
-               return NULL;
-       }
-       return list->next;
+       return smk_seq_next(s, v, pos, &tsp->smk_rules);
 }
 
 static int load_self_seq_show(struct seq_file *s, void *v)
@@ -1442,16 +1428,12 @@ static int load_self_seq_show(struct seq_file *s, void *v)
        return 0;
 }
 
-static void load_self_seq_stop(struct seq_file *s, void *v)
-{
-       /* No-op */
-}
 
 static const struct seq_operations load_self_seq_ops = {
        .start = load_self_seq_start,
        .next  = load_self_seq_next,
        .show  = load_self_seq_show,
-       .stop  = load_self_seq_stop,
+       .stop  = smk_seq_stop,
 };
 
 
@@ -1504,6 +1486,7 @@ static ssize_t smk_write_access(struct file *file, const char __user *buf,
 {
        struct smack_rule rule;
        char *data;
+       int res;
 
        if (!capable(CAP_MAC_ADMIN))
                return -EPERM;
@@ -1512,13 +1495,15 @@ static ssize_t smk_write_access(struct file *file, const char __user *buf,
        if (IS_ERR(data))
                return PTR_ERR(data);
 
-       if (count < SMK_LOADLEN || smk_parse_rule(data, &rule))
+       if (count < SMK_LOADLEN || smk_parse_rule(data, &rule, 0))
                return -EINVAL;
 
-       data[0] = smk_access(rule.smk_subject, rule.smk_object,
-                            rule.smk_access, NULL) == 0;
+       res = smk_access(rule.smk_subject, rule.smk_object, rule.smk_access,
+                         NULL);
+       data[0] = res == 0 ? '1' : '0';
+       data[1] = '\0';
 
-       simple_transaction_set(file, 1);
+       simple_transaction_set(file, 2);
        return SMK_LOADLEN;
 }
 
@@ -1564,7 +1549,7 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
                [SMK_LOAD_SELF] = {
                        "load-self", &smk_load_self_ops, S_IRUGO|S_IWUGO},
                [SMK_ACCESSES] = {
-                       "access", &smk_access_ops, S_IRUGO|S_IWUSR},
+                       "access", &smk_access_ops, S_IRUGO|S_IWUGO},
                /* last one */
                        {""}
        };