|
|
090aae |
commit 06ccdf016154fde8eccb5355613ba04c59127b2e
|
|
|
090aae |
Author: Nicolas Ruff <nruff@google.com>
|
|
|
090aae |
Date: Mon Sep 1 14:36:26 2014 +0200
|
|
|
090aae |
|
|
|
090aae |
Fix multiple stack-based buffer overflows in file transfer feature
|
|
|
090aae |
|
|
|
090aae |
diff --git a/libvncserver/rfbserver.c b/libvncserver/rfbserver.c
|
|
|
090aae |
index df7d74c..445331a 100644
|
|
|
090aae |
--- a/libvncserver/rfbserver.c
|
|
|
090aae |
+++ b/libvncserver/rfbserver.c
|
|
|
090aae |
@@ -1241,21 +1241,35 @@ typedef struct {
|
|
|
090aae |
#define RFB_FILE_ATTRIBUTE_TEMPORARY 0x100
|
|
|
090aae |
#define RFB_FILE_ATTRIBUTE_COMPRESSED 0x800
|
|
|
090aae |
|
|
|
090aae |
-rfbBool rfbFilenameTranslate2UNIX(rfbClientPtr cl, char *path, char *unixPath)
|
|
|
090aae |
+rfbBool rfbFilenameTranslate2UNIX(rfbClientPtr cl, /* in */ char *path, /* out */ char *unixPath, size_t unixPathMaxLen )
|
|
|
090aae |
{
|
|
|
090aae |
int x;
|
|
|
090aae |
char *home=NULL;
|
|
|
090aae |
|
|
|
090aae |
FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, FALSE);
|
|
|
090aae |
|
|
|
090aae |
+ /*
|
|
|
090aae |
+ * Do not use strncpy() - truncating the file name would probably have undesirable side effects
|
|
|
090aae |
+ * Instead check if destination buffer is big enough
|
|
|
090aae |
+ */
|
|
|
090aae |
+
|
|
|
090aae |
+ if (strlen(path) >= unixPathMaxLen)
|
|
|
090aae |
+ return FALSE;
|
|
|
090aae |
+
|
|
|
090aae |
/* C: */
|
|
|
090aae |
if (path[0]=='C' && path[1]==':')
|
|
|
090aae |
+ {
|
|
|
090aae |
strcpy(unixPath, &path[2]);
|
|
|
090aae |
+ }
|
|
|
090aae |
else
|
|
|
090aae |
{
|
|
|
090aae |
home = getenv("HOME");
|
|
|
090aae |
if (home!=NULL)
|
|
|
090aae |
{
|
|
|
090aae |
+ /* Re-check buffer size */
|
|
|
090aae |
+ if ((strlen(path) + strlen(home) + 1) >= unixPathMaxLen)
|
|
|
090aae |
+ return FALSE;
|
|
|
090aae |
+
|
|
|
090aae |
strcpy(unixPath, home);
|
|
|
090aae |
strcat(unixPath,"/");
|
|
|
090aae |
strcat(unixPath, path);
|
|
|
090aae |
@@ -1293,7 +1307,8 @@ rfbBool rfbSendDirContent(rfbClientPtr cl, int length, char *buffer)
|
|
|
090aae |
FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, FALSE);
|
|
|
090aae |
|
|
|
090aae |
/* Client thinks we are Winblows */
|
|
|
090aae |
- rfbFilenameTranslate2UNIX(cl, buffer, path);
|
|
|
090aae |
+ if (!rfbFilenameTranslate2UNIX(cl, buffer, path, sizeof(path)))
|
|
|
090aae |
+ return FALSE;
|
|
|
090aae |
|
|
|
090aae |
if (DB) rfbLog("rfbProcessFileTransfer() rfbDirContentRequest: rfbRDirContent: \"%s\"->\"%s\"\n",buffer, path);
|
|
|
090aae |
|
|
|
090aae |
@@ -1570,7 +1585,11 @@ rfbBool rfbProcessFileTransfer(rfbClientPtr cl, uint8_t contentType, uint8_t con
|
|
|
090aae |
/* add some space to the end of the buffer as we will be adding a timespec to it */
|
|
|
090aae |
if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE;
|
|
|
090aae |
/* The client requests a File */
|
|
|
090aae |
- rfbFilenameTranslate2UNIX(cl, buffer, filename1);
|
|
|
090aae |
+ if (!rfbFilenameTranslate2UNIX(cl, buffer, filename1, sizeof(filename1)))
|
|
|
090aae |
+ {
|
|
|
090aae |
+ if (buffer!=NULL) free(buffer);
|
|
|
090aae |
+ return FALSE;
|
|
|
090aae |
+ }
|
|
|
090aae |
cl->fileTransfer.fd=open(filename1, O_RDONLY, 0744);
|
|
|
090aae |
|
|
|
090aae |
/*
|
|
|
090aae |
@@ -1685,7 +1704,11 @@ rfbBool rfbProcessFileTransfer(rfbClientPtr cl, uint8_t contentType, uint8_t con
|
|
|
090aae |
}
|
|
|
090aae |
sizeHtmp = Swap32IfLE(sizeHtmp);
|
|
|
090aae |
|
|
|
090aae |
- rfbFilenameTranslate2UNIX(cl, buffer, filename1);
|
|
|
090aae |
+ if (!rfbFilenameTranslate2UNIX(cl, buffer, filename1, sizeof(filename1)))
|
|
|
090aae |
+ {
|
|
|
090aae |
+ if (buffer!=NULL) free(buffer);
|
|
|
090aae |
+ return FALSE;
|
|
|
090aae |
+ }
|
|
|
090aae |
|
|
|
090aae |
/* If the file exists... We can send a rfbFileChecksums back to the client before we send an rfbFileAcceptHeader */
|
|
|
090aae |
/* TODO: Delta Transfer */
|
|
|
090aae |
@@ -1814,7 +1837,12 @@ rfbBool rfbProcessFileTransfer(rfbClientPtr cl, uint8_t contentType, uint8_t con
|
|
|
090aae |
if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE;
|
|
|
090aae |
switch (contentParam) {
|
|
|
090aae |
case rfbCDirCreate: /* Client requests the creation of a directory */
|
|
|
090aae |
- rfbFilenameTranslate2UNIX(cl, buffer, filename1);
|
|
|
090aae |
+ if (!rfbFilenameTranslate2UNIX(cl, buffer, filename1, sizeof(filename1)))
|
|
|
090aae |
+ {
|
|
|
090aae |
+ if (buffer!=NULL) free(buffer);
|
|
|
090aae |
+ return FALSE;
|
|
|
090aae |
+ }
|
|
|
090aae |
+
|
|
|
090aae |
retval = mkdir(filename1, 0755);
|
|
|
090aae |
if (DB) rfbLog("rfbProcessFileTransfer() rfbCommand: rfbCDirCreate(\"%s\"->\"%s\") %s\n", buffer, filename1, (retval==-1?"Failed":"Success"));
|
|
|
090aae |
/*
|
|
|
090aae |
@@ -1823,7 +1851,12 @@ rfbBool rfbProcessFileTransfer(rfbClientPtr cl, uint8_t contentType, uint8_t con
|
|
|
090aae |
if (buffer!=NULL) free(buffer);
|
|
|
090aae |
return retval;
|
|
|
090aae |
case rfbCFileDelete: /* Client requests the deletion of a file */
|
|
|
090aae |
- rfbFilenameTranslate2UNIX(cl, buffer, filename1);
|
|
|
090aae |
+ if (!rfbFilenameTranslate2UNIX(cl, buffer, filename1, sizeof(filename1)))
|
|
|
090aae |
+ {
|
|
|
090aae |
+ if (buffer!=NULL) free(buffer);
|
|
|
090aae |
+ return FALSE;
|
|
|
090aae |
+ }
|
|
|
090aae |
+
|
|
|
090aae |
if (stat(filename1,&statbuf)==0)
|
|
|
090aae |
{
|
|
|
090aae |
if (S_ISDIR(statbuf.st_mode))
|
|
|
090aae |
@@ -1841,8 +1874,18 @@ rfbBool rfbProcessFileTransfer(rfbClientPtr cl, uint8_t contentType, uint8_t con
|
|
|
090aae |
{
|
|
|
090aae |
/* Split into 2 filenames ('*' is a seperator) */
|
|
|
090aae |
*p = '\0';
|
|
|
090aae |
- rfbFilenameTranslate2UNIX(cl, buffer, filename1);
|
|
|
090aae |
- rfbFilenameTranslate2UNIX(cl, p+1, filename2);
|
|
|
090aae |
+ if (!rfbFilenameTranslate2UNIX(cl, buffer, filename1, sizeof(filename1)))
|
|
|
090aae |
+ {
|
|
|
090aae |
+ if (buffer!=NULL) free(buffer);
|
|
|
090aae |
+ return FALSE;
|
|
|
090aae |
+ }
|
|
|
090aae |
+
|
|
|
090aae |
+ if (!rfbFilenameTranslate2UNIX(cl, p+1, filename2, sizeof(filename2)))
|
|
|
090aae |
+ {
|
|
|
090aae |
+ if (buffer!=NULL) free(buffer);
|
|
|
090aae |
+ return FALSE;
|
|
|
090aae |
+ }
|
|
|
090aae |
+
|
|
|
090aae |
retval = rename(filename1,filename2);
|
|
|
090aae |
if (DB) rfbLog("rfbProcessFileTransfer() rfbCommand: rfbCFileRename(\"%s\"->\"%s\" -->> \"%s\"->\"%s\") %s\n", buffer, filename1, p+1, filename2, (retval==-1?"Failed":"Success"));
|
|
|
090aae |
/*
|
|
|
090aae |
|
|
|
090aae |
commit f528072216dec01cee7ca35d94e171a3b909e677
|
|
|
090aae |
Author: Nicolas Ruff <nruff@google.com>
|
|
|
090aae |
Date: Mon Sep 1 14:51:07 2014 +0200
|
|
|
090aae |
|
|
|
090aae |
Fix stack-based buffer overflow in rfbFileTransferOffer message, FileTime processing
|
|
|
090aae |
|
|
|
090aae |
diff --git a/libvncserver/rfbserver.c b/libvncserver/rfbserver.c
|
|
|
090aae |
index 445331a..23532b0 100644
|
|
|
090aae |
--- a/libvncserver/rfbserver.c
|
|
|
090aae |
+++ b/libvncserver/rfbserver.c
|
|
|
090aae |
@@ -1683,16 +1683,17 @@ rfbBool rfbProcessFileTransfer(rfbClientPtr cl, uint8_t contentType, uint8_t con
|
|
|
090aae |
*/
|
|
|
090aae |
if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE;
|
|
|
090aae |
|
|
|
090aae |
- /* Parse the FileTime */
|
|
|
090aae |
+ /* Parse the FileTime
|
|
|
090aae |
+ * TODO: FileTime is actually never used afterwards
|
|
|
090aae |
+ */
|
|
|
090aae |
p = strrchr(buffer, ',');
|
|
|
090aae |
if (p!=NULL) {
|
|
|
090aae |
*p = '\0';
|
|
|
090aae |
- strcpy(szFileTime, p+1);
|
|
|
090aae |
+ strncpy(szFileTime, p+1, sizeof(szFileTime));
|
|
|
090aae |
+ szFileTime[sizeof(szFileTime)-1] = '\x00'; /* ensure NULL terminating byte is present, even if copy overflowed */
|
|
|
090aae |
} else
|
|
|
090aae |
szFileTime[0]=0;
|
|
|
090aae |
|
|
|
090aae |
-
|
|
|
090aae |
-
|
|
|
090aae |
/* Need to read in sizeHtmp */
|
|
|
090aae |
if ((n = rfbReadExact(cl, (char *)&sizeHtmp, 4)) <= 0) {
|
|
|
090aae |
if (n != 0)
|