097f276
Description: Fix symlink directory traversal.
097f276
 Do not allow symlinks that traverse the current directoru, nor absolute
097f276
 symlinks.
097f276
 .
097f276
 Fixes CVE-2015-0556.
097f276
Author: Guillem Jover <guillem@debian.org>
097f276
Origin: vendor
097f276
Bug-Debian: https://bugs.debian.org/774434
097f276
Forwarded: no
097f276
Last-Update: 2015-03-28
097f276
097f276
---
097f276
 uxspec.c |   54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
097f276
 1 file changed, 54 insertions(+)
097f276
097f276
--- a/uxspec.c
097f276
+++ b/uxspec.c
097f276
@@ -120,6 +120,58 @@ int query_uxspecial(char FAR **dest, cha
097f276
 }
097f276
 #endif
097f276
 
097f276
+#if TARGET==UNIX
097f276
+static int is_link_traversal(const char *name)
097f276
+{
097f276
+  enum {
097f276
+    STATE_NONE,
097f276
+    STATE_DOTS,
097f276
+    STATE_NAME,
097f276
+  } state = STATE_NONE;
097f276
+  int ndir = 0;
097f276
+  int dots = 0;
097f276
+
097f276
+  while(*name) {
097f276
+    int c = *name++;
097f276
+
097f276
+    if (c == '/')
097f276
+    {
097f276
+      if ((state == STATE_DOTS) && (dots == 2))
097f276
+        ndir--;
097f276
+      if (ndir < 0)
097f276
+        return 1;
097f276
+      if ((state == STATE_DOTS && dots == 1) && ndir == 0)
097f276
+        return 1;
097f276
+      if (state == STATE_NONE && ndir == 0)
097f276
+        return 1;
097f276
+      if ((state == STATE_DOTS) && (dots > 2))
097f276
+        ndir++;
097f276
+      state = STATE_NONE;
097f276
+      dots = 0;
097f276
+    }
097f276
+    else if (c == '.')
097f276
+    {
097f276
+      if (state == STATE_NONE)
097f276
+        state = STATE_DOTS;
097f276
+      dots++;
097f276
+    }
097f276
+    else
097f276
+    {
097f276
+      if (state == STATE_NONE)
097f276
+        ndir++;
097f276
+      state = STATE_NAME;
097f276
+    }
097f276
+  }
097f276
+
097f276
+  if ((state == STATE_DOTS) && (dots == 2))
097f276
+    ndir--;
097f276
+  if ((state == STATE_DOTS) && (dots > 2))
097f276
+    ndir++;
097f276
+
097f276
+  return ndir < 0;
097f276
+}
097f276
+#endif
097f276
+
097f276
 /* Restores the UNIX special file data */
097f276
 
097f276
 int set_uxspecial(char FAR *storage, char *name)
097f276
@@ -156,6 +208,8 @@ int set_uxspecial(char FAR *storage, cha
097f276
      l=sizeof(tmp_name)-1;
097f276
     far_memmove((char FAR *)tmp_name, dptr, l);
097f276
     tmp_name[l]='\0';
097f276
+    if (is_link_traversal(tmp_name))
097f276
+      return(UXSPEC_RC_ERROR);
097f276
     rc=(id==UXSB_HLNK)?link(tmp_name, name):symlink(tmp_name, name);
097f276
     if(!rc)
097f276
      return(0);