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:
Alexander Larsson 2023-04-19 13:44:21 +02:00 committed by Amir Goldstein
parent 52a93d39b1
commit ae8cba4033
5 changed files with 114 additions and 3 deletions

View File

@ -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
======================

View File

@ -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
--------------------------

View File

@ -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:

View File

@ -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;

View File

@ -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;
}