Merge tag 'for-linus-5.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml
[linux-2.6-microblaze.git] / fs / overlayfs / namei.c
index f7d4358..3fe05fb 100644 (file)
@@ -30,8 +30,9 @@ static int ovl_check_redirect(struct dentry *dentry, struct ovl_lookup_data *d,
 {
        int res;
        char *buf;
+       struct ovl_fs *ofs = OVL_FS(d->sb);
 
-       buf = ovl_get_redirect_xattr(dentry, prelen + strlen(post));
+       buf = ovl_get_redirect_xattr(ofs, dentry, prelen + strlen(post));
        if (IS_ERR_OR_NULL(buf))
                return PTR_ERR(buf);
 
@@ -104,12 +105,13 @@ int ovl_check_fb_len(struct ovl_fb *fb, int fb_len)
        return 0;
 }
 
-static struct ovl_fh *ovl_get_fh(struct dentry *dentry, const char *name)
+static struct ovl_fh *ovl_get_fh(struct ovl_fs *ofs, struct dentry *dentry,
+                                enum ovl_xattr ox)
 {
        int res, err;
        struct ovl_fh *fh = NULL;
 
-       res = vfs_getxattr(dentry, name, NULL, 0);
+       res = ovl_do_getxattr(ofs, dentry, ox, NULL, 0);
        if (res < 0) {
                if (res == -ENODATA || res == -EOPNOTSUPP)
                        return NULL;
@@ -123,7 +125,7 @@ static struct ovl_fh *ovl_get_fh(struct dentry *dentry, const char *name)
        if (!fh)
                return ERR_PTR(-ENOMEM);
 
-       res = vfs_getxattr(dentry, name, fh->buf, res);
+       res = ovl_do_getxattr(ofs, dentry, ox, fh->buf, res);
        if (res < 0)
                goto fail;
 
@@ -148,17 +150,22 @@ invalid:
        goto out;
 }
 
-struct dentry *ovl_decode_real_fh(struct ovl_fh *fh, struct vfsmount *mnt,
-                                 bool connected)
+struct dentry *ovl_decode_real_fh(struct ovl_fs *ofs, struct ovl_fh *fh,
+                                 struct vfsmount *mnt, bool connected)
 {
        struct dentry *real;
        int bytes;
 
+       if (!capable(CAP_DAC_READ_SEARCH))
+               return NULL;
+
        /*
         * Make sure that the stored uuid matches the uuid of the lower
         * layer where file handle will be decoded.
+        * In case of uuid=off option just make sure that stored uuid is null.
         */
-       if (!uuid_equal(&fh->fb.uuid, &mnt->mnt_sb->s_uuid))
+       if (ofs->config.uuid ? !uuid_equal(&fh->fb.uuid, &mnt->mnt_sb->s_uuid) :
+                             !uuid_is_null(&fh->fb.uuid))
                return NULL;
 
        bytes = (fh->fb.len - offsetof(struct ovl_fb, fid));
@@ -186,9 +193,9 @@ struct dentry *ovl_decode_real_fh(struct ovl_fh *fh, struct vfsmount *mnt,
        return real;
 }
 
-static bool ovl_is_opaquedir(struct dentry *dentry)
+static bool ovl_is_opaquedir(struct super_block *sb, struct dentry *dentry)
 {
-       return ovl_check_dir_xattr(dentry, OVL_XATTR_OPAQUE);
+       return ovl_check_dir_xattr(sb, dentry, OVL_XATTR_OPAQUE);
 }
 
 static struct dentry *ovl_lookup_positive_unlocked(const char *name,
@@ -251,7 +258,7 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
                        d->stop = true;
                        goto put_and_out;
                }
-               err = ovl_check_metacopy_xattr(this);
+               err = ovl_check_metacopy_xattr(OVL_FS(d->sb), this);
                if (err < 0)
                        goto out_err;
 
@@ -271,7 +278,7 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
                if (d->last)
                        goto out;
 
-               if (ovl_is_opaquedir(this)) {
+               if (ovl_is_opaquedir(d->sb, this)) {
                        d->stop = true;
                        if (last_element)
                                d->opaque = true;
@@ -352,7 +359,7 @@ int ovl_check_origin_fh(struct ovl_fs *ofs, struct ovl_fh *fh, bool connected,
                    ofs->layers[i].fs->bad_uuid)
                        continue;
 
-               origin = ovl_decode_real_fh(fh, ofs->layers[i].mnt,
+               origin = ovl_decode_real_fh(ofs, fh, ofs->layers[i].mnt,
                                            connected);
                if (origin)
                        break;
@@ -391,7 +398,7 @@ invalid:
 static int ovl_check_origin(struct ovl_fs *ofs, struct dentry *upperdentry,
                            struct ovl_path **stackp)
 {
-       struct ovl_fh *fh = ovl_get_fh(upperdentry, OVL_XATTR_ORIGIN);
+       struct ovl_fh *fh = ovl_get_fh(ofs, upperdentry, OVL_XATTR_ORIGIN);
        int err;
 
        if (IS_ERR_OR_NULL(fh))
@@ -413,10 +420,10 @@ static int ovl_check_origin(struct ovl_fs *ofs, struct dentry *upperdentry,
  * Verify that @fh matches the file handle stored in xattr @name.
  * Return 0 on match, -ESTALE on mismatch, < 0 on error.
  */
-static int ovl_verify_fh(struct dentry *dentry, const char *name,
-                        const struct ovl_fh *fh)
+static int ovl_verify_fh(struct ovl_fs *ofs, struct dentry *dentry,
+                        enum ovl_xattr ox, const struct ovl_fh *fh)
 {
-       struct ovl_fh *ofh = ovl_get_fh(dentry, name);
+       struct ovl_fh *ofh = ovl_get_fh(ofs, dentry, ox);
        int err = 0;
 
        if (!ofh)
@@ -440,23 +447,24 @@ static int ovl_verify_fh(struct dentry *dentry, const char *name,
  *
  * Return 0 on match, -ESTALE on mismatch, -ENODATA on no xattr, < 0 on error.
  */
-int ovl_verify_set_fh(struct dentry *dentry, const char *name,
-                     struct dentry *real, bool is_upper, bool set)
+int ovl_verify_set_fh(struct ovl_fs *ofs, struct dentry *dentry,
+                     enum ovl_xattr ox, struct dentry *real, bool is_upper,
+                     bool set)
 {
        struct inode *inode;
        struct ovl_fh *fh;
        int err;
 
-       fh = ovl_encode_real_fh(real, is_upper);
+       fh = ovl_encode_real_fh(ofs, real, is_upper);
        err = PTR_ERR(fh);
        if (IS_ERR(fh)) {
                fh = NULL;
                goto fail;
        }
 
-       err = ovl_verify_fh(dentry, name, fh);
+       err = ovl_verify_fh(ofs, dentry, ox, fh);
        if (set && err == -ENODATA)
-               err = ovl_do_setxattr(dentry, name, fh->buf, fh->fb.len, 0);
+               err = ovl_do_setxattr(ofs, dentry, ox, fh->buf, fh->fb.len);
        if (err)
                goto fail;
 
@@ -481,11 +489,11 @@ struct dentry *ovl_index_upper(struct ovl_fs *ofs, struct dentry *index)
        if (!d_is_dir(index))
                return dget(index);
 
-       fh = ovl_get_fh(index, OVL_XATTR_UPPER);
+       fh = ovl_get_fh(ofs, index, OVL_XATTR_UPPER);
        if (IS_ERR_OR_NULL(fh))
                return ERR_CAST(fh);
 
-       upper = ovl_decode_real_fh(fh, ovl_upper_mnt(ofs), true);
+       upper = ovl_decode_real_fh(ofs, fh, ovl_upper_mnt(ofs), true);
        kfree(fh);
 
        if (IS_ERR_OR_NULL(upper))
@@ -574,7 +582,7 @@ int ovl_verify_index(struct ovl_fs *ofs, struct dentry *index)
                goto fail;
        }
 
-       err = ovl_verify_fh(upper, OVL_XATTR_ORIGIN, fh);
+       err = ovl_verify_fh(ofs, upper, OVL_XATTR_ORIGIN, fh);
        dput(upper);
        if (err)
                goto fail;
@@ -585,7 +593,7 @@ int ovl_verify_index(struct ovl_fs *ofs, struct dentry *index)
                if (err)
                        goto fail;
 
-               if (ovl_get_nlink(origin.dentry, index, 0) == 0)
+               if (ovl_get_nlink(ofs, origin.dentry, index, 0) == 0)
                        goto orphan;
        }
 
@@ -637,12 +645,13 @@ static int ovl_get_index_name_fh(struct ovl_fh *fh, struct qstr *name)
  * index dir was cleared. Either way, that index cannot be used to indentify
  * the overlay inode.
  */
-int ovl_get_index_name(struct dentry *origin, struct qstr *name)
+int ovl_get_index_name(struct ovl_fs *ofs, struct dentry *origin,
+                      struct qstr *name)
 {
        struct ovl_fh *fh;
        int err;
 
-       fh = ovl_encode_real_fh(origin, false);
+       fh = ovl_encode_real_fh(ofs, origin, false);
        if (IS_ERR(fh))
                return PTR_ERR(fh);
 
@@ -691,7 +700,7 @@ struct dentry *ovl_lookup_index(struct ovl_fs *ofs, struct dentry *upper,
        bool is_dir = d_is_dir(origin);
        int err;
 
-       err = ovl_get_index_name(origin, &name);
+       err = ovl_get_index_name(ofs, origin, &name);
        if (err)
                return ERR_PTR(err);
 
@@ -741,7 +750,7 @@ struct dentry *ovl_lookup_index(struct ovl_fs *ofs, struct dentry *upper,
                }
 
                /* Verify that dir index 'upper' xattr points to upper dir */
-               err = ovl_verify_upper(index, upper, false);
+               err = ovl_verify_upper(ofs, index, upper, false);
                if (err) {
                        if (err == -ESTALE) {
                                pr_warn_ratelimited("suspected multiply redirected dir found (upper=%pd2, origin=%pd2, index=%pd2).\n",
@@ -790,19 +799,19 @@ int ovl_path_next(int idx, struct dentry *dentry, struct path *path)
 }
 
 /* Fix missing 'origin' xattr */
-static int ovl_fix_origin(struct dentry *dentry, struct dentry *lower,
-                         struct dentry *upper)
+static int ovl_fix_origin(struct ovl_fs *ofs, struct dentry *dentry,
+                         struct dentry *lower, struct dentry *upper)
 {
        int err;
 
-       if (ovl_check_origin_xattr(upper))
+       if (ovl_check_origin_xattr(ofs, upper))
                return 0;
 
        err = ovl_want_write(dentry);
        if (err)
                return err;
 
-       err = ovl_set_origin(dentry, lower, upper);
+       err = ovl_set_origin(ofs, dentry, lower, upper);
        if (!err)
                err = ovl_set_impure(dentry->d_parent, upper->d_parent);
 
@@ -920,7 +929,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
                 * of lower dir and set upper parent "impure".
                 */
                if (upperdentry && !ctr && !ofs->noxattr && d.is_dir) {
-                       err = ovl_fix_origin(dentry, this, upperdentry);
+                       err = ovl_fix_origin(ofs, dentry, this, upperdentry);
                        if (err) {
                                dput(this);
                                goto out_put;
@@ -939,7 +948,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
                if (upperdentry && !ctr &&
                    ((d.is_dir && ovl_verify_lower(dentry->d_sb)) ||
                     (!d.is_dir && ofs->config.index && origin_path))) {
-                       err = ovl_verify_origin(upperdentry, this, false);
+                       err = ovl_verify_origin(ofs, upperdentry, this, false);
                        if (err) {
                                dput(this);
                                if (d.is_dir)
@@ -1000,6 +1009,8 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
         * Just make sure a corresponding data dentry has been found.
         */
        if (d.metacopy || (uppermetacopy && !ctr)) {
+               pr_warn_ratelimited("metacopy with no lower data found - abort lookup (%pd2)\n",
+                                   dentry);
                err = -EIO;
                goto out_put;
        } else if (!d.is_dir && upperdentry && !ctr && origin_path) {
@@ -1060,13 +1071,13 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
                ovl_dentry_set_upper_alias(dentry);
        else if (index) {
                upperdentry = dget(index);
-               upperredirect = ovl_get_redirect_xattr(upperdentry, 0);
+               upperredirect = ovl_get_redirect_xattr(ofs, upperdentry, 0);
                if (IS_ERR(upperredirect)) {
                        err = PTR_ERR(upperredirect);
                        upperredirect = NULL;
                        goto out_free_oe;
                }
-               err = ovl_check_metacopy_xattr(upperdentry);
+               err = ovl_check_metacopy_xattr(ofs, upperdentry);
                if (err < 0)
                        goto out_free_oe;
                uppermetacopy = err;