core: Validate structure of objects in fsck
This commit is contained in:
parent
10b2f30165
commit
8792007bc1
|
|
@ -35,30 +35,7 @@ gboolean
|
||||||
ostree_validate_checksum_string (const char *sha256,
|
ostree_validate_checksum_string (const char *sha256,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
int i = 0;
|
return ostree_validate_structureof_checksum_string (sha256, error);
|
||||||
size_t len = strlen (sha256);
|
|
||||||
|
|
||||||
if (len != 64)
|
|
||||||
{
|
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
||||||
"Invalid rev '%s'", sha256);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
guint8 c = ((guint8*) sha256)[i];
|
|
||||||
|
|
||||||
if (!((c >= 48 && c <= 57)
|
|
||||||
|| (c >= 97 && c <= 102)))
|
|
||||||
{
|
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
||||||
"Invalid character '%d' in rev '%s'",
|
|
||||||
c, sha256);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
|
|
@ -1477,6 +1454,36 @@ ostree_validate_structureof_checksum (GVariant *checksum,
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
ostree_validate_structureof_checksum_string (const char *checksum,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
size_t len = strlen (checksum);
|
||||||
|
|
||||||
|
if (len != 64)
|
||||||
|
{
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
"Invalid rev '%s'", checksum);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
guint8 c = ((guint8*) checksum)[i];
|
||||||
|
|
||||||
|
if (!((c >= 48 && c <= 57)
|
||||||
|
|| (c >= 97 && c <= 102)))
|
||||||
|
{
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
"Invalid character '%d' in rev '%s'",
|
||||||
|
c, checksum);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
validate_variant (GVariant *variant,
|
validate_variant (GVariant *variant,
|
||||||
const GVariantType *variant_type,
|
const GVariantType *variant_type,
|
||||||
|
|
@ -1498,6 +1505,156 @@ validate_variant (GVariant *variant,
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
ostree_validate_structureof_commit (GVariant *commit,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
const char *parent;
|
||||||
|
const char *contents;
|
||||||
|
const char *metadata;
|
||||||
|
|
||||||
|
if (!validate_variant (commit, OSTREE_COMMIT_GVARIANT_FORMAT, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
g_variant_get_child (commit, 2, "&s", &parent);
|
||||||
|
|
||||||
|
if (*parent)
|
||||||
|
{
|
||||||
|
if (!ostree_validate_structureof_checksum_string (parent, error))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_variant_get_child (commit, 6, "&s", &contents);
|
||||||
|
if (!ostree_validate_structureof_checksum_string (contents, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
g_variant_get_child (commit, 7, "&s", &metadata);
|
||||||
|
if (!ostree_validate_structureof_checksum_string (metadata, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
ostree_validate_structureof_dirtree (GVariant *dirtree,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
GVariantIter *contents_iter = NULL;
|
||||||
|
const char *filename;
|
||||||
|
const char *meta_checksum;
|
||||||
|
const char *content_checksum;
|
||||||
|
|
||||||
|
if (!validate_variant (dirtree, OSTREE_TREE_GVARIANT_FORMAT, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
g_variant_get_child (dirtree, 2, "a(ss)", &contents_iter);
|
||||||
|
|
||||||
|
while (g_variant_iter_loop (contents_iter, "(&s&s)",
|
||||||
|
&filename, &content_checksum))
|
||||||
|
{
|
||||||
|
if (!ot_util_filename_validate (filename, error))
|
||||||
|
goto out;
|
||||||
|
if (!ostree_validate_structureof_checksum_string (content_checksum, error))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_variant_iter_free (contents_iter);
|
||||||
|
g_variant_get_child (dirtree, 3, "a(sss)", &contents_iter);
|
||||||
|
|
||||||
|
while (g_variant_iter_loop (contents_iter, "(&s&s&s)",
|
||||||
|
&filename, &content_checksum, &meta_checksum))
|
||||||
|
{
|
||||||
|
if (!ot_util_filename_validate (filename, error))
|
||||||
|
goto out;
|
||||||
|
if (!ostree_validate_structureof_checksum_string (content_checksum, error))
|
||||||
|
goto out;
|
||||||
|
if (!ostree_validate_structureof_checksum_string (meta_checksum, error))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
out:
|
||||||
|
if (contents_iter)
|
||||||
|
g_variant_iter_free (contents_iter);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
validate_stat_mode_perms (guint32 mode,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
guint32 otherbits = (~S_IFMT & ~S_IRWXU & ~S_IRWXG & ~S_IRWXO);
|
||||||
|
|
||||||
|
if (mode & otherbits)
|
||||||
|
{
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
"Invalid mode %u; invalid bits in mode", mode);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
ostree_validate_structureof_file_mode (guint32 mode,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
|
||||||
|
if (!(S_ISREG (mode)
|
||||||
|
|| S_ISLNK (mode)
|
||||||
|
|| S_ISCHR (mode)
|
||||||
|
|| S_ISBLK (mode)
|
||||||
|
|| S_ISFIFO (mode)))
|
||||||
|
{
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
"Invalid file metadata mode %u; not a valid file type", mode);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validate_stat_mode_perms (mode, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
ostree_validate_structureof_dirmeta (GVariant *dirmeta,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
guint32 mode;
|
||||||
|
|
||||||
|
if (!validate_variant (dirmeta, OSTREE_DIRMETA_GVARIANT_FORMAT, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
g_variant_get_child (dirmeta, 3, "u", &mode);
|
||||||
|
mode = GUINT32_FROM_BE (mode);
|
||||||
|
|
||||||
|
if (!S_ISDIR (mode))
|
||||||
|
{
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
"Invalid directory metadata mode %u; not a directory", mode);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validate_stat_mode_perms (mode, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
ostree_validate_structureof_pack_index (GVariant *index,
|
ostree_validate_structureof_pack_index (GVariant *index,
|
||||||
GError **error)
|
GError **error)
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ typedef enum {
|
||||||
* u - mode
|
* u - mode
|
||||||
* a(ayay) - xattrs
|
* a(ayay) - xattrs
|
||||||
*/
|
*/
|
||||||
#define OSTREE_DIRMETA_GVARIANT_FORMAT "(uuuua(ayay))"
|
#define OSTREE_DIRMETA_GVARIANT_FORMAT G_VARIANT_TYPE ("(uuuua(ayay))")
|
||||||
|
|
||||||
#define OSTREE_TREE_VERSION 0
|
#define OSTREE_TREE_VERSION 0
|
||||||
/*
|
/*
|
||||||
|
|
@ -70,7 +70,7 @@ typedef enum {
|
||||||
* a(ss) - array of (filename, checksum) for files
|
* a(ss) - array of (filename, checksum) for files
|
||||||
* a(sss) - array of (dirname, tree_checksum, meta_checksum) for directories
|
* a(sss) - array of (dirname, tree_checksum, meta_checksum) for directories
|
||||||
*/
|
*/
|
||||||
#define OSTREE_TREE_GVARIANT_FORMAT "(ua{sv}a(ss)a(sss)"
|
#define OSTREE_TREE_GVARIANT_FORMAT G_VARIANT_TYPE ("(ua{sv}a(ss)a(sss))")
|
||||||
|
|
||||||
#define OSTREE_COMMIT_VERSION 0
|
#define OSTREE_COMMIT_VERSION 0
|
||||||
/*
|
/*
|
||||||
|
|
@ -84,7 +84,7 @@ typedef enum {
|
||||||
* s - Root tree contents
|
* s - Root tree contents
|
||||||
* s - Root tree metadata
|
* s - Root tree metadata
|
||||||
*/
|
*/
|
||||||
#define OSTREE_COMMIT_GVARIANT_FORMAT "(ua{sv}ssstss)"
|
#define OSTREE_COMMIT_GVARIANT_FORMAT G_VARIANT_TYPE ("(ua{sv}ssstss)")
|
||||||
|
|
||||||
/* Archive file objects:
|
/* Archive file objects:
|
||||||
* u - Version
|
* u - Version
|
||||||
|
|
@ -300,6 +300,21 @@ gboolean ostree_validate_structureof_objtype (guint32 objtype,
|
||||||
gboolean ostree_validate_structureof_checksum (GVariant *checksum,
|
gboolean ostree_validate_structureof_checksum (GVariant *checksum,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
|
gboolean ostree_validate_structureof_checksum_string (const char *checksum,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
gboolean ostree_validate_structureof_file_mode (guint32 mode,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
gboolean ostree_validate_structureof_commit (GVariant *index,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
gboolean ostree_validate_structureof_dirtree (GVariant *index,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
gboolean ostree_validate_structureof_dirmeta (GVariant *index,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
gboolean ostree_validate_structureof_pack_index (GVariant *index,
|
gboolean ostree_validate_structureof_pack_index (GVariant *index,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -200,6 +200,24 @@ fsck_reachable_objects_from_commits (OtFsckData *data,
|
||||||
if (!ostree_repo_load_variant (data->repo, objtype,
|
if (!ostree_repo_load_variant (data->repo, objtype,
|
||||||
checksum, &metadata, error))
|
checksum, &metadata, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
|
||||||
|
{
|
||||||
|
if (!ostree_validate_structureof_commit (metadata, error))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
else if (objtype == OSTREE_OBJECT_TYPE_DIR_TREE)
|
||||||
|
{
|
||||||
|
if (!ostree_validate_structureof_dirtree (metadata, error))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
else if (objtype == OSTREE_OBJECT_TYPE_DIR_META)
|
||||||
|
{
|
||||||
|
if (!ostree_validate_structureof_dirmeta (metadata, error))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
g_assert_not_reached ();
|
||||||
|
|
||||||
ot_clear_gvariant (&metadata_wrapped);
|
ot_clear_gvariant (&metadata_wrapped);
|
||||||
metadata_wrapped = ostree_wrap_metadata_variant (objtype, metadata);
|
metadata_wrapped = ostree_wrap_metadata_variant (objtype, metadata);
|
||||||
|
|
@ -216,10 +234,15 @@ fsck_reachable_objects_from_commits (OtFsckData *data,
|
||||||
else if (objtype == OSTREE_OBJECT_TYPE_RAW_FILE
|
else if (objtype == OSTREE_OBJECT_TYPE_RAW_FILE
|
||||||
|| objtype == OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META)
|
|| objtype == OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META)
|
||||||
{
|
{
|
||||||
|
guint32 mode;
|
||||||
if (!ostree_repo_load_file (data->repo, checksum, &input, &file_info,
|
if (!ostree_repo_load_file (data->repo, checksum, &input, &file_info,
|
||||||
&xattrs, cancellable, error))
|
&xattrs, cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
checksum_objtype = OSTREE_OBJECT_TYPE_RAW_FILE; /* Override */
|
checksum_objtype = OSTREE_OBJECT_TYPE_RAW_FILE; /* Override */
|
||||||
|
|
||||||
|
mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode");
|
||||||
|
if (!ostree_validate_structureof_file_mode (mode, error))
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue