if (buf[0] == '/') {
d->absolute_redirect = true; /* * One of the ancestor path elements in an absolute path * lookup in ovl_lookup_layer() could have been opaque and * that will stop further lookup in lower layers (d->stop=true) * But we have found an absolute redirect in descendant path * element and that should force continue lookup in lower * layers (reset d->stop).
*/
d->stop = false;
} else {
res = strlen(buf) + 1;
memmove(buf + prelen, buf, res);
memcpy(buf, d->name.name, prelen);
}
staticint ovl_acceptable(void *ctx, struct dentry *dentry)
{ /* * A non-dir origin may be disconnected, which is fine, because * we only need it for its unique inode number.
*/ if (!d_is_dir(dentry)) return 1;
/* Don't decode a deleted empty directory */ if (d_unhashed(dentry)) return 0;
/* Check if directory belongs to the layer we are decoding from */ return is_subdir(dentry, ((struct vfsmount *)ctx)->mnt_root);
}
/* * Check validity of an overlay file handle buffer. * * Return 0 for a valid file handle. * Return -ENODATA for "origin unknown". * Return <0 for an invalid file handle.
*/ int ovl_check_fb_len(struct ovl_fb *fb, int fb_len)
{ if (fb_len < sizeof(struct ovl_fb) || fb_len < fb->len) return -EINVAL;
if (fb->magic != OVL_FH_MAGIC) return -EINVAL;
/* Treat larger version and unknown flags as "origin unknown" */ if (fb->version > OVL_FH_VERSION || fb->flags & ~OVL_FH_FLAG_ALL) return -ENODATA;
/* Treat endianness mismatch as "origin unknown" */ if (!(fb->flags & OVL_FH_FLAG_ANY_ENDIAN) &&
(fb->flags & OVL_FH_FLAG_BIG_ENDIAN) != OVL_FH_FLAG_CPU_ENDIAN) return -ENODATA;
res = ovl_getxattr_upper(ofs, upperdentry, ox, NULL, 0); if (res < 0) { if (res == -ENODATA || res == -EOPNOTSUPP) return NULL; goto fail;
} /* Zero size value means "copied up but origin unknown" */ if (res == 0) return NULL;
fh = kzalloc(res + OVL_FH_WIRE_OFFSET, GFP_KERNEL); if (!fh) return ERR_PTR(-ENOMEM);
res = ovl_getxattr_upper(ofs, upperdentry, ox, fh->buf, res); if (res < 0) goto fail;
err = ovl_check_fb_len(&fh->fb, res); if (err < 0) { if (err == -ENODATA) goto out; goto invalid;
}
return fh;
out:
kfree(fh); return NULL;
fail:
pr_warn_ratelimited("failed to get origin (%i)\n", res); goto out;
invalid:
pr_warn_ratelimited("invalid origin (%*phN)\n", res, fh); goto out;
}
/* * Make sure that the stored uuid matches the uuid of the lower * layer where file handle will be decoded. * In case of uuid=off option just make sure that stored uuid is null.
*/ if (ovl_origin_uuid(ofs) ?
!uuid_equal(&fh->fb.uuid, &mnt->mnt_sb->s_uuid) :
!uuid_is_null(&fh->fb.uuid)) return NULL;
bytes = (fh->fb.len - offsetof(struct ovl_fb, fid));
real = exportfs_decode_fh(mnt, (struct fid *)fh->fb.fid,
bytes >> 2, (int)fh->fb.type,
connected ? ovl_acceptable : NULL, mnt); if (IS_ERR(real)) { /* * Treat stale file handle to lower file as "origin unknown". * upper file handle could become stale when upper file is * unlinked and this information is needed to handle stale * index entries correctly.
*/ if (real == ERR_PTR(-ESTALE) &&
!(fh->fb.flags & OVL_FH_FLAG_PATH_UPPER))
real = NULL; return real;
}
if (ovl_dentry_weird(real)) {
dput(real); return NULL;
}
/* * We allow filesystems that are case-folding capable but deny composing * ovl stack from case-folded directories. If someone has enabled case * folding on a directory on underlying layer, the warranty of the ovl * stack is voided.
*/ if (ovl_dentry_casefolded(base)) {
warn = "case folded parent";
err = -ESTALE; goto out_warn;
}
this = ovl_lookup_positive_unlocked(d, name, base, namelen, drop_negative); if (IS_ERR(this)) {
err = PTR_ERR(this); this = NULL; if (err == -ENOENT || err == -ENAMETOOLONG) goto out; goto out_err;
}
staticint ovl_lookup_layer(struct dentry *base, struct ovl_lookup_data *d, struct dentry **ret, bool drop_negative)
{ /* Counting down from the end, since the prefix can change */
size_t rem = d->name.len - 1; struct dentry *dentry = NULL; int err;
for (i = 1; i <= ovl_numlowerlayer(ofs); i++) { /* * If lower fs uuid is not unique among lower fs we cannot match * fh->uuid to layer.
*/ if (ofs->layers[i].fsid &&
ofs->layers[i].fs->bad_uuid) continue;
origin = ovl_decode_real_fh(ofs, fh, ofs->layers[i].mnt,
connected); if (origin) break;
}
if (!origin) return -ESTALE; elseif (IS_ERR(origin)) return PTR_ERR(origin);
if (upperdentry && !ovl_upper_is_whiteout(ofs, upperdentry) &&
inode_wrong_type(d_inode(upperdentry), d_inode(origin)->i_mode)) goto invalid;
/* * Verify that @real dentry matches the file handle stored in xattr @name. * * If @set is true and there is no stored file handle, encode @real and store * file handle in xattr @name. * * Return 0 on match, -ESTALE on mismatch, -ENODATA on no xattr, < 0 on error.
*/ int ovl_verify_origin_xattr(struct ovl_fs *ofs, struct dentry *dentry, enum ovl_xattr ox, struct dentry *real, bool is_upper, bool set)
{ struct inode *inode; struct ovl_fh *fh; int err;
if (IS_ERR_OR_NULL(upper)) return upper ?: ERR_PTR(-ESTALE);
if (!d_is_dir(upper)) {
pr_warn_ratelimited("invalid index upper (%pd2, upper=%pd2).\n",
index, upper);
dput(upper); return ERR_PTR(-EIO);
}
return upper;
}
/* * Verify that an index entry name matches the origin file handle stored in * OVL_XATTR_ORIGIN and that origin file handle can be decoded to lower path. * Return 0 on match, -ESTALE on mismatch or stale origin, < 0 on error.
*/ int ovl_verify_index(struct ovl_fs *ofs, struct dentry *index)
{ struct ovl_fh *fh = NULL;
size_t len; struct ovl_path origin = { }; struct ovl_path *stack = &origin; struct dentry *upper = NULL; int err;
if (!d_inode(index)) return 0;
err = -EINVAL; if (index->d_name.len < sizeof(struct ovl_fb)*2) goto fail;
err = -ENOMEM;
len = index->d_name.len / 2;
fh = kzalloc(len + OVL_FH_WIRE_OFFSET, GFP_KERNEL); if (!fh) goto fail;
err = -EINVAL; if (hex2bin(fh->buf, index->d_name.name, len)) goto fail;
err = ovl_check_fb_len(&fh->fb, len); if (err) goto fail;
/* * Whiteout index entries are used as an indication that an exported * overlay file handle should be treated as stale (i.e. after unlink * of the overlay inode). These entries contain no origin xattr.
*/ if (ovl_is_whiteout(index)) goto out;
/* * Verifying directory index entries are not stale is expensive, so * only verify stale dir index if NFS export is enabled.
*/ if (d_is_dir(index) && !ofs->config.nfs_export) goto out;
/* * Directory index entries should have 'upper' xattr pointing to the * real upper dir. Non-dir index entries are hardlinks to the upper * real inode. For non-dir index, we can read the copy up origin xattr * directly from the index dentry, but for dir index we first need to * decode the upper directory.
*/
upper = ovl_index_upper(ofs, index, false); if (IS_ERR_OR_NULL(upper)) {
err = PTR_ERR(upper); /* * Directory index entries with no 'upper' xattr need to be * removed. When dir index entry has a stale 'upper' xattr, * we assume that upper dir was removed and we treat the dir * index as orphan entry that needs to be whited out.
*/ if (err == -ESTALE) goto orphan; elseif (!err)
err = -ESTALE; goto fail;
}
/* Check if non-dir index is orphan and don't warn before cleaning it */ if (!d_is_dir(index) && d_inode(index)->i_nlink == 1) {
err = ovl_check_origin_fh(ofs, fh, false, index, &stack); if (err) goto fail;
if (ovl_get_nlink(ofs, origin.dentry, index, 0) == 0) goto orphan;
}
out:
dput(origin.dentry);
kfree(fh); return err;
fail:
pr_warn_ratelimited("failed to verify index (%pd2, ftype=%x, err=%i)\n",
index, d_inode(index)->i_mode & S_IFMT, err); goto out;
n = kcalloc(fh->fb.len, 2, GFP_KERNEL); if (!n) return -ENOMEM;
s = bin2hex(n, fh->buf, fh->fb.len);
*name = (struct qstr) QSTR_INIT(n, s - n);
return 0;
}
/* * Lookup in indexdir for the index entry of a lower real inode or a copy up * origin inode. The index entry name is the hex representation of the lower * inode file handle. * * If the index dentry in negative, then either no lower aliases have been * copied up yet, or aliases have been copied up in older kernels and are * not indexed. * * If the index dentry for a copy up origin inode is positive, but points * to an inode different than the upper inode, then either the upper inode * has been copied up and not indexed or it was indexed, but since then * index dir was cleared. Either way, that index cannot be used to identify * the overlay inode.
*/ int ovl_get_index_name(struct ovl_fs *ofs, struct dentry *origin, struct qstr *name)
{ struct ovl_fh *fh; int err;
fh = ovl_encode_real_fh(ofs, d_inode(origin), false); if (IS_ERR(fh)) return PTR_ERR(fh);
err = ovl_get_index_name_fh(fh, name);
kfree(fh); return err;
}
/* Lookup index by file handle for NFS export */ struct dentry *ovl_get_index_fh(struct ovl_fs *ofs, struct ovl_fh *fh)
{ struct dentry *index; struct qstr name; int err;
err = ovl_get_index_name_fh(fh, &name); if (err) return ERR_PTR(err);
index = lookup_noperm_positive_unlocked(&name, ofs->workdir);
kfree(name.name); if (IS_ERR(index)) { if (PTR_ERR(index) == -ENOENT)
index = NULL; return index;
}
err = ovl_get_index_name(ofs, origin, &name); if (err) return ERR_PTR(err);
index = lookup_one_positive_unlocked(ovl_upper_mnt_idmap(ofs), &name,
ofs->workdir); if (IS_ERR(index)) {
err = PTR_ERR(index); if (err == -ENOENT) {
index = NULL; goto out;
}
pr_warn_ratelimited("failed inode index lookup (ino=%lu, key=%.*s, err=%i);\n" "overlayfs: mount with '-o index=off' to disable inodes index.\n",
d_inode(origin)->i_ino, name.len, name.name,
err); goto out;
}
inode = d_inode(index); if (ovl_is_whiteout(index) && !verify) { /* * When index lookup is called with !verify for decoding an * overlay file handle, a whiteout index implies that decode * should treat file handle as stale and no need to print a * warning about it.
*/
dput(index);
index = ERR_PTR(-ESTALE); goto out;
} elseif (ovl_dentry_weird(index) || ovl_is_whiteout(index) ||
inode_wrong_type(inode, d_inode(origin)->i_mode)) { /* * Index should always be of the same file type as origin * except for the case of a whiteout index. A whiteout * index should only exist if all lower aliases have been * unlinked, which means that finding a lower origin on lookup * whose index is a whiteout should be treated as an error.
*/
pr_warn_ratelimited("bad index found (index=%pd2, ftype=%x, origin ftype=%x).\n",
index, d_inode(index)->i_mode & S_IFMT,
d_inode(origin)->i_mode & S_IFMT); goto fail;
} elseif (is_dir && verify) { if (!upper) {
pr_warn_ratelimited("suspected uncovered redirected dir found (origin=%pd2, index=%pd2).\n",
origin, index); goto fail;
}
/* Verify that dir index 'upper' xattr points to upper dir */
err = ovl_verify_upper(ofs, index, upper, false); if (err) { if (err == -ESTALE) {
pr_warn_ratelimited("suspected multiply redirected dir found (upper=%pd2, origin=%pd2, index=%pd2).\n",
upper, origin, index);
} goto fail;
}
} elseif (upper && d_inode(upper) != inode) { goto out_dput;
}
out:
kfree(name.name); return index;
out_dput:
dput(index);
index = NULL; goto out;
fail:
dput(index);
index = ERR_PTR(-EIO); goto out;
}
/* * Returns next layer in stack starting from top. * Returns -1 if this is the last layer.
*/ int ovl_path_next(int idx, struct dentry *dentry, struct path *path, conststruct ovl_layer **layer)
{ struct ovl_entry *oe = OVL_E(dentry); struct ovl_path *lowerstack = ovl_lowerstack(oe);
int ovl_verify_lowerdata(struct dentry *dentry)
{ int err;
err = ovl_maybe_lookup_lowerdata(dentry); if (err) return err;
return ovl_maybe_validate_verity(dentry);
}
/* * 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.
*/ staticbool ovl_check_follow_redirect(struct ovl_lookup_data *d)
{ struct ovl_fs *ofs = OVL_FS(d->sb);
if (d->metacopy && !ofs->config.metacopy) {
pr_warn_ratelimited("refusing to follow metacopy origin for (%pd2)\n", d->dentry); returnfalse;
} if ((d->redirect || d->upperredirect) && !ovl_redirect_follow(ofs)) {
pr_warn_ratelimited("refusing to follow redirect for (%pd2)\n", d->dentry); returnfalse;
} returntrue;
}
if (upperdentry && upperdentry->d_flags & DCACHE_OP_REAL) {
dput(upperdentry);
err = -EREMOTE; goto out;
} if (upperdentry && !d.is_dir) { /* * Lookup copy up origin by decoding origin file handle. * We may get a disconnected dentry, which is fine, * because we only need to hold the origin inode in * cache and use its inode number. We may even get a * connected dentry, that is not under any of the lower * layers root. That is also fine for using it's inode * number - it's the same as if we held a reference * to a dentry in lower layer that was moved under us.
*/
err = ovl_check_origin(ofs, upperdentry, &origin_path); if (err) goto out_put_upper;
if (d.metacopy)
uppermetacopy = true;
metacopy_size = d.metacopy;
}
if (d.redirect) {
err = -ENOMEM;
d.upperredirect = kstrdup(d.redirect, GFP_KERNEL); if (!d.upperredirect) goto out_put_upper; if (d.redirect[0] == '/')
poe = roe;
}
upperopaque = d.opaque;
}
if (!d.stop && ovl_numlower(poe)) {
err = -ENOMEM;
stack = ovl_stack_alloc(ofs->numlayer - 1); if (!stack) goto out_put_upper;
}
for (i = 0; !d.stop && i < ovl_numlower(poe); i++) { struct ovl_path lower = ovl_lowerstack(poe)[i];
if (!ovl_check_follow_redirect(&d)) {
err = -EPERM; goto out_put;
}
if (!check_redirect)
d.last = i == ovl_numlower(poe) - 1; elseif (d.is_dir || !ofs->numdatalayer)
d.last = lower.layer->idx == ovl_numlower(roe);
/* * If no origin fh is stored in upper of a merge dir, store fh * of lower dir and set upper parent "impure".
*/ if (upperdentry && !ctr && !ofs->noxattr && d.is_dir) {
err = ovl_fix_origin(ofs, dentry, this, upperdentry); if (err) {
dput(this); goto out_put;
}
}
/* * When "verify_lower" feature is enabled, do not merge with a * lower dir that does not match a stored origin xattr. In any * case, only verified origin is used for index lookup. * * For non-dir dentry, if index=on, then ensure origin * matches the dentry found using path based lookup, * otherwise error out.
*/ if (upperdentry && !ctr &&
((d.is_dir && ovl_verify_lower(dentry->d_sb)) ||
(!d.is_dir && ofs->config.index && origin_path))) {
err = ovl_verify_origin(ofs, upperdentry, this, false); if (err) {
dput(this); if (d.is_dir) break; goto out_put;
}
origin = this;
}
if (d.metacopy && ctr) { /* * Do not store intermediate metacopy dentries in * lower chain, except top most lower metacopy dentry. * Continue the loop so that if there is an absolute * redirect on this dentry, poe can be reset to roe.
*/
dput(this); this = NULL;
} else {
stack[ctr].dentry = this;
stack[ctr].layer = lower.layer;
ctr++;
}
if (d.stop) break;
if (d.redirect && d.redirect[0] == '/' && poe != roe) {
poe = roe; /* Find the current layer on the root dentry */
i = lower.layer->idx - 1;
}
}
/* * Defer lookup of lowerdata in data-only layers to first access. * Don't require redirect=follow and metacopy=on in this case.
*/ if (d.metacopy && ctr && ofs->numdatalayer && d.absolute_redirect) {
d.metacopy = 0;
ctr++;
} elseif (!ovl_check_follow_redirect(&d)) {
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 * using ORIGIN xattr on upper, install it in stack. * * For metacopy dentry, path based lookup will find lower dentries. * Just make sure a corresponding data dentry has been found.
*/ if (d.metacopy || (uppermetacopy && !ctr)) {
pr_warn_ratelimited("metacopy with no lower data found - abort lookup (%pd2)\n",
dentry);
err = -EIO; goto out_put;
} elseif (!d.is_dir && upperdentry && !ctr && origin_path) { if (WARN_ON(stack != NULL)) {
err = -EIO; goto out_put;
}
stack = origin_path;
ctr = 1;
origin = origin_path->dentry;
origin_path = NULL;
}
/* * Always lookup index if there is no-upperdentry. * * For the case of upperdentry, we have set origin by now if it * needed to be set. There are basically three cases. * * For directories, lookup index by lower inode and verify it matches * upper inode. We only trust dir index if we verified that lower dir * matches origin, otherwise dir index entries may be inconsistent * and we ignore them. * * For regular upper, we already set origin if upper had ORIGIN * xattr. There is no verification though as there is no path * based dentry lookup in lower in this case. * * For metacopy upper, we set a verified origin already if index * is enabled and if upper had an ORIGIN xattr. *
*/ if (!upperdentry && ctr)
origin = stack[0].dentry;
if (origin && ovl_indexdir(dentry->d_sb) &&
(!d.is_dir || ovl_index_all(dentry->d_sb))) {
index = ovl_lookup_index(ofs, upperdentry, origin, true); if (IS_ERR(index)) {
err = PTR_ERR(index);
index = NULL; goto out_put;
}
}
if (ctr) {
oe = ovl_alloc_entry(ctr);
err = -ENOMEM; if (!oe) goto out_put;
ovl_stack_cpy(ovl_lowerstack(oe), stack, ctr);
}
if (upperopaque)
ovl_dentry_set_opaque(dentry); if (d.xwhiteouts)
ovl_dentry_set_xwhiteouts(dentry);
/* * It's safe to assign upperredirect here: the previous * assignment happens only if upperdentry is non-NULL, and * this one only if upperdentry is NULL.
*/
d.upperredirect = ovl_get_redirect_xattr(ofs, &upperpath, 0); if (IS_ERR(d.upperredirect)) {
err = PTR_ERR(d.upperredirect);
d.upperredirect = NULL; goto out_free_oe;
}
/* * If dentry is negative, then lower is positive iff this is a * whiteout.
*/ if (!dentry->d_inode) return ovl_dentry_is_opaque(dentry);
/* Negative upper -> positive lower */ if (!ovl_dentry_upper(dentry)) returntrue;
old_cred = ovl_override_creds(dentry->d_sb); /* Positive upper -> have to look up lower to see whether it exists */ for (i = 0; !done && !positive && i < ovl_numlower(poe); i++) { struct dentry *this; struct ovl_path *parentpath = &ovl_lowerstack(poe)[i];
/* * We need to make a non-const copy of dentry->d_name, * because lookup_one_positive_unlocked() will hash name * with parentpath base, which is on another (lower fs).
*/ this = lookup_one_positive_unlocked(
mnt_idmap(parentpath->layer->mnt),
&QSTR_LEN(name->name, name->len),
parentpath->dentry); if (IS_ERR(this)) { switch (PTR_ERR(this)) { case -ENOENT: case -ENAMETOOLONG: break;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.