deltas: Handle untrusted checksums faster and more robustly
When reworking the ostree core [to use O_TMPFILE](https://github.com/ostreedev/ostree/pull/369), I hit an issue in the way the untrusted delta codepath ends up trying to re-open the file to checksum it. That's not possible with `O_TMPFILE` since the fd (which we opened `O_WRONLY`) is the only accessible reference to the content. Fix this by changing the delta processing code to update a checksum as we're doing writes, which is also faster, and ends up simplifying the code as well. What would be an even larger simplification here is if we e.g. used a separate thread calling `write_object()` or something like that; the main issue I see there is somehow bridging the fact that function wants a `GInputStream*` but the delta code is generating stream of writes. Closes: #392 Approved by: jlebon
This commit is contained in:
1 parent
fb0bf27d10
commit
6ffcb24d22
5 files changed
+126
-195
No files matched your search
@@ -446,109 +446,14 @@ fallocate_stream (GFileDescriptorBased *stream,
|
||||
}
|
||||
|
||||
gboolean
|
||||
_ostree_repo_open_untrusted_content_bare (OstreeRepo *self,
|
||||
const char *expected_checksum,
|
||||
guint64 content_len,
|
||||
OstreeRepoContentBareCommit *out_state,
|
||||
GOutputStream **out_stream,
|
||||
gboolean *out_have_object,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
/* The trusted codepath is fine here */
|
||||
return _ostree_repo_open_trusted_content_bare (self,
|
||||
expected_checksum,
|
||||
content_len,
|
||||
out_state,
|
||||
out_stream,
|
||||
out_have_object,
|
||||
cancellable,
|
||||
error);
|
||||
}
|
||||
|
||||
gboolean
|
||||
_ostree_repo_commit_untrusted_content_bare (OstreeRepo *self,
|
||||
const char *expected_checksum,
|
||||
OstreeRepoContentBareCommit *state,
|
||||
guint32 uid,
|
||||
guint32 gid,
|
||||
guint32 mode,
|
||||
GVariant *xattrs,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
|
||||
if (state->fd != -1)
|
||||
{
|
||||
GMappedFile *mapped;
|
||||
g_autoptr(GBytes) bytes = NULL;
|
||||
g_autoptr(GInputStream) raw_in = NULL;
|
||||
g_autoptr(GInputStream) in = NULL;
|
||||
g_autoptr(GFileInfo) file_info = NULL;
|
||||
g_autofree guchar *actual_csum = NULL;
|
||||
g_autofree char *actual_checksum = NULL;
|
||||
int fd;
|
||||
|
||||
fd = openat (self->tmp_dir_fd, state->temp_filename, O_RDONLY);
|
||||
if (fd == -1)
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
mapped = g_mapped_file_new_from_fd (fd, FALSE, error);
|
||||
|
||||
close (fd);
|
||||
if (mapped == NULL)
|
||||
goto out;
|
||||
|
||||
bytes = g_mapped_file_get_bytes (mapped);
|
||||
g_mapped_file_unref (mapped);
|
||||
|
||||
raw_in = g_memory_input_stream_new_from_bytes (bytes);
|
||||
|
||||
file_info = _ostree_header_gfile_info_new (mode, uid, gid);
|
||||
|
||||
if (!ostree_raw_file_to_content_stream (raw_in, file_info, xattrs, &in, NULL, cancellable, error))
|
||||
goto out;
|
||||
|
||||
if (!ot_gio_checksum_stream (in, &actual_csum, cancellable, error))
|
||||
goto out;
|
||||
|
||||
actual_checksum = ostree_checksum_from_bytes (actual_csum);
|
||||
|
||||
if (strcmp (actual_checksum, expected_checksum) != 0)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Corrupted object %s (actual checksum is %s)",
|
||||
expected_checksum, actual_checksum);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!commit_loose_object_trusted (self, expected_checksum, OSTREE_OBJECT_TYPE_FILE,
|
||||
state->temp_filename,
|
||||
FALSE, uid, gid, mode,
|
||||
xattrs, state->fd,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
g_free (state->temp_filename);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean
|
||||
_ostree_repo_open_trusted_content_bare (OstreeRepo *self,
|
||||
const char *checksum,
|
||||
guint64 content_len,
|
||||
OstreeRepoContentBareCommit *out_state,
|
||||
GOutputStream **out_stream,
|
||||
gboolean *out_have_object,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
_ostree_repo_open_content_bare (OstreeRepo *self,
|
||||
const char *checksum,
|
||||
guint64 content_len,
|
||||
OstreeRepoContentBareCommit *out_state,
|
||||
GOutputStream **out_stream,
|
||||
gboolean *out_have_object,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
g_autofree char *temp_filename = NULL;
|
||||
|
||||
Reference in new issue
Block a user