aboutsummaryrefslogtreecommitdiffstats
path: root/net/krfb/files/patch-CVE-2014-6055
blob: a39aea378353826a683e1ee562f1c878d2b030f1 (plain) (blame)
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
Fixes for CVE-2014-6055, taken from upstream.

commit d931eafccf3140d740ac61e876dce72a23ade7f4
Author: Martin T. H. Sandsmark <martin.sandsmark@kde.org>
Date:   Tue Sep 23 22:46:27 2014 +0200

    libvncserver: Check malloc() return value on client->server ClientCutText message.

    Client can send up to 2**32-1 bytes of text, and such a large allocation
    is likely to fail in case of high memory pressure. This would in a
    server crash (write at address 0).

    Upstream commit: 6037a9074d52b1963c97cb28ea1096c7c14cbf28

commit 126a746dd7bee35840083e9bec7a52935a010346
Author: Martin T. H. Sandsmark <martin.sandsmark@kde.org>
Date:   Tue Sep 23 22:43:38 2014 +0200

    libnvcserver: Do not accept a scaling factor of zero.

    This would cause a division by zero and crash the server.

    Upstream commit: 05a9bd41a8ec0a9d580a8f420f41718bdd235446

commit 2e211579455fd832fb21322482c005b6a85aa1bf
Author: Martin T. H. Sandsmark <martin.sandsmark@kde.org>
Date:   Tue Sep 23 22:40:17 2014 +0200

    libvncserver: Fix multiple stack-based buffer overflows in file transfer feature

    Upstream commit: 06ccdf016154fde8eccb5355613ba04c59127b2e

    CVE-2014-6055

commit 857c2b411ed806ef806116407612a2d2a40fab9c
Author: Martin T. H. Sandsmark <martin.sandsmark@kde.org>
Date:   Tue Sep 23 17:54:11 2014 +0200

    libvncserver: Fix stack-based buffer overflow in rfbFileTransferOffer message, FileTime processing

    Upstream commit: f528072216dec01cee7ca35d94e171a3b909e677

    CVE-2014-6055
--- libvncserver/rfbserver.c
+++ libvncserver/rfbserver.c
@@ -1175,13 +1175,21 @@ typedef struct {
 #define RFB_FILE_ATTRIBUTE_TEMPORARY  0x100
 #define RFB_FILE_ATTRIBUTE_COMPRESSED 0x800
 
-rfbBool rfbFilenameTranslate2UNIX(rfbClientPtr cl, char *path, char *unixPath)
+rfbBool rfbFilenameTranslate2UNIX(rfbClientPtr cl, char *path, char *unixPath, size_t unixPathMaxLen)
 {
     int x;
     char *home=NULL;
 
     FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, FALSE);
 
+    /*
+     * Do not use strncpy() - truncating the file name would probably have undesirable side effects
+     * Instead check if destination buffer is big enough
+     */
+
+    if (strlen(path) >= unixPathMaxLen)
+        return FALSE;
+
     /* C: */
     if (path[0]=='C' && path[1]==':')
       strcpy(unixPath, &path[2]);
@@ -1190,6 +1198,10 @@ rfbBool rfbFilenameTranslate2UNIX(rfbClientPtr cl, char *path, char *unixPath)
       home = getenv("HOME");
       if (home!=NULL)
       {
+        /* Re-check buffer size */
+        if ((strlen(path) + strlen(home) + 1) >= unixPathMaxLen)
+          return FALSE;
+
         strcpy(unixPath, home);
         strcat(unixPath,"/");
         strcat(unixPath, path);
@@ -1227,7 +1239,9 @@ rfbBool rfbSendDirContent(rfbClientPtr cl, int length, char *buffer)
     FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, FALSE);
 
     /* Client thinks we are Winblows */
-    rfbFilenameTranslate2UNIX(cl, buffer, path);
+    if (!rfbFilenameTranslate2UNIX(cl, buffer, path, sizeof(path)))
+      return FALSE;
+
 
     if (DB) rfbLog("rfbProcessFileTransfer() rfbDirContentRequest: rfbRDirContent: \"%s\"->\"%s\"\n",buffer, path);
 
@@ -1504,7 +1518,12 @@ rfbBool rfbProcessFileTransfer(rfbClientPtr cl, uint8_t contentType, uint8_t con
         /* add some space to the end of the buffer as we will be adding a timespec to it */
         if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE;
         /* The client requests a File */
-        rfbFilenameTranslate2UNIX(cl, buffer, filename1);
+        if (!rfbFilenameTranslate2UNIX(cl, buffer, filename1, sizeof(filename1)))
+        {
+          if (buffer!=NULL) free(buffer);
+          return FALSE;
+        }
+
         cl->fileTransfer.fd=open(filename1, O_RDONLY, 0744);
 
         /*
@@ -1602,7 +1621,8 @@ rfbBool rfbProcessFileTransfer(rfbClientPtr cl, uint8_t contentType, uint8_t con
         p = strrchr(buffer, ',');
         if (p!=NULL) {
             *p = '\0';
-            strcpy(szFileTime, p+1);
+            strncpy(szFileTime, p+1, sizeof(szFileTime));
+            szFileTime[sizeof(szFileTime)-1] = '\x00'; /* ensure NULL terminating byte is present, even if copy overflowed */
         } else
             szFileTime[0]=0;
 
@@ -1619,7 +1639,12 @@ rfbBool rfbProcessFileTransfer(rfbClientPtr cl, uint8_t contentType, uint8_t con
         }
         sizeHtmp = Swap32IfLE(sizeHtmp);
         
-        rfbFilenameTranslate2UNIX(cl, buffer, filename1);
+        if (!rfbFilenameTranslate2UNIX(cl, buffer, filename1, sizeof(filename1)))
+        {
+          if (buffer!=NULL) free(buffer);
+          return FALSE;
+        }
+
 
         /* If the file exists... We can send a rfbFileChecksums back to the client before we send an rfbFileAcceptHeader */
         /* TODO: Delta Transfer */
@@ -1745,7 +1770,12 @@ rfbBool rfbProcessFileTransfer(rfbClientPtr cl, uint8_t contentType, uint8_t con
         if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE;
         switch (contentParam) {
         case rfbCDirCreate:  /* Client requests the creation of a directory */
-            rfbFilenameTranslate2UNIX(cl, buffer, filename1);
+            if (!rfbFilenameTranslate2UNIX(cl, buffer, filename1, sizeof(filename1)))
+            {
+              if (buffer!=NULL) free(buffer);
+              return FALSE;
+            }
+
             retval = mkdir(filename1, 0755);
             if (DB) rfbLog("rfbProcessFileTransfer() rfbCommand: rfbCDirCreate(\"%s\"->\"%s\") %s\n", buffer, filename1, (retval==-1?"Failed":"Success"));
             /*
@@ -1754,7 +1784,11 @@ rfbBool rfbProcessFileTransfer(rfbClientPtr cl, uint8_t contentType, uint8_t con
             if (buffer!=NULL) free(buffer);
             return retval;
         case rfbCFileDelete: /* Client requests the deletion of a file */
-            rfbFilenameTranslate2UNIX(cl, buffer, filename1);
+            if (!rfbFilenameTranslate2UNIX(cl, buffer, filename1, sizeof(filename1)))
+            {
+              if (buffer!=NULL) free(buffer);
+              return FALSE;
+            }
             if (stat(filename1,&statbuf)==0)
             {
                 if (S_ISDIR(statbuf.st_mode))
@@ -1772,8 +1806,17 @@ rfbBool rfbProcessFileTransfer(rfbClientPtr cl, uint8_t contentType, uint8_t con
             {
                 /* Split into 2 filenames ('*' is a seperator) */
                 *p = '\0';
-                rfbFilenameTranslate2UNIX(cl, buffer, filename1);
-                rfbFilenameTranslate2UNIX(cl, p+1,    filename2);
+                if (!rfbFilenameTranslate2UNIX(cl, buffer, filename1, sizeof(filename1)))
+                {
+                  if (buffer!=NULL) free(buffer);
+                  return FALSE;
+                }
+
+                if (!rfbFilenameTranslate2UNIX(cl, p+1,    filename2, sizeof(filename2)))
+                {
+                  if (buffer!=NULL) free(buffer);
+                  return FALSE;
+                }
                 retval = rename(filename1,filename2);
                 if (DB) rfbLog("rfbProcessFileTransfer() rfbCommand: rfbCFileRename(\"%s\"->\"%s\" -->> \"%s\"->\"%s\") %s\n", buffer, filename1, p+1, filename2, (retval==-1?"Failed":"Success"));
                 /*
@@ -2361,6 +2404,12 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
 
    str = (char *)malloc(msg.cct.length);
 
+    if (str == NULL) {
+        rfbLogPerror("rfbProcessClientNormalMessage: not enough memory");
+        rfbCloseClient(cl);
+        return;
+    }
+
    if ((n = rfbReadExact(cl, str, msg.cct.length)) <= 0) {
        if (n != 0)
            rfbLogPerror("rfbProcessClientNormalMessage: read");
@@ -2385,6 +2434,11 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
           rfbCloseClient(cl);
           return;
       }
+      if (msg.ssc.scale == 0) {
+          rfbLogPerror("rfbProcessClientNormalMessage: will not accept a scale factor of zero");
+          rfbCloseClient(cl);
+          return;
+      }
       rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetScaleMsg, sz_rfbSetScaleMsg);
       rfbLog("rfbSetScale(%d)\n", msg.ssc.scale);
       rfbScalingSetup(cl,cl->screen->width/msg.ssc.scale, cl->screen->height/msg.ssc.scale);
@@ -2401,6 +2455,11 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
           rfbCloseClient(cl);
           return;
       }
+      if (msg.ssc.scale == 0) {
+          rfbLogPerror("rfbProcessClientNormalMessage: will not accept a scale factor of zero");
+          rfbCloseClient(cl);
+          return;
+      }
       rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetScaleMsg, sz_rfbSetScaleMsg);
       rfbLog("rfbSetScale(%d)\n", msg.ssc.scale);
       rfbScalingSetup(cl,cl->screen->width/msg.ssc.scale, cl->screen->height/msg.ssc.scale);