staticbool ovl_redirect_dir_def = IS_ENABLED(CONFIG_OVERLAY_FS_REDIRECT_DIR);
module_param_named(redirect_dir, ovl_redirect_dir_def, bool, 0644);
MODULE_PARM_DESC(redirect_dir, "Default to on or off for the redirect_dir feature");
staticbool ovl_redirect_always_follow =
IS_ENABLED(CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW);
module_param_named(redirect_always_follow, ovl_redirect_always_follow, bool, 0644);
MODULE_PARM_DESC(redirect_always_follow, "Follow redirects even if redirect_dir feature is turned off");
staticbool ovl_index_def = IS_ENABLED(CONFIG_OVERLAY_FS_INDEX);
module_param_named(index, ovl_index_def, bool, 0644);
MODULE_PARM_DESC(index, "Default to on or off for the inodes index feature");
staticbool ovl_nfs_export_def = IS_ENABLED(CONFIG_OVERLAY_FS_NFS_EXPORT);
module_param_named(nfs_export, ovl_nfs_export_def, bool, 0644);
MODULE_PARM_DESC(nfs_export, "Default to on or off for the NFS export feature");
staticbool ovl_metacopy_def = IS_ENABLED(CONFIG_OVERLAY_FS_METACOPY);
module_param_named(metacopy, ovl_metacopy_def, bool, 0644);
MODULE_PARM_DESC(metacopy, "Default to on or off for the metadata only copy up feature");
for (s = d = str;; s++, d++) { if (*s == '\\') { /* keep esc chars in split lowerdir */
*d++ = *s++;
} elseif (*s == ':') { bool next_colon = (*(s + 1) == ':');
nr_colons++; if (nr_colons == 2 && next_colon) {
pr_err("only single ':' or double '::' sequences of unescaped colons in lowerdir mount option allowed.\n"); return -EINVAL;
} /* count layers, not colons */ if (!next_colon)
nr_layers++;
*d = '\0'; continue;
}
*d = *s; if (!*s) { /* trailing colons */ if (nr_colons) {
pr_err("unescaped trailing colons in lowerdir mount option.\n"); return -EINVAL;
} break;
}
nr_colons = 0;
}
if (!d_is_dir(path->dentry)) return invalfc(fc, "%s is not a directory", name);
/* * Allow filesystems that are case-folding capable but deny composing * ovl stack from case-folded directories.
*/ if (ovl_dentry_casefolded(path->dentry)) return invalfc(fc, "case-insensitive directory on %s not supported", name);
if (ovl_dentry_weird(path->dentry)) return invalfc(fc, "filesystem on %s not supported", name);
/* * Check whether upper path is read-only here to report failures * early. Don't forget to recheck when the superblock is created * as the mount attributes could change.
*/ if (upper) { if (path->dentry->d_flags & DCACHE_OP_REAL) return invalfc(fc, "filesystem on %s not supported as upperdir", name); if (__mnt_is_readonly(path->mnt)) return invalfc(fc, "filesystem on %s is read-only", name);
} else { if (ctx->lowerdir_all && layer != Opt_lowerdir) return invalfc(fc, "lowerdir+ and datadir+ cannot follow lowerdir"); if (ctx->nr_data && layer == Opt_lowerdir_add) return invalfc(fc, "regular lower layers cannot follow data layers"); if (ctx->nr == OVL_MAX_STACK) return invalfc(fc, "too many lower directories, limit is %d",
OVL_MAX_STACK);
} return 0;
}
if (nr_lower > OVL_MAX_STACK) {
pr_err("too many lower directories, limit is %d\n", OVL_MAX_STACK); goto out_err;
}
iter = dup; for (nr = 0; nr < nr_lower; nr++) { struct path path __free(path_put) = {};
err = ovl_kern_path(iter, &path, Opt_lowerdir); if (err) goto out_err;
err = ovl_do_parse_layer(fc, iter, &path, Opt_lowerdir); if (err) goto out_err;
if (data_layer)
ctx->nr_data++;
/* Calling strchr() again would overrun. */ if (ctx->nr == nr_lower) break;
err = -EINVAL;
iter = strchr(iter, '\0') + 1; if (*iter) { /* * This is a regular layer so we require that * there are no data layers.
*/ if (ctx->nr_data > 0) {
pr_err("regular lower layers cannot follow data lower layers\n"); goto out_err;
}
data_layer = false; continue;
}
/* This is a data lower layer. */
data_layer = true;
iter++;
}
kfree(dup); return 0;
out_err:
kfree(dup);
/* Intentionally don't realloc to a smaller size. */ return err;
}
if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE) { /* * On remount overlayfs has always ignored all mount * options no matter if malformed or not so for * backwards compatibility we do the same here.
*/ if (fc->oldapi) return 0;
/* * Give us the freedom to allow changing mount options * with the new mount api in the future. So instead of * silently ignoring everything we report a proper * error. This is only visible for users of the new * mount api.
*/ return invalfc(fc, "No changes allowed in reconfigure");
}
/* * ofs is stored in the fs_context when it is initialized. * ofs is transferred to the superblock on a successful mount, * but if an error occurs before the transfer we have to free * it here.
*/ if (ofs)
ovl_free_fs(ofs);
/* * This is called during fsopen() and will record the user namespace of * the caller in fc->user_ns since we've raised FS_USERNS_MOUNT. We'll * need it when we actually create the superblock to verify that the * process creating the superblock is in the same user namespace as * process that called fsopen().
*/ int ovl_init_fs_context(struct fs_context *fc)
{ struct ovl_fs_context *ctx; struct ovl_fs *ofs;
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL_ACCOUNT); if (!ctx) return -ENOMEM;
/* * By default we allocate for three lower layers. It's likely * that it'll cover most users.
*/
ctx->lower = kmalloc_array(3, sizeof(*ctx->lower), GFP_KERNEL_ACCOUNT); if (!ctx->lower) goto out_err;
ctx->capacity = 3;
ofs = kzalloc(sizeof(struct ovl_fs), GFP_KERNEL); if (!ofs) goto out_err;
iput(ofs->workbasedir_trap);
iput(ofs->workdir_trap);
dput(ofs->whiteout);
dput(ofs->workdir); if (ofs->workdir_locked)
ovl_inuse_unlock(ofs->workbasedir);
dput(ofs->workbasedir); if (ofs->upperdir_locked)
ovl_inuse_unlock(ovl_upper_mnt(ofs)->mnt_root);
/* Reuse ofs->config.lowerdirs as a vfsmount array before freeing it */
mounts = (struct vfsmount **) ofs->config.lowerdirs; for (i = 0; i < ofs->numlayer; i++) {
iput(ofs->layers[i].trap);
kfree(ofs->config.lowerdirs[i]);
mounts[i] = ofs->layers[i].mnt;
}
kern_unmount_array(mounts, ofs->numlayer);
kfree(ofs->layers); for (i = 0; i < ofs->numfs; i++)
free_anon_bdev(ofs->fs[i].pseudo_dev);
kfree(ofs->fs);
kfree(ofs->config.lowerdirs);
kfree(ofs->config.upperdir);
kfree(ofs->config.workdir); if (ofs->creator_cred)
put_cred(ofs->creator_cred);
kfree(ofs);
}
int ovl_fs_params_verify(conststruct ovl_fs_context *ctx, struct ovl_config *config)
{ struct ovl_opt_set set = ctx->set;
/* Workdir/index are useless in non-upper mount */ if (!config->upperdir) { if (config->workdir) {
pr_info("option \"workdir=%s\" is useless in a non-upper mount, ignore\n",
config->workdir);
kfree(config->workdir);
config->workdir = NULL;
} if (config->index && set.index) {
pr_info("option \"index=on\" is useless in a non-upper mount, ignore\n");
set.index = false;
}
config->index = false;
}
if (!config->upperdir && config->ovl_volatile) {
pr_info("option \"volatile\" is meaningless in a non-upper mount, ignoring it.\n");
config->ovl_volatile = false;
}
if (!config->upperdir && config->uuid == OVL_UUID_ON) {
pr_info("option \"uuid=on\" requires an upper fs, falling back to uuid=null.\n");
config->uuid = OVL_UUID_NULL;
}
/* * This is to make the logic below simpler. It doesn't make any other * difference, since redirect_dir=on is only used for upper.
*/ if (!config->upperdir && config->redirect_mode == OVL_REDIRECT_FOLLOW)
config->redirect_mode = OVL_REDIRECT_ON;
/* metacopy -> redirect_dir dependency */ if (config->metacopy && config->redirect_mode != OVL_REDIRECT_ON) { if (set.metacopy && set.redirect) {
pr_err("conflicting options: metacopy=on,redirect_dir=%s\n",
ovl_redirect_mode(config)); return -EINVAL;
} if (set.redirect) { /* * There was an explicit redirect_dir=... that resulted * in this conflict.
*/
pr_info("disabling metacopy due to redirect_dir=%s\n",
ovl_redirect_mode(config));
config->metacopy = false;
} else { /* Automatically enable redirect otherwise. */
config->redirect_mode = OVL_REDIRECT_ON;
}
}
/* Resolve nfs_export -> index dependency */ if (config->nfs_export && !config->index) { if (!config->upperdir &&
config->redirect_mode != OVL_REDIRECT_NOFOLLOW) {
pr_info("NFS export requires \"redirect_dir=nofollow\" on non-upper mount, falling back to nfs_export=off.\n");
config->nfs_export = false;
} elseif (set.nfs_export && set.index) {
pr_err("conflicting options: nfs_export=on,index=off\n"); return -EINVAL;
} elseif (set.index) { /* * There was an explicit index=off that resulted * in this conflict.
*/
pr_info("disabling nfs_export due to index=off\n");
config->nfs_export = false;
} else { /* Automatically enable index otherwise. */
config->index = true;
}
}
/* Resolve nfs_export -> !metacopy && !verity dependency */ if (config->nfs_export && config->metacopy) { if (set.nfs_export && set.metacopy) {
pr_err("conflicting options: nfs_export=on,metacopy=on\n"); return -EINVAL;
} if (set.metacopy) { /* * There was an explicit metacopy=on that resulted * in this conflict.
*/
pr_info("disabling nfs_export due to metacopy=on\n");
config->nfs_export = false;
} elseif (config->verity_mode) { /* * There was an explicit verity=.. that resulted * in this conflict.
*/
pr_info("disabling nfs_export due to verity=%s\n",
ovl_verity_mode(config));
config->nfs_export = false;
} else { /* * There was an explicit nfs_export=on that resulted * in this conflict.
*/
pr_info("disabling metacopy due to nfs_export=on\n");
config->metacopy = false;
}
}
/* Resolve userxattr -> !redirect && !metacopy dependency */ if (config->userxattr) { if (set.redirect &&
config->redirect_mode != OVL_REDIRECT_NOFOLLOW) {
pr_err("conflicting options: userxattr,redirect_dir=%s\n",
ovl_redirect_mode(config)); return -EINVAL;
} if (config->metacopy && set.metacopy) {
pr_err("conflicting options: userxattr,metacopy=on\n"); return -EINVAL;
} /* * Silently disable default setting of redirect and metacopy. * This shall be the default in the future as well: these * options must be explicitly enabled if used together with * userxattr.
*/
config->redirect_mode = OVL_REDIRECT_NOFOLLOW;
config->metacopy = false;
}
/* * Fail if we don't have trusted xattr capability and a feature was * explicitly requested that requires them.
*/ if (!config->userxattr && !capable(CAP_SYS_ADMIN)) { if (set.redirect &&
config->redirect_mode != OVL_REDIRECT_NOFOLLOW) {
pr_err("redirect_dir requires permission to access trusted xattrs\n"); return -EPERM;
} if (config->metacopy && set.metacopy) {
pr_err("metacopy requires permission to access trusted xattrs\n"); return -EPERM;
} if (config->verity_mode) {
pr_err("verity requires permission to access trusted xattrs\n"); return -EPERM;
} if (ctx->nr_data > 0) {
pr_err("lower data-only dirs require permission to access trusted xattrs\n"); return -EPERM;
} /* * Other xattr-dependent features should be disabled without * great disturbance to the user in ovl_make_workdir().
*/
}
return 0;
}
/** * ovl_show_options * @m: the seq_file handle * @dentry: The dentry to query * * Prints the mount options for a given superblock. * Returns zero; does not fail.
*/ int ovl_show_options(struct seq_file *m, struct dentry *dentry)
{ struct super_block *sb = dentry->d_sb; struct ovl_fs *ofs = OVL_FS(sb);
size_t nr, nr_merged_lower, nr_lower = 0; char **lowerdirs = ofs->config.lowerdirs;
/* * lowerdirs[0] holds the colon separated list that user provided * with lowerdir mount option. * lowerdirs[1..numlayer] hold the lowerdir paths that were added * using the lowerdir+ and datadir+ mount options. * For now, we do not allow mixing the legacy lowerdir mount option * with the new lowerdir+ and datadir+ mount options.
*/ if (lowerdirs[0]) {
seq_show_option(m, "lowerdir", lowerdirs[0]);
} else {
nr_lower = ofs->numlayer;
nr_merged_lower = nr_lower - ofs->numdatalayer;
} for (nr = 1; nr < nr_lower; nr++) { if (nr < nr_merged_lower)
seq_show_option(m, "lowerdir+", lowerdirs[nr]); else
seq_show_option(m, "datadir+", lowerdirs[nr]);
} if (ofs->config.upperdir) {
seq_show_option(m, "upperdir", ofs->config.upperdir);
seq_show_option(m, "workdir", ofs->config.workdir);
} if (ofs->config.default_permissions)
seq_puts(m, ",default_permissions"); if (ofs->config.redirect_mode != ovl_redirect_mode_def())
seq_printf(m, ",redirect_dir=%s",
ovl_redirect_mode(&ofs->config)); if (ofs->config.index != ovl_index_def)
seq_printf(m, ",index=%s", str_on_off(ofs->config.index)); if (ofs->config.uuid != ovl_uuid_def())
seq_printf(m, ",uuid=%s", ovl_uuid_mode(&ofs->config)); if (ofs->config.nfs_export != ovl_nfs_export_def)
seq_printf(m, ",nfs_export=%s",
str_on_off(ofs->config.nfs_export)); if (ofs->config.xino != ovl_xino_def() && !ovl_same_fs(ofs))
seq_printf(m, ",xino=%s", ovl_xino_mode(&ofs->config)); if (ofs->config.metacopy != ovl_metacopy_def)
seq_printf(m, ",metacopy=%s", str_on_off(ofs->config.metacopy)); if (ofs->config.ovl_volatile)
seq_puts(m, ",volatile"); if (ofs->config.userxattr)
seq_puts(m, ",userxattr"); if (ofs->config.verity_mode != ovl_verity_mode_def())
seq_printf(m, ",verity=%s",
ovl_verity_mode(&ofs->config)); return 0;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.3 Sekunden
(vorverarbeitet)
¤
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.