Merge remote-tracking branch 'selinux/next'
authorStephen Rothwell <sfr@canb.auug.org.au>
Tue, 13 Sep 2016 01:37:45 +0000 (11:37 +1000)
committerStephen Rothwell <sfr@canb.auug.org.au>
Tue, 13 Sep 2016 01:37:45 +0000 (11:37 +1000)
1  2 
fs/overlayfs/copy_up.c
fs/overlayfs/dir.c
include/linux/lsm_hooks.h
include/linux/security.h

diff --combined fs/overlayfs/copy_up.c
index 43fdc2765aea65b85a20b0f28b844a3ba1b40d4e,cd65f12b3464d089327014e290f1e6ca0cf54021..db37a0e02d32b6e351a396e55f3ce9cb75e8b3a5
@@@ -80,8 -80,6 +80,8 @@@ int ovl_copy_xattr(struct dentry *old, 
        }
  
        for (name = buf; name < (buf + list_size); name += strlen(name) + 1) {
 +              if (ovl_is_private_xattr(name))
 +                      continue;
  retry:
                size = vfs_getxattr(old, name, value, value_size);
                if (size == -ERANGE)
                        goto retry;
                }
  
+               error = security_inode_copy_up_xattr(name);
+               if (error < 0 && error != -EOPNOTSUPP)
+                       break;
+               if (error == 1) {
+                       error = 0;
+                       continue; /* Discard */
+               }
                error = vfs_setxattr(new, name, value, size, 0);
                if (error)
                        break;
@@@ -248,6 -253,8 +255,8 @@@ static int ovl_copy_up_locked(struct de
        struct dentry *upper = NULL;
        umode_t mode = stat->mode;
        int err;
+       const struct cred *old_creds = NULL;
+       struct cred *new_creds = NULL;
  
        newdentry = ovl_lookup_temp(workdir, dentry);
        err = PTR_ERR(newdentry);
        if (IS_ERR(upper))
                goto out1;
  
+       err = security_inode_copy_up(dentry, &new_creds);
+       if (err < 0)
+               goto out2;
+       if (new_creds)
+               old_creds = override_creds(new_creds);
        /* Can't properly set mode on creation because of the umask */
        stat->mode &= S_IFMT;
        err = ovl_create_real(wdir, newdentry, stat, link, NULL, true);
        stat->mode = mode;
+       if (new_creds) {
+               revert_creds(old_creds);
+               put_cred(new_creds);
+       }
        if (err)
                goto out2;
  
diff --combined fs/overlayfs/dir.c
index 480fc7868a2f75398c04427a8571964210c749d9,a155e52db9fe90ef7d60465126af532991d7cefc..1bd188394a077d53b058993a5fc57cb113b2f8f3
@@@ -12,8 -12,6 +12,8 @@@
  #include <linux/xattr.h>
  #include <linux/security.h>
  #include <linux/cred.h>
 +#include <linux/posix_acl.h>
 +#include <linux/posix_acl_xattr.h>
  #include "overlayfs.h"
  
  void ovl_cleanup(struct inode *wdir, struct dentry *wdentry)
@@@ -188,9 -186,6 +188,9 @@@ static int ovl_create_upper(struct dent
        struct dentry *newdentry;
        int err;
  
 +      if (!hardlink && !IS_POSIXACL(udir))
 +              stat->mode &= ~current_umask();
 +
        inode_lock_nested(udir, I_MUTEX_PARENT);
        newdentry = lookup_one_len(dentry->d_name.name, upperdir,
                                   dentry->d_name.len);
@@@ -340,32 -335,6 +340,32 @@@ out_free
        return ret;
  }
  
 +static int ovl_set_upper_acl(struct dentry *upperdentry, const char *name,
 +                           const struct posix_acl *acl)
 +{
 +      void *buffer;
 +      size_t size;
 +      int err;
 +
 +      if (!IS_ENABLED(CONFIG_FS_POSIX_ACL) || !acl)
 +              return 0;
 +
 +      size = posix_acl_to_xattr(NULL, acl, NULL, 0);
 +      buffer = kmalloc(size, GFP_KERNEL);
 +      if (!buffer)
 +              return -ENOMEM;
 +
 +      size = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
 +      err = size;
 +      if (err < 0)
 +              goto out_free;
 +
 +      err = vfs_setxattr(upperdentry, name, buffer, size, XATTR_CREATE);
 +out_free:
 +      kfree(buffer);
 +      return err;
 +}
 +
  static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
                                    struct kstat *stat, const char *link,
                                    struct dentry *hardlink)
        struct dentry *upper;
        struct dentry *newdentry;
        int err;
 +      struct posix_acl *acl, *default_acl;
  
        if (WARN_ON(!workdir))
                return -EROFS;
  
 +      if (!hardlink) {
 +              err = posix_acl_create(dentry->d_parent->d_inode,
 +                                     &stat->mode, &default_acl, &acl);
 +              if (err)
 +                      return err;
 +      }
 +
        err = ovl_lock_rename_workdir(workdir, upperdir);
        if (err)
                goto out;
                if (err)
                        goto out_cleanup;
        }
 +      if (!hardlink) {
 +              err = ovl_set_upper_acl(newdentry, XATTR_NAME_POSIX_ACL_ACCESS,
 +                                      acl);
 +              if (err)
 +                      goto out_cleanup;
 +
 +              err = ovl_set_upper_acl(newdentry, XATTR_NAME_POSIX_ACL_DEFAULT,
 +                                      default_acl);
 +              if (err)
 +                      goto out_cleanup;
 +      }
  
        if (!hardlink && S_ISDIR(stat->mode)) {
                err = ovl_set_opaque(newdentry);
@@@ -460,10 -410,6 +460,10 @@@ out_dput
  out_unlock:
        unlock_rename(workdir, upperdir);
  out:
 +      if (!hardlink) {
 +              posix_acl_release(acl);
 +              posix_acl_release(default_acl);
 +      }
        return err;
  
  out_cleanup:
@@@ -489,6 -435,15 +489,15 @@@ static int ovl_create_or_link(struct de
        if (override_cred) {
                override_cred->fsuid = inode->i_uid;
                override_cred->fsgid = inode->i_gid;
+               if (!hardlink) {
+                       err = security_dentry_create_files_as(dentry,
+                                       stat->mode, &dentry->d_name, old_cred,
+                                       override_cred);
+                       if (err) {
+                               put_cred(override_cred);
+                               goto out_revert_creds;
+                       }
+               }
                put_cred(override_creds(override_cred));
                put_cred(override_cred);
  
                        err = ovl_create_over_whiteout(dentry, inode, stat,
                                                        link, hardlink);
        }
+ out_revert_creds:
        revert_creds(old_cred);
        if (!err) {
                struct inode *realinode = d_inode(ovl_dentry_upper(dentry));
@@@ -996,7 -952,7 +1006,7 @@@ const struct inode_operations ovl_dir_i
        .symlink        = ovl_symlink,
        .unlink         = ovl_unlink,
        .rmdir          = ovl_rmdir,
 -      .rename2        = ovl_rename2,
 +      .rename         = ovl_rename2,
        .link           = ovl_link,
        .setattr        = ovl_setattr,
        .create         = ovl_create,
        .permission     = ovl_permission,
        .getattr        = ovl_dir_getattr,
        .setxattr       = generic_setxattr,
 -      .getxattr       = ovl_getxattr,
 +      .getxattr       = generic_getxattr,
        .listxattr      = ovl_listxattr,
 -      .removexattr    = ovl_removexattr,
 +      .removexattr    = generic_removexattr,
        .get_acl        = ovl_get_acl,
        .update_time    = ovl_update_time,
  };
index dc56ae3a68cdda5669cb7ed342f7e62a875e000c,f2af2af131ac536ac6087d81dffc493bc4d49a82..558adfa5c8a87730f0d0177a1def7570e4883596
   *    @name name of the last path component used to create file
   *    @ctx pointer to place the pointer to the resulting context in.
   *    @ctxlen point to place the length of the resulting context.
+  * @dentry_create_files_as:
+  *    Compute a context for a dentry as the inode is not yet available
+  *    and set that context in passed in creds so that new files are
+  *    created using that context. Context is calculated using the
+  *    passed in creds and not the creds of the caller.
+  *    @dentry dentry to use in calculating the context.
+  *    @mode mode used to determine resource type.
+  *    @name name of the last path component used to create file
+  *    @old creds which should be used for context calculation
+  *    @new creds to modify
   *
   *
   * Security hooks for inode operations.
   *    @inode contains a pointer to the inode.
   *    @secid contains a pointer to the location where result will be saved.
   *    In case of failure, @secid will be set to zero.
+  * @inode_copy_up:
+  *    A file is about to be copied up from lower layer to upper layer of
+  *    overlay filesystem. Security module can prepare a set of new creds
+  *    and modify as need be and return new creds. Caller will switch to
+  *    new creds temporarily to create new file and release newly allocated
+  *    creds.
+  *    @src indicates the union dentry of file that is being copied up.
+  *    @new pointer to pointer to return newly allocated creds.
+  *    Returns 0 on success or a negative error code on error.
+  * @inode_copy_up_xattr:
+  *    Filter the xattrs being copied up when a unioned file is copied
+  *    up from a lower layer to the union/overlay layer.
+  *    @name indicates the name of the xattr.
+  *    Returns 0 to accept the xattr, 1 to discard the xattr, -EOPNOTSUPP if
+  *    security module does not know about attribute or a negative error code
+  *    to abort the copy up. Note that the caller is responsible for reading
+  *    and writing the xattrs as this hook is merely a filter.
   *
   * Security hooks for file operations
   *
@@@ -1358,6 -1385,10 +1385,10 @@@ union security_list_options 
        int (*dentry_init_security)(struct dentry *dentry, int mode,
                                        const struct qstr *name, void **ctx,
                                        u32 *ctxlen);
+       int (*dentry_create_files_as)(struct dentry *dentry, int mode,
+                                       struct qstr *name,
+                                       const struct cred *old,
+                                       struct cred *new);
  
  
  #ifdef CONFIG_SECURITY_PATH
        int (*inode_listsecurity)(struct inode *inode, char *buffer,
                                        size_t buffer_size);
        void (*inode_getsecid)(struct inode *inode, u32 *secid);
+       int (*inode_copy_up)(struct dentry *src, struct cred **new);
+       int (*inode_copy_up_xattr)(const char *name);
  
        int (*file_permission)(struct file *file, int mask);
        int (*file_alloc_security)(struct file *file);
        int (*kernel_act_as)(struct cred *new, u32 secid);
        int (*kernel_create_files_as)(struct cred *new, struct inode *inode);
        int (*kernel_module_request)(char *kmod_name);
 -      int (*kernel_module_from_file)(struct file *file);
        int (*kernel_read_file)(struct file *file, enum kernel_read_file_id id);
        int (*kernel_post_read_file)(struct file *file, char *buf, loff_t size,
                                     enum kernel_read_file_id id);
@@@ -1655,6 -1689,7 +1688,7 @@@ struct security_hook_heads 
        struct list_head sb_clone_mnt_opts;
        struct list_head sb_parse_opts_str;
        struct list_head dentry_init_security;
+       struct list_head dentry_create_files_as;
  #ifdef CONFIG_SECURITY_PATH
        struct list_head path_unlink;
        struct list_head path_mkdir;
        struct list_head inode_setsecurity;
        struct list_head inode_listsecurity;
        struct list_head inode_getsecid;
+       struct list_head inode_copy_up;
+       struct list_head inode_copy_up_xattr;
        struct list_head file_permission;
        struct list_head file_alloc_security;
        struct list_head file_free_security;
diff --combined include/linux/security.h
index 4c7412943b8114632d41994497a2aae7f2638293,a6c6d5d0fa5d6f903bc907a1b8ab64e0fd02337d..c2125e9093e8e51b51662ba8ce4a5faa767710b6
@@@ -242,6 -242,10 +242,10 @@@ int security_sb_parse_opts_str(char *op
  int security_dentry_init_security(struct dentry *dentry, int mode,
                                        const struct qstr *name, void **ctx,
                                        u32 *ctxlen);
+ int security_dentry_create_files_as(struct dentry *dentry, int mode,
+                                       struct qstr *name,
+                                       const struct cred *old,
+                                       struct cred *new);
  
  int security_inode_alloc(struct inode *inode);
  void security_inode_free(struct inode *inode);
@@@ -282,6 -286,8 +286,8 @@@ int security_inode_getsecurity(struct i
  int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags);
  int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size);
  void security_inode_getsecid(struct inode *inode, u32 *secid);
+ int security_inode_copy_up(struct dentry *src, struct cred **new);
+ int security_inode_copy_up_xattr(const char *name);
  int security_file_permission(struct file *file, int mask);
  int security_file_alloc(struct file *file);
  void security_file_free(struct file *file);
@@@ -307,6 -313,7 +313,6 @@@ void security_transfer_creds(struct cre
  int security_kernel_act_as(struct cred *new, u32 secid);
  int security_kernel_create_files_as(struct cred *new, struct inode *inode);
  int security_kernel_module_request(char *kmod_name);
 -int security_kernel_module_from_file(struct file *file);
  int security_kernel_read_file(struct file *file, enum kernel_read_file_id id);
  int security_kernel_post_read_file(struct file *file, char *buf, loff_t size,
                                   enum kernel_read_file_id id);
@@@ -597,6 -604,14 +603,14 @@@ static inline int security_dentry_init_
        return -EOPNOTSUPP;
  }
  
+ static inline int security_dentry_create_files_as(struct dentry *dentry,
+                                                 int mode, struct qstr *name,
+                                                 const struct cred *old,
+                                                 struct cred *new)
+ {
+       return 0;
+ }
  
  static inline int security_inode_init_security(struct inode *inode,
                                                struct inode *dir,
@@@ -757,6 -772,16 +771,16 @@@ static inline void security_inode_getse
        *secid = 0;
  }
  
+ static inline int security_inode_copy_up(struct dentry *src, struct cred **new)
+ {
+       return 0;
+ }
+ static inline int security_inode_copy_up_xattr(const char *name)
+ {
+       return -EOPNOTSUPP;
+ }
  static inline int security_file_permission(struct file *file, int mask)
  {
        return 0;
This page took 0.038014 seconds and 5 git commands to generate.