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)
1  2 
Documentation/feature-removal-schedule.txt
include/linux/security.h
kernel/capability.c
security/commoncap.c
security/security.c
security/selinux/selinuxfs.c
security/smack/smack_lsm.c

@@@ -310,8 -310,29 +310,20 @@@ Who:  Krzysztof Piotr Oledzki <ole@ans.
  
  ---------------------------
  
 -What: ide-scsi (BLK_DEV_IDESCSI)
 -When: 2.6.29
 -Why:  The 2.6 kernel supports direct writing to ide CD drives, which
 -      eliminates the need for ide-scsi. The new method is more
 -      efficient in every way.
 -Who:  FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
 -
 ----------------------------
 -
  What: i2c_attach_client(), i2c_detach_client(), i2c_driver->detach_client()
  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>
diff --combined include/linux/security.h
@@@ -48,7 -48,8 +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);
@@@ -335,37 -336,17 +336,37 @@@ static inline void security_free_mnt_op
   *    @dir contains the inode structure of the parent directory of the new link.
   *    @new_dentry contains the dentry structure for the new link.
   *    Return 0 if permission is granted.
 + * @path_link:
 + *    Check permission before creating a new hard link to a file.
 + *    @old_dentry contains the dentry structure for an existing link
 + *    to the file.
 + *    @new_dir contains the path structure of the parent directory of
 + *    the new link.
 + *    @new_dentry contains the dentry structure for the new link.
 + *    Return 0 if permission is granted.
   * @inode_unlink:
   *    Check the permission to remove a hard link to a file.
   *    @dir contains the inode structure of parent directory of the file.
   *    @dentry contains the dentry structure for file to be unlinked.
   *    Return 0 if permission is granted.
 + * @path_unlink:
 + *    Check the permission to remove a hard link to a file.
 + *    @dir contains the path structure of parent directory of the file.
 + *    @dentry contains the dentry structure for file to be unlinked.
 + *    Return 0 if permission is granted.
   * @inode_symlink:
   *    Check the permission to create a symbolic link to a file.
   *    @dir contains the inode structure of parent directory of the symbolic link.
   *    @dentry contains the dentry structure of the symbolic link.
   *    @old_name contains the pathname of file.
   *    Return 0 if permission is granted.
 + * @path_symlink:
 + *    Check the permission to create a symbolic link to a file.
 + *    @dir contains the path structure of parent directory of
 + *    the symbolic link.
 + *    @dentry contains the dentry structure of the symbolic link.
 + *    @old_name contains the pathname of file.
 + *    Return 0 if permission is granted.
   * @inode_mkdir:
   *    Check permissions to create a new directory in the existing directory
   *    associated with inode strcture @dir.
   *    @dentry contains the dentry structure of new directory.
   *    @mode contains the mode of new directory.
   *    Return 0 if permission is granted.
 + * @path_mkdir:
 + *    Check permissions to create a new directory in the existing directory
 + *    associated with path strcture @path.
 + *    @dir containst the path structure of parent of the directory
 + *    to be created.
 + *    @dentry contains the dentry structure of new directory.
 + *    @mode contains the mode of new directory.
 + *    Return 0 if permission is granted.
   * @inode_rmdir:
   *    Check the permission to remove a directory.
   *    @dir contains the inode structure of parent of the directory to be removed.
   *    @dentry contains the dentry structure of directory to be removed.
   *    Return 0 if permission is granted.
 + * @path_rmdir:
 + *    Check the permission to remove a directory.
 + *    @dir contains the path structure of parent of the directory to be
 + *    removed.
 + *    @dentry contains the dentry structure of directory to be removed.
 + *    Return 0 if permission is granted.
   * @inode_mknod:
   *    Check permissions when creating a special file (or a socket or a fifo
   *    file created via the mknod system call).  Note that if mknod operation
   *    @mode contains the mode of the new file.
   *    @dev contains the device number.
   *    Return 0 if permission is granted.
 + * @path_mknod:
 + *    Check permissions when creating a file. Note that this hook is called
 + *    even if mknod operation is being done for a regular file.
 + *    @dir contains the path structure of parent of the new file.
 + *    @dentry contains the dentry structure of the new file.
 + *    @mode contains the mode of the new file.
 + *    @dev contains the undecoded device number. Use new_decode_dev() to get
 + *    the decoded device number.
 + *    Return 0 if permission is granted.
   * @inode_rename:
   *    Check for permission to rename a file or directory.
   *    @old_dir contains the inode structure for parent of the old link.
   *    @new_dir contains the inode structure for parent of the new link.
   *    @new_dentry contains the dentry structure of the new link.
   *    Return 0 if permission is granted.
 + * @path_rename:
 + *    Check for permission to rename a file or directory.
 + *    @old_dir contains the path structure for parent of the old link.
 + *    @old_dentry contains the dentry structure of the old link.
 + *    @new_dir contains the path structure for parent of the new link.
 + *    @new_dentry contains the dentry structure of the new link.
 + *    Return 0 if permission is granted.
   * @inode_readlink:
   *    Check the permission to read the symbolic link.
   *    @dentry contains the dentry structure for the file link.
   *    @dentry contains the dentry structure for the file.
   *    @attr is the iattr structure containing the new file attributes.
   *    Return 0 if permission is granted.
 + * @path_truncate:
 + *    Check permission before truncating a file.
 + *    @path contains the path structure for the file.
 + *    @length is the new length of the file.
 + *    @time_attrs is the flags passed to do_truncate().
 + *    Return 0 if permission is granted.
   * @inode_getattr:
   *    Check permission before obtaining file attributes.
   *    @mnt is the vfsmount where the dentry was looked up
   *    @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 -1294,8 +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);
                                   struct super_block *newsb);
        int (*sb_parse_opts_str) (char *options, struct security_mnt_opts *opts);
  
 +#ifdef CONFIG_SECURITY_PATH
 +      int (*path_unlink) (struct path *dir, struct dentry *dentry);
 +      int (*path_mkdir) (struct path *dir, struct dentry *dentry, int mode);
 +      int (*path_rmdir) (struct path *dir, struct dentry *dentry);
 +      int (*path_mknod) (struct path *dir, struct dentry *dentry, int mode,
 +                         unsigned int dev);
 +      int (*path_truncate) (struct path *path, loff_t length,
 +                            unsigned int time_attrs);
 +      int (*path_symlink) (struct path *dir, struct dentry *dentry,
 +                           const char *old_name);
 +      int (*path_link) (struct dentry *old_dentry, struct path *new_dir,
 +                        struct dentry *new_dentry);
 +      int (*path_rename) (struct path *old_dir, struct dentry *old_dentry,
 +                          struct path *new_dir, struct dentry *new_dentry);
 +#endif
 +
        int (*inode_alloc_security) (struct inode *inode);
        void (*inode_free_security) (struct inode *inode);
        int (*inode_init_security) (struct inode *inode, struct inode *dir,
@@@ -1628,8 -1561,9 +1633,9 @@@ int security_capset(struct cred *new, c
                    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 -1760,31 +1832,31 @@@ static inline int security_capset(struc
        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)
@@@ -2777,71 -2728,6 +2800,71 @@@ static inline void security_skb_classif
  
  #endif        /* CONFIG_SECURITY_NETWORK_XFRM */
  
 +#ifdef CONFIG_SECURITY_PATH
 +int security_path_unlink(struct path *dir, struct dentry *dentry);
 +int security_path_mkdir(struct path *dir, struct dentry *dentry, int mode);
 +int security_path_rmdir(struct path *dir, struct dentry *dentry);
 +int security_path_mknod(struct path *dir, struct dentry *dentry, int mode,
 +                      unsigned int dev);
 +int security_path_truncate(struct path *path, loff_t length,
 +                         unsigned int time_attrs);
 +int security_path_symlink(struct path *dir, struct dentry *dentry,
 +                        const char *old_name);
 +int security_path_link(struct dentry *old_dentry, struct path *new_dir,
 +                     struct dentry *new_dentry);
 +int security_path_rename(struct path *old_dir, struct dentry *old_dentry,
 +                       struct path *new_dir, struct dentry *new_dentry);
 +#else /* CONFIG_SECURITY_PATH */
 +static inline int security_path_unlink(struct path *dir, struct dentry *dentry)
 +{
 +      return 0;
 +}
 +
 +static inline int security_path_mkdir(struct path *dir, struct dentry *dentry,
 +                                    int mode)
 +{
 +      return 0;
 +}
 +
 +static inline int security_path_rmdir(struct path *dir, struct dentry *dentry)
 +{
 +      return 0;
 +}
 +
 +static inline int security_path_mknod(struct path *dir, struct dentry *dentry,
 +                                    int mode, unsigned int dev)
 +{
 +      return 0;
 +}
 +
 +static inline int security_path_truncate(struct path *path, loff_t length,
 +                                       unsigned int time_attrs)
 +{
 +      return 0;
 +}
 +
 +static inline int security_path_symlink(struct path *dir, struct dentry *dentry,
 +                                      const char *old_name)
 +{
 +      return 0;
 +}
 +
 +static inline int security_path_link(struct dentry *old_dentry,
 +                                   struct path *new_dir,
 +                                   struct dentry *new_dentry)
 +{
 +      return 0;
 +}
 +
 +static inline int security_path_rename(struct path *old_dir,
 +                                     struct dentry *old_dentry,
 +                                     struct path *new_dir,
 +                                     struct dentry *new_dentry)
 +{
 +      return 0;
 +}
 +#endif        /* CONFIG_SECURITY_PATH */
 +
  #ifdef CONFIG_KEYS
  #ifdef CONFIG_SECURITY
  
diff --combined kernel/capability.c
@@@ -280,7 -280,9 +280,7 @@@ asmlinkage long sys_capset(cap_user_hea
        if (ret < 0)
                goto error;
  
 -      ret = audit_log_capset(pid, new, current_cred());
 -      if (ret < 0)
 -              return ret;
 +      audit_log_capset(pid, new, current_cred());
  
        return commit_creds(new);
  
@@@ -306,7 -308,7 +306,7 @@@ int capable(int cap
                BUG();
        }
  
-       if (has_capability(current, cap)) {
+       if (security_capable(cap) == 0) {
                current->flags |= PF_SUPERPRIV;
                return 1;
        }
diff --combined security/commoncap.c
@@@ -45,26 -45,22 +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 +156,8 @@@ static inline int cap_inh_is_capped(voi
        /* 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;
@@@ -238,7 -235,7 +235,7 @@@ int cap_inode_need_killpriv(struct dent
        struct inode *inode = dentry->d_inode;
        int error;
  
 -      if (!inode->i_op || !inode->i_op->getxattr)
 +      if (!inode->i_op->getxattr)
               return 0;
  
        error = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS, NULL, 0);
@@@ -259,7 -256,7 +256,7 @@@ int cap_inode_killpriv(struct dentry *d
  {
        struct inode *inode = dentry->d_inode;
  
 -      if (!inode->i_op || !inode->i_op->removexattr)
 +      if (!inode->i_op->removexattr)
               return 0;
  
        return inode->i_op->removexattr(dentry, XATTR_NAME_CAPS);
@@@ -317,7 -314,7 +314,7 @@@ int get_vfs_caps_from_disk(const struc
  
        memset(cpu_caps, 0, sizeof(struct cpu_vfs_cap_data));
  
 -      if (!inode || !inode->i_op || !inode->i_op->getxattr)
 +      if (!inode || !inode->i_op->getxattr)
                return -ENODATA;
  
        size = inode->i_op->getxattr((struct dentry *)dentry, XATTR_NAME_CAPS, &caps,
@@@ -869,7 -866,8 +866,8 @@@ int cap_task_prctl(int option, unsigne
                     & (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 +948,8 @@@ int cap_vm_enough_memory(struct mm_stru
  {
        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);
  }
diff --combined security/security.c
@@@ -154,14 -154,32 +154,32 @@@ int security_capset(struct cred *new, c
                                    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)
@@@ -355,72 -373,6 +373,72 @@@ int security_inode_init_security(struc
  }
  EXPORT_SYMBOL(security_inode_init_security);
  
 +#ifdef CONFIG_SECURITY_PATH
 +int security_path_mknod(struct path *path, struct dentry *dentry, int mode,
 +                      unsigned int dev)
 +{
 +      if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
 +              return 0;
 +      return security_ops->path_mknod(path, dentry, mode, dev);
 +}
 +EXPORT_SYMBOL(security_path_mknod);
 +
 +int security_path_mkdir(struct path *path, struct dentry *dentry, int mode)
 +{
 +      if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
 +              return 0;
 +      return security_ops->path_mkdir(path, dentry, mode);
 +}
 +
 +int security_path_rmdir(struct path *path, struct dentry *dentry)
 +{
 +      if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
 +              return 0;
 +      return security_ops->path_rmdir(path, dentry);
 +}
 +
 +int security_path_unlink(struct path *path, struct dentry *dentry)
 +{
 +      if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
 +              return 0;
 +      return security_ops->path_unlink(path, dentry);
 +}
 +
 +int security_path_symlink(struct path *path, struct dentry *dentry,
 +                        const char *old_name)
 +{
 +      if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
 +              return 0;
 +      return security_ops->path_symlink(path, dentry, old_name);
 +}
 +
 +int security_path_link(struct dentry *old_dentry, struct path *new_dir,
 +                     struct dentry *new_dentry)
 +{
 +      if (unlikely(IS_PRIVATE(old_dentry->d_inode)))
 +              return 0;
 +      return security_ops->path_link(old_dentry, new_dir, new_dentry);
 +}
 +
 +int security_path_rename(struct path *old_dir, struct dentry *old_dentry,
 +                       struct path *new_dir, struct dentry *new_dentry)
 +{
 +      if (unlikely(IS_PRIVATE(old_dentry->d_inode) ||
 +                   (new_dentry->d_inode && IS_PRIVATE(new_dentry->d_inode))))
 +              return 0;
 +      return security_ops->path_rename(old_dir, old_dentry, new_dir,
 +                                       new_dentry);
 +}
 +
 +int security_path_truncate(struct path *path, loff_t length,
 +                         unsigned int time_attrs)
 +{
 +      if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
 +              return 0;
 +      return security_ops->path_truncate(path, length, time_attrs);
 +}
 +#endif
 +
  int security_inode_create(struct inode *dir, struct dentry *dentry, int mode)
  {
        if (unlikely(IS_PRIVATE(dir)))
@@@ -47,13 -47,7 +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 +488,13 @@@ static ssize_t sel_write_compat_net(str
        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);
@@@ -847,6 -847,8 +847,6 @@@ static struct inode *sel_make_inode(str
  
        if (ret) {
                ret->i_mode = mode;
 -              ret->i_uid = ret->i_gid = 0;
 -              ret->i_blocks = 0;
                ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
        }
        return ret;
@@@ -1209,7 -1211,7 +1209,7 @@@ static struct avc_cache_stats *sel_avc_
  {
        int cpu;
  
 -      for (cpu = *idx; cpu < NR_CPUS; ++cpu) {
 +      for (cpu = *idx; cpu < nr_cpu_ids; ++cpu) {
                if (!cpu_possible(cpu))
                        continue;
                *idx = cpu + 1;
@@@ -1277,6 -1277,7 +1277,7 @@@ static int smack_sk_alloc_security(stru
  
        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 +1342,69 @@@ static void smack_to_secattr(char *smac
        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 +1457,7 @@@ static int smack_inode_setsecurity(stru
                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 +1487,108 @@@ static int smack_socket_post_create(str
        /*
         * 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 +2227,14 @@@ static int smack_setprocattr(struct tas
        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 +2275,49 @@@ static int smack_unix_may_send(struct s
        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
  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 +2404,7 @@@ static int smack_socket_sock_rcv_skb(st
        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)
        /*
         * 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 +2499,6 @@@ static int smack_socket_getpeersec_dgra
        /*
         * 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 +2541,7 @@@ static void smack_sock_graft(struct soc
        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 +2567,6 @@@ static int smack_inet_conn_request(stru
        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)
@@@ -2492,7 -2691,7 +2691,7 @@@ static int smack_audit_rule_init(u32 fi
        if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER)
                return -EINVAL;
  
 -      if (op != AUDIT_EQUAL && op != AUDIT_NOT_EQUAL)
 +      if (op != Audit_equal && op != Audit_not_equal)
                return -EINVAL;
  
        *rule = smk_import(rulestr, 0);
@@@ -2556,9 -2755,9 +2755,9 @@@ static int smack_audit_rule_match(u32 s
         * both pointers will point to the same smack_known
         * label.
         */
 -      if (op == AUDIT_EQUAL)
 +      if (op == Audit_equal)
                return (rule == smack);
 -      if (op == AUDIT_NOT_EQUAL)
 +      if (op == Audit_not_equal)
                return (rule != smack);
  
        return 0;
@@@ -2732,6 -2931,8 +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 +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);