OSDN Git Service

Prevent from extracting files follow symbolic link
authorKoji Arai <jca02266@gmail.com>
Sun, 29 Nov 2015 11:25:07 +0000 (20:25 +0900)
committerKoji Arai <jca02266@gmail.com>
Sun, 29 Nov 2015 11:50:09 +0000 (20:50 +0900)
Thanks to Yohei Endo.

src/lhext.c
src/util.c

index acdeaf8..24b8dc9 100644 (file)
@@ -83,6 +83,47 @@ inquire_extract(name)
     return TRUE;
 }
 
+static boolean
+make_name_with_pathcheck(char *name, size_t namesz, const char *dir, const char *q)
+{
+    int offset = 0;
+    const char *p;
+    int sz;
+    struct stat stbuf;
+
+    if (extract_directory) {
+        sz = xsnprintf(name, namesz, "%s/", extract_directory);
+        if (sz == -1) {
+            return FALSE;
+        }
+        offset += sz;
+    }
+
+    while ((p = strchr(q, '/')) != NULL) {
+        if (namesz - offset < (p - q) + 2) {
+            return FALSE;
+        }
+        memcpy(name + offset, q, (p - q));
+        name[offset + (p - q)] = 0;
+
+        offset += (p - q);
+        q = p + 1;
+
+        if (lstat(name, &stbuf) < 0) {
+            name[offset++] = '/';
+            break;
+        }
+        if (is_symlink(&stbuf)) {
+            return FALSE;
+        }
+        name[offset++] = '/';
+    }
+
+    str_safe_copy(name + offset, q, namesz - offset);
+
+    return TRUE;
+}
+
 /* ------------------------------------------------------------------------ */
 static          boolean
 make_parent_path(name)
@@ -254,10 +295,10 @@ extract_one(afp, hdr)
         }
     }
 
-    if (extract_directory)
-        xsnprintf(name, sizeof(name), "%s/%s", extract_directory, q);
-    else
-        str_safe_copy(name, q, sizeof(name));
+    if (!make_name_with_pathcheck(name, sizeof(name), extract_directory, q)) {
+        fprintf(stderr, "Possible symlink traversal hack attempt in %s\n", q);
+        exit(111);
+    }
 
     /* LZHDIRS_METHODを持つヘッダをチェックする */
     /* 1999.4.30 t.okamoto */
index cb1047f..191b298 100644 (file)
@@ -214,7 +214,7 @@ xsnprintf(dest, size, fmt, va_alist)
     len = vsnprintf(dest, size, fmt, v);
     va_end(v);
 
-    if (len == -1)
+    if (len < 0)
         return -1;
 
     if (len >= size) {
@@ -222,7 +222,7 @@ xsnprintf(dest, size, fmt, va_alist)
         return -1;
     }
 
-    return 0;
+    return len;
 }
 
 #if !STRCHR_8BIT_CLEAN