summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Kitt <steve@sk2.org>2015-03-12 05:54:00 +0000
committerMarc-André Lureau <marcandre.lureau@gmail.com>2015-03-12 20:57:25 +0100
commitbe1d0a23b4aa4f43e89b405edaaccbab8c50eee8 (patch)
treebb071741e5266238c40e57586d6430ed343b9924
parentc68131bb16366d87041ce3ae3ac510a2c1e4ba88 (diff)
downloadgcab-be1d0a23b4aa4f43e89b405edaaccbab8c50eee8.tar.gz
Fix for the AFL-detected crashes
Jakub Wilk pointed out at https://bugs.debian.org/775941 that AFL (http://lcamtuf.coredump.cx/afl/) finds quite a few crashes caused by invalid CABs. They're mostly due to either missing input validation or error paths which don't fill in error information; the attached patch fixes these. With the patch applied AFL no longer finds any crashes. https://bugzilla.gnome.org/show_bug.cgi?id=743389
-rw-r--r--gcab.c18
-rw-r--r--libgcab/cabinet.c19
-rw-r--r--libgcab/gcab-cabinet.c14
-rw-r--r--libgcab/gcab-folder.c11
4 files changed, 46 insertions, 16 deletions
diff --git a/gcab.c b/gcab.c
index 7ee8614..88836f0 100644
--- a/gcab.c
+++ b/gcab.c
@@ -140,7 +140,7 @@ individual files from the archive.\
g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
if (!g_option_context_parse (context, &argc, &argv, &error))
- gcab_error (_("option parsing failed: %s\n"), error->message);
+ gcab_error (_("option parsing failed: %s\n"), (error && error->message) ? error->message : "unknown error");
g_option_context_free(context);
if (version) {
@@ -166,9 +166,9 @@ individual files from the archive.\
GInputStream *in = G_INPUT_STREAM (g_file_read (file, cancellable, &error));
if (!in)
- gcab_error (_("can't open %s for reading: %s\n"), args[0], error->message);
+ gcab_error (_("can't open %s for reading: %s\n"), args[0], (error && error->message) ? error->message : "unknown error");
if (!gcab_cabinet_load (cabinet, in, cancellable, &error))
- gcab_error (_("error reading %s: %s\n"), args[0], error->message);
+ gcab_error (_("error reading %s: %s\n"), args[0], (error && error->message) ? error->message : "unknown error");
if (list) {
GPtrArray *folders = gcab_cabinet_get_folders (cabinet);
@@ -185,7 +185,7 @@ individual files from the archive.\
file = g_file_new_for_path (change);
if (!gcab_cabinet_extract (cabinet, file, file_callback, NULL, NULL, cancellable, &error))
- gcab_error (_("error during extraction: %s"), error->message);
+ gcab_error (_("error during extraction: %s"), (error && error->message) ? error->message : "unknown error");
} else if (dump_reserved) {
GByteArray *reserved;
@@ -197,7 +197,7 @@ individual files from the archive.\
reserved = (GByteArray *)gcab_cabinet_get_signature (cabinet, cancellable, &error);
if (error)
- gcab_error (_("error while reading signature: %s"), error->message);
+ gcab_error (_("error while reading signature: %s"), (error && error->message) ? error->message : "unknown error");
if (reserved != NULL)
save_array_to_file (reserved, args[0], "signature");
}
@@ -226,7 +226,7 @@ individual files from the archive.\
remove_leading_path (name), file);
if (!gcab_folder_add_file (folder, cabfile, TRUE, NULL, &error)) {
- g_warning (_("Can't add file %s: %s"), args[i], error->message);
+ g_warning (_("Can't add file %s: %s"), args[i], (error && error->message) ? error->message : "unknown error");
g_clear_error (&error);
}
@@ -242,11 +242,11 @@ individual files from the archive.\
output = G_OUTPUT_STREAM (g_file_replace (outputfile, NULL, FALSE,
0, NULL, &error));
if (error)
- gcab_error (_("can't create cab file %s: %s"), args[0], error->message);
+ gcab_error (_("can't create cab file %s: %s"), args[0], (error && error->message) ? error->message : "unknown error");
cwd = g_file_new_for_commandline_arg (".");
if (!gcab_cabinet_add_folder (cabinet, folder, &error))
- gcab_error (_("can't add folder to cab file %s: %s"), args[0], error->message);
+ gcab_error (_("can't add folder to cab file %s: %s"), args[0], (error && error->message) ? error->message : "unknown error");
if (!gcab_cabinet_write (cabinet, output,
file_callback,
@@ -254,7 +254,7 @@ individual files from the archive.\
cwd,
NULL,
&error))
- gcab_error (_("can't write cab file %s: %s"), args[0], error->message);
+ gcab_error (_("can't write cab file %s: %s"), args[0], (error && error->message) ? error->message : "unknown error");
g_object_unref (cwd);
g_object_unref (output);
diff --git a/libgcab/cabinet.c b/libgcab/cabinet.c
index cdcd4dd..1fcd36a 100644
--- a/libgcab/cabinet.c
+++ b/libgcab/cabinet.c
@@ -96,14 +96,29 @@ _data_input_stream_read_until (GDataInputStream *stream,
#define RS(val) G_STMT_START{ \
val = _data_input_stream_read_until (in, "\0", 1, \
cancellable, error); \
- if (!val || (error && *error)) \
+ if (error && *error) \
goto end; \
+ if (!val) { \
+ g_set_error(error, GCAB_ERROR, GCAB_ERROR_FORMAT, \
+ "Invalid contents"); \
+ goto end; \
+ } \
}G_STMT_END
#define RN(buff, size) G_STMT_START{ \
if (size) { \
gint _val = g_input_stream_read (G_INPUT_STREAM (in), buff, size, cancellable, error); \
- if (_val == -1 || (error && *error)) \
+ if (error && *error) \
+ goto end; \
+ if (_val >= 0 && _val < size) { \
+ g_set_error(error, GCAB_ERROR, GCAB_ERROR_FORMAT, \
+ "Expected %d bytes, got %d", size, _val); \
+ goto end; \
+ } \
+ if (_val == -1) { \
+ g_set_error(error, GCAB_ERROR, GCAB_ERROR_FORMAT, \
+ "Invalid contents"); \
goto end; \
+ } \
} \
}G_STMT_END
diff --git a/libgcab/gcab-cabinet.c b/libgcab/gcab-cabinet.c
index f958c6e..faac13c 100644
--- a/libgcab/gcab-cabinet.c
+++ b/libgcab/gcab-cabinet.c
@@ -415,8 +415,20 @@ gcab_cabinet_load (GCabCabinet *self,
if (!cfile_read (&cfile, in, cancellable, error))
goto end;
- GCabFile *file = gcab_file_new_with_cfile (&cfile);
+ if (cfile.index >= folders->len) {
+ g_set_error (error, GCAB_ERROR, GCAB_ERROR_FORMAT,
+ "Invalid folder index");
+ goto end;
+ }
+
GCabFolder *folder = g_ptr_array_index (folders, cfile.index);
+ if (folder == NULL) {
+ g_set_error (error, GCAB_ERROR, GCAB_ERROR_FORMAT,
+ "Invalid folder pointer");
+ goto end;
+ }
+
+ GCabFile *file = gcab_file_new_with_cfile (&cfile);
if (!gcab_folder_add_file (folder, file, FALSE, cancellable, error)) {
g_object_unref (file);
goto end;
diff --git a/libgcab/gcab-folder.c b/libgcab/gcab-folder.c
index 9510cf3..e63fb49 100644
--- a/libgcab/gcab-folder.c
+++ b/libgcab/gcab-folder.c
@@ -143,10 +143,13 @@ gcab_folder_get_ndatablocks (GCabFolder *self)
}
static gboolean
-add_file (GCabFolder *self, GCabFile *file)
+add_file (GCabFolder *self, GCabFile *file, GError **error)
{
- if (g_hash_table_lookup (self->hash, (gpointer)gcab_file_get_name (file)))
+ if (g_hash_table_lookup (self->hash, (gpointer)gcab_file_get_name (file))) {
+ g_set_error (error, GCAB_ERROR, GCAB_ERROR_FORMAT,
+ "File '%s' has already been added", gcab_file_get_name (file));
return FALSE;
+ }
g_hash_table_insert (self->hash,
(gpointer)gcab_file_get_name (file), g_object_ref (file));
@@ -196,7 +199,7 @@ add_file_info (GCabFolder *self, GCabFile *file, GFileInfo *info,
} else if (file_type == G_FILE_TYPE_REGULAR) {
gcab_file_update_info (file, info);
- if (!add_file (self, file))
+ if (!add_file (self, file, error))
return FALSE;
} else {
@@ -244,7 +247,7 @@ gcab_folder_add_file (GCabFolder *self, GCabFile *file,
gcab_file_get_name (file), recurse, error);
g_object_unref (info);
} else {
- success = add_file (self, file);
+ success = add_file (self, file, error);
}
return success;