Merge remote-tracking branch 'userns/for-next'
authorStephen Rothwell <sfr@canb.auug.org.au>
Thu, 5 Nov 2015 04:19:47 +0000 (15:19 +1100)
committerStephen Rothwell <sfr@canb.auug.org.au>
Thu, 5 Nov 2015 04:19:47 +0000 (15:19 +1100)
1  2 
fs/namei.c

diff --combined fs/namei.c
@@@ -955,26 -955,23 +955,23 @@@ static bool safe_hardlink_source(struc
   *  - sysctl_protected_hardlinks enabled
   *  - fsuid does not match inode
   *  - hardlink source is unsafe (see safe_hardlink_source() above)
-  *  - not CAP_FOWNER
+  *  - not CAP_FOWNER in a namespace with the inode owner uid mapped
   *
   * Returns 0 if successful, -ve on error.
   */
  static int may_linkat(struct path *link)
  {
-       const struct cred *cred;
        struct inode *inode;
  
        if (!sysctl_protected_hardlinks)
                return 0;
  
-       cred = current_cred();
        inode = link->dentry->d_inode;
  
        /* Source inode owner (or CAP_FOWNER) can hardlink all they like,
         * otherwise, it must be a safe source.
         */
-       if (uid_eq(cred->fsuid, inode->i_uid) || safe_hardlink_source(inode) ||
-           capable(CAP_FOWNER))
+       if (inode_owner_or_capable(inode) || safe_hardlink_source(inode))
                return 0;
  
        audit_log_link_denied("linkat", link);
@@@ -1558,6 -1555,8 +1555,6 @@@ static int lookup_fast(struct nameidat
                negative = d_is_negative(dentry);
                if (read_seqcount_retry(&dentry->d_seq, seq))
                        return -ECHILD;
 -              if (negative)
 -                      return -ENOENT;
  
                /*
                 * This sequence count validates that the parent had no
                                goto unlazy;
                        }
                }
 +              /*
 +               * Note: do negative dentry check after revalidation in
 +               * case that drops it.
 +               */
 +              if (negative)
 +                      return -ENOENT;
                path->mnt = mnt;
                path->dentry = dentry;
                if (likely(__follow_mount_rcu(nd, path, inode, seqp)))
@@@ -1969,7 -1962,7 +1966,7 @@@ OK
                if (err) {
                        const char *s = get_link(nd);
  
 -                      if (unlikely(IS_ERR(s)))
 +                      if (IS_ERR(s))
                                return PTR_ERR(s);
                        err = 0;
                        if (unlikely(!s)) {
@@@ -2282,8 -2275,6 +2279,8 @@@ EXPORT_SYMBOL(vfs_path_lookup)
   *
   * Note that this routine is purely a helper for filesystem usage and should
   * not be called by generic code.
 + *
 + * The caller must hold base->i_mutex.
   */
  struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
  {
  }
  EXPORT_SYMBOL(lookup_one_len);
  
 +/**
 + * lookup_one_len_unlocked - filesystem helper to lookup single pathname component
 + * @name:     pathname component to lookup
 + * @base:     base directory to lookup from
 + * @len:      maximum length @len should be interpreted to
 + *
 + * Note that this routine is purely a helper for filesystem usage and should
 + * not be called by generic code.
 + *
 + * Unlike lookup_one_len, it should be called without the parent
 + * i_mutex held, and will take the i_mutex itself if necessary.
 + */
 +struct dentry *lookup_one_len_unlocked(const char *name,
 +                                     struct dentry *base, int len)
 +{
 +      struct qstr this;
 +      unsigned int c;
 +      int err;
 +      struct dentry *ret;
 +
 +      this.name = name;
 +      this.len = len;
 +      this.hash = full_name_hash(name, len);
 +      if (!len)
 +              return ERR_PTR(-EACCES);
 +
 +      if (unlikely(name[0] == '.')) {
 +              if (len < 2 || (len == 2 && name[1] == '.'))
 +                      return ERR_PTR(-EACCES);
 +      }
 +
 +      while (len--) {
 +              c = *(const unsigned char *)name++;
 +              if (c == '/' || c == '\0')
 +                      return ERR_PTR(-EACCES);
 +      }
 +      /*
 +       * See if the low-level filesystem might want
 +       * to use its own hash..
 +       */
 +      if (base->d_flags & DCACHE_OP_HASH) {
 +              int err = base->d_op->d_hash(base, &this);
 +              if (err < 0)
 +                      return ERR_PTR(err);
 +      }
 +
 +      err = inode_permission(base->d_inode, MAY_EXEC);
 +      if (err)
 +              return ERR_PTR(err);
 +
 +      ret = __d_lookup(base, &this);
 +      if (ret)
 +              return ret;
 +      /*
 +       * __d_lookup() is used to try to get a quick answer and avoid the
 +       * mutex.  A false-negative does no harm.
 +       */
 +      ret = __d_lookup(base, &this);
 +      if (ret && ret->d_flags & DCACHE_OP_REVALIDATE) {
 +              dput(ret);
 +              ret = NULL;
 +      }
 +      if (ret)
 +              return ret;
 +
 +      mutex_lock(&base->d_inode->i_mutex);
 +      ret =  __lookup_hash(&this, base, 0);
 +      mutex_unlock(&base->d_inode->i_mutex);
 +      return ret;
 +}
 +EXPORT_SYMBOL(lookup_one_len_unlocked);
 +
  int user_path_at_empty(int dfd, const char __user *name, unsigned flags,
                 struct path *path, int *empty)
  {
@@@ -3457,7 -3376,7 +3454,7 @@@ struct file *do_file_open_root(struct d
                return ERR_PTR(-ELOOP);
  
        filename = getname_kernel(name);
 -      if (unlikely(IS_ERR(filename)))
 +      if (IS_ERR(filename))
                return ERR_CAST(filename);
  
        set_nameidata(&nd, -1, filename);