ovl: do not get metacopy for userxattr
[linux-2.6-microblaze.git] / fs / overlayfs / util.c
index 7d86dba..6569031 100644 (file)
@@ -50,6 +50,9 @@ const struct cred *ovl_override_creds(struct super_block *sb)
  */
 int ovl_can_decode_fh(struct super_block *sb)
 {
+       if (!capable(CAP_DAC_READ_SEARCH))
+               return 0;
+
        if (!sb->s_export_op || !sb->s_export_op->fh_to_dentry)
                return 0;
 
@@ -544,11 +547,11 @@ void ovl_copy_up_end(struct dentry *dentry)
        ovl_inode_unlock(d_inode(dentry));
 }
 
-bool ovl_check_origin_xattr(struct dentry *dentry)
+bool ovl_check_origin_xattr(struct ovl_fs *ofs, struct dentry *dentry)
 {
        int res;
 
-       res = ovl_do_getxattr(dentry, OVL_XATTR_ORIGIN, NULL, 0);
+       res = ovl_do_getxattr(ofs, dentry, OVL_XATTR_ORIGIN, NULL, 0);
 
        /* Zero size value means "copied up but origin unknown" */
        if (res >= 0)
@@ -557,7 +560,8 @@ bool ovl_check_origin_xattr(struct dentry *dentry)
        return false;
 }
 
-bool ovl_check_dir_xattr(struct dentry *dentry, const char *name)
+bool ovl_check_dir_xattr(struct super_block *sb, struct dentry *dentry,
+                        enum ovl_xattr ox)
 {
        int res;
        char val;
@@ -565,15 +569,37 @@ bool ovl_check_dir_xattr(struct dentry *dentry, const char *name)
        if (!d_is_dir(dentry))
                return false;
 
-       res = ovl_do_getxattr(dentry, name, &val, 1);
+       res = ovl_do_getxattr(OVL_FS(sb), dentry, ox, &val, 1);
        if (res == 1 && val == 'y')
                return true;
 
        return false;
 }
 
+#define OVL_XATTR_OPAQUE_POSTFIX       "opaque"
+#define OVL_XATTR_REDIRECT_POSTFIX     "redirect"
+#define OVL_XATTR_ORIGIN_POSTFIX       "origin"
+#define OVL_XATTR_IMPURE_POSTFIX       "impure"
+#define OVL_XATTR_NLINK_POSTFIX                "nlink"
+#define OVL_XATTR_UPPER_POSTFIX                "upper"
+#define OVL_XATTR_METACOPY_POSTFIX     "metacopy"
+
+#define OVL_XATTR_TAB_ENTRY(x) \
+       [x] = { [false] = OVL_XATTR_TRUSTED_PREFIX x ## _POSTFIX, \
+               [true] = OVL_XATTR_USER_PREFIX x ## _POSTFIX }
+
+const char *const ovl_xattr_table[][2] = {
+       OVL_XATTR_TAB_ENTRY(OVL_XATTR_OPAQUE),
+       OVL_XATTR_TAB_ENTRY(OVL_XATTR_REDIRECT),
+       OVL_XATTR_TAB_ENTRY(OVL_XATTR_ORIGIN),
+       OVL_XATTR_TAB_ENTRY(OVL_XATTR_IMPURE),
+       OVL_XATTR_TAB_ENTRY(OVL_XATTR_NLINK),
+       OVL_XATTR_TAB_ENTRY(OVL_XATTR_UPPER),
+       OVL_XATTR_TAB_ENTRY(OVL_XATTR_METACOPY),
+};
+
 int ovl_check_setxattr(struct dentry *dentry, struct dentry *upperdentry,
-                      const char *name, const void *value, size_t size,
+                      enum ovl_xattr ox, const void *value, size_t size,
                       int xerr)
 {
        int err;
@@ -582,10 +608,10 @@ int ovl_check_setxattr(struct dentry *dentry, struct dentry *upperdentry,
        if (ofs->noxattr)
                return xerr;
 
-       err = ovl_do_setxattr(upperdentry, name, value, size);
+       err = ovl_do_setxattr(ofs, upperdentry, ox, value, size);
 
        if (err == -EOPNOTSUPP) {
-               pr_warn("cannot set %s xattr on upper\n", name);
+               pr_warn("cannot set %s xattr on upper\n", ovl_xattr(ofs, ox));
                ofs->noxattr = true;
                return xerr;
        }
@@ -694,6 +720,7 @@ bool ovl_need_index(struct dentry *dentry)
 /* Caller must hold OVL_I(inode)->lock */
 static void ovl_cleanup_index(struct dentry *dentry)
 {
+       struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
        struct dentry *indexdir = ovl_indexdir(dentry->d_sb);
        struct inode *dir = indexdir->d_inode;
        struct dentry *lowerdentry = ovl_dentry_lower(dentry);
@@ -703,7 +730,7 @@ static void ovl_cleanup_index(struct dentry *dentry)
        struct qstr name = { };
        int err;
 
-       err = ovl_get_index_name(lowerdentry, &name);
+       err = ovl_get_index_name(ofs, lowerdentry, &name);
        if (err)
                goto fail;
 
@@ -845,7 +872,7 @@ err:
 }
 
 /* err < 0, 0 if no metacopy xattr, 1 if metacopy xattr found */
-int ovl_check_metacopy_xattr(struct dentry *dentry)
+int ovl_check_metacopy_xattr(struct ovl_fs *ofs, struct dentry *dentry)
 {
        int res;
 
@@ -853,10 +880,17 @@ int ovl_check_metacopy_xattr(struct dentry *dentry)
        if (!S_ISREG(d_inode(dentry)->i_mode))
                return 0;
 
-       res = ovl_do_getxattr(dentry, OVL_XATTR_METACOPY, NULL, 0);
+       res = ovl_do_getxattr(ofs, dentry, OVL_XATTR_METACOPY, NULL, 0);
        if (res < 0) {
                if (res == -ENODATA || res == -EOPNOTSUPP)
                        return 0;
+               /*
+                * getxattr on user.* may fail with EACCES in case there's no
+                * read permission on the inode.  Not much we can do, other than
+                * tell the caller that this is not a metacopy inode.
+                */
+               if (ofs->config.userxattr && res == -EACCES)
+                       return 0;
                goto out;
        }
 
@@ -882,12 +916,13 @@ bool ovl_is_metacopy_dentry(struct dentry *dentry)
        return (oe->numlower > 1);
 }
 
-char *ovl_get_redirect_xattr(struct dentry *dentry, int padding)
+char *ovl_get_redirect_xattr(struct ovl_fs *ofs, struct dentry *dentry,
+                            int padding)
 {
        int res;
        char *s, *next, *buf = NULL;
 
-       res = ovl_do_getxattr(dentry, OVL_XATTR_REDIRECT, NULL, 0);
+       res = ovl_do_getxattr(ofs, dentry, OVL_XATTR_REDIRECT, NULL, 0);
        if (res == -ENODATA || res == -EOPNOTSUPP)
                return NULL;
        if (res < 0)
@@ -899,7 +934,7 @@ char *ovl_get_redirect_xattr(struct dentry *dentry, int padding)
        if (!buf)
                return ERR_PTR(-ENOMEM);
 
-       res = ovl_do_getxattr(dentry, OVL_XATTR_REDIRECT, buf, res);
+       res = ovl_do_getxattr(ofs, dentry, OVL_XATTR_REDIRECT, buf, res);
        if (res < 0)
                goto fail;
        if (res == 0)