Merge branch 'next' into for-linus
authorJames Morris <jmorris@namei.org>
Tue, 6 Jan 2009 22:58:22 +0000 (09:58 +1100)
committerJames Morris <jmorris@namei.org>
Tue, 6 Jan 2009 22:58:22 +0000 (09:58 +1100)
26 files changed:
Documentation/feature-removal-schedule.txt
include/linux/capability.h
include/linux/security.h
include/net/cipso_ipv4.h
include/net/netlabel.h
kernel/capability.c
net/ipv4/cipso_ipv4.c
net/netlabel/netlabel_cipso_v4.c
net/netlabel/netlabel_domainhash.c
net/netlabel/netlabel_domainhash.h
net/netlabel/netlabel_kapi.c
net/netlabel/netlabel_unlabeled.c
net/netlabel/netlabel_unlabeled.h
security/commoncap.c
security/keys/keyctl.c
security/security.c
security/selinux/Kconfig
security/selinux/avc.c
security/selinux/hooks.c
security/selinux/include/avc_ss.h
security/selinux/selinuxfs.c
security/selinux/ss/context.h
security/smack/smack.h
security/smack/smack_access.c
security/smack/smack_lsm.c
security/smack/smackfs.c

index df18d87..2193be5 100644 (file)
@@ -315,3 +315,15 @@ When:      2.6.29 (ideally) or 2.6.30 (more likely)
 Why:   Deprecated by the new (standard) device driver binding model. Use
        i2c_driver->probe() and ->remove() instead.
 Who:   Jean Delvare <khali@linux-fr.org>
+
+---------------------------
+
+What:  SELinux "compat_net" functionality
+When:  2.6.30 at the earliest
+Why:   In 2.6.18 the Secmark concept was introduced to replace the "compat_net"
+       network access control functionality of SELinux.  Secmark offers both
+       better performance and greater flexibility than the "compat_net"
+       mechanism.  Now that the major Linux distributions have moved to
+       Secmark, it is time to deprecate the older mechanism and start the
+       process of removing the old code.
+Who:   Paul Moore <paul.moore@hp.com>
index e22f48c..02bdb76 100644 (file)
@@ -529,8 +529,21 @@ extern const kernel_cap_t __cap_init_eff_set;
  *
  * Note that this does not set PF_SUPERPRIV on the task.
  */
-#define has_capability(t, cap) (security_capable((t), (cap)) == 0)
-#define has_capability_noaudit(t, cap) (security_capable_noaudit((t), (cap)) == 0)
+#define has_capability(t, cap) (security_real_capable((t), (cap)) == 0)
+
+/**
+ * has_capability_noaudit - Determine if a task has a superior capability available (unaudited)
+ * @t: The task in question
+ * @cap: The capability to be tested for
+ *
+ * Return true if the specified task has the given superior capability
+ * currently in effect, false if not, but don't write an audit message for the
+ * check.
+ *
+ * Note that this does not set PF_SUPERPRIV on the task.
+ */
+#define has_capability_noaudit(t, cap) \
+       (security_real_capable_noaudit((t), (cap)) == 0)
 
 extern int capable(int cap);
 
index b92b5e4..1f2ab63 100644 (file)
@@ -48,7 +48,8 @@ struct audit_krule;
  * These functions are in security/capability.c and are used
  * as the default capabilities functions
  */
-extern int cap_capable(struct task_struct *tsk, int cap, int audit);
+extern int cap_capable(struct task_struct *tsk, const struct cred *cred,
+                      int cap, int audit);
 extern int cap_settime(struct timespec *ts, struct timezone *tz);
 extern int cap_ptrace_may_access(struct task_struct *child, unsigned int mode);
 extern int cap_ptrace_traceme(struct task_struct *parent);
@@ -1251,9 +1252,12 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     @permitted contains the permitted capability set.
  *     Return 0 and update @new if permission is granted.
  * @capable:
- *     Check whether the @tsk process has the @cap capability.
+ *     Check whether the @tsk process has the @cap capability in the indicated
+ *     credentials.
  *     @tsk contains the task_struct for the process.
+ *     @cred contains the credentials to use.
  *     @cap contains the capability <include/linux/capability.h>.
+ *     @audit: Whether to write an audit message or not
  *     Return 0 if the capability is granted for @tsk.
  * @acct:
  *     Check permission before enabling or disabling process accounting.  If
@@ -1346,7 +1350,8 @@ struct security_operations {
                       const kernel_cap_t *effective,
                       const kernel_cap_t *inheritable,
                       const kernel_cap_t *permitted);
-       int (*capable) (struct task_struct *tsk, int cap, int audit);
+       int (*capable) (struct task_struct *tsk, const struct cred *cred,
+                       int cap, int audit);
        int (*acct) (struct file *file);
        int (*sysctl) (struct ctl_table *table, int op);
        int (*quotactl) (int cmds, int type, int id, struct super_block *sb);
@@ -1628,8 +1633,9 @@ int security_capset(struct cred *new, const struct cred *old,
                    const kernel_cap_t *effective,
                    const kernel_cap_t *inheritable,
                    const kernel_cap_t *permitted);
-int security_capable(struct task_struct *tsk, int cap);
-int security_capable_noaudit(struct task_struct *tsk, int cap);
+int security_capable(int cap);
+int security_real_capable(struct task_struct *tsk, int cap);
+int security_real_capable_noaudit(struct task_struct *tsk, int cap);
 int security_acct(struct file *file);
 int security_sysctl(struct ctl_table *table, int op);
 int security_quotactl(int cmds, int type, int id, struct super_block *sb);
@@ -1826,14 +1832,31 @@ static inline int security_capset(struct cred *new,
        return cap_capset(new, old, effective, inheritable, permitted);
 }
 
-static inline int security_capable(struct task_struct *tsk, int cap)
+static inline int security_capable(int cap)
 {
-       return cap_capable(tsk, cap, SECURITY_CAP_AUDIT);
+       return cap_capable(current, current_cred(), cap, SECURITY_CAP_AUDIT);
 }
 
-static inline int security_capable_noaudit(struct task_struct *tsk, int cap)
+static inline int security_real_capable(struct task_struct *tsk, int cap)
 {
-       return cap_capable(tsk, cap, SECURITY_CAP_NOAUDIT);
+       int ret;
+
+       rcu_read_lock();
+       ret = cap_capable(tsk, __task_cred(tsk), cap, SECURITY_CAP_AUDIT);
+       rcu_read_unlock();
+       return ret;
+}
+
+static inline
+int security_real_capable_noaudit(struct task_struct *tsk, int cap)
+{
+       int ret;
+
+       rcu_read_lock();
+       ret = cap_capable(tsk, __task_cred(tsk), cap,
+                              SECURITY_CAP_NOAUDIT);
+       rcu_read_unlock();
+       return ret;
 }
 
 static inline int security_acct(struct file *file)
index 9909774..bedc7f6 100644 (file)
@@ -131,7 +131,8 @@ extern int cipso_v4_rbm_strictvalid;
  */
 
 #ifdef CONFIG_NETLABEL
-int cipso_v4_doi_add(struct cipso_v4_doi *doi_def);
+int cipso_v4_doi_add(struct cipso_v4_doi *doi_def,
+                    struct netlbl_audit *audit_info);
 void cipso_v4_doi_free(struct cipso_v4_doi *doi_def);
 int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info);
 struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi);
@@ -140,7 +141,8 @@ int cipso_v4_doi_walk(u32 *skip_cnt,
                     int (*callback) (struct cipso_v4_doi *doi_def, void *arg),
                     void *cb_arg);
 #else
-static inline int cipso_v4_doi_add(struct cipso_v4_doi *doi_def)
+static inline int cipso_v4_doi_add(struct cipso_v4_doi *doi_def,
+                                  struct netlbl_audit *audit_info)
 {
        return -ENOSYS;
 }
index 17c442a..749011e 100644 (file)
@@ -33,6 +33,8 @@
 #include <linux/types.h>
 #include <linux/net.h>
 #include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/in6.h>
 #include <net/netlink.h>
 #include <asm/atomic.h>
 
@@ -353,13 +355,37 @@ static inline void netlbl_secattr_free(struct netlbl_lsm_secattr *secattr)
 /*
  * LSM configuration operations
  */
-int netlbl_cfg_map_del(const char *domain, struct netlbl_audit *audit_info);
-int netlbl_cfg_unlbl_add_map(const char *domain,
+int netlbl_cfg_map_del(const char *domain,
+                      u16 family,
+                      const void *addr,
+                      const void *mask,
+                      struct netlbl_audit *audit_info);
+int netlbl_cfg_unlbl_map_add(const char *domain,
+                            u16 family,
+                            const void *addr,
+                            const void *mask,
                             struct netlbl_audit *audit_info);
-int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def,
+int netlbl_cfg_unlbl_static_add(struct net *net,
+                               const char *dev_name,
+                               const void *addr,
+                               const void *mask,
+                               u16 family,
+                               u32 secid,
+                               struct netlbl_audit *audit_info);
+int netlbl_cfg_unlbl_static_del(struct net *net,
+                               const char *dev_name,
+                               const void *addr,
+                               const void *mask,
+                               u16 family,
+                               struct netlbl_audit *audit_info);
+int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def,
+                          struct netlbl_audit *audit_info);
+void netlbl_cfg_cipsov4_del(u32 doi, struct netlbl_audit *audit_info);
+int netlbl_cfg_cipsov4_map_add(u32 doi,
                               const char *domain,
+                              const struct in_addr *addr,
+                              const struct in_addr *mask,
                               struct netlbl_audit *audit_info);
-
 /*
  * LSM security attribute operations
  */
@@ -401,19 +427,62 @@ void netlbl_skbuff_err(struct sk_buff *skb, int error, int gateway);
 void netlbl_cache_invalidate(void);
 int netlbl_cache_add(const struct sk_buff *skb,
                     const struct netlbl_lsm_secattr *secattr);
+
+/*
+ * Protocol engine operations
+ */
+struct audit_buffer *netlbl_audit_start(int type,
+                                       struct netlbl_audit *audit_info);
 #else
 static inline int netlbl_cfg_map_del(const char *domain,
+                                    u16 family,
+                                    const void *addr,
+                                    const void *mask,
                                     struct netlbl_audit *audit_info)
 {
        return -ENOSYS;
 }
-static inline int netlbl_cfg_unlbl_add_map(const char *domain,
+static inline int netlbl_cfg_unlbl_map_add(const char *domain,
+                                          u16 family,
+                                          void *addr,
+                                          void *mask,
                                           struct netlbl_audit *audit_info)
 {
        return -ENOSYS;
 }
-static inline int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def,
+static inline int netlbl_cfg_unlbl_static_add(struct net *net,
+                                             const char *dev_name,
+                                             const void *addr,
+                                             const void *mask,
+                                             u16 family,
+                                             u32 secid,
+                                             struct netlbl_audit *audit_info)
+{
+       return -ENOSYS;
+}
+static inline int netlbl_cfg_unlbl_static_del(struct net *net,
+                                             const char *dev_name,
+                                             const void *addr,
+                                             const void *mask,
+                                             u16 family,
+                                             struct netlbl_audit *audit_info)
+{
+       return -ENOSYS;
+}
+static inline int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def,
+                                        struct netlbl_audit *audit_info)
+{
+       return -ENOSYS;
+}
+static inline void netlbl_cfg_cipsov4_del(u32 doi,
+                                         struct netlbl_audit *audit_info)
+{
+       return;
+}
+static inline int netlbl_cfg_cipsov4_map_add(u32 doi,
                                             const char *domain,
+                                            const struct in_addr *addr,
+                                            const struct in_addr *mask,
                                             struct netlbl_audit *audit_info)
 {
        return -ENOSYS;
@@ -495,6 +564,11 @@ static inline int netlbl_cache_add(const struct sk_buff *skb,
 {
        return 0;
 }
+static inline struct audit_buffer *netlbl_audit_start(int type,
+                                               struct netlbl_audit *audit_info)
+{
+       return NULL;
+}
 #endif /* CONFIG_NETLABEL */
 
 #endif /* _NETLABEL_H */
index c598d9d..688926e 100644 (file)
@@ -306,7 +306,7 @@ int capable(int cap)
                BUG();
        }
 
-       if (has_capability(current, cap)) {
+       if (security_capable(cap) == 0) {
                current->flags |= PF_SUPERPRIV;
                return 1;
        }
index e527990..6bb2635 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/spinlock.h>
 #include <linux/string.h>
 #include <linux/jhash.h>
+#include <linux/audit.h>
 #include <net/ip.h>
 #include <net/icmp.h>
 #include <net/tcp.h>
@@ -449,6 +450,7 @@ static struct cipso_v4_doi *cipso_v4_doi_search(u32 doi)
 /**
  * cipso_v4_doi_add - Add a new DOI to the CIPSO protocol engine
  * @doi_def: the DOI structure
+ * @audit_info: NetLabel audit information
  *
  * Description:
  * The caller defines a new DOI for use by the CIPSO engine and calls this
@@ -458,50 +460,78 @@ static struct cipso_v4_doi *cipso_v4_doi_search(u32 doi)
  * zero on success and non-zero on failure.
  *
  */
-int cipso_v4_doi_add(struct cipso_v4_doi *doi_def)
+int cipso_v4_doi_add(struct cipso_v4_doi *doi_def,
+                    struct netlbl_audit *audit_info)
 {
+       int ret_val = -EINVAL;
        u32 iter;
+       u32 doi;
+       u32 doi_type;
+       struct audit_buffer *audit_buf;
+
+       doi = doi_def->doi;
+       doi_type = doi_def->type;
 
        if (doi_def == NULL || doi_def->doi == CIPSO_V4_DOI_UNKNOWN)
-               return -EINVAL;
+               goto doi_add_return;
        for (iter = 0; iter < CIPSO_V4_TAG_MAXCNT; iter++) {
                switch (doi_def->tags[iter]) {
                case CIPSO_V4_TAG_RBITMAP:
                        break;
                case CIPSO_V4_TAG_RANGE:
-                       if (doi_def->type != CIPSO_V4_MAP_PASS)
-                               return -EINVAL;
-                       break;
-               case CIPSO_V4_TAG_INVALID:
-                       if (iter == 0)
-                               return -EINVAL;
-                       break;
                case CIPSO_V4_TAG_ENUM:
                        if (doi_def->type != CIPSO_V4_MAP_PASS)
-                               return -EINVAL;
+                               goto doi_add_return;
                        break;
                case CIPSO_V4_TAG_LOCAL:
                        if (doi_def->type != CIPSO_V4_MAP_LOCAL)
-                               return -EINVAL;
+                               goto doi_add_return;
+                       break;
+               case CIPSO_V4_TAG_INVALID:
+                       if (iter == 0)
+                               goto doi_add_return;
                        break;
                default:
-                       return -EINVAL;
+                       goto doi_add_return;
                }
        }
 
        atomic_set(&doi_def->refcount, 1);
 
        spin_lock(&cipso_v4_doi_list_lock);
-       if (cipso_v4_doi_search(doi_def->doi) != NULL)
-               goto doi_add_failure;
+       if (cipso_v4_doi_search(doi_def->doi) != NULL) {
+               spin_unlock(&cipso_v4_doi_list_lock);
+               ret_val = -EEXIST;
+               goto doi_add_return;
+       }
        list_add_tail_rcu(&doi_def->list, &cipso_v4_doi_list);
        spin_unlock(&cipso_v4_doi_list_lock);
+       ret_val = 0;
 
-       return 0;
+doi_add_return:
+       audit_buf = netlbl_audit_start(AUDIT_MAC_CIPSOV4_ADD, audit_info);
+       if (audit_buf != NULL) {
+               const char *type_str;
+               switch (doi_type) {
+               case CIPSO_V4_MAP_TRANS:
+                       type_str = "trans";
+                       break;
+               case CIPSO_V4_MAP_PASS:
+                       type_str = "pass";
+                       break;
+               case CIPSO_V4_MAP_LOCAL:
+                       type_str = "local";
+                       break;
+               default:
+                       type_str = "(unknown)";
+               }
+               audit_log_format(audit_buf,
+                                " cipso_doi=%u cipso_type=%s res=%u",
+                                doi, type_str, ret_val == 0 ? 1 : 0);
+               audit_log_end(audit_buf);
+       }
 
-doi_add_failure:
-       spin_unlock(&cipso_v4_doi_list_lock);
-       return -EEXIST;
+       return ret_val;
 }
 
 /**
@@ -559,25 +589,39 @@ static void cipso_v4_doi_free_rcu(struct rcu_head *entry)
  */
 int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info)
 {
+       int ret_val;
        struct cipso_v4_doi *doi_def;
+       struct audit_buffer *audit_buf;
 
        spin_lock(&cipso_v4_doi_list_lock);
        doi_def = cipso_v4_doi_search(doi);
        if (doi_def == NULL) {
                spin_unlock(&cipso_v4_doi_list_lock);
-               return -ENOENT;
+               ret_val = -ENOENT;
+               goto doi_remove_return;
        }
        if (!atomic_dec_and_test(&doi_def->refcount)) {
                spin_unlock(&cipso_v4_doi_list_lock);
-               return -EBUSY;
+               ret_val = -EBUSY;
+               goto doi_remove_return;
        }
        list_del_rcu(&doi_def->list);
        spin_unlock(&cipso_v4_doi_list_lock);
 
        cipso_v4_cache_invalidate();
        call_rcu(&doi_def->rcu, cipso_v4_doi_free_rcu);
+       ret_val = 0;
+
+doi_remove_return:
+       audit_buf = netlbl_audit_start(AUDIT_MAC_CIPSOV4_DEL, audit_info);
+       if (audit_buf != NULL) {
+               audit_log_format(audit_buf,
+                                " cipso_doi=%u res=%u",
+                                doi, ret_val == 0 ? 1 : 0);
+               audit_log_end(audit_buf);
+       }
 
-       return 0;
+       return ret_val;
 }
 
 /**
index fff32b7..bf1ab1a 100644 (file)
@@ -130,6 +130,7 @@ static int netlbl_cipsov4_add_common(struct genl_info *info,
 /**
  * netlbl_cipsov4_add_std - Adds a CIPSO V4 DOI definition
  * @info: the Generic NETLINK info block
+ * @audit_info: NetLabel audit information
  *
  * Description:
  * Create a new CIPSO_V4_MAP_TRANS DOI definition based on the given ADD
@@ -137,7 +138,8 @@ static int netlbl_cipsov4_add_common(struct genl_info *info,
  * non-zero on error.
  *
  */
-static int netlbl_cipsov4_add_std(struct genl_info *info)
+static int netlbl_cipsov4_add_std(struct genl_info *info,
+                                 struct netlbl_audit *audit_info)
 {
        int ret_val = -EINVAL;
        struct cipso_v4_doi *doi_def = NULL;
@@ -316,7 +318,7 @@ static int netlbl_cipsov4_add_std(struct genl_info *info)
                        }
        }
 
-       ret_val = cipso_v4_doi_add(doi_def);
+       ret_val = cipso_v4_doi_add(doi_def, audit_info);
        if (ret_val != 0)
                goto add_std_failure;
        return 0;
@@ -330,6 +332,7 @@ add_std_failure:
 /**
  * netlbl_cipsov4_add_pass - Adds a CIPSO V4 DOI definition
  * @info: the Generic NETLINK info block
+ * @audit_info: NetLabel audit information
  *
  * Description:
  * Create a new CIPSO_V4_MAP_PASS DOI definition based on the given ADD message
@@ -337,7 +340,8 @@ add_std_failure:
  * error.
  *
  */
-static int netlbl_cipsov4_add_pass(struct genl_info *info)
+static int netlbl_cipsov4_add_pass(struct genl_info *info,
+                                  struct netlbl_audit *audit_info)
 {
        int ret_val;
        struct cipso_v4_doi *doi_def = NULL;
@@ -354,7 +358,7 @@ static int netlbl_cipsov4_add_pass(struct genl_info *info)
        if (ret_val != 0)
                goto add_pass_failure;
 
-       ret_val = cipso_v4_doi_add(doi_def);
+       ret_val = cipso_v4_doi_add(doi_def, audit_info);
        if (ret_val != 0)
                goto add_pass_failure;
        return 0;
@@ -367,6 +371,7 @@ add_pass_failure:
 /**
  * netlbl_cipsov4_add_local - Adds a CIPSO V4 DOI definition
  * @info: the Generic NETLINK info block
+ * @audit_info: NetLabel audit information
  *
  * Description:
  * Create a new CIPSO_V4_MAP_LOCAL DOI definition based on the given ADD
@@ -374,7 +379,8 @@ add_pass_failure:
  * non-zero on error.
  *
  */
-static int netlbl_cipsov4_add_local(struct genl_info *info)
+static int netlbl_cipsov4_add_local(struct genl_info *info,
+                                   struct netlbl_audit *audit_info)
 {
        int ret_val;
        struct cipso_v4_doi *doi_def = NULL;
@@ -391,7 +397,7 @@ static int netlbl_cipsov4_add_local(struct genl_info *info)
        if (ret_val != 0)
                goto add_local_failure;
 
-       ret_val = cipso_v4_doi_add(doi_def);
+       ret_val = cipso_v4_doi_add(doi_def, audit_info);
        if (ret_val != 0)
                goto add_local_failure;
        return 0;
@@ -415,48 +421,31 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
 
 {
        int ret_val = -EINVAL;
-       u32 type;
-       u32 doi;
        const char *type_str = "(unknown)";
-       struct audit_buffer *audit_buf;
        struct netlbl_audit audit_info;
 
        if (!info->attrs[NLBL_CIPSOV4_A_DOI] ||
            !info->attrs[NLBL_CIPSOV4_A_MTYPE])
                return -EINVAL;
 
-       doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
        netlbl_netlink_auditinfo(skb, &audit_info);
-
-       type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]);
-       switch (type) {
+       switch (nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE])) {
        case CIPSO_V4_MAP_TRANS:
                type_str = "trans";
-               ret_val = netlbl_cipsov4_add_std(info);
+               ret_val = netlbl_cipsov4_add_std(info, &audit_info);
                break;
        case CIPSO_V4_MAP_PASS:
                type_str = "pass";
-               ret_val = netlbl_cipsov4_add_pass(info);
+               ret_val = netlbl_cipsov4_add_pass(info, &audit_info);
                break;
        case CIPSO_V4_MAP_LOCAL:
                type_str = "local";
-               ret_val = netlbl_cipsov4_add_local(info);
+               ret_val = netlbl_cipsov4_add_local(info, &audit_info);
                break;
        }
        if (ret_val == 0)
                atomic_inc(&netlabel_mgmt_protocount);
 
-       audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD,
-                                             &audit_info);
-       if (audit_buf != NULL) {
-               audit_log_format(audit_buf,
-                                " cipso_doi=%u cipso_type=%s res=%u",
-                                doi,
-                                type_str,
-                                ret_val == 0 ? 1 : 0);
-               audit_log_end(audit_buf);
-       }
-
        return ret_val;
 }
 
@@ -725,9 +714,7 @@ static int netlbl_cipsov4_remove_cb(struct netlbl_dom_map *entry, void *arg)
 static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
 {
        int ret_val = -EINVAL;
-       u32 doi = 0;
        struct netlbl_domhsh_walk_arg cb_arg;
-       struct audit_buffer *audit_buf;
        struct netlbl_audit audit_info;
        u32 skip_bkt = 0;
        u32 skip_chain = 0;
@@ -735,29 +722,17 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
        if (!info->attrs[NLBL_CIPSOV4_A_DOI])
                return -EINVAL;
 
-       doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
        netlbl_netlink_auditinfo(skb, &audit_info);
-
-       cb_arg.doi = doi;
+       cb_arg.doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
        cb_arg.audit_info = &audit_info;
        ret_val = netlbl_domhsh_walk(&skip_bkt, &skip_chain,
                                     netlbl_cipsov4_remove_cb, &cb_arg);
        if (ret_val == 0 || ret_val == -ENOENT) {
-               ret_val = cipso_v4_doi_remove(doi, &audit_info);
+               ret_val = cipso_v4_doi_remove(cb_arg.doi, &audit_info);
                if (ret_val == 0)
                        atomic_dec(&netlabel_mgmt_protocount);
        }
 
-       audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL,
-                                             &audit_info);
-       if (audit_buf != NULL) {
-               audit_log_format(audit_buf,
-                                " cipso_doi=%u res=%u",
-                                doi,
-                                ret_val == 0 ? 1 : 0);
-               audit_log_end(audit_buf);
-       }
-
        return ret_val;
 }
 
index 5fadf10..7a10bbe 100644 (file)
@@ -482,6 +482,73 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
        return ret_val;
 }
 
+/**
+ * netlbl_domhsh_remove_af4 - Removes an address selector entry
+ * @domain: the domain
+ * @addr: IPv4 address
+ * @mask: IPv4 address mask
+ * @audit_info: NetLabel audit information
+ *
+ * Description:
+ * Removes an individual address selector from a domain mapping and potentially
+ * the entire mapping if it is empty.  Returns zero on success, negative values
+ * on failure.
+ *
+ */
+int netlbl_domhsh_remove_af4(const char *domain,
+                            const struct in_addr *addr,
+                            const struct in_addr *mask,
+                            struct netlbl_audit *audit_info)
+{
+       struct netlbl_dom_map *entry_map;
+       struct netlbl_af4list *entry_addr;
+       struct netlbl_af4list *iter4;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       struct netlbl_af6list *iter6;
+#endif /* IPv6 */
+       struct netlbl_domaddr4_map *entry;
+
+       rcu_read_lock();
+
+       if (domain)
+               entry_map = netlbl_domhsh_search(domain);
+       else
+               entry_map = netlbl_domhsh_search_def(domain);
+       if (entry_map == NULL || entry_map->type != NETLBL_NLTYPE_ADDRSELECT)
+               goto remove_af4_failure;
+
+       spin_lock(&netlbl_domhsh_lock);
+       entry_addr = netlbl_af4list_remove(addr->s_addr, mask->s_addr,
+                                          &entry_map->type_def.addrsel->list4);
+       spin_unlock(&netlbl_domhsh_lock);
+
+       if (entry_addr == NULL)
+               goto remove_af4_failure;
+       netlbl_af4list_foreach_rcu(iter4, &entry_map->type_def.addrsel->list4)
+               goto remove_af4_single_addr;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       netlbl_af6list_foreach_rcu(iter6, &entry_map->type_def.addrsel->list6)
+               goto remove_af4_single_addr;
+#endif /* IPv6 */
+       /* the domain mapping is empty so remove it from the mapping table */
+       netlbl_domhsh_remove_entry(entry_map, audit_info);
+
+remove_af4_single_addr:
+       rcu_read_unlock();
+       /* yick, we can't use call_rcu here because we don't have a rcu head
+        * pointer but hopefully this should be a rare case so the pause
+        * shouldn't be a problem */
+       synchronize_rcu();
+       entry = netlbl_domhsh_addr4_entry(entry_addr);
+       cipso_v4_doi_putdef(entry->type_def.cipsov4);
+       kfree(entry);
+       return 0;
+
+remove_af4_failure:
+       rcu_read_unlock();
+       return -ENOENT;
+}
+
 /**
  * netlbl_domhsh_remove - Removes an entry from the domain hash table
  * @domain: the domain to remove
index bfcb676..0261dda 100644 (file)
@@ -90,6 +90,10 @@ int netlbl_domhsh_add_default(struct netlbl_dom_map *entry,
                              struct netlbl_audit *audit_info);
 int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
                               struct netlbl_audit *audit_info);
+int netlbl_domhsh_remove_af4(const char *domain,
+                            const struct in_addr *addr,
+                            const struct in_addr *mask,
+                            struct netlbl_audit *audit_info);
 int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info);
 int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info);
 struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain);
index b32eceb..fd9229d 100644 (file)
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/audit.h>
+#include <linux/in.h>
+#include <linux/in6.h>
 #include <net/ip.h>
+#include <net/ipv6.h>
 #include <net/netlabel.h>
 #include <net/cipso_ipv4.h>
 #include <asm/bug.h>
@@ -42,6 +45,7 @@
 #include "netlabel_cipso_v4.h"
 #include "netlabel_user.h"
 #include "netlabel_mgmt.h"
+#include "netlabel_addrlist.h"
 
 /*
  * Configuration Functions
@@ -50,6 +54,9 @@
 /**
  * netlbl_cfg_map_del - Remove a NetLabel/LSM domain mapping
  * @domain: the domain mapping to remove
+ * @family: address family
+ * @addr: IP address
+ * @mask: IP address mask
  * @audit_info: NetLabel audit information
  *
  * Description:
  * values on failure.
  *
  */
-int netlbl_cfg_map_del(const char *domain, struct netlbl_audit *audit_info)
+int netlbl_cfg_map_del(const char *domain,
+                      u16 family,
+                      const void *addr,
+                      const void *mask,
+                      struct netlbl_audit *audit_info)
 {
-       return netlbl_domhsh_remove(domain, audit_info);
+       if (addr == NULL && mask == NULL) {
+               return netlbl_domhsh_remove(domain, audit_info);
+       } else if (addr != NULL && mask != NULL) {
+               switch (family) {
+               case AF_INET:
+                       return netlbl_domhsh_remove_af4(domain, addr, mask,
+                                                       audit_info);
+               default:
+                       return -EPFNOSUPPORT;
+               }
+       } else
+               return -EINVAL;
 }
 
 /**
- * netlbl_cfg_unlbl_add_map - Add an unlabeled NetLabel/LSM domain mapping
+ * netlbl_cfg_unlbl_map_add - Add a new unlabeled mapping
  * @domain: the domain mapping to add
+ * @family: address family
+ * @addr: IP address
+ * @mask: IP address mask
  * @audit_info: NetLabel audit information
  *
  * Description:
@@ -74,11 +99,19 @@ int netlbl_cfg_map_del(const char *domain, struct netlbl_audit *audit_info)
  * negative values on failure.
  *
  */
-int netlbl_cfg_unlbl_add_map(const char *domain,
+int netlbl_cfg_unlbl_map_add(const char *domain,
+                            u16 family,
+                            const void *addr,
+                            const void *mask,
                             struct netlbl_audit *audit_info)
 {
        int ret_val = -ENOMEM;
        struct netlbl_dom_map *entry;
+       struct netlbl_domaddr_map *addrmap = NULL;
+       struct netlbl_domaddr4_map *map4 = NULL;
+       struct netlbl_domaddr6_map *map6 = NULL;
+       const struct in_addr *addr4, *mask4;
+       const struct in6_addr *addr6, *mask6;
 
        entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
        if (entry == NULL)
@@ -86,49 +119,225 @@ int netlbl_cfg_unlbl_add_map(const char *domain,
        if (domain != NULL) {
                entry->domain = kstrdup(domain, GFP_ATOMIC);
                if (entry->domain == NULL)
-                       goto cfg_unlbl_add_map_failure;
+                       goto cfg_unlbl_map_add_failure;
+       }
+
+       if (addr == NULL && mask == NULL)
+               entry->type = NETLBL_NLTYPE_UNLABELED;
+       else if (addr != NULL && mask != NULL) {
+               addrmap = kzalloc(sizeof(*addrmap), GFP_ATOMIC);
+               if (addrmap == NULL)
+                       goto cfg_unlbl_map_add_failure;
+               INIT_LIST_HEAD(&addrmap->list4);
+               INIT_LIST_HEAD(&addrmap->list6);
+
+               switch (family) {
+               case AF_INET:
+                       addr4 = addr;
+                       mask4 = mask;
+                       map4 = kzalloc(sizeof(*map4), GFP_ATOMIC);
+                       if (map4 == NULL)
+                               goto cfg_unlbl_map_add_failure;
+                       map4->type = NETLBL_NLTYPE_UNLABELED;
+                       map4->list.addr = addr4->s_addr & mask4->s_addr;
+                       map4->list.mask = mask4->s_addr;
+                       map4->list.valid = 1;
+                       ret_val = netlbl_af4list_add(&map4->list,
+                                                    &addrmap->list4);
+                       if (ret_val != 0)
+                               goto cfg_unlbl_map_add_failure;
+                       break;
+               case AF_INET6:
+                       addr6 = addr;
+                       mask6 = mask;
+                       map6 = kzalloc(sizeof(*map6), GFP_ATOMIC);
+                       if (map4 == NULL)
+                               goto cfg_unlbl_map_add_failure;
+                       map6->type = NETLBL_NLTYPE_UNLABELED;
+                       ipv6_addr_copy(&map6->list.addr, addr6);
+                       map6->list.addr.s6_addr32[0] &= mask6->s6_addr32[0];
+                       map6->list.addr.s6_addr32[1] &= mask6->s6_addr32[1];
+                       map6->list.addr.s6_addr32[2] &= mask6->s6_addr32[2];
+                       map6->list.addr.s6_addr32[3] &= mask6->s6_addr32[3];
+                       ipv6_addr_copy(&map6->list.mask, mask6);
+                       map6->list.valid = 1;
+                       ret_val = netlbl_af4list_add(&map4->list,
+                                                    &addrmap->list4);
+                       if (ret_val != 0)
+                               goto cfg_unlbl_map_add_failure;
+                       break;
+               default:
+                       goto cfg_unlbl_map_add_failure;
+                       break;
+               }
+
+               entry->type_def.addrsel = addrmap;
+               entry->type = NETLBL_NLTYPE_ADDRSELECT;
+       } else {
+               ret_val = -EINVAL;
+               goto cfg_unlbl_map_add_failure;
        }
-       entry->type = NETLBL_NLTYPE_UNLABELED;
 
        ret_val = netlbl_domhsh_add(entry, audit_info);
        if (ret_val != 0)
-               goto cfg_unlbl_add_map_failure;
+               goto cfg_unlbl_map_add_failure;
 
        return 0;
 
-cfg_unlbl_add_map_failure:
+cfg_unlbl_map_add_failure:
        if (entry != NULL)
                kfree(entry->domain);
        kfree(entry);
+       kfree(addrmap);
+       kfree(map4);
+       kfree(map6);
        return ret_val;
 }
 
+
+/**
+ * netlbl_cfg_unlbl_static_add - Adds a new static label
+ * @net: network namespace
+ * @dev_name: interface name
+ * @addr: IP address in network byte order (struct in[6]_addr)
+ * @mask: address mask in network byte order (struct in[6]_addr)
+ * @family: address family
+ * @secid: LSM secid value for the entry
+ * @audit_info: NetLabel audit information
+ *
+ * Description:
+ * Adds a new NetLabel static label to be used when protocol provided labels
+ * are not present on incoming traffic.  If @dev_name is NULL then the default
+ * interface will be used.  Returns zero on success, negative values on failure.
+ *
+ */
+int netlbl_cfg_unlbl_static_add(struct net *net,
+                               const char *dev_name,
+                               const void *addr,
+                               const void *mask,
+                               u16 family,
+                               u32 secid,
+                               struct netlbl_audit *audit_info)
+{
+       u32 addr_len;
+
+       switch (family) {
+       case AF_INET:
+               addr_len = sizeof(struct in_addr);
+               break;
+       case AF_INET6:
+               addr_len = sizeof(struct in6_addr);
+               break;
+       default:
+               return -EPFNOSUPPORT;
+       }
+
+       return netlbl_unlhsh_add(net,
+                                dev_name, addr, mask, addr_len,
+                                secid, audit_info);
+}
+
+/**
+ * netlbl_cfg_unlbl_static_del - Removes an existing static label
+ * @net: network namespace
+ * @dev_name: interface name
+ * @addr: IP address in network byte order (struct in[6]_addr)
+ * @mask: address mask in network byte order (struct in[6]_addr)
+ * @family: address family
+ * @secid: LSM secid value for the entry
+ * @audit_info: NetLabel audit information
+ *
+ * Description:
+ * Removes an existing NetLabel static label used when protocol provided labels
+ * are not present on incoming traffic.  If @dev_name is NULL then the default
+ * interface will be used.  Returns zero on success, negative values on failure.
+ *
+ */
+int netlbl_cfg_unlbl_static_del(struct net *net,
+                               const char *dev_name,
+                               const void *addr,
+                               const void *mask,
+                               u16 family,
+                               struct netlbl_audit *audit_info)
+{
+       u32 addr_len;
+
+       switch (family) {
+       case AF_INET:
+               addr_len = sizeof(struct in_addr);
+               break;
+       case AF_INET6:
+               addr_len = sizeof(struct in6_addr);
+               break;
+       default:
+               return -EPFNOSUPPORT;
+       }
+
+       return netlbl_unlhsh_remove(net,
+                                   dev_name, addr, mask, addr_len,
+                                   audit_info);
+}
+
+/**
+ * netlbl_cfg_cipsov4_add - Add a new CIPSOv4 DOI definition
+ * @doi_def: CIPSO DOI definition
+ * @audit_info: NetLabel audit information
+ *
+ * Description:
+ * Add a new CIPSO DOI definition as defined by @doi_def.  Returns zero on
+ * success and negative values on failure.
+ *
+ */
+int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def,
+                          struct netlbl_audit *audit_info)
+{
+       return cipso_v4_doi_add(doi_def, audit_info);
+}
+
+/**
+ * netlbl_cfg_cipsov4_del - Remove an existing CIPSOv4 DOI definition
+ * @doi: CIPSO DOI
+ * @audit_info: NetLabel audit information
+ *
+ * Description:
+ * Remove an existing CIPSO DOI definition matching @doi.  Returns zero on
+ * success and negative values on failure.
+ *
+ */
+void netlbl_cfg_cipsov4_del(u32 doi, struct netlbl_audit *audit_info)
+{
+       cipso_v4_doi_remove(doi, audit_info);
+}
+
 /**
- * netlbl_cfg_cipsov4_add_map - Add a new CIPSOv4 DOI definition and mapping
- * @doi_def: the DOI definition
+ * netlbl_cfg_cipsov4_map_add - Add a new CIPSOv4 DOI mapping
+ * @doi: the CIPSO DOI
  * @domain: the domain mapping to add
+ * @addr: IP address
+ * @mask: IP address mask
  * @audit_info: NetLabel audit information
  *
  * Description:
- * Add a new CIPSOv4 DOI definition and NetLabel/LSM domain mapping for this
- * new DOI definition to the NetLabel subsystem.  A @domain value of NULL adds
- * a new default domain mapping.  Returns zero on success, negative values on
- * failure.
+ * Add a new NetLabel/LSM domain mapping for the given CIPSO DOI to the NetLabel
+ * subsystem.  A @domain value of NULL adds a new default domain mapping.
+ * Returns zero on success, negative values on failure.
  *
  */
-int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def,
+int netlbl_cfg_cipsov4_map_add(u32 doi,
                               const char *domain,
+                              const struct in_addr *addr,
+                              const struct in_addr *mask,
                               struct netlbl_audit *audit_info)
 {
        int ret_val = -ENOMEM;
-       u32 doi;
-       u32 doi_type;
+       struct cipso_v4_doi *doi_def;
        struct netlbl_dom_map *entry;
-       const char *type_str;
-       struct audit_buffer *audit_buf;
+       struct netlbl_domaddr_map *addrmap = NULL;
+       struct netlbl_domaddr4_map *addrinfo = NULL;
 
-       doi = doi_def->doi;
-       doi_type = doi_def->type;
+       doi_def = cipso_v4_doi_getdef(doi);
+       if (doi_def == NULL)
+               return -ENOENT;
 
        entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
        if (entry == NULL)
@@ -136,56 +345,52 @@ int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def,
        if (domain != NULL) {
                entry->domain = kstrdup(domain, GFP_ATOMIC);
                if (entry->domain == NULL)
-                       goto cfg_cipsov4_add_map_failure;
+                       goto cfg_cipsov4_map_add_failure;
        }
 
-       ret_val = cipso_v4_doi_add(doi_def);
-       if (ret_val != 0)
-               goto cfg_cipsov4_add_map_failure_remove_doi;
-       entry->type = NETLBL_NLTYPE_CIPSOV4;
-       entry->type_def.cipsov4 = cipso_v4_doi_getdef(doi);
-       if (entry->type_def.cipsov4 == NULL) {
-               ret_val = -ENOENT;
-               goto cfg_cipsov4_add_map_failure_remove_doi;
+       if (addr == NULL && mask == NULL) {
+               entry->type_def.cipsov4 = doi_def;
+               entry->type = NETLBL_NLTYPE_CIPSOV4;
+       } else if (addr != NULL && mask != NULL) {
+               addrmap = kzalloc(sizeof(*addrmap), GFP_ATOMIC);
+               if (addrmap == NULL)
+                       goto cfg_cipsov4_map_add_failure;
+               INIT_LIST_HEAD(&addrmap->list4);
+               INIT_LIST_HEAD(&addrmap->list6);
+
+               addrinfo = kzalloc(sizeof(*addrinfo), GFP_ATOMIC);
+               if (addrinfo == NULL)
+                       goto cfg_cipsov4_map_add_failure;
+               addrinfo->type_def.cipsov4 = doi_def;
+               addrinfo->type = NETLBL_NLTYPE_CIPSOV4;
+               addrinfo->list.addr = addr->s_addr & mask->s_addr;
+               addrinfo->list.mask = mask->s_addr;
+               addrinfo->list.valid = 1;
+               ret_val = netlbl_af4list_add(&addrinfo->list, &addrmap->list4);
+               if (ret_val != 0)
+                       goto cfg_cipsov4_map_add_failure;
+
+               entry->type_def.addrsel = addrmap;
+               entry->type = NETLBL_NLTYPE_ADDRSELECT;
+       } else {
+               ret_val = -EINVAL;
+               goto cfg_cipsov4_map_add_failure;
        }
+
        ret_val = netlbl_domhsh_add(entry, audit_info);
        if (ret_val != 0)
-               goto cfg_cipsov4_add_map_failure_release_doi;
-
-cfg_cipsov4_add_map_return:
-       audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD,
-                                             audit_info);
-       if (audit_buf != NULL) {
-               switch (doi_type) {
-               case CIPSO_V4_MAP_TRANS:
-                       type_str = "trans";
-                       break;
-               case CIPSO_V4_MAP_PASS:
-                       type_str = "pass";
-                       break;
-               case CIPSO_V4_MAP_LOCAL:
-                       type_str = "local";
-                       break;
-               default:
-                       type_str = "(unknown)";
-               }
-               audit_log_format(audit_buf,
-                                " cipso_doi=%u cipso_type=%s res=%u",
-                                doi, type_str, ret_val == 0 ? 1 : 0);
-               audit_log_end(audit_buf);
-       }
+               goto cfg_cipsov4_map_add_failure;
 
-       return ret_val;
+       return 0;
 
-cfg_cipsov4_add_map_failure_release_doi:
+cfg_cipsov4_map_add_failure:
        cipso_v4_doi_putdef(doi_def);
-cfg_cipsov4_add_map_failure_remove_doi:
-       cipso_v4_doi_remove(doi, audit_info);
-cfg_cipsov4_add_map_failure:
        if (entry != NULL)
                kfree(entry->domain);
        kfree(entry);
-       goto cfg_cipsov4_add_map_return;
+       kfree(addrmap);
+       kfree(addrinfo);
+       return ret_val;
 }
 
 /*
@@ -690,6 +895,28 @@ int netlbl_cache_add(const struct sk_buff *skb,
        return -ENOMSG;
 }
 
+/*
+ * Protocol Engine Functions
+ */
+
+/**
+ * netlbl_audit_start - Start an audit message
+ * @type: audit message type
+ * @audit_info: NetLabel audit information
+ *
+ * Description:
+ * Start an audit message using the type specified in @type and fill the audit
+ * message with some fields common to all NetLabel audit messages.  This
+ * function should only be used by protocol engines, not LSMs.  Returns a
+ * pointer to the audit buffer on success, NULL on failure.
+ *
+ */
+struct audit_buffer *netlbl_audit_start(int type,
+                                       struct netlbl_audit *audit_info)
+{
+       return netlbl_audit_start_common(type, audit_info);
+}
+
 /*
  * Setup Functions
  */
index 8c03080..f3c5c68 100644 (file)
@@ -450,13 +450,13 @@ add_iface_failure:
  * success, negative values on failure.
  *
  */
-static int netlbl_unlhsh_add(struct net *net,
-                            const char *dev_name,
-                            const void *addr,
-                            const void *mask,
-                            u32 addr_len,
-                            u32 secid,
-                            struct netlbl_audit *audit_info)
+int netlbl_unlhsh_add(struct net *net,
+                     const char *dev_name,
+                     const void *addr,
+                     const void *mask,
+                     u32 addr_len,
+                     u32 secid,
+                     struct netlbl_audit *audit_info)
 {
        int ret_val;
        int ifindex;
@@ -720,12 +720,12 @@ unlhsh_condremove_failure:
  * Returns zero on success, negative values on failure.
  *
  */
-static int netlbl_unlhsh_remove(struct net *net,
-                               const char *dev_name,
-                               const void *addr,
-                               const void *mask,
-                               u32 addr_len,
-                               struct netlbl_audit *audit_info)
+int netlbl_unlhsh_remove(struct net *net,
+                        const char *dev_name,
+                        const void *addr,
+                        const void *mask,
+                        u32 addr_len,
+                        struct netlbl_audit *audit_info)
 {
        int ret_val;
        struct net_device *dev;
index 06b1301..7aba635 100644 (file)
@@ -221,6 +221,21 @@ int netlbl_unlabel_genl_init(void);
 /* General Unlabeled init function */
 int netlbl_unlabel_init(u32 size);
 
+/* Static/Fallback label management functions */
+int netlbl_unlhsh_add(struct net *net,
+                     const char *dev_name,
+                     const void *addr,
+                     const void *mask,
+                     u32 addr_len,
+                     u32 secid,
+                     struct netlbl_audit *audit_info);
+int netlbl_unlhsh_remove(struct net *net,
+                        const char *dev_name,
+                        const void *addr,
+                        const void *mask,
+                        u32 addr_len,
+                        struct netlbl_audit *audit_info);
+
 /* Process Unlabeled incoming network packets */
 int netlbl_unlabel_getattr(const struct sk_buff *skb,
                           u16 family,
index 69fc995..7cd61a5 100644 (file)
@@ -45,26 +45,22 @@ EXPORT_SYMBOL(cap_netlink_recv);
 /**
  * cap_capable - Determine whether a task has a particular effective capability
  * @tsk: The task to query
+ * @cred: The credentials to use
  * @cap: The capability to check for
  * @audit: Whether to write an audit message or not
  *
  * Determine whether the nominated task has the specified capability amongst
  * its effective set, returning 0 if it does, -ve if it does not.
  *
- * NOTE WELL: cap_capable() cannot be used like the kernel's capable()
- * function.  That is, it has the reverse semantics: cap_capable() returns 0
- * when a task has a capability, but the kernel's capable() returns 1 for this
- * case.
+ * NOTE WELL: cap_has_capability() cannot be used like the kernel's capable()
+ * and has_capability() functions.  That is, it has the reverse semantics:
+ * cap_has_capability() returns 0 when a task has a capability, but the
+ * kernel's capable() and has_capability() returns 1 for this case.
  */
-int cap_capable(struct task_struct *tsk, int cap, int audit)
+int cap_capable(struct task_struct *tsk, const struct cred *cred, int cap,
+               int audit)
 {
-       __u32 cap_raised;
-
-       /* Derived from include/linux/sched.h:capable. */
-       rcu_read_lock();
-       cap_raised = cap_raised(__task_cred(tsk)->cap_effective, cap);
-       rcu_read_unlock();
-       return cap_raised ? 0 : -EPERM;
+       return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM;
 }
 
 /**
@@ -160,7 +156,8 @@ static inline int cap_inh_is_capped(void)
        /* they are so limited unless the current task has the CAP_SETPCAP
         * capability
         */
-       if (cap_capable(current, CAP_SETPCAP, SECURITY_CAP_AUDIT) == 0)
+       if (cap_capable(current, current_cred(), CAP_SETPCAP,
+                       SECURITY_CAP_AUDIT) == 0)
                return 0;
 #endif
        return 1;
@@ -869,7 +866,8 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
                     & (new->securebits ^ arg2))                        /*[1]*/
                    || ((new->securebits & SECURE_ALL_LOCKS & ~arg2))   /*[2]*/
                    || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS))   /*[3]*/
-                   || (cap_capable(current, CAP_SETPCAP, SECURITY_CAP_AUDIT) != 0) /*[4]*/
+                   || (cap_capable(current, current_cred(), CAP_SETPCAP,
+                                   SECURITY_CAP_AUDIT) != 0)           /*[4]*/
                        /*
                         * [1] no changing of bits that are locked
                         * [2] no unlocking of locks
@@ -950,7 +948,8 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages)
 {
        int cap_sys_admin = 0;
 
-       if (cap_capable(current, CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT) == 0)
+       if (cap_capable(current, current_cred(), CAP_SYS_ADMIN,
+                       SECURITY_CAP_NOAUDIT) == 0)
                cap_sys_admin = 1;
        return __vm_enough_memory(mm, pages, cap_sys_admin);
 }
index 6688765..0979679 100644 (file)
@@ -1294,7 +1294,7 @@ asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3,
 
        case KEYCTL_GET_SECURITY:
                return keyctl_get_security((key_serial_t) arg2,
-                                          (char *) arg3,
+                                          (char __user *) arg3,
                                           (size_t) arg4);
 
        default:
index 678d4d0..c3586c0 100644 (file)
@@ -154,14 +154,32 @@ int security_capset(struct cred *new, const struct cred *old,
                                    effective, inheritable, permitted);
 }
 
-int security_capable(struct task_struct *tsk, int cap)
+int security_capable(int cap)
 {
-       return security_ops->capable(tsk, cap, SECURITY_CAP_AUDIT);
+       return security_ops->capable(current, current_cred(), cap,
+                                    SECURITY_CAP_AUDIT);
 }
 
-int security_capable_noaudit(struct task_struct *tsk, int cap)
+int security_real_capable(struct task_struct *tsk, int cap)
 {
-       return security_ops->capable(tsk, cap, SECURITY_CAP_NOAUDIT);
+       const struct cred *cred;
+       int ret;
+
+       cred = get_task_cred(tsk);
+       ret = security_ops->capable(tsk, cred, cap, SECURITY_CAP_AUDIT);
+       put_cred(cred);
+       return ret;
+}
+
+int security_real_capable_noaudit(struct task_struct *tsk, int cap)
+{
+       const struct cred *cred;
+       int ret;
+
+       cred = get_task_cred(tsk);
+       ret = security_ops->capable(tsk, cred, cap, SECURITY_CAP_NOAUDIT);
+       put_cred(cred);
+       return ret;
 }
 
 int security_acct(struct file *file)
index 26301dd..bca1b74 100644 (file)
@@ -94,33 +94,6 @@ config SECURITY_SELINUX_CHECKREQPROT_VALUE
 
          If you are unsure how to answer this question, answer 1.
 
-config SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT
-       bool "NSA SELinux enable new secmark network controls by default"
-       depends on SECURITY_SELINUX
-       default n
-       help
-         This option determines whether the new secmark-based network
-         controls will be enabled by default.  If not, the old internal
-         per-packet controls will be enabled by default, preserving
-         old behavior.
-
-         If you enable the new controls, you will need updated
-         SELinux userspace libraries, tools and policy.  Typically,
-         your distribution will provide these and enable the new controls
-         in the kernel they also distribute.
-
-         Note that this option can be overridden at boot with the
-         selinux_compat_net parameter, and after boot via
-         /selinux/compat_net.  See Documentation/kernel-parameters.txt
-         for details on this parameter.
-
-         If you enable the new network controls, you will likely
-         also require the SECMARK and CONNSECMARK targets, as
-         well as any conntrack helpers for protocols which you
-         wish to control.
-
-         If you are unsure what to do here, select N.
-
 config SECURITY_SELINUX_POLICYDB_VERSION_MAX
        bool "NSA SELinux maximum supported policy format version"
        depends on SECURITY_SELINUX
index d43bd6b..eb41f43 100644 (file)
@@ -53,18 +53,20 @@ static const char *class_to_string[] = {
 #undef S_
 
 static const struct av_inherit av_inherit[] = {
-#define S_(c, i, b) { c, common_##i##_perm_to_string, b },
+#define S_(c, i, b) {  .tclass = c,\
+                       .common_pts = common_##i##_perm_to_string,\
+                       .common_base =  b },
 #include "av_inherit.h"
 #undef S_
 };
 
 const struct selinux_class_perm selinux_class_perm = {
-       av_perm_to_string,
-       ARRAY_SIZE(av_perm_to_string),
-       class_to_string,
-       ARRAY_SIZE(class_to_string),
-       av_inherit,
-       ARRAY_SIZE(av_inherit)
+       .av_perm_to_string = av_perm_to_string,
+       .av_pts_len = ARRAY_SIZE(av_perm_to_string),
+       .class_to_string = class_to_string,
+       .cts_len = ARRAY_SIZE(class_to_string),
+       .av_inherit = av_inherit,
+       .av_inherit_len = ARRAY_SIZE(av_inherit)
 };
 
 #define AVC_CACHE_SLOTS                        512
index dbeaa78..0081597 100644 (file)
@@ -1433,12 +1433,13 @@ static int current_has_perm(const struct task_struct *tsk,
 
 /* Check whether a task is allowed to use a capability. */
 static int task_has_capability(struct task_struct *tsk,
+                              const struct cred *cred,
                               int cap, int audit)
 {
        struct avc_audit_data ad;
        struct av_decision avd;
        u16 sclass;
-       u32 sid = task_sid(tsk);
+       u32 sid = cred_sid(cred);
        u32 av = CAP_TO_MASK(cap);
        int rc;
 
@@ -1865,15 +1866,16 @@ static int selinux_capset(struct cred *new, const struct cred *old,
        return cred_has_perm(old, new, PROCESS__SETCAP);
 }
 
-static int selinux_capable(struct task_struct *tsk, int cap, int audit)
+static int selinux_capable(struct task_struct *tsk, const struct cred *cred,
+                          int cap, int audit)
 {
        int rc;
 
-       rc = secondary_ops->capable(tsk, cap, audit);
+       rc = secondary_ops->capable(tsk, cred, cap, audit);
        if (rc)
                return rc;
 
-       return task_has_capability(tsk, cap, audit);
+       return task_has_capability(tsk, cred, cap, audit);
 }
 
 static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid)
@@ -2037,7 +2039,8 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
 {
        int rc, cap_sys_admin = 0;
 
-       rc = selinux_capable(current, CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT);
+       rc = selinux_capable(current, current_cred(), CAP_SYS_ADMIN,
+                            SECURITY_CAP_NOAUDIT);
        if (rc == 0)
                cap_sys_admin = 1;
 
@@ -2880,7 +2883,8 @@ static int selinux_inode_getsecurity(const struct inode *inode, const char *name
         * and lack of permission just means that we fall back to the
         * in-core context value, not a denial.
         */
-       error = selinux_capable(current, CAP_MAC_ADMIN, SECURITY_CAP_NOAUDIT);
+       error = selinux_capable(current, current_cred(), CAP_MAC_ADMIN,
+                               SECURITY_CAP_NOAUDIT);
        if (!error)
                error = security_sid_to_context_force(isec->sid, &context,
                                                      &size);
@@ -4185,7 +4189,7 @@ static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk,
 static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
                                       u16 family)
 {
-       int err;
+       int err = 0;
        struct sk_security_struct *sksec = sk->sk_security;
        u32 peer_sid;
        u32 sk_sid = sksec->sid;
@@ -4202,7 +4206,7 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
        if (selinux_compat_net)
                err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad,
                                                           family, addrp);
-       else
+       else if (selinux_secmark_enabled())
                err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
                                   PACKET__RECV, &ad);
        if (err)
@@ -4705,7 +4709,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
                if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex,
                                                         &ad, family, addrp))
                        return NF_DROP;
-       } else {
+       } else if (selinux_secmark_enabled()) {
                if (avc_has_perm(sksec->sid, skb->secmark,
                                 SECCLASS_PACKET, PACKET__SEND, &ad))
                        return NF_DROP;
index c0d314d..bb1ec80 100644 (file)
@@ -17,16 +17,16 @@ struct av_perm_to_string {
 };
 
 struct av_inherit {
-       u16 tclass;
        const char **common_pts;
        u32 common_base;
+       u16 tclass;
 };
 
 struct selinux_class_perm {
        const struct av_perm_to_string *av_perm_to_string;
        u32 av_pts_len;
-       const char **class_to_string;
        u32 cts_len;
+       const char **class_to_string;
        const struct av_inherit *av_inherit;
        u32 av_inherit_len;
 };
index 8f612c8..01ec6d2 100644 (file)
@@ -47,13 +47,7 @@ static char *policycap_names[] = {
 
 unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE;
 
-#ifdef CONFIG_SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT
-#define SELINUX_COMPAT_NET_VALUE 0
-#else
-#define SELINUX_COMPAT_NET_VALUE 1
-#endif
-
-int selinux_compat_net = SELINUX_COMPAT_NET_VALUE;
+int selinux_compat_net = 0;
 
 static int __init checkreqprot_setup(char *str)
 {
@@ -494,7 +488,13 @@ static ssize_t sel_write_compat_net(struct file *file, const char __user *buf,
        if (sscanf(page, "%d", &new_value) != 1)
                goto out;
 
-       selinux_compat_net = new_value ? 1 : 0;
+       if (new_value) {
+               printk(KERN_NOTICE
+                      "SELinux: compat_net is deprecated, please use secmark"
+                      " instead\n");
+               selinux_compat_net = 1;
+       } else
+               selinux_compat_net = 0;
        length = count;
 out:
        free_page((unsigned long) page);
index 658c2bd..d9dd7a2 100644 (file)
@@ -27,9 +27,9 @@ struct context {
        u32 user;
        u32 role;
        u32 type;
+       u32 len;        /* length of string in bytes */
        struct mls_range range;
        char *str;      /* string representation if context cannot be mapped. */
-       u32 len;        /* length of string in bytes */
 };
 
 static inline void mls_context_init(struct context *c)
index 31dce55..b79582e 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/capability.h>
 #include <linux/spinlock.h>
 #include <linux/security.h>
+#include <linux/in.h>
 #include <net/netlabel.h>
 
 /*
@@ -39,6 +40,7 @@ struct superblock_smack {
 struct socket_smack {
        char            *smk_out;                       /* outbound label */
        char            *smk_in;                        /* inbound label */
+       int             smk_labeled;                    /* label scheme */
        char            smk_packet[SMK_LABELLEN];       /* TCP peer label */
 };
 
@@ -79,6 +81,16 @@ struct smack_cipso {
        char    smk_catset[SMK_LABELLEN];
 };
 
+/*
+ * An entry in the table identifying hosts.
+ */
+struct smk_netlbladdr {
+       struct smk_netlbladdr   *smk_next;
+       struct sockaddr_in      smk_host;       /* network address */
+       struct in_addr          smk_mask;       /* network mask */
+       char                    *smk_label;     /* label */
+};
+
 /*
  * This is the repository for labels seen so that it is
  * not necessary to keep allocating tiny chuncks of memory
@@ -127,6 +139,20 @@ struct smack_known {
 #define XATTR_NAME_SMACKIPOUT  XATTR_SECURITY_PREFIX XATTR_SMACK_IPOUT
 
 /*
+ * How communications on this socket are treated.
+ * Usually it's determined by the underlying netlabel code
+ * but there are certain cases, including single label hosts
+ * and potentially single label interfaces for which the
+ * treatment can not be known in advance.
+ *
+ * The possibility of additional labeling schemes being
+ * introduced in the future exists as well.
+ */
+#define SMACK_UNLABELED_SOCKET 0
+#define SMACK_CIPSO_SOCKET     1
+
+/*
+ * smackfs magic number
  * smackfs macic number
  */
 #define SMACK_MAGIC    0x43415d53 /* "SMAC" */
@@ -141,6 +167,7 @@ struct smack_known {
  * CIPSO defaults.
  */
 #define SMACK_CIPSO_DOI_DEFAULT                3       /* Historical */
+#define SMACK_CIPSO_DOI_INVALID                -1      /* Not a DOI */
 #define SMACK_CIPSO_DIRECT_DEFAULT     250     /* Arbitrary */
 #define SMACK_CIPSO_MAXCATVAL          63      /* Bigger gets harder */
 #define SMACK_CIPSO_MAXLEVEL            255     /* CIPSO 2.2 standard */
@@ -176,7 +203,6 @@ u32 smack_to_secid(const char *);
  * Shared data.
  */
 extern int smack_cipso_direct;
-extern int smack_net_nltype;
 extern char *smack_net_ambient;
 extern char *smack_onlycap;
 
@@ -186,9 +212,10 @@ extern struct smack_known smack_known_hat;
 extern struct smack_known smack_known_huh;
 extern struct smack_known smack_known_invalid;
 extern struct smack_known smack_known_star;
-extern struct smack_known smack_known_unset;
+extern struct smack_known smack_known_web;
 
 extern struct smk_list_entry *smack_list;
+extern struct smk_netlbladdr *smack_netlbladdrs;
 extern struct security_operations smack_ops;
 
 /*
index 247cec3..2e0b83e 100644 (file)
 #include <linux/sched.h>
 #include "smack.h"
 
-struct smack_known smack_known_unset = {
-       .smk_next       = NULL,
-       .smk_known      = "UNSET",
-       .smk_secid      = 1,
-       .smk_cipso      = NULL,
-};
-
 struct smack_known smack_known_huh = {
-       .smk_next       = &smack_known_unset,
+       .smk_next       = NULL,
        .smk_known      = "?",
        .smk_secid      = 2,
        .smk_cipso      = NULL,
@@ -57,7 +50,14 @@ struct smack_known smack_known_invalid = {
        .smk_cipso      = NULL,
 };
 
-struct smack_known *smack_known = &smack_known_invalid;
+struct smack_known smack_known_web = {
+       .smk_next       = &smack_known_invalid,
+       .smk_known      = "@",
+       .smk_secid      = 7,
+       .smk_cipso      = NULL,
+};
+
+struct smack_known *smack_known = &smack_known_web;
 
 /*
  * The initial value needs to be bigger than any of the
@@ -98,6 +98,16 @@ int smk_access(char *subject_label, char *object_label, int request)
        if (subject_label == smack_known_star.smk_known ||
            strcmp(subject_label, smack_known_star.smk_known) == 0)
                return -EACCES;
+       /*
+        * An internet object can be accessed by any subject.
+        * Tasks cannot be assigned the internet label.
+        * An internet subject can access any object.
+        */
+       if (object_label == smack_known_web.smk_known ||
+           subject_label == smack_known_web.smk_known ||
+           strcmp(object_label, smack_known_web.smk_known) == 0 ||
+           strcmp(subject_label, smack_known_web.smk_known) == 0)
+               return 0;
        /*
         * A star object can be accessed by any subject.
         */
index 848212f..0278bc0 100644 (file)
@@ -1277,6 +1277,7 @@ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
 
        ssp->smk_in = csp;
        ssp->smk_out = csp;
+       ssp->smk_labeled = SMACK_CIPSO_SOCKET;
        ssp->smk_packet[0] = '\0';
 
        sk->sk_security = ssp;
@@ -1341,45 +1342,69 @@ static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp)
        struct smack_cipso cipso;
        int rc;
 
-       switch (smack_net_nltype) {
-       case NETLBL_NLTYPE_CIPSOV4:
-               nlsp->domain = smack;
-               nlsp->flags = NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL;
+       nlsp->domain = smack;
+       nlsp->flags = NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL;
 
-               rc = smack_to_cipso(smack, &cipso);
-               if (rc == 0) {
-                       nlsp->attr.mls.lvl = cipso.smk_level;
-                       smack_set_catset(cipso.smk_catset, nlsp);
-               } else {
-                       nlsp->attr.mls.lvl = smack_cipso_direct;
-                       smack_set_catset(smack, nlsp);
-               }
-               break;
-       default:
-               break;
+       rc = smack_to_cipso(smack, &cipso);
+       if (rc == 0) {
+               nlsp->attr.mls.lvl = cipso.smk_level;
+               smack_set_catset(cipso.smk_catset, nlsp);
+       } else {
+               nlsp->attr.mls.lvl = smack_cipso_direct;
+               smack_set_catset(smack, nlsp);
        }
 }
 
 /**
  * smack_netlabel - Set the secattr on a socket
  * @sk: the socket
+ * @labeled: socket label scheme
  *
  * Convert the outbound smack value (smk_out) to a
  * secattr and attach it to the socket.
  *
  * Returns 0 on success or an error code
  */
-static int smack_netlabel(struct sock *sk)
+static int smack_netlabel(struct sock *sk, int labeled)
 {
        struct socket_smack *ssp;
        struct netlbl_lsm_secattr secattr;
-       int rc;
+       int rc = 0;
 
        ssp = sk->sk_security;
-       netlbl_secattr_init(&secattr);
-       smack_to_secattr(ssp->smk_out, &secattr);
-       rc = netlbl_sock_setattr(sk, &secattr);
-       netlbl_secattr_destroy(&secattr);
+       /*
+        * Usually the netlabel code will handle changing the
+        * packet labeling based on the label.
+        * The case of a single label host is different, because
+        * a single label host should never get a labeled packet
+        * even though the label is usually associated with a packet
+        * label.
+        */
+       local_bh_disable();
+       bh_lock_sock_nested(sk);
+
+       if (ssp->smk_out == smack_net_ambient ||
+           labeled == SMACK_UNLABELED_SOCKET)
+               netlbl_sock_delattr(sk);
+       else {
+               netlbl_secattr_init(&secattr);
+               smack_to_secattr(ssp->smk_out, &secattr);
+               rc = netlbl_sock_setattr(sk, &secattr);
+               netlbl_secattr_destroy(&secattr);
+       }
+
+       bh_unlock_sock(sk);
+       local_bh_enable();
+       /*
+        * Remember the label scheme used so that it is not
+        * necessary to do the netlabel setting if it has not
+        * changed the next time through.
+        *
+        * The -EDESTADDRREQ case is an indication that there's
+        * a single level host involved.
+        */
+       if (rc == 0)
+               ssp->smk_labeled = labeled;
 
        return rc;
 }
@@ -1432,7 +1457,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
                ssp->smk_in = sp;
        else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) {
                ssp->smk_out = sp;
-               rc = smack_netlabel(sock->sk);
+               rc = smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
                if (rc != 0)
                        printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n",
                               __func__, -rc);
@@ -1462,7 +1487,108 @@ static int smack_socket_post_create(struct socket *sock, int family,
        /*
         * Set the outbound netlbl.
         */
-       return smack_netlabel(sock->sk);
+       return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
+}
+
+
+/**
+ * smack_host_label - check host based restrictions
+ * @sip: the object end
+ *
+ * looks for host based access restrictions
+ *
+ * This version will only be appropriate for really small
+ * sets of single label hosts. Because of the masking
+ * it cannot shortcut out on the first match. There are
+ * numerious ways to address the problem, but none of them
+ * have been applied here.
+ *
+ * Returns the label of the far end or NULL if it's not special.
+ */
+static char *smack_host_label(struct sockaddr_in *sip)
+{
+       struct smk_netlbladdr *snp;
+       char *bestlabel = NULL;
+       struct in_addr *siap = &sip->sin_addr;
+       struct in_addr *liap;
+       struct in_addr *miap;
+       struct in_addr bestmask;
+
+       if (siap->s_addr == 0)
+               return NULL;
+
+       bestmask.s_addr = 0;
+
+       for (snp = smack_netlbladdrs; snp != NULL; snp = snp->smk_next) {
+               liap = &snp->smk_host.sin_addr;
+               miap = &snp->smk_mask;
+               /*
+                * If the addresses match after applying the list entry mask
+                * the entry matches the address. If it doesn't move along to
+                * the next entry.
+                */
+               if ((liap->s_addr & miap->s_addr) !=
+                   (siap->s_addr & miap->s_addr))
+                       continue;
+               /*
+                * If the list entry mask identifies a single address
+                * it can't get any more specific.
+                */
+               if (miap->s_addr == 0xffffffff)
+                       return snp->smk_label;
+               /*
+                * If the list entry mask is less specific than the best
+                * already found this entry is uninteresting.
+                */
+               if ((miap->s_addr | bestmask.s_addr) == bestmask.s_addr)
+                       continue;
+               /*
+                * This is better than any entry found so far.
+                */
+               bestmask.s_addr = miap->s_addr;
+               bestlabel = snp->smk_label;
+       }
+
+       return bestlabel;
+}
+
+/**
+ * smack_socket_connect - connect access check
+ * @sock: the socket
+ * @sap: the other end
+ * @addrlen: size of sap
+ *
+ * Verifies that a connection may be possible
+ *
+ * Returns 0 on success, and error code otherwise
+ */
+static int smack_socket_connect(struct socket *sock, struct sockaddr *sap,
+                               int addrlen)
+{
+       struct socket_smack *ssp = sock->sk->sk_security;
+       char *hostsp;
+       int rc;
+
+       if (sock->sk == NULL || sock->sk->sk_family != PF_INET)
+               return 0;
+
+       if (addrlen < sizeof(struct sockaddr_in))
+               return -EINVAL;
+
+       hostsp = smack_host_label((struct sockaddr_in *)sap);
+       if (hostsp == NULL) {
+               if (ssp->smk_labeled != SMACK_CIPSO_SOCKET)
+                       return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
+               return 0;
+       }
+
+       rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE);
+       if (rc != 0)
+               return rc;
+
+       if (ssp->smk_labeled != SMACK_UNLABELED_SOCKET)
+               return smack_netlabel(sock->sk, SMACK_UNLABELED_SOCKET);
+       return 0;
 }
 
 /**
@@ -2101,8 +2227,14 @@ static int smack_setprocattr(struct task_struct *p, char *name,
        if (newsmack == NULL)
                return -EINVAL;
 
+       /*
+        * No process is ever allowed the web ("@") label.
+        */
+       if (newsmack == smack_known_web.smk_known)
+               return -EPERM;
+
        new = prepare_creds();
-       if (!new)
+       if (new == NULL)
                return -ENOMEM;
        new->security = newsmack;
        commit_creds(new);
@@ -2143,6 +2275,49 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other)
        return smk_access(smk_of_inode(sp), smk_of_inode(op), MAY_WRITE);
 }
 
+/**
+ * smack_socket_sendmsg - Smack check based on destination host
+ * @sock: the socket
+ * @msghdr: the message
+ * @size: the size of the message
+ *
+ * Return 0 if the current subject can write to the destination
+ * host. This is only a question if the destination is a single
+ * label host.
+ */
+static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
+                               int size)
+{
+       struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name;
+       struct socket_smack *ssp = sock->sk->sk_security;
+       char *hostsp;
+       int rc;
+
+       /*
+        * Perfectly reasonable for this to be NULL
+        */
+       if (sip == NULL || sip->sin_family != PF_INET)
+               return 0;
+
+       hostsp = smack_host_label(sip);
+       if (hostsp == NULL) {
+               if (ssp->smk_labeled != SMACK_CIPSO_SOCKET)
+                       return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
+               return 0;
+       }
+
+       rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE);
+       if (rc != 0)
+               return rc;
+
+       if (ssp->smk_labeled != SMACK_UNLABELED_SOCKET)
+               return smack_netlabel(sock->sk, SMACK_UNLABELED_SOCKET);
+
+       return 0;
+
+}
+
+
 /**
  * smack_from_secattr - Convert a netlabel attr.mls.lvl/attr.mls.cat
  *     pair to smack
@@ -2154,44 +2329,66 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other)
 static void smack_from_secattr(struct netlbl_lsm_secattr *sap, char *sip)
 {
        char smack[SMK_LABELLEN];
+       char *sp;
        int pcat;
 
-       if ((sap->flags & NETLBL_SECATTR_MLS_LVL) == 0) {
+       if ((sap->flags & NETLBL_SECATTR_MLS_LVL) != 0) {
                /*
+                * Looks like a CIPSO packet.
                 * If there are flags but no level netlabel isn't
                 * behaving the way we expect it to.
                 *
+                * Get the categories, if any
                 * Without guidance regarding the smack value
                 * for the packet fall back on the network
                 * ambient value.
                 */
-               strncpy(sip, smack_net_ambient, SMK_MAXLEN);
+               memset(smack, '\0', SMK_LABELLEN);
+               if ((sap->flags & NETLBL_SECATTR_MLS_CAT) != 0)
+                       for (pcat = -1;;) {
+                               pcat = netlbl_secattr_catmap_walk(
+                                       sap->attr.mls.cat, pcat + 1);
+                               if (pcat < 0)
+                                       break;
+                               smack_catset_bit(pcat, smack);
+                       }
+               /*
+                * If it is CIPSO using smack direct mapping
+                * we are already done. WeeHee.
+                */
+               if (sap->attr.mls.lvl == smack_cipso_direct) {
+                       memcpy(sip, smack, SMK_MAXLEN);
+                       return;
+               }
+               /*
+                * Look it up in the supplied table if it is not
+                * a direct mapping.
+                */
+               smack_from_cipso(sap->attr.mls.lvl, smack, sip);
                return;
        }
-       /*
-        * Get the categories, if any
-        */
-       memset(smack, '\0', SMK_LABELLEN);
-       if ((sap->flags & NETLBL_SECATTR_MLS_CAT) != 0)
-               for (pcat = -1;;) {
-                       pcat = netlbl_secattr_catmap_walk(sap->attr.mls.cat,
-                                                         pcat + 1);
-                       if (pcat < 0)
-                               break;
-                       smack_catset_bit(pcat, smack);
-               }
-       /*
-        * If it is CIPSO using smack direct mapping
-        * we are already done. WeeHee.
-        */
-       if (sap->attr.mls.lvl == smack_cipso_direct) {
-               memcpy(sip, smack, SMK_MAXLEN);
+       if ((sap->flags & NETLBL_SECATTR_SECID) != 0) {
+               /*
+                * Looks like a fallback, which gives us a secid.
+                */
+               sp = smack_from_secid(sap->attr.secid);
+               /*
+                * This has got to be a bug because it is
+                * impossible to specify a fallback without
+                * specifying the label, which will ensure
+                * it has a secid, and the only way to get a
+                * secid is from a fallback.
+                */
+               BUG_ON(sp == NULL);
+               strncpy(sip, sp, SMK_MAXLEN);
                return;
        }
        /*
-        * Look it up in the supplied table if it is not a direct mapping.
+        * Without guidance regarding the smack value
+        * for the packet fall back on the network
+        * ambient value.
         */
-       smack_from_cipso(sap->attr.mls.lvl, smack, sip);
+       strncpy(sip, smack_net_ambient, SMK_MAXLEN);
        return;
 }
 
@@ -2207,6 +2404,7 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
        struct netlbl_lsm_secattr secattr;
        struct socket_smack *ssp = sk->sk_security;
        char smack[SMK_LABELLEN];
+       char *csp;
        int rc;
 
        if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6)
@@ -2215,21 +2413,24 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
        /*
         * Translate what netlabel gave us.
         */
-       memset(smack, '\0', SMK_LABELLEN);
        netlbl_secattr_init(&secattr);
+
        rc = netlbl_skbuff_getattr(skb, sk->sk_family, &secattr);
-       if (rc == 0)
+       if (rc == 0) {
                smack_from_secattr(&secattr, smack);
-       else
-               strncpy(smack, smack_net_ambient, SMK_MAXLEN);
+               csp = smack;
+       } else
+               csp = smack_net_ambient;
+
        netlbl_secattr_destroy(&secattr);
+
        /*
         * Receiving a packet requires that the other end
         * be able to write here. Read access is not required.
         * This is the simplist possible security model
         * for networking.
         */
-       rc = smk_access(smack, ssp->smk_in, MAY_WRITE);
+       rc = smk_access(csp, ssp->smk_in, MAY_WRITE);
        if (rc != 0)
                netlbl_skbuff_err(skb, rc, 0);
        return rc;
@@ -2298,7 +2499,6 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
        /*
         * Translate what netlabel gave us.
         */
-       memset(smack, '\0', SMK_LABELLEN);
        netlbl_secattr_init(&secattr);
        rc = netlbl_skbuff_getattr(skb, family, &secattr);
        if (rc == 0)
@@ -2341,7 +2541,7 @@ static void smack_sock_graft(struct sock *sk, struct socket *parent)
        ssp->smk_in = ssp->smk_out = current_security();
        ssp->smk_packet[0] = '\0';
 
-       rc = smack_netlabel(sk);
+       rc = smack_netlabel(sk, SMACK_CIPSO_SOCKET);
        if (rc != 0)
                printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n",
                       __func__, -rc);
@@ -2367,7 +2567,6 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
        if (skb == NULL)
                return -EACCES;
 
-       memset(smack, '\0', SMK_LABELLEN);
        netlbl_secattr_init(&skb_secattr);
        rc = netlbl_skbuff_getattr(skb, sk->sk_family, &skb_secattr);
        if (rc == 0)
@@ -2732,6 +2931,8 @@ struct security_operations smack_ops = {
        .unix_may_send =                smack_unix_may_send,
 
        .socket_post_create =           smack_socket_post_create,
+       .socket_connect =               smack_socket_connect,
+       .socket_sendmsg =               smack_socket_sendmsg,
        .socket_sock_rcv_skb =          smack_socket_sock_rcv_skb,
        .socket_getpeersec_stream =     smack_socket_getpeersec_stream,
        .socket_getpeersec_dgram =      smack_socket_getpeersec_dgram,
@@ -2783,7 +2984,6 @@ static __init int smack_init(void)
        /*
         * Initialize locks
         */
-       spin_lock_init(&smack_known_unset.smk_cipsolock);
        spin_lock_init(&smack_known_huh.smk_cipsolock);
        spin_lock_init(&smack_known_hat.smk_cipsolock);
        spin_lock_init(&smack_known_star.smk_cipsolock);
index 247dc9e..bf107a3 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/vmalloc.h>
 #include <linux/security.h>
 #include <linux/mutex.h>
+#include <net/net_namespace.h>
 #include <net/netlabel.h>
 #include <net/cipso_ipv4.h>
 #include <linux/seq_file.h>
@@ -38,7 +39,7 @@ enum smk_inos {
        SMK_DOI         = 5,    /* CIPSO DOI */
        SMK_DIRECT      = 6,    /* CIPSO level indicating direct label */
        SMK_AMBIENT     = 7,    /* internet ambient label */
-       SMK_NLTYPE      = 8,    /* label scheme to use by default */
+       SMK_NETLBLADDR  = 8,    /* single label hosts */
        SMK_ONLYCAP     = 9,    /* the only "capable" label */
 };
 
@@ -48,6 +49,7 @@ enum smk_inos {
 static DEFINE_MUTEX(smack_list_lock);
 static DEFINE_MUTEX(smack_cipso_lock);
 static DEFINE_MUTEX(smack_ambient_lock);
+static DEFINE_MUTEX(smk_netlbladdr_lock);
 
 /*
  * This is the "ambient" label for network traffic.
@@ -56,12 +58,6 @@ static DEFINE_MUTEX(smack_ambient_lock);
  */
 char *smack_net_ambient = smack_known_floor.smk_known;
 
-/*
- * This is the default packet marking scheme for network traffic.
- * It can be reset via smackfs/nltype
- */
-int smack_net_nltype = NETLBL_NLTYPE_CIPSOV4;
-
 /*
  * This is the level in a CIPSO header that indicates a
  * smack label is contained directly in the category set.
@@ -79,6 +75,13 @@ int smack_cipso_direct = SMACK_CIPSO_DIRECT_DEFAULT;
  */
 char *smack_onlycap;
 
+/*
+ * Certain IP addresses may be designated as single label hosts.
+ * Packets are sent there unlabeled, but only from tasks that
+ * can write to the specified label.
+ */
+struct smk_netlbladdr *smack_netlbladdrs;
+
 static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
 struct smk_list_entry *smack_list;
 
@@ -104,6 +107,24 @@ struct smk_list_entry *smack_list;
 #define SMK_ACCESSLEN (sizeof(SMK_ACCESS) - 1)
 #define SMK_LOADLEN   (SMK_LABELLEN + SMK_LABELLEN + SMK_ACCESSLEN)
 
+/**
+ * smk_netlabel_audit_set - fill a netlbl_audit struct
+ * @nap: structure to fill
+ */
+static void smk_netlabel_audit_set(struct netlbl_audit *nap)
+{
+       nap->loginuid = audit_get_loginuid(current);
+       nap->sessionid = audit_get_sessionid(current);
+       nap->secid = smack_to_secid(current_security());
+}
+
+/*
+ * Values for parsing single label host rules
+ * "1.2.3.4 X"
+ * "192.168.138.129/32 abcdefghijklmnopqrstuvw"
+ */
+#define SMK_NETLBLADDRMIN      9
+#define SMK_NETLBLADDRMAX      42
 
 /*
  * Seq_file read operations for /smack/load
@@ -344,13 +365,11 @@ static void smk_cipso_doi(void)
 {
        int rc;
        struct cipso_v4_doi *doip;
-       struct netlbl_audit audit_info;
+       struct netlbl_audit nai;
 
-       audit_info.loginuid = audit_get_loginuid(current);
-       audit_info.sessionid = audit_get_sessionid(current);
-       audit_info.secid = smack_to_secid(current_security());
+       smk_netlabel_audit_set(&nai);
 
-       rc = netlbl_cfg_map_del(NULL, &audit_info);
+       rc = netlbl_cfg_map_del(NULL, PF_INET, NULL, NULL, &nai);
        if (rc != 0)
                printk(KERN_WARNING "%s:%d remove rc = %d\n",
                       __func__, __LINE__, rc);
@@ -365,11 +384,19 @@ static void smk_cipso_doi(void)
        for (rc = 1; rc < CIPSO_V4_TAG_MAXCNT; rc++)
                doip->tags[rc] = CIPSO_V4_TAG_INVALID;
 
-       rc = netlbl_cfg_cipsov4_add_map(doip, NULL, &audit_info);
+       rc = netlbl_cfg_cipsov4_add(doip, &nai);
        if (rc != 0) {
-               printk(KERN_WARNING "%s:%d add rc = %d\n",
+               printk(KERN_WARNING "%s:%d cipso add rc = %d\n",
                       __func__, __LINE__, rc);
                kfree(doip);
+               return;
+       }
+       rc = netlbl_cfg_cipsov4_map_add(doip->doi, NULL, NULL, NULL, &nai);
+       if (rc != 0) {
+               printk(KERN_WARNING "%s:%d map add rc = %d\n",
+                      __func__, __LINE__, rc);
+               kfree(doip);
+               return;
        }
 }
 
@@ -379,20 +406,19 @@ static void smk_cipso_doi(void)
 static void smk_unlbl_ambient(char *oldambient)
 {
        int rc;
-       struct netlbl_audit audit_info;
+       struct netlbl_audit nai;
 
-       audit_info.loginuid = audit_get_loginuid(current);
-       audit_info.sessionid = audit_get_sessionid(current);
-       audit_info.secid = smack_to_secid(current_security());
+       smk_netlabel_audit_set(&nai);
 
        if (oldambient != NULL) {
-               rc = netlbl_cfg_map_del(oldambient, &audit_info);
+               rc = netlbl_cfg_map_del(oldambient, PF_INET, NULL, NULL, &nai);
                if (rc != 0)
                        printk(KERN_WARNING "%s:%d remove rc = %d\n",
                               __func__, __LINE__, rc);
        }
 
-       rc = netlbl_cfg_unlbl_add_map(smack_net_ambient, &audit_info);
+       rc = netlbl_cfg_unlbl_map_add(smack_net_ambient, PF_INET,
+                                     NULL, NULL, &nai);
        if (rc != 0)
                printk(KERN_WARNING "%s:%d add rc = %d\n",
                       __func__, __LINE__, rc);
@@ -603,6 +629,201 @@ static const struct file_operations smk_cipso_ops = {
        .release        = seq_release,
 };
 
+/*
+ * Seq_file read operations for /smack/netlabel
+ */
+
+static void *netlbladdr_seq_start(struct seq_file *s, loff_t *pos)
+{
+       if (*pos == SEQ_READ_FINISHED)
+               return NULL;
+
+       return smack_netlbladdrs;
+}
+
+static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+       struct smk_netlbladdr *skp = ((struct smk_netlbladdr *) v)->smk_next;
+
+       if (skp == NULL)
+               *pos = SEQ_READ_FINISHED;
+
+       return skp;
+}
+/*
+#define BEMASK 0x80000000
+*/
+#define BEMASK 0x00000001
+#define BEBITS (sizeof(__be32) * 8)
+
+/*
+ * Print host/label pairs
+ */
+static int netlbladdr_seq_show(struct seq_file *s, void *v)
+{
+       struct smk_netlbladdr *skp = (struct smk_netlbladdr *) v;
+       unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr;
+       __be32 bebits;
+       int maskn = 0;
+
+       for (bebits = BEMASK; bebits != 0; maskn++, bebits <<= 1)
+               if ((skp->smk_mask.s_addr & bebits) == 0)
+                       break;
+
+       seq_printf(s, "%u.%u.%u.%u/%d %s\n",
+               hp[0], hp[1], hp[2], hp[3], maskn, skp->smk_label);
+
+       return 0;
+}
+
+static void netlbladdr_seq_stop(struct seq_file *s, void *v)
+{
+       /* No-op */
+}
+
+static struct seq_operations netlbladdr_seq_ops = {
+       .start = netlbladdr_seq_start,
+       .stop  = netlbladdr_seq_stop,
+       .next  = netlbladdr_seq_next,
+       .show  = netlbladdr_seq_show,
+};
+
+/**
+ * smk_open_netlbladdr - open() for /smack/netlabel
+ * @inode: inode structure representing file
+ * @file: "netlabel" file pointer
+ *
+ * Connect our netlbladdr_seq_* operations with /smack/netlabel
+ * file_operations
+ */
+static int smk_open_netlbladdr(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &netlbladdr_seq_ops);
+}
+
+/**
+ * smk_write_netlbladdr - write() for /smack/netlabel
+ * @filp: file pointer, not actually used
+ * @buf: where to get the data from
+ * @count: bytes sent
+ * @ppos: where to start
+ *
+ * Accepts only one netlbladdr per write call.
+ * Returns number of bytes written or error code, as appropriate
+ */
+static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
+                               size_t count, loff_t *ppos)
+{
+       struct smk_netlbladdr *skp;
+       struct sockaddr_in newname;
+       char smack[SMK_LABELLEN];
+       char *sp;
+       char data[SMK_NETLBLADDRMAX];
+       char *host = (char *)&newname.sin_addr.s_addr;
+       int rc;
+       struct netlbl_audit audit_info;
+       struct in_addr mask;
+       unsigned int m;
+       __be32 bebits = BEMASK;
+       __be32 nsa;
+
+       /*
+        * Must have privilege.
+        * No partial writes.
+        * Enough data must be present.
+        * "<addr/mask, as a.b.c.d/e><space><label>"
+        * "<addr, as a.b.c.d><space><label>"
+        */
+       if (!capable(CAP_MAC_ADMIN))
+               return -EPERM;
+       if (*ppos != 0)
+               return -EINVAL;
+       if (count < SMK_NETLBLADDRMIN || count > SMK_NETLBLADDRMAX)
+               return -EINVAL;
+       if (copy_from_user(data, buf, count) != 0)
+               return -EFAULT;
+
+       data[count] = '\0';
+
+       rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd/%d %s",
+               &host[0], &host[1], &host[2], &host[3], &m, smack);
+       if (rc != 6) {
+               rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd %s",
+                       &host[0], &host[1], &host[2], &host[3], smack);
+               if (rc != 5)
+                       return -EINVAL;
+               m = BEBITS;
+       }
+       if (m > BEBITS)
+               return -EINVAL;
+
+       sp = smk_import(smack, 0);
+       if (sp == NULL)
+               return -EINVAL;
+
+       for (mask.s_addr = 0; m > 0; m--) {
+               mask.s_addr |= bebits;
+               bebits <<= 1;
+       }
+       /*
+        * Only allow one writer at a time. Writes should be
+        * quite rare and small in any case.
+        */
+       mutex_lock(&smk_netlbladdr_lock);
+
+       nsa = newname.sin_addr.s_addr;
+       for (skp = smack_netlbladdrs; skp != NULL; skp = skp->smk_next)
+               if (skp->smk_host.sin_addr.s_addr == nsa &&
+                   skp->smk_mask.s_addr == mask.s_addr)
+                       break;
+
+       smk_netlabel_audit_set(&audit_info);
+
+       if (skp == NULL) {
+               skp = kzalloc(sizeof(*skp), GFP_KERNEL);
+               if (skp == NULL)
+                       rc = -ENOMEM;
+               else {
+                       rc = 0;
+                       skp->smk_host.sin_addr.s_addr = newname.sin_addr.s_addr;
+                       skp->smk_mask.s_addr = mask.s_addr;
+                       skp->smk_next = smack_netlbladdrs;
+                       skp->smk_label = sp;
+                       smack_netlbladdrs = skp;
+               }
+       } else {
+               rc = netlbl_cfg_unlbl_static_del(&init_net, NULL,
+                       &skp->smk_host.sin_addr, &skp->smk_mask,
+                       PF_INET, &audit_info);
+               skp->smk_label = sp;
+       }
+
+       /*
+        * Now tell netlabel about the single label nature of
+        * this host so that incoming packets get labeled.
+        */
+
+       if (rc == 0)
+               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);
+
+       if (rc == 0)
+               rc = count;
+
+       mutex_unlock(&smk_netlbladdr_lock);
+
+       return rc;
+}
+
+static const struct file_operations smk_netlbladdr_ops = {
+       .open           = smk_open_netlbladdr,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .write          = smk_write_netlbladdr,
+       .release        = seq_release,
+};
+
 /**
  * smk_read_doi - read() for /smack/doi
  * @filp: file pointer, not actually used
@@ -891,110 +1112,6 @@ static const struct file_operations smk_onlycap_ops = {
        .write          = smk_write_onlycap,
 };
 
-struct option_names {
-       int     o_number;
-       char    *o_name;
-       char    *o_alias;
-};
-
-static struct option_names netlbl_choices[] = {
-       { NETLBL_NLTYPE_RIPSO,
-               NETLBL_NLTYPE_RIPSO_NAME,       "ripso" },
-       { NETLBL_NLTYPE_CIPSOV4,
-               NETLBL_NLTYPE_CIPSOV4_NAME,     "cipsov4" },
-       { NETLBL_NLTYPE_CIPSOV4,
-               NETLBL_NLTYPE_CIPSOV4_NAME,     "cipso" },
-       { NETLBL_NLTYPE_CIPSOV6,
-               NETLBL_NLTYPE_CIPSOV6_NAME,     "cipsov6" },
-       { NETLBL_NLTYPE_UNLABELED,
-               NETLBL_NLTYPE_UNLABELED_NAME,   "unlabeled" },
-};
-
-/**
- * smk_read_nltype - read() for /smack/nltype
- * @filp: file pointer, not actually used
- * @buf: where to put the result
- * @count: maximum to send along
- * @ppos: where to start
- *
- * Returns number of bytes read or error code, as appropriate
- */
-static ssize_t smk_read_nltype(struct file *filp, char __user *buf,
-                              size_t count, loff_t *ppos)
-{
-       char bound[40];
-       ssize_t rc;
-       int i;
-
-       if (count < SMK_LABELLEN)
-               return -EINVAL;
-
-       if (*ppos != 0)
-               return 0;
-
-       sprintf(bound, "unknown");
-
-       for (i = 0; i < ARRAY_SIZE(netlbl_choices); i++)
-               if (smack_net_nltype == netlbl_choices[i].o_number) {
-                       sprintf(bound, "%s", netlbl_choices[i].o_name);
-                       break;
-               }
-
-       rc = simple_read_from_buffer(buf, count, ppos, bound, strlen(bound));
-
-       return rc;
-}
-
-/**
- * smk_write_nltype - write() for /smack/nltype
- * @filp: 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_nltype(struct file *file, const char __user *buf,
-                               size_t count, loff_t *ppos)
-{
-       char bound[40];
-       char *cp;
-       int i;
-
-       if (!capable(CAP_MAC_ADMIN))
-               return -EPERM;
-
-       if (count >= 40)
-               return -EINVAL;
-
-       if (copy_from_user(bound, buf, count) != 0)
-               return -EFAULT;
-
-       bound[count] = '\0';
-       cp = strchr(bound, ' ');
-       if (cp != NULL)
-               *cp = '\0';
-       cp = strchr(bound, '\n');
-       if (cp != NULL)
-               *cp = '\0';
-
-       for (i = 0; i < ARRAY_SIZE(netlbl_choices); i++)
-               if (strcmp(bound, netlbl_choices[i].o_name) == 0 ||
-                   strcmp(bound, netlbl_choices[i].o_alias) == 0) {
-                       smack_net_nltype = netlbl_choices[i].o_number;
-                       return count;
-               }
-       /*
-        * Not a valid choice.
-        */
-       return -EINVAL;
-}
-
-static const struct file_operations smk_nltype_ops = {
-       .read           = smk_read_nltype,
-       .write          = smk_write_nltype,
-};
-
 /**
  * smk_fill_super - fill the /smackfs superblock
  * @sb: the empty superblock
@@ -1021,8 +1138,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
                        {"direct", &smk_direct_ops, S_IRUGO|S_IWUSR},
                [SMK_AMBIENT]   =
                        {"ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR},
-               [SMK_NLTYPE]    =
-                       {"nltype", &smk_nltype_ops, S_IRUGO|S_IWUSR},
+               [SMK_NETLBLADDR] =
+                       {"netlabel", &smk_netlbladdr_ops, S_IRUGO|S_IWUSR},
                [SMK_ONLYCAP]   =
                        {"onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR},
                /* last one */ {""}