summaryrefslogtreecommitdiff
path: root/archivers/arj/patches/patch-uxspec.c
blob: 8de52b1555af432fd1aa6d5f509bd86fe92a96d8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
$NetBSD: patch-uxspec.c,v 1.2 2015/04/12 15:54:02 tnn Exp $

Fix build on systems without lchown.
Fix CVE-2015-0556. Via Debian security-traversal-symlink.patch.

--- uxspec.c.orig	2015-04-12 15:46:11.000000000 +0000
+++ uxspec.c
@@ -125,6 +125,58 @@ int query_uxspecial(char FAR **dest, cha
 }
 #endif
 
+#if TARGET==UNIX
+static int is_link_traversal(const char *name)
+{
+  enum {
+    STATE_NONE,
+    STATE_DOTS,
+    STATE_NAME,
+  } state = STATE_NONE;
+  int ndir = 0;
+  int dots = 0;
+
+  while(*name) {
+    int c = *name++;
+
+    if (c == '/')
+    {
+      if ((state == STATE_DOTS) && (dots == 2))
+        ndir--;
+      if (ndir < 0)
+        return 1;
+      if ((state == STATE_DOTS && dots == 1) && ndir == 0)
+        return 1;
+      if (state == STATE_NONE && ndir == 0)
+        return 1;
+      if ((state == STATE_DOTS) && (dots > 2))
+        ndir++;
+      state = STATE_NONE;
+      dots = 0;
+    }
+    else if (c == '.')
+    {
+      if (state == STATE_NONE)
+        state = STATE_DOTS;
+      dots++;
+    }
+    else
+    {
+      if (state == STATE_NONE)
+        ndir++;
+      state = STATE_NAME;
+    }
+  }
+
+  if ((state == STATE_DOTS) && (dots == 2))
+    ndir--;
+  if ((state == STATE_DOTS) && (dots > 2))
+    ndir++;
+
+  return ndir < 0;
+}
+#endif
+
 /* Restores the UNIX special file data */
 
 int set_uxspecial(char FAR *storage, char *name)
@@ -161,6 +213,8 @@ int set_uxspecial(char FAR *storage, cha
      l=sizeof(tmp_name)-1;
     far_memmove((char FAR *)tmp_name, dptr, l);
     tmp_name[l]='\0';
+    if (is_link_traversal(tmp_name))
+      return(UXSPEC_RC_ERROR);
     rc=(id==UXSB_HLNK)?link(tmp_name, name):symlink(tmp_name, name);
     if(!rc)
      return(0);