Re: [PATCH 3/5] ovl: make redirect/metacopy rejection consistent

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Feb 10, 2025 at 8:45 PM Miklos Szeredi <mszeredi@xxxxxxxxxx> wrote:
>
> When overlayfs finds a file with metacopy and/or redirect attributes and
> the metacopy and/or redirect features are not enabled, then it refuses to
> act on those attributes while also issuing a warning.
>
> There was a slight inconsistency of only warning on an upper metacopy if it
> found the next file on the lower layer, while always warning for metacopy
> found on a lower layer.
>
> Fix this inconsistency and make the logic more straightforward, pavig the
> way for following patches to change when dataredirects are allowed.
>
> Signed-off-by: Miklos Szeredi <mszeredi@xxxxxxxxxx>
> ---
>  fs/overlayfs/namei.c | 67 +++++++++++++++++++++++++++++---------------
>  1 file changed, 44 insertions(+), 23 deletions(-)
>
> diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c
> index be5c65d6f848..da322e9768d1 100644
> --- a/fs/overlayfs/namei.c
> +++ b/fs/overlayfs/namei.c
> @@ -1040,6 +1040,8 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
>         struct inode *inode = NULL;
>         bool upperopaque = false;
>         char *upperredirect = NULL;
> +       bool nextredirect = false;
> +       bool nextmetacopy = false;
>         struct dentry *this;
>         unsigned int i;
>         int err;
> @@ -1087,8 +1089,10 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
>                         if (err)
>                                 goto out_put_upper;
>
> -                       if (d.metacopy)
> +                       if (d.metacopy) {
>                                 uppermetacopy = true;
> +                               nextmetacopy = true;
> +                       }
>                         metacopy_size = d.metacopy;
>                 }
>
> @@ -1099,6 +1103,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
>                                 goto out_put_upper;
>                         if (d.redirect[0] == '/')
>                                 poe = roe;
> +                       nextredirect = true;
>                 }
>                 upperopaque = d.opaque;
>         }
> @@ -1113,6 +1118,29 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
>         for (i = 0; !d.stop && i < ovl_numlower(poe); i++) {
>                 struct ovl_path lower = ovl_lowerstack(poe)[i];
>
> +               /*
> +                * Following redirects/metacopy can have security consequences:
> +                * it's like a symlink into the lower layer without the
> +                * permission checks.
> +                *
> +                * This is only a problem if the upper layer is untrusted (e.g
> +                * comes from an USB drive).  This can allow a non-readable file
> +                * or directory to become readable.
> +                *
> +                * Only following redirects when redirects are enabled disables
> +                * this attack vector when not necessary.
> +                */

What do you say about moving this comment outside the loop and leaving here
only:

    /* Should redirects/metacopy to lower layers be followed? */
    if ((nextmetacopy && !ofs->config.metacopy) ||
        (nextredirect && !ovl_redirect_follow(ofs)))
          break;

> +               if (nextmetacopy && !ofs->config.metacopy) {
> +                       pr_warn_ratelimited("refusing to follow metacopy origin for (%pd2)\n", dentry);
> +                       err = -EPERM;
> +                       goto out_put;
> +               }
> +               if (nextredirect && !ovl_redirect_follow(ofs)) {
> +                       pr_warn_ratelimited("refusing to follow redirect for (%pd2)\n", dentry);
> +                       err = -EPERM;
> +                       goto out_put;
> +               }
> +
>                 if (!ovl_redirect_follow(ofs))
>                         d.last = i == ovl_numlower(poe) - 1;
>                 else if (d.is_dir || !ofs->numdatalayer)
> @@ -1126,12 +1154,8 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
>                 if (!this)
>                         continue;
>
> -               if ((uppermetacopy || d.metacopy) && !ofs->config.metacopy) {
> -                       dput(this);
> -                       err = -EPERM;
> -                       pr_warn_ratelimited("refusing to follow metacopy origin for (%pd2)\n", dentry);
> -                       goto out_put;
> -               }
> +               if (d.metacopy)
> +                       nextmetacopy = true;
>
>                 /*
>                  * If no origin fh is stored in upper of a merge dir, store fh
> @@ -1185,22 +1209,8 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
>                         ctr++;
>                 }
>
> -               /*
> -                * Following redirects can have security consequences: it's like
> -                * a symlink into the lower layer without the permission checks.
> -                * This is only a problem if the upper layer is untrusted (e.g
> -                * comes from an USB drive).  This can allow a non-readable file
> -                * or directory to become readable.
> -                *
> -                * Only following redirects when redirects are enabled disables
> -                * this attack vector when not necessary.
> -                */
> -               err = -EPERM;
> -               if (d.redirect && !ovl_redirect_follow(ofs)) {
> -                       pr_warn_ratelimited("refusing to follow redirect for (%pd2)\n",
> -                                           dentry);
> -                       goto out_put;
> -               }
> +               if (d.redirect)
> +                       nextredirect = true;
>
>                 if (d.stop)
>                         break;
> @@ -1218,6 +1228,17 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
>                 ctr++;
>         }
>
> +       if (nextmetacopy && !ofs->config.metacopy) {
> +               pr_warn_ratelimited("refusing to follow metacopy origin for (%pd2)\n", dentry);
> +               err = -EPERM;
> +               goto out_put;
> +       }
> +       if (nextredirect && !ovl_redirect_follow(ofs)) {
> +               pr_warn_ratelimited("refusing to follow redirect for (%pd2)\n", dentry);
> +               err = -EPERM;
> +               goto out_put;
> +       }
> +
>         /*
>          * For regular non-metacopy upper dentries, there is no lower
>          * path based lookup, hence ctr will be zero. If a dentry is found
> --
> 2.48.1
>





[Index of Archives]     [Linux Filesystems Devel]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux