[msitools: 4/6] libmsi: allocate decoded stream name to avoid buffer overflow




commit ab4b63dc815812df8eee0cbab9d8a4c70315469c
Author: Marc-André Lureau <marcandre lureau redhat com>
Date:   Tue Mar 16 13:28:53 2021 +0400

    libmsi: allocate decoded stream name to avoid buffer overflow
    
    Fixes #36 "Buffer overflow in create_stream"

 libmsi/libmsi-database.c | 13 +++++++------
 libmsi/msipriv.h         |  2 +-
 libmsi/streams.c         |  4 ++--
 libmsi/table.c           | 26 +++++++++++++++++---------
 4 files changed, 27 insertions(+), 18 deletions(-)
---
diff --git a/libmsi/libmsi-database.c b/libmsi/libmsi-database.c
index e02d65c..e0c68cc 100644
--- a/libmsi/libmsi-database.c
+++ b/libmsi/libmsi-database.c
@@ -491,10 +491,10 @@ unsigned clone_infile_stream( LibmsiDatabase *db, const char *name, GsfInput **s
 unsigned msi_get_raw_stream( LibmsiDatabase *db, const char *stname, GsfInput **stm )
 {
     unsigned ret = LIBMSI_RESULT_FUNCTION_FAILED;
-    char decoded[MAX_STREAM_NAME_LEN];
+    g_autofree char *decoded = NULL;
     LibmsiTransform *transform;
 
-    decode_streamname( stname, decoded );
+    decoded = decode_streamname(stname);
     TRACE("%s -> %s\n", debugstr_a(stname), debugstr_a(decoded));
 
     if (clone_infile_stream( db, stname, stm ) == LIBMSI_RESULT_SUCCESS)
@@ -2110,7 +2110,6 @@ libmsi_database_is_readonly (LibmsiDatabase *db)
 static void cache_infile_structure( LibmsiDatabase *db )
 {
     int i, n;
-    char decname[0x40];
     unsigned r;
 
     n = gsf_infile_num_children(db->infile);
@@ -2132,7 +2131,9 @@ static void cache_infile_structure( LibmsiDatabase *db )
             /* UTF-8 encoding of 0x4840.  */
             if (name8[0] == 0xe4 && name8[1] == 0xa1 && name8[2] == 0x80)
             {
-                decode_streamname(name + 3, decname);
+                g_autofree char *decname = NULL;
+
+                decname = decode_streamname(name + 3);
                 if ( !strcmp( decname, szStringPool ) ||
                      !strcmp( decname, szStringData ) )
                     continue;
@@ -2340,9 +2341,9 @@ static unsigned commit_stream( const char *name, GsfInput *stm, void *opaque)
     LibmsiDatabase *db = opaque;
     GsfOutput *outstm;
     unsigned ret = LIBMSI_RESULT_FUNCTION_FAILED;
-    char decname[0x40];
+    g_autofree char *decname = NULL;
 
-    decode_streamname(name, decname);
+    decname = decode_streamname(name);
     TRACE("%s(%s) %p %p\n", debugstr_a(name), debugstr_a(decname), stm, opaque);
 
     outstm = gsf_outfile_new_child( db->outfile, name, false );
diff --git a/libmsi/msipriv.h b/libmsi/msipriv.h
index f7a80a6..35dbb91 100644
--- a/libmsi/msipriv.h
+++ b/libmsi/msipriv.h
@@ -389,7 +389,7 @@ extern bool _libmsi_record_compare_fields(const LibmsiRecord *a, const LibmsiRec
 /* stream internals */
 extern void enum_stream_names( GsfInfile *stg );
 extern char *encode_streamname(bool bTable, const char *in);
-extern void decode_streamname(const char *in, char *out);
+extern char *decode_streamname(const char *in);
 
 /* database internals */
 extern LibmsiResult _libmsi_database_start_transaction(LibmsiDatabase *db);
diff --git a/libmsi/streams.c b/libmsi/streams.c
index 379dcee..025e53c 100644
--- a/libmsi/streams.c
+++ b/libmsi/streams.c
@@ -62,7 +62,7 @@ static bool streams_set_table_size(LibmsiStreamsView *sv, unsigned size)
 static STREAM *create_stream(LibmsiStreamsView *sv, const char *name, bool encoded, GsfInput *stm)
 {
     STREAM *stream;
-    char decoded[MAX_STREAM_NAME_LEN];
+    g_autofree char *decoded = NULL;
 
     stream = msi_alloc(sizeof(STREAM));
     if (!stream)
@@ -70,7 +70,7 @@ static STREAM *create_stream(LibmsiStreamsView *sv, const char *name, bool encod
 
     if (encoded)
     {
-        decode_streamname(name, decoded);
+        decoded = decode_streamname(name);
         TRACE("stream -> %s %s\n", debugstr_a(name), debugstr_a(decoded));
         name = decoded;
     }
diff --git a/libmsi/table.c b/libmsi/table.c
index 5c207e3..5e0a6f8 100644
--- a/libmsi/table.c
+++ b/libmsi/table.c
@@ -188,12 +188,16 @@ static int mime2utf(int x)
     return '_';
 }
 
-void decode_streamname(const char *in, char *out)
+char *decode_streamname(const char *in)
 {
     unsigned count = 0;
     const uint8_t *p = (const uint8_t *)in;
-    uint8_t *q = (uint8_t *)out;
+    char *out;
+    uint8_t *q;
 
+    g_return_val_if_fail(in != NULL, NULL);
+    out = g_malloc0(strlen(in) + 1);
+    q = (uint8_t *)out;
     while ( *p )
     {
         uint8_t ch = *p;
@@ -226,18 +230,23 @@ void decode_streamname(const char *in, char *out)
         count++;
     }
     *q = 0;
+    return out;
 }
 
 void enum_stream_names( GsfInfile *stg )
 {
     unsigned n, i;
-    char name[0x40];
 
     n = gsf_infile_num_children(stg);
     for (i = 0; i < n; i++)
     {
+        g_autofree char *name = NULL;
         const char *stname = gsf_infile_name_by_index(stg, i);
-        decode_streamname( stname, name );
+
+        if (!stname)
+            continue;
+
+        name = decode_streamname(stname);
         TRACE("stream %2d -> %s %s\n", n,
               debugstr_a(stname), debugstr_a(name) );
     }
@@ -562,15 +571,14 @@ static unsigned table_get_column_info( LibmsiDatabase *db, const char *name, Lib
 
 unsigned _libmsi_open_table( LibmsiDatabase *db, const char *name, bool encoded )
 {
-    char decname[0x40];
+    g_autofree char *decname = NULL;
     LibmsiTable *table;
     guint8 *name8 = (guint8*)name;
 
     if (encoded)
     {
         assert(name8[0] == 0xe4 && name8[1] == 0xa1 && name8[2] == 0x80);
-        decode_streamname( name + 1, decname );
-        name = decname;
+        decname = decode_streamname(name + 1);
     }
 
     table = msi_alloc_zero( sizeof(LibmsiTable) + strlen( name ) * sizeof(char) );
@@ -2568,13 +2576,13 @@ unsigned msi_table_apply_transform( LibmsiDatabase *db, GsfInfile *stg )
     {
         LibmsiTableView *tv = NULL;
         const uint8_t *encname;
-        char name[0x40];
+        g_autofree char *name = NULL;
 
         encname = (const uint8_t *) gsf_infile_name_by_index(stg, i);
         if ( encname[0] != 0xe4 || encname[1] != 0xa1 || encname[2] != 0x80)
             continue;
 
-        decode_streamname( (char*)encname, name );
+        name = decode_streamname((char*)encname);
         if ( !strcmp( name+3, szStringPool ) ||
              !strcmp( name+3, szStringData ) )
             continue;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]