aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-12-15 15:46:48 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2017-12-15 15:46:48 -0500
commit227701e0e7078065f24f5a6ca220218fd80023a5 (patch)
tree6cf2337d3a9a57f81c7e96278fceb505256327b8
parent06f976ecc7afbf2e68c44ec9e591af4ceca04ca6 (diff)
parentda2e6b7eeda8919f677c790ef51161dd02e513a6 (diff)
Merge branch 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs
Pull overlayfs fixes from Miklos Szeredi: - fix incomplete syncing of filesystem - fix regression in readdir on ovl over 9p - only follow redirects when needed - misc fixes and cleanups * 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs: ovl: fix overlay: warning prefix ovl: Use PTR_ERR_OR_ZERO() ovl: Sync upper dirty data when syncing overlayfs ovl: update ctx->pos on impure dir iteration ovl: Pass ovl_get_nlink() parameters in right order ovl: don't follow redirects if redirect_dir=off
-rw-r--r--Documentation/filesystems/overlayfs.txt34
-rw-r--r--fs/overlayfs/Kconfig10
-rw-r--r--fs/overlayfs/dir.c3
-rw-r--r--fs/overlayfs/namei.c18
-rw-r--r--fs/overlayfs/overlayfs.h2
-rw-r--r--fs/overlayfs/ovl_entry.h2
-rw-r--r--fs/overlayfs/readdir.c7
-rw-r--r--fs/overlayfs/super.c87
8 files changed, 137 insertions, 26 deletions
diff --git a/Documentation/filesystems/overlayfs.txt b/Documentation/filesystems/overlayfs.txt
index 8caa60734647..e6a5f4912b6d 100644
--- a/Documentation/filesystems/overlayfs.txt
+++ b/Documentation/filesystems/overlayfs.txt
@@ -156,6 +156,40 @@ handle it in two different ways:
156 root of the overlay. Finally the directory is moved to the new 156 root of the overlay. Finally the directory is moved to the new
157 location. 157 location.
158 158
159There are several ways to tune the "redirect_dir" feature.
160
161Kernel config options:
162
163- OVERLAY_FS_REDIRECT_DIR:
164 If this is enabled, then redirect_dir is turned on by default.
165- OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW:
166 If this is enabled, then redirects are always followed by default. Enabling
167 this results in a less secure configuration. Enable this option only when
168 worried about backward compatibility with kernels that have the redirect_dir
169 feature and follow redirects even if turned off.
170
171Module options (can also be changed through /sys/module/overlay/parameters/*):
172
173- "redirect_dir=BOOL":
174 See OVERLAY_FS_REDIRECT_DIR kernel config option above.
175- "redirect_always_follow=BOOL":
176 See OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW kernel config option above.
177- "redirect_max=NUM":
178 The maximum number of bytes in an absolute redirect (default is 256).
179
180Mount options:
181
182- "redirect_dir=on":
183 Redirects are enabled.
184- "redirect_dir=follow":
185 Redirects are not created, but followed.
186- "redirect_dir=off":
187 Redirects are not created and only followed if "redirect_always_follow"
188 feature is enabled in the kernel/module config.
189- "redirect_dir=nofollow":
190 Redirects are not created and not followed (equivalent to "redirect_dir=off"
191 if "redirect_always_follow" feature is not enabled).
192
159Non-directories 193Non-directories
160--------------- 194---------------
161 195
diff --git a/fs/overlayfs/Kconfig b/fs/overlayfs/Kconfig
index cbfc196e5dc5..5ac415466861 100644
--- a/fs/overlayfs/Kconfig
+++ b/fs/overlayfs/Kconfig
@@ -24,6 +24,16 @@ config OVERLAY_FS_REDIRECT_DIR
24 an overlay which has redirects on a kernel that doesn't support this 24 an overlay which has redirects on a kernel that doesn't support this
25 feature will have unexpected results. 25 feature will have unexpected results.
26 26
27config OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW
28 bool "Overlayfs: follow redirects even if redirects are turned off"
29 default y
30 depends on OVERLAY_FS
31 help
32 Disable this to get a possibly more secure configuration, but that
33 might not be backward compatible with previous kernels.
34
35 For more information, see Documentation/filesystems/overlayfs.txt
36
27config OVERLAY_FS_INDEX 37config OVERLAY_FS_INDEX
28 bool "Overlayfs: turn on inodes index feature by default" 38 bool "Overlayfs: turn on inodes index feature by default"
29 depends on OVERLAY_FS 39 depends on OVERLAY_FS
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index e13921824c70..f9788bc116a8 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -887,7 +887,8 @@ static int ovl_set_redirect(struct dentry *dentry, bool samedir)
887 spin_unlock(&dentry->d_lock); 887 spin_unlock(&dentry->d_lock);
888 } else { 888 } else {
889 kfree(redirect); 889 kfree(redirect);
890 pr_warn_ratelimited("overlay: failed to set redirect (%i)\n", err); 890 pr_warn_ratelimited("overlayfs: failed to set redirect (%i)\n",
891 err);
891 /* Fall back to userspace copy-up */ 892 /* Fall back to userspace copy-up */
892 err = -EXDEV; 893 err = -EXDEV;
893 } 894 }
diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c
index 625ed8066570..beb945e1963c 100644
--- a/fs/overlayfs/namei.c
+++ b/fs/overlayfs/namei.c
@@ -435,7 +435,7 @@ int ovl_verify_index(struct dentry *index, struct ovl_path *lower,
435 435
436 /* Check if index is orphan and don't warn before cleaning it */ 436 /* Check if index is orphan and don't warn before cleaning it */
437 if (d_inode(index)->i_nlink == 1 && 437 if (d_inode(index)->i_nlink == 1 &&
438 ovl_get_nlink(index, origin.dentry, 0) == 0) 438 ovl_get_nlink(origin.dentry, index, 0) == 0)
439 err = -ENOENT; 439 err = -ENOENT;
440 440
441 dput(origin.dentry); 441 dput(origin.dentry);
@@ -681,6 +681,22 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
681 if (d.stop) 681 if (d.stop)
682 break; 682 break;
683 683
684 /*
685 * Following redirects can have security consequences: it's like
686 * a symlink into the lower layer without the permission checks.
687 * This is only a problem if the upper layer is untrusted (e.g
688 * comes from an USB drive). This can allow a non-readable file
689 * or directory to become readable.
690 *
691 * Only following redirects when redirects are enabled disables
692 * this attack vector when not necessary.
693 */
694 err = -EPERM;
695 if (d.redirect && !ofs->config.redirect_follow) {
696 pr_warn_ratelimited("overlay: refusing to follow redirect for (%pd2)\n", dentry);
697 goto out_put;
698 }
699
684 if (d.redirect && d.redirect[0] == '/' && poe != roe) { 700 if (d.redirect && d.redirect[0] == '/' && poe != roe) {
685 poe = roe; 701 poe = roe;
686 702
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index 13eab09a6b6f..b489099ccd49 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -180,7 +180,7 @@ static inline int ovl_do_whiteout(struct inode *dir, struct dentry *dentry)
180static inline struct dentry *ovl_do_tmpfile(struct dentry *dentry, umode_t mode) 180static inline struct dentry *ovl_do_tmpfile(struct dentry *dentry, umode_t mode)
181{ 181{
182 struct dentry *ret = vfs_tmpfile(dentry, mode, 0); 182 struct dentry *ret = vfs_tmpfile(dentry, mode, 0);
183 int err = IS_ERR(ret) ? PTR_ERR(ret) : 0; 183 int err = PTR_ERR_OR_ZERO(ret);
184 184
185 pr_debug("tmpfile(%pd2, 0%o) = %i\n", dentry, mode, err); 185 pr_debug("tmpfile(%pd2, 0%o) = %i\n", dentry, mode, err);
186 return ret; 186 return ret;
diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h
index 752bab645879..9d0bc03bf6e4 100644
--- a/fs/overlayfs/ovl_entry.h
+++ b/fs/overlayfs/ovl_entry.h
@@ -14,6 +14,8 @@ struct ovl_config {
14 char *workdir; 14 char *workdir;
15 bool default_permissions; 15 bool default_permissions;
16 bool redirect_dir; 16 bool redirect_dir;
17 bool redirect_follow;
18 const char *redirect_mode;
17 bool index; 19 bool index;
18}; 20};
19 21
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
index 0daa4354fec4..8c98578d27a1 100644
--- a/fs/overlayfs/readdir.c
+++ b/fs/overlayfs/readdir.c
@@ -499,7 +499,7 @@ out:
499 return err; 499 return err;
500 500
501fail: 501fail:
502 pr_warn_ratelimited("overlay: failed to look up (%s) for ino (%i)\n", 502 pr_warn_ratelimited("overlayfs: failed to look up (%s) for ino (%i)\n",
503 p->name, err); 503 p->name, err);
504 goto out; 504 goto out;
505} 505}
@@ -663,7 +663,10 @@ static int ovl_iterate_real(struct file *file, struct dir_context *ctx)
663 return PTR_ERR(rdt.cache); 663 return PTR_ERR(rdt.cache);
664 } 664 }
665 665
666 return iterate_dir(od->realfile, &rdt.ctx); 666 err = iterate_dir(od->realfile, &rdt.ctx);
667 ctx->pos = rdt.ctx.pos;
668
669 return err;
667} 670}
668 671
669 672
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index 288d20f9a55a..76440feb79f6 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -33,6 +33,13 @@ module_param_named(redirect_dir, ovl_redirect_dir_def, bool, 0644);
33MODULE_PARM_DESC(ovl_redirect_dir_def, 33MODULE_PARM_DESC(ovl_redirect_dir_def,
34 "Default to on or off for the redirect_dir feature"); 34 "Default to on or off for the redirect_dir feature");
35 35
36static bool ovl_redirect_always_follow =
37 IS_ENABLED(CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW);
38module_param_named(redirect_always_follow, ovl_redirect_always_follow,
39 bool, 0644);
40MODULE_PARM_DESC(ovl_redirect_always_follow,
41 "Follow redirects even if redirect_dir feature is turned off");
42
36static bool ovl_index_def = IS_ENABLED(CONFIG_OVERLAY_FS_INDEX); 43static bool ovl_index_def = IS_ENABLED(CONFIG_OVERLAY_FS_INDEX);
37module_param_named(index, ovl_index_def, bool, 0644); 44module_param_named(index, ovl_index_def, bool, 0644);
38MODULE_PARM_DESC(ovl_index_def, 45MODULE_PARM_DESC(ovl_index_def,
@@ -232,6 +239,7 @@ static void ovl_free_fs(struct ovl_fs *ofs)
232 kfree(ofs->config.lowerdir); 239 kfree(ofs->config.lowerdir);
233 kfree(ofs->config.upperdir); 240 kfree(ofs->config.upperdir);
234 kfree(ofs->config.workdir); 241 kfree(ofs->config.workdir);
242 kfree(ofs->config.redirect_mode);
235 if (ofs->creator_cred) 243 if (ofs->creator_cred)
236 put_cred(ofs->creator_cred); 244 put_cred(ofs->creator_cred);
237 kfree(ofs); 245 kfree(ofs);
@@ -244,6 +252,7 @@ static void ovl_put_super(struct super_block *sb)
244 ovl_free_fs(ofs); 252 ovl_free_fs(ofs);
245} 253}
246 254
255/* Sync real dirty inodes in upper filesystem (if it exists) */
247static int ovl_sync_fs(struct super_block *sb, int wait) 256static int ovl_sync_fs(struct super_block *sb, int wait)
248{ 257{
249 struct ovl_fs *ofs = sb->s_fs_info; 258 struct ovl_fs *ofs = sb->s_fs_info;
@@ -252,14 +261,24 @@ static int ovl_sync_fs(struct super_block *sb, int wait)
252 261
253 if (!ofs->upper_mnt) 262 if (!ofs->upper_mnt)
254 return 0; 263 return 0;
255 upper_sb = ofs->upper_mnt->mnt_sb; 264
256 if (!upper_sb->s_op->sync_fs) 265 /*
266 * If this is a sync(2) call or an emergency sync, all the super blocks
267 * will be iterated, including upper_sb, so no need to do anything.
268 *
269 * If this is a syncfs(2) call, then we do need to call
270 * sync_filesystem() on upper_sb, but enough if we do it when being
271 * called with wait == 1.
272 */
273 if (!wait)
257 return 0; 274 return 0;
258 275
259 /* real inodes have already been synced by sync_filesystem(ovl_sb) */ 276 upper_sb = ofs->upper_mnt->mnt_sb;
277
260 down_read(&upper_sb->s_umount); 278 down_read(&upper_sb->s_umount);
261 ret = upper_sb->s_op->sync_fs(upper_sb, wait); 279 ret = sync_filesystem(upper_sb);
262 up_read(&upper_sb->s_umount); 280 up_read(&upper_sb->s_umount);
281
263 return ret; 282 return ret;
264} 283}
265 284
@@ -295,6 +314,11 @@ static bool ovl_force_readonly(struct ovl_fs *ofs)
295 return (!ofs->upper_mnt || !ofs->workdir); 314 return (!ofs->upper_mnt || !ofs->workdir);
296} 315}
297 316
317static const char *ovl_redirect_mode_def(void)
318{
319 return ovl_redirect_dir_def ? "on" : "off";
320}
321
298/** 322/**
299 * ovl_show_options 323 * ovl_show_options
300 * 324 *
@@ -313,12 +337,10 @@ static int ovl_show_options(struct seq_file *m, struct dentry *dentry)
313 } 337 }
314 if (ofs->config.default_permissions) 338 if (ofs->config.default_permissions)
315 seq_puts(m, ",default_permissions"); 339 seq_puts(m, ",default_permissions");
316 if (ofs->config.redirect_dir != ovl_redirect_dir_def) 340 if (strcmp(ofs->config.redirect_mode, ovl_redirect_mode_def()) != 0)
317 seq_printf(m, ",redirect_dir=%s", 341 seq_printf(m, ",redirect_dir=%s", ofs->config.redirect_mode);
318 ofs->config.redirect_dir ? "on" : "off");
319 if (ofs->config.index != ovl_index_def) 342 if (ofs->config.index != ovl_index_def)
320 seq_printf(m, ",index=%s", 343 seq_printf(m, ",index=%s", ofs->config.index ? "on" : "off");
321 ofs->config.index ? "on" : "off");
322 return 0; 344 return 0;
323} 345}
324 346
@@ -348,8 +370,7 @@ enum {
348 OPT_UPPERDIR, 370 OPT_UPPERDIR,
349 OPT_WORKDIR, 371 OPT_WORKDIR,
350 OPT_DEFAULT_PERMISSIONS, 372 OPT_DEFAULT_PERMISSIONS,
351 OPT_REDIRECT_DIR_ON, 373 OPT_REDIRECT_DIR,
352 OPT_REDIRECT_DIR_OFF,
353 OPT_INDEX_ON, 374 OPT_INDEX_ON,
354 OPT_INDEX_OFF, 375 OPT_INDEX_OFF,
355 OPT_ERR, 376 OPT_ERR,
@@ -360,8 +381,7 @@ static const match_table_t ovl_tokens = {
360 {OPT_UPPERDIR, "upperdir=%s"}, 381 {OPT_UPPERDIR, "upperdir=%s"},
361 {OPT_WORKDIR, "workdir=%s"}, 382 {OPT_WORKDIR, "workdir=%s"},
362 {OPT_DEFAULT_PERMISSIONS, "default_permissions"}, 383 {OPT_DEFAULT_PERMISSIONS, "default_permissions"},
363 {OPT_REDIRECT_DIR_ON, "redirect_dir=on"}, 384 {OPT_REDIRECT_DIR, "redirect_dir=%s"},
364 {OPT_REDIRECT_DIR_OFF, "redirect_dir=off"},
365 {OPT_INDEX_ON, "index=on"}, 385 {OPT_INDEX_ON, "index=on"},
366 {OPT_INDEX_OFF, "index=off"}, 386 {OPT_INDEX_OFF, "index=off"},
367 {OPT_ERR, NULL} 387 {OPT_ERR, NULL}
@@ -390,10 +410,37 @@ static char *ovl_next_opt(char **s)
390 return sbegin; 410 return sbegin;
391} 411}
392 412
413static int ovl_parse_redirect_mode(struct ovl_config *config, const char *mode)
414{
415 if (strcmp(mode, "on") == 0) {
416 config->redirect_dir = true;
417 /*
418 * Does not make sense to have redirect creation without
419 * redirect following.
420 */
421 config->redirect_follow = true;
422 } else if (strcmp(mode, "follow") == 0) {
423 config->redirect_follow = true;
424 } else if (strcmp(mode, "off") == 0) {
425 if (ovl_redirect_always_follow)
426 config->redirect_follow = true;
427 } else if (strcmp(mode, "nofollow") != 0) {
428 pr_err("overlayfs: bad mount option \"redirect_dir=%s\"\n",
429 mode);
430 return -EINVAL;
431 }
432
433 return 0;
434}
435
393static int ovl_parse_opt(char *opt, struct ovl_config *config) 436static int ovl_parse_opt(char *opt, struct ovl_config *config)
394{ 437{
395 char *p; 438 char *p;
396 439
440 config->redirect_mode = kstrdup(ovl_redirect_mode_def(), GFP_KERNEL);
441 if (!config->redirect_mode)
442 return -ENOMEM;
443
397 while ((p = ovl_next_opt(&opt)) != NULL) { 444 while ((p = ovl_next_opt(&opt)) != NULL) {
398 int token; 445 int token;
399 substring_t args[MAX_OPT_ARGS]; 446 substring_t args[MAX_OPT_ARGS];
@@ -428,12 +475,11 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config)
428 config->default_permissions = true; 475 config->default_permissions = true;
429 break; 476 break;
430 477
431 case OPT_REDIRECT_DIR_ON: 478 case OPT_REDIRECT_DIR:
432 config->redirect_dir = true; 479 kfree(config->redirect_mode);
433 break; 480 config->redirect_mode = match_strdup(&args[0]);
434 481 if (!config->redirect_mode)
435 case OPT_REDIRECT_DIR_OFF: 482 return -ENOMEM;
436 config->redirect_dir = false;
437 break; 483 break;
438 484
439 case OPT_INDEX_ON: 485 case OPT_INDEX_ON:
@@ -458,7 +504,7 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config)
458 config->workdir = NULL; 504 config->workdir = NULL;
459 } 505 }
460 506
461 return 0; 507 return ovl_parse_redirect_mode(config, config->redirect_mode);
462} 508}
463 509
464#define OVL_WORKDIR_NAME "work" 510#define OVL_WORKDIR_NAME "work"
@@ -1160,7 +1206,6 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
1160 if (!cred) 1206 if (!cred)
1161 goto out_err; 1207 goto out_err;
1162 1208
1163 ofs->config.redirect_dir = ovl_redirect_dir_def;
1164 ofs->config.index = ovl_index_def; 1209 ofs->config.index = ovl_index_def;
1165 err = ovl_parse_opt((char *) data, &ofs->config); 1210 err = ovl_parse_opt((char *) data, &ofs->config);
1166 if (err) 1211 if (err)