aboutsummaryrefslogtreecommitdiffstats
path: root/fs/overlayfs
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2016-06-06 10:21:37 -0400
committerMiklos Szeredi <mszeredi@redhat.com>2016-06-06 10:21:37 -0400
commitb581755b1c565391c72d03b157ba2dd0b18e9d15 (patch)
tree9db3109b50d47faad07d457feb671eb0e90fcbe1 /fs/overlayfs
parentaf8c34ce6ae32addda3788d54a7e340cad22516b (diff)
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 <vgoyal@redhat.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> Fixes: b96809173e94 ("security_d_instantiate(): move to the point prior to attaching dentry to inode")
Diffstat (limited to 'fs/overlayfs')
-rw-r--r--fs/overlayfs/inode.c26
1 files changed, 6 insertions, 20 deletions
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index 0ed7c4012437..1dbeab6cf96e 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -238,41 +238,27 @@ out:
238 return err; 238 return err;
239} 239}
240 240
241static bool ovl_need_xattr_filter(struct dentry *dentry,
242 enum ovl_path_type type)
243{
244 if ((type & (__OVL_PATH_PURE | __OVL_PATH_UPPER)) == __OVL_PATH_UPPER)
245 return S_ISDIR(dentry->d_inode->i_mode);
246 else
247 return false;
248}
249
250ssize_t ovl_getxattr(struct dentry *dentry, struct inode *inode, 241ssize_t ovl_getxattr(struct dentry *dentry, struct inode *inode,
251 const char *name, void *value, size_t size) 242 const char *name, void *value, size_t size)
252{ 243{
253 struct path realpath; 244 struct dentry *realdentry = ovl_dentry_real(dentry);
254 enum ovl_path_type type = ovl_path_real(dentry, &realpath);
255 245
256 if (ovl_need_xattr_filter(dentry, type) && ovl_is_private_xattr(name)) 246 if (ovl_is_private_xattr(name))
257 return -ENODATA; 247 return -ENODATA;
258 248
259 return vfs_getxattr(realpath.dentry, name, value, size); 249 return vfs_getxattr(realdentry, name, value, size);
260} 250}
261 251
262ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size) 252ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
263{ 253{
264 struct path realpath; 254 struct dentry *realdentry = ovl_dentry_real(dentry);
265 enum ovl_path_type type = ovl_path_real(dentry, &realpath);
266 ssize_t res; 255 ssize_t res;
267 int off; 256 int off;
268 257
269 res = vfs_listxattr(realpath.dentry, list, size); 258 res = vfs_listxattr(realdentry, list, size);
270 if (res <= 0 || size == 0) 259 if (res <= 0 || size == 0)
271 return res; 260 return res;
272 261
273 if (!ovl_need_xattr_filter(dentry, type))
274 return res;
275
276 /* filter out private xattrs */ 262 /* filter out private xattrs */
277 for (off = 0; off < res;) { 263 for (off = 0; off < res;) {
278 char *s = list + off; 264 char *s = list + off;
@@ -302,7 +288,7 @@ int ovl_removexattr(struct dentry *dentry, const char *name)
302 goto out; 288 goto out;
303 289
304 err = -ENODATA; 290 err = -ENODATA;
305 if (ovl_need_xattr_filter(dentry, type) && ovl_is_private_xattr(name)) 291 if (ovl_is_private_xattr(name))
306 goto out_drop_write; 292 goto out_drop_write;
307 293
308 if (!OVL_TYPE_UPPER(type)) { 294 if (!OVL_TYPE_UPPER(type)) {