From c99f00ee885562bb4f269263a320703c8d4a55fa Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Mon, 6 Jun 2016 16:21:37 +0200 Subject: [PATCH] ovl: xattr filter fix a) ovl_need_xattr_filter() is wrong, we can have multiple lower layers overlaid, all of which (except the lowest one) honouring the "trusted.overlay.opaque" xattr. So need to filter everything except the bottom and the pure-upper layer. b) we no longer can assume that inode is attached to dentry in get/setxattr. This patch unconditionally filters private xattrs to fix both of the above. Performance impact for get/removexattrs is likely in the noise. For listxattrs it might be measurable in pathological cases, but I very much hope nobody cares. If they do, we'll fix it then. Reported-by: Vivek Goyal Signed-off-by: Miklos Szeredi Fixes: b96809173e94 ("security_d_instantiate(): move to the point prior to attaching dentry to inode") Orabug: 26401569 (backport upstream commit b581755b1c565391c72d03b157ba2dd0b18e9d15) Signed-off-by: Shan Hai Reviewed-by: Somasundaram Krishnasamy --- fs/overlayfs/inode.c | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index f692ec5bee2d..3fc2eccf0749 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -244,49 +244,35 @@ out: return err; } -static bool ovl_need_xattr_filter(struct dentry *dentry, - enum ovl_path_type type) -{ - if ((type & (__OVL_PATH_PURE | __OVL_PATH_UPPER)) == __OVL_PATH_UPPER) - return S_ISDIR(dentry->d_inode->i_mode); - else - return false; -} - ssize_t ovl_getxattr(struct dentry *dentry, const char *name, void *value, size_t size) { - struct path realpath; - enum ovl_path_type type = ovl_path_real(dentry, &realpath); + struct dentry *realdentry = ovl_dentry_real(dentry); ssize_t res; const struct cred *old_cred; - if (ovl_need_xattr_filter(dentry, type) && ovl_is_private_xattr(name)) + if (ovl_is_private_xattr(name)) return -ENODATA; old_cred = ovl_override_creds(dentry->d_sb); - res = vfs_getxattr(realpath.dentry, name, value, size); + res = vfs_getxattr(realdentry, name, value, size); revert_creds(old_cred); return res; } ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size) { - struct path realpath; - enum ovl_path_type type = ovl_path_real(dentry, &realpath); + struct dentry *realdentry = ovl_dentry_real(dentry); ssize_t res; int off; const struct cred *old_cred; old_cred = ovl_override_creds(dentry->d_sb); - res = vfs_listxattr(realpath.dentry, list, size); + res = vfs_listxattr(realdentry, list, size); revert_creds(old_cred); if (res <= 0 || size == 0) return res; - if (!ovl_need_xattr_filter(dentry, type)) - return res; - /* filter out private xattrs */ for (off = 0; off < res;) { char *s = list + off; @@ -317,7 +303,7 @@ int ovl_removexattr(struct dentry *dentry, const char *name) goto out; err = -ENODATA; - if (ovl_need_xattr_filter(dentry, type) && ovl_is_private_xattr(name)) + if (ovl_is_private_xattr(name)) goto out_drop_write; if (!OVL_TYPE_UPPER(type)) { -- 2.50.1