repo: Move fsverity bits to ostree-repo-verity.c
This file will get larger when we start doing more with fsverity.
This commit is contained in:
parent
0b90f1f9a8
commit
441233b51c
|
|
@ -101,6 +101,7 @@ libostree_1_la_SOURCES = \
|
||||||
src/libostree/ostree-repo-libarchive.c \
|
src/libostree/ostree-repo-libarchive.c \
|
||||||
src/libostree/ostree-repo-prune.c \
|
src/libostree/ostree-repo-prune.c \
|
||||||
src/libostree/ostree-repo-refs.c \
|
src/libostree/ostree-repo-refs.c \
|
||||||
|
src/libostree/ostree-repo-verity.c \
|
||||||
src/libostree/ostree-repo-traverse.c \
|
src/libostree/ostree-repo-traverse.c \
|
||||||
src/libostree/ostree-repo-private.h \
|
src/libostree/ostree-repo-private.h \
|
||||||
src/libostree/ostree-repo-file.c \
|
src/libostree/ostree-repo-file.c \
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,6 @@
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <ext2fs/ext2_fs.h>
|
#include <ext2fs/ext2_fs.h>
|
||||||
#ifdef HAVE_LINUX_FSVERITY_H
|
|
||||||
#include <linux/fsverity.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "otutil.h"
|
#include "otutil.h"
|
||||||
#include "ostree.h"
|
#include "ostree.h"
|
||||||
|
|
@ -190,113 +187,6 @@ ot_security_smack_reset_fd (int fd)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wrapper around the fsverity ioctl, compressing the result to
|
|
||||||
* "success, unsupported or error". This is used for /boot where
|
|
||||||
* we enable verity if supported.
|
|
||||||
* */
|
|
||||||
gboolean
|
|
||||||
_ostree_tmpf_fsverity_core (GLnxTmpfile *tmpf,
|
|
||||||
_OstreeFeatureSupport fsverity_requested,
|
|
||||||
gboolean *supported,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
/* Set this by default to simplify the code below */
|
|
||||||
if (supported)
|
|
||||||
*supported = FALSE;
|
|
||||||
|
|
||||||
if (fsverity_requested == _OSTREE_FEATURE_NO)
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
#ifdef HAVE_LINUX_FSVERITY_H
|
|
||||||
GLNX_AUTO_PREFIX_ERROR ("fsverity", error);
|
|
||||||
|
|
||||||
/* fs-verity requires a read-only file descriptor */
|
|
||||||
if (!glnx_tmpfile_reopen_rdonly (tmpf, error))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
struct fsverity_enable_arg arg = { 0, };
|
|
||||||
arg.version = 1;
|
|
||||||
arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256; /* TODO configurable? */
|
|
||||||
arg.block_size = 4096; /* FIXME query */
|
|
||||||
arg.salt_size = 0; /* TODO store salt in ostree repo config */
|
|
||||||
arg.salt_ptr = 0;
|
|
||||||
arg.sig_size = 0; /* We don't currently expect use of in-kernel signature verification */
|
|
||||||
arg.sig_ptr = 0;
|
|
||||||
|
|
||||||
if (ioctl (tmpf->fd, FS_IOC_ENABLE_VERITY, &arg) < 0)
|
|
||||||
{
|
|
||||||
switch (errno)
|
|
||||||
{
|
|
||||||
case ENOTTY:
|
|
||||||
case EOPNOTSUPP:
|
|
||||||
return TRUE;
|
|
||||||
default:
|
|
||||||
return glnx_throw_errno_prefix (error, "ioctl(FS_IOC_ENABLE_VERITY)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (supported)
|
|
||||||
*supported = TRUE;
|
|
||||||
#endif
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Enable verity on a file, respecting the "wanted" and "supported" states.
|
|
||||||
* The main idea here is to optimize out pointlessly calling the ioctl()
|
|
||||||
* over and over in cases where it's not supported for the repo's filesystem,
|
|
||||||
* as well as to support "opportunistic" use (requested and if filesystem supports).
|
|
||||||
* */
|
|
||||||
gboolean
|
|
||||||
_ostree_tmpf_fsverity (OstreeRepo *self,
|
|
||||||
GLnxTmpfile *tmpf,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
#ifdef HAVE_LINUX_FSVERITY_H
|
|
||||||
g_mutex_lock (&self->txn_lock);
|
|
||||||
_OstreeFeatureSupport fsverity_wanted = self->fs_verity_wanted;
|
|
||||||
_OstreeFeatureSupport fsverity_supported = self->fs_verity_supported;
|
|
||||||
g_mutex_unlock (&self->txn_lock);
|
|
||||||
|
|
||||||
switch (fsverity_wanted)
|
|
||||||
{
|
|
||||||
case _OSTREE_FEATURE_YES:
|
|
||||||
{
|
|
||||||
if (fsverity_supported == _OSTREE_FEATURE_NO)
|
|
||||||
return glnx_throw (error, "fsverity required but filesystem does not support it");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case _OSTREE_FEATURE_MAYBE:
|
|
||||||
break;
|
|
||||||
case _OSTREE_FEATURE_NO:
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean supported = FALSE;
|
|
||||||
if (!_ostree_tmpf_fsverity_core (tmpf, fsverity_wanted, &supported, error))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
if (!supported)
|
|
||||||
{
|
|
||||||
if (G_UNLIKELY (fsverity_wanted == _OSTREE_FEATURE_YES))
|
|
||||||
return glnx_throw (error, "fsverity required but filesystem does not support it");
|
|
||||||
|
|
||||||
/* If we got here, we must be trying "opportunistic" use of fs-verity */
|
|
||||||
g_assert_cmpint (fsverity_wanted, ==, _OSTREE_FEATURE_MAYBE);
|
|
||||||
g_mutex_lock (&self->txn_lock);
|
|
||||||
self->fs_verity_supported = _OSTREE_FEATURE_NO;
|
|
||||||
g_mutex_unlock (&self->txn_lock);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_mutex_lock (&self->txn_lock);
|
|
||||||
self->fs_verity_supported = _OSTREE_FEATURE_YES;
|
|
||||||
g_mutex_unlock (&self->txn_lock);
|
|
||||||
#else
|
|
||||||
g_assert_cmpint (self->fs_verity_wanted, !=, _OSTREE_FEATURE_YES);
|
|
||||||
#endif
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Given an O_TMPFILE regular file, link it into place. */
|
/* Given an O_TMPFILE regular file, link it into place. */
|
||||||
gboolean
|
gboolean
|
||||||
_ostree_repo_commit_tmpf_final (OstreeRepo *self,
|
_ostree_repo_commit_tmpf_final (OstreeRepo *self,
|
||||||
|
|
|
||||||
|
|
@ -521,6 +521,8 @@ OstreeRepoAutoLock * _ostree_repo_auto_lock_push (OstreeRepo *self,
|
||||||
void _ostree_repo_auto_lock_cleanup (OstreeRepoAutoLock *lock);
|
void _ostree_repo_auto_lock_cleanup (OstreeRepoAutoLock *lock);
|
||||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoAutoLock, _ostree_repo_auto_lock_cleanup)
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoAutoLock, _ostree_repo_auto_lock_cleanup)
|
||||||
|
|
||||||
|
gboolean _ostree_repo_parse_fsverity_config (OstreeRepo *self, GError **error);
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
_ostree_tmpf_fsverity_core (GLnxTmpfile *tmpf,
|
_ostree_tmpf_fsverity_core (GLnxTmpfile *tmpf,
|
||||||
_OstreeFeatureSupport fsverity_requested,
|
_OstreeFeatureSupport fsverity_requested,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,174 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.0+
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
#include "ostree-core-private.h"
|
||||||
|
#include "ostree-repo-private.h"
|
||||||
|
#include "otutil.h"
|
||||||
|
#include "ot-fs-utils.h"
|
||||||
|
#ifdef HAVE_LINUX_FSVERITY_H
|
||||||
|
#include <linux/fsverity.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
_ostree_repo_parse_fsverity_config (OstreeRepo *self, GError **error)
|
||||||
|
{
|
||||||
|
/* Currently experimental */
|
||||||
|
static const char fsverity_key[] = "ex-fsverity";
|
||||||
|
self->fs_verity_wanted = _OSTREE_FEATURE_NO;
|
||||||
|
#ifdef HAVE_LINUX_FSVERITY_H
|
||||||
|
self->fs_verity_supported = _OSTREE_FEATURE_MAYBE;
|
||||||
|
#else
|
||||||
|
self->fs_verity_supported = _OSTREE_FEATURE_NO;
|
||||||
|
#endif
|
||||||
|
gboolean fsverity_required = FALSE;
|
||||||
|
if (!ot_keyfile_get_boolean_with_default (self->config, fsverity_key, "required",
|
||||||
|
FALSE, &fsverity_required, error))
|
||||||
|
return FALSE;
|
||||||
|
if (fsverity_required)
|
||||||
|
{
|
||||||
|
self->fs_verity_wanted = _OSTREE_FEATURE_YES;
|
||||||
|
if (self->fs_verity_supported == _OSTREE_FEATURE_NO)
|
||||||
|
return glnx_throw (error, "fsverity required, but libostree compiled without support");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gboolean fsverity_opportunistic = FALSE;
|
||||||
|
if (!ot_keyfile_get_boolean_with_default (self->config, fsverity_key, "opportunistic",
|
||||||
|
FALSE, &fsverity_opportunistic, error))
|
||||||
|
return FALSE;
|
||||||
|
if (fsverity_opportunistic)
|
||||||
|
self->fs_verity_wanted = _OSTREE_FEATURE_MAYBE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Wrapper around the fsverity ioctl, compressing the result to
|
||||||
|
* "success, unsupported or error". This is used for /boot where
|
||||||
|
* we enable verity if supported.
|
||||||
|
* */
|
||||||
|
gboolean
|
||||||
|
_ostree_tmpf_fsverity_core (GLnxTmpfile *tmpf,
|
||||||
|
_OstreeFeatureSupport fsverity_requested,
|
||||||
|
gboolean *supported,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
/* Set this by default to simplify the code below */
|
||||||
|
if (supported)
|
||||||
|
*supported = FALSE;
|
||||||
|
|
||||||
|
if (fsverity_requested == _OSTREE_FEATURE_NO)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
#ifdef HAVE_LINUX_FSVERITY_H
|
||||||
|
GLNX_AUTO_PREFIX_ERROR ("fsverity", error);
|
||||||
|
|
||||||
|
/* fs-verity requires a read-only file descriptor */
|
||||||
|
if (!glnx_tmpfile_reopen_rdonly (tmpf, error))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
struct fsverity_enable_arg arg = { 0, };
|
||||||
|
arg.version = 1;
|
||||||
|
arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256; /* TODO configurable? */
|
||||||
|
arg.block_size = 4096; /* FIXME query */
|
||||||
|
arg.salt_size = 0; /* TODO store salt in ostree repo config */
|
||||||
|
arg.salt_ptr = 0;
|
||||||
|
arg.sig_size = 0; /* We don't currently expect use of in-kernel signature verification */
|
||||||
|
arg.sig_ptr = 0;
|
||||||
|
|
||||||
|
if (ioctl (tmpf->fd, FS_IOC_ENABLE_VERITY, &arg) < 0)
|
||||||
|
{
|
||||||
|
switch (errno)
|
||||||
|
{
|
||||||
|
case ENOTTY:
|
||||||
|
case EOPNOTSUPP:
|
||||||
|
return TRUE;
|
||||||
|
default:
|
||||||
|
return glnx_throw_errno_prefix (error, "ioctl(FS_IOC_ENABLE_VERITY)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supported)
|
||||||
|
*supported = TRUE;
|
||||||
|
#endif
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enable verity on a file, respecting the "wanted" and "supported" states.
|
||||||
|
* The main idea here is to optimize out pointlessly calling the ioctl()
|
||||||
|
* over and over in cases where it's not supported for the repo's filesystem,
|
||||||
|
* as well as to support "opportunistic" use (requested and if filesystem supports).
|
||||||
|
* */
|
||||||
|
gboolean
|
||||||
|
_ostree_tmpf_fsverity (OstreeRepo *self,
|
||||||
|
GLnxTmpfile *tmpf,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_LINUX_FSVERITY_H
|
||||||
|
g_mutex_lock (&self->txn_lock);
|
||||||
|
_OstreeFeatureSupport fsverity_wanted = self->fs_verity_wanted;
|
||||||
|
_OstreeFeatureSupport fsverity_supported = self->fs_verity_supported;
|
||||||
|
g_mutex_unlock (&self->txn_lock);
|
||||||
|
|
||||||
|
switch (fsverity_wanted)
|
||||||
|
{
|
||||||
|
case _OSTREE_FEATURE_YES:
|
||||||
|
{
|
||||||
|
if (fsverity_supported == _OSTREE_FEATURE_NO)
|
||||||
|
return glnx_throw (error, "fsverity required but filesystem does not support it");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case _OSTREE_FEATURE_MAYBE:
|
||||||
|
break;
|
||||||
|
case _OSTREE_FEATURE_NO:
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean supported = FALSE;
|
||||||
|
if (!_ostree_tmpf_fsverity_core (tmpf, fsverity_wanted, &supported, error))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!supported)
|
||||||
|
{
|
||||||
|
if (G_UNLIKELY (fsverity_wanted == _OSTREE_FEATURE_YES))
|
||||||
|
return glnx_throw (error, "fsverity required but filesystem does not support it");
|
||||||
|
|
||||||
|
/* If we got here, we must be trying "opportunistic" use of fs-verity */
|
||||||
|
g_assert_cmpint (fsverity_wanted, ==, _OSTREE_FEATURE_MAYBE);
|
||||||
|
g_mutex_lock (&self->txn_lock);
|
||||||
|
self->fs_verity_supported = _OSTREE_FEATURE_NO;
|
||||||
|
g_mutex_unlock (&self->txn_lock);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_mutex_lock (&self->txn_lock);
|
||||||
|
self->fs_verity_supported = _OSTREE_FEATURE_YES;
|
||||||
|
g_mutex_unlock (&self->txn_lock);
|
||||||
|
#else
|
||||||
|
g_assert_cmpint (self->fs_verity_wanted, !=, _OSTREE_FEATURE_YES);
|
||||||
|
#endif
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
@ -3017,33 +3017,8 @@ reload_core_config (OstreeRepo *self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Currently experimental */
|
if (!_ostree_repo_parse_fsverity_config (self, error))
|
||||||
static const char fsverity_key[] = "ex-fsverity";
|
|
||||||
self->fs_verity_wanted = _OSTREE_FEATURE_NO;
|
|
||||||
#ifdef HAVE_LINUX_FSVERITY_H
|
|
||||||
self->fs_verity_supported = _OSTREE_FEATURE_MAYBE;
|
|
||||||
#else
|
|
||||||
self->fs_verity_supported = _OSTREE_FEATURE_NO;
|
|
||||||
#endif
|
|
||||||
gboolean fsverity_required = FALSE;
|
|
||||||
if (!ot_keyfile_get_boolean_with_default (self->config, fsverity_key, "required",
|
|
||||||
FALSE, &fsverity_required, error))
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
if (fsverity_required)
|
|
||||||
{
|
|
||||||
self->fs_verity_wanted = _OSTREE_FEATURE_YES;
|
|
||||||
if (self->fs_verity_supported == _OSTREE_FEATURE_NO)
|
|
||||||
return glnx_throw (error, "fsverity required, but libostree compiled without support");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gboolean fsverity_opportunistic = FALSE;
|
|
||||||
if (!ot_keyfile_get_boolean_with_default (self->config, fsverity_key, "opportunistic",
|
|
||||||
FALSE, &fsverity_opportunistic, error))
|
|
||||||
return FALSE;
|
|
||||||
if (fsverity_opportunistic)
|
|
||||||
self->fs_verity_wanted = _OSTREE_FEATURE_MAYBE;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
g_clear_pointer (&self->collection_id, g_free);
|
g_clear_pointer (&self->collection_id, g_free);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue