core: Validate structure of objects in fsck

This commit is contained in:
Colin Walters 2012-04-03 08:52:58 -04:00
parent 10b2f30165
commit 8792007bc1
3 changed files with 222 additions and 27 deletions

View File

@ -35,30 +35,7 @@ gboolean
ostree_validate_checksum_string (const char *sha256,
GError **error)
{
int i = 0;
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;
return ostree_validate_structureof_checksum_string (sha256, error);
}
gboolean
@ -1477,6 +1454,36 @@ ostree_validate_structureof_checksum (GVariant *checksum,
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
validate_variant (GVariant *variant,
const GVariantType *variant_type,
@ -1498,6 +1505,156 @@ validate_variant (GVariant *variant,
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
ostree_validate_structureof_pack_index (GVariant *index,
GError **error)

View File

@ -60,7 +60,7 @@ typedef enum {
* u - mode
* 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
/*
@ -70,7 +70,7 @@ typedef enum {
* a(ss) - array of (filename, checksum) for files
* 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
/*
@ -84,7 +84,7 @@ typedef enum {
* s - Root tree contents
* 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:
* u - Version
@ -300,6 +300,21 @@ gboolean ostree_validate_structureof_objtype (guint32 objtype,
gboolean ostree_validate_structureof_checksum (GVariant *checksum,
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,
GError **error);

View File

@ -200,6 +200,24 @@ fsck_reachable_objects_from_commits (OtFsckData *data,
if (!ostree_repo_load_variant (data->repo, objtype,
checksum, &metadata, error))
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);
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
|| objtype == OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META)
{
guint32 mode;
if (!ostree_repo_load_file (data->repo, checksum, &input, &file_info,
&xattrs, cancellable, error))
goto out;
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
{