On Fri, 2018-07-27 at 23:41 +0800, Ben Hutchings wrote:
[...]
> Sorry about this.  You didn't give an example to reproduce this, but I
> was able to construct one.  Please could you test that the attached
> patch also works for your real usage?
[...]

Really attached this time.

Ben.

-- 
Ben Hutchings
Power corrupts.  Absolute power is kind of neat. - John Lehman

From 9f15821377ec57bd36ae28eb3d430a66b87c9906 Mon Sep 17 00:00:00 2001
From: Ben Hutchings <b...@decadent.org.uk>
Date: Fri, 27 Jul 2018 22:40:49 +0800
Subject: [PATCH] Fix validation of GNU-style long names in archives

Commit bc9d72beb0cb "Resolve issues discovered by static code
analysis." added range checks on archive member name length.  However,
in the case of GNU-style long names, it range-checked the *offset* in
the name map as if it was a length.  This caused valid long names to
be rejected.

* Record the size of the name map, and validate offsets against that
* Ensure that the last entry in the name map is null-terminated
* Check the length after finding the name in the name map

Reported-by: Philipp Wolski <philipp.wol...@kisters.de>
---
 arscan.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/arscan.c b/arscan.c
index 6bc5af2467c2..f424128c2a8b 100644
--- a/arscan.c
+++ b/arscan.c
@@ -414,6 +414,7 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
 # endif
 #endif
   char *namemap = 0;
+  int namemap_size = 0;
   int desc = open (archive, O_RDONLY, 0);
   if (desc < 0)
     return -1;
@@ -667,10 +668,15 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
               && namemap != 0)
             {
               int name_off = atoi (name + 1);
-              if (name_off < 1 || name_off > ARNAME_MAX)
+              int name_len;
+
+              if (name_off < 0 || name_off >= namemap_size)
                 goto invalid;
 
               name = namemap + name_off;
+              name_len = strlen(name);
+              if (name_len < 1 || name_len > ARNAME_MAX)
+                goto invalid;
               long_name = 1;
             }
           else if (name[0] == '#'
@@ -747,10 +753,11 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
             char *clear;
             char *limit;
 
-            namemap = alloca (eltsize);
+            namemap = alloca (eltsize + 1);
             EINTRLOOP (nread, read (desc, namemap, eltsize));
             if (nread != eltsize)
               goto invalid;
+            namemap_size = eltsize;
 
             /* The names are separated by newlines.  Some formats have
                a trailing slash.  Null terminate the strings for
@@ -765,6 +772,7 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
                       clear[-1] = '\0';
                   }
               }
+            *limit = '\0';
 
             is_namemap = 0;
           }

Attachment: signature.asc
Description: This is a digitally signed message part

Reply via email to