ovl: Add framework for verity support
This adds the scaffolding (docs, config, mount options) for supporting the new digest field in the metacopy xattr. This contains a fs-verity digest that need to match the fs-verity digest of the lowerdata file. The mount option "verity" specifies how this xattr is handled. If you enable verity ("verity=on") all existing xattrs are validated before use, and during metacopy we generate verity xattr in the upper metacopy file (if the source file has verity enabled). This means later accesses can guarantee that the same data is used. Additionally you can use "verity=require". In this mode all metacopy files must have a valid verity xattr. For this to work metadata copy-up must be able to create a verity xattr (so that later accesses are validated). Therefore, in this mode, if the lower data file doesn't have fs-verity enabled we fall back to a full copy rather than a metacopy. Actual implementation follows in a separate commit. Signed-off-by: Alexander Larsson <alexl@redhat.com> Reviewed-by: Amir Goldstein <amir73il@gmail.com> Acked-by: Eric Biggers <ebiggers@google.com> Signed-off-by: Amir Goldstein <amir73il@gmail.com>
This commit is contained in:
parent
52a93d39b1
commit
ae8cba4033
|
@ -326,6 +326,8 @@ the file has fs-verity enabled. This can perform better than
|
|||
FS_IOC_GETFLAGS and FS_IOC_MEASURE_VERITY because it doesn't require
|
||||
opening the file, and opening verity files can be expensive.
|
||||
|
||||
.. _accessing_verity_files:
|
||||
|
||||
Accessing verity files
|
||||
======================
|
||||
|
||||
|
|
|
@ -405,6 +405,53 @@ when a "metacopy" file in one of the lower layers above it, has a "redirect"
|
|||
to the absolute path of the "lower data" file in the "data-only" lower layer.
|
||||
|
||||
|
||||
fs-verity support
|
||||
----------------------
|
||||
|
||||
During metadata copy up of a lower file, if the source file has
|
||||
fs-verity enabled and overlay verity support is enabled, then the
|
||||
digest of the lower file is added to the "trusted.overlay.metacopy"
|
||||
xattr. This is then used to verify the content of the lower file
|
||||
each the time the metacopy file is opened.
|
||||
|
||||
When a layer containing verity xattrs is used, it means that any such
|
||||
metacopy file in the upper layer is guaranteed to match the content
|
||||
that was in the lower at the time of the copy-up. If at any time
|
||||
(during a mount, after a remount, etc) such a file in the lower is
|
||||
replaced or modified in any way, access to the corresponding file in
|
||||
overlayfs will result in EIO errors (either on open, due to overlayfs
|
||||
digest check, or from a later read due to fs-verity) and a detailed
|
||||
error is printed to the kernel logs. For more details of how fs-verity
|
||||
file access works, see :ref:`Documentation/filesystems/fsverity.rst
|
||||
<accessing_verity_files>`.
|
||||
|
||||
Verity can be used as a general robustness check to detect accidental
|
||||
changes in the overlayfs directories in use. But, with additional care
|
||||
it can also give more powerful guarantees. For example, if the upper
|
||||
layer is fully trusted (by using dm-verity or something similar), then
|
||||
an untrusted lower layer can be used to supply validated file content
|
||||
for all metacopy files. If additionally the untrusted lower
|
||||
directories are specified as "Data-only", then they can only supply
|
||||
such file content, and the entire mount can be trusted to match the
|
||||
upper layer.
|
||||
|
||||
This feature is controlled by the "verity" mount option, which
|
||||
supports these values:
|
||||
|
||||
- "off":
|
||||
The metacopy digest is never generated or used. This is the
|
||||
default if verity option is not specified.
|
||||
- "on":
|
||||
Whenever a metacopy files specifies an expected digest, the
|
||||
corresponding data file must match the specified digest. When
|
||||
generating a metacopy file the verity digest will be set in it
|
||||
based on the source file (if it has one).
|
||||
- "require":
|
||||
Same as "on", but additionally all metacopy files must specify a
|
||||
digest (or EIO is returned on open). This means metadata copy up
|
||||
will only be used if the data file has fs-verity enabled,
|
||||
otherwise a full copy-up is used.
|
||||
|
||||
Sharing and copying layers
|
||||
--------------------------
|
||||
|
||||
|
|
|
@ -70,6 +70,12 @@ enum {
|
|||
OVL_XINO_ON,
|
||||
};
|
||||
|
||||
enum {
|
||||
OVL_VERITY_OFF,
|
||||
OVL_VERITY_ON,
|
||||
OVL_VERITY_REQUIRE,
|
||||
};
|
||||
|
||||
/*
|
||||
* The tuple (fh,uuid) is a universal unique identifier for a copy up origin,
|
||||
* where:
|
||||
|
|
|
@ -10,6 +10,7 @@ struct ovl_config {
|
|||
char *workdir;
|
||||
bool default_permissions;
|
||||
int redirect_mode;
|
||||
int verity_mode;
|
||||
bool index;
|
||||
bool uuid;
|
||||
bool nfs_export;
|
||||
|
|
|
@ -55,6 +55,7 @@ enum {
|
|||
Opt_userxattr,
|
||||
Opt_xino,
|
||||
Opt_metacopy,
|
||||
Opt_verity,
|
||||
Opt_volatile,
|
||||
};
|
||||
|
||||
|
@ -101,6 +102,23 @@ static int ovl_redirect_mode_def(void)
|
|||
OVL_REDIRECT_NOFOLLOW;
|
||||
}
|
||||
|
||||
static const struct constant_table ovl_parameter_verity[] = {
|
||||
{ "off", OVL_VERITY_OFF },
|
||||
{ "on", OVL_VERITY_ON },
|
||||
{ "require", OVL_VERITY_REQUIRE },
|
||||
{}
|
||||
};
|
||||
|
||||
static const char *ovl_verity_mode(struct ovl_config *config)
|
||||
{
|
||||
return ovl_parameter_verity[config->verity_mode].name;
|
||||
}
|
||||
|
||||
static int ovl_verity_mode_def(void)
|
||||
{
|
||||
return OVL_VERITY_OFF;
|
||||
}
|
||||
|
||||
#define fsparam_string_empty(NAME, OPT) \
|
||||
__fsparam(fs_param_is_string, NAME, OPT, fs_param_can_be_empty, NULL)
|
||||
|
||||
|
@ -116,6 +134,7 @@ const struct fs_parameter_spec ovl_parameter_spec[] = {
|
|||
fsparam_flag("userxattr", Opt_userxattr),
|
||||
fsparam_enum("xino", Opt_xino, ovl_parameter_xino),
|
||||
fsparam_enum("metacopy", Opt_metacopy, ovl_parameter_bool),
|
||||
fsparam_enum("verity", Opt_verity, ovl_parameter_verity),
|
||||
fsparam_flag("volatile", Opt_volatile),
|
||||
{}
|
||||
};
|
||||
|
@ -572,6 +591,9 @@ static int ovl_parse_param(struct fs_context *fc, struct fs_parameter *param)
|
|||
config->metacopy = result.uint_32;
|
||||
ctx->set.metacopy = true;
|
||||
break;
|
||||
case Opt_verity:
|
||||
config->verity_mode = result.uint_32;
|
||||
break;
|
||||
case Opt_volatile:
|
||||
config->ovl_volatile = true;
|
||||
break;
|
||||
|
@ -762,6 +784,18 @@ int ovl_fs_params_verify(const struct ovl_fs_context *ctx,
|
|||
config->ovl_volatile = false;
|
||||
}
|
||||
|
||||
/* Resolve verity -> metacopy dependency */
|
||||
if (config->verity_mode && !config->metacopy) {
|
||||
/* Don't allow explicit specified conflicting combinations */
|
||||
if (set.metacopy) {
|
||||
pr_err("conflicting options: metacopy=off,verity=%s\n",
|
||||
ovl_verity_mode(config));
|
||||
return -EINVAL;
|
||||
}
|
||||
/* Otherwise automatically enable metacopy. */
|
||||
config->metacopy = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is to make the logic below simpler. It doesn't make any other
|
||||
* difference, since redirect_dir=on is only used for upper.
|
||||
|
@ -769,13 +803,18 @@ int ovl_fs_params_verify(const struct ovl_fs_context *ctx,
|
|||
if (!config->upperdir && config->redirect_mode == OVL_REDIRECT_FOLLOW)
|
||||
config->redirect_mode = OVL_REDIRECT_ON;
|
||||
|
||||
/* Resolve metacopy -> redirect_dir dependency */
|
||||
/* Resolve verity -> 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 (config->verity_mode && set.redirect) {
|
||||
pr_err("conflicting options: verity=%s,redirect_dir=%s\n",
|
||||
ovl_verity_mode(config), ovl_redirect_mode(config));
|
||||
return -EINVAL;
|
||||
}
|
||||
if (set.redirect) {
|
||||
/*
|
||||
* There was an explicit redirect_dir=... that resulted
|
||||
|
@ -812,7 +851,7 @@ int ovl_fs_params_verify(const struct ovl_fs_context *ctx,
|
|||
}
|
||||
}
|
||||
|
||||
/* Resolve nfs_export -> !metacopy dependency */
|
||||
/* 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");
|
||||
|
@ -825,6 +864,14 @@ int ovl_fs_params_verify(const struct ovl_fs_context *ctx,
|
|||
*/
|
||||
pr_info("disabling nfs_export due to metacopy=on\n");
|
||||
config->nfs_export = false;
|
||||
} else if (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
|
||||
|
@ -836,7 +883,7 @@ int ovl_fs_params_verify(const struct ovl_fs_context *ctx,
|
|||
}
|
||||
|
||||
|
||||
/* Resolve userxattr -> !redirect && !metacopy dependency */
|
||||
/* Resolve userxattr -> !redirect && !metacopy && !verity dependency */
|
||||
if (config->userxattr) {
|
||||
if (set.redirect &&
|
||||
config->redirect_mode != OVL_REDIRECT_NOFOLLOW) {
|
||||
|
@ -848,6 +895,11 @@ int ovl_fs_params_verify(const struct ovl_fs_context *ctx,
|
|||
pr_err("conflicting options: userxattr,metacopy=on\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (config->verity_mode) {
|
||||
pr_err("conflicting options: userxattr,verity=%s\n",
|
||||
ovl_verity_mode(config));
|
||||
return -EINVAL;
|
||||
}
|
||||
/*
|
||||
* Silently disable default setting of redirect and metacopy.
|
||||
* This shall be the default in the future as well: these
|
||||
|
@ -909,5 +961,8 @@ int ovl_show_options(struct seq_file *m, struct dentry *dentry)
|
|||
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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue