Reimplemented memory management in dirlisting generation

This should eliminate all bufferoverflows introduced by the previous
usage of strcat() and various assumptions.
This commit is contained in:
Thomas Kolb 2016-12-16 23:40:44 +01:00
parent 4722639ae1
commit 1bcc672503
3 changed files with 57 additions and 52 deletions

View file

@ -17,5 +17,6 @@
void remove_trailing_slash(char *str); void remove_trailing_slash(char *str);
void urlencode(const char *str, char *result); void urlencode(const char *str, char *result);
char* safe_append(char *target, size_t *targetsize, const char *src);
#endif // UTIL_H #endif // UTIL_H

View file

@ -79,21 +79,20 @@ char* gen_html(const char *url, struct Entry *entries, size_t numentries, int up
result = malloc(allocated * sizeof(char)); result = malloc(allocated * sizeof(char));
result[0] = '\0'; result[0] = '\0';
// this is still safe result = safe_append(result, &allocated, HEADER1);
strcat(result, HEADER1);
snprintf(buf, BUFSIZE, "<title>Directory listing for %s</title>", url); snprintf(buf, BUFSIZE, "<title>Directory listing for %s</title>", url);
strcat(result, buf); result = safe_append(result, &allocated, buf);
strcat(result, HEADER2); result = safe_append(result, &allocated, HEADER2);
snprintf(buf, BUFSIZE, "<h1>Directory listing for %s</h1>", url); snprintf(buf, BUFSIZE, "<h1>Directory listing for %s</h1>", url);
strcat(result, buf); result = safe_append(result, &allocated, buf);
int isrootdir = strcmp(url, "/") == 0; int isrootdir = strcmp(url, "/") == 0;
// Begin Navigation // Begin Navigation
strcat(result, "<p>Navigation: "); result = safe_append(result, &allocated, "<p>Navigation: ");
// tokenize the URL: init // tokenize the URL: init
char *token, *urlclone; char *token, *urlclone;
@ -103,30 +102,31 @@ char* gen_html(const char *url, struct Entry *entries, size_t numentries, int up
strcpy(fullpath, "/"); strcpy(fullpath, "/");
if(isrootdir) { if(isrootdir) {
strcat(result, "/"); result = safe_append(result, &allocated, "/");
} else { } else {
strcat(result, "<a href=\"/\">/</a>"); result = safe_append(result, &allocated, "<a href=\"/\">/</a>");
// create a link for each token in URL // create a link for each token in URL
do { do {
LOG(LVL_DUMP, "Found token of %s: %s", url, token); LOG(LVL_DUMP, "Found token of %s: %s", url, token);
// TODO: check if this is safe
strcat(fullpath, token); strcat(fullpath, token);
strcat(fullpath, "/"); strcat(fullpath, "/");
snprintf(buf, BUFSIZE, " <a href=\"%s\">%s</a> /", fullpath, token); snprintf(buf, BUFSIZE, " <a href=\"%s\">%s</a> /", fullpath, token);
strcat(result, buf); result = safe_append(result, &allocated, buf);
} }
while((token = strtok(NULL, "/")) != NULL); while((token = strtok(NULL, "/")) != NULL);
} }
free(urlclone); free(urlclone);
strcat(result, "</p>"); result = safe_append(result, &allocated, "</p>");
// begin listing subdirs // begin listing subdirs
strcat(result, "<h2>Sub-directories</h2>"); result = safe_append(result, &allocated, "<h2>Sub-directories</h2>");
strcat(result, "<ul>"); result = safe_append(result, &allocated, "<ul>");
for(i = 0; i < numentries; i++) { for(i = 0; i < numentries; i++) {
// skip all non-directories // skip all non-directories
@ -135,21 +135,6 @@ char* gen_html(const char *url, struct Entry *entries, size_t numentries, int up
urlencode(entries[i].name, encName); urlencode(entries[i].name, encName);
size_t entrylen = 64 + strlen(url) + strlen(entries[i].name) + strlen(encName);
size_t resultlen = strlen(result);
if(allocated < resultlen + entrylen) {
allocated = 2*allocated + entrylen; // be on the safe side
LOG(LVL_DEBUG, "reallocating result string (subdirs) - new size: %lu bytes", allocated * sizeof(char));
char *tmpresult = realloc(result, allocated * sizeof(char));
if(!tmpresult) {
LOG(LVL_ERR, "realloc failed for result string: %s", strerror(errno));
break;
}
result = tmpresult;
}
if(isrootdir) { if(isrootdir) {
snprintf(buf, BUFSIZE, "<li><a href=\"/%s/\">%s/</a></li>\n", snprintf(buf, BUFSIZE, "<li><a href=\"/%s/\">%s/</a></li>\n",
encName, entries[i].name); encName, entries[i].name);
@ -157,14 +142,14 @@ char* gen_html(const char *url, struct Entry *entries, size_t numentries, int up
snprintf(buf, BUFSIZE, "<li><a href=\"%s/%s/\">%s/</a></li>\n", snprintf(buf, BUFSIZE, "<li><a href=\"%s/%s/\">%s/</a></li>\n",
url, encName, entries[i].name); url, encName, entries[i].name);
} }
strcat(result, buf); result = safe_append(result, &allocated, buf);
} }
strcat(result, "</ul>"); result = safe_append(result, &allocated, "</ul>");
// begin listing files // begin listing files
strcat(result, "<h2>Files</h2>"); result = safe_append(result, &allocated, "<h2>Files</h2>");
strcat(result, "<ul>"); result = safe_append(result, &allocated, "<ul>");
// here the listing entries are generated // here the listing entries are generated
for(i = 0; i < numentries; i++) { for(i = 0; i < numentries; i++) {
@ -174,21 +159,6 @@ char* gen_html(const char *url, struct Entry *entries, size_t numentries, int up
urlencode(entries[i].name, encName); urlencode(entries[i].name, encName);
size_t entrylen = 64 + strlen(url) + strlen(entries[i].name) + strlen(encName);
size_t resultlen = strlen(result);
if(allocated < resultlen + entrylen) {
allocated = 2*allocated + entrylen; // be on the safe side
LOG(LVL_DEBUG, "reallocating result string (files) - new size: %lu bytes", allocated * sizeof(char));
char *tmpresult = realloc(result, allocated * sizeof(char));
if(!tmpresult) {
LOG(LVL_ERR, "realloc failed for result string: %s", strerror(errno));
break;
}
result = tmpresult;
}
if(isrootdir) { if(isrootdir) {
snprintf(buf, BUFSIZE, "<li><a href=\"/%s\">%s</a> [%s]</li>\n", snprintf(buf, BUFSIZE, "<li><a href=\"/%s\">%s</a> [%s]</li>\n",
encName, entries[i].name, format_size(entries[i].size)); encName, entries[i].name, format_size(entries[i].size));
@ -196,15 +166,15 @@ char* gen_html(const char *url, struct Entry *entries, size_t numentries, int up
snprintf(buf, BUFSIZE, "<li><a href=\"%s/%s\">%s</a> [%s]</li>\n", snprintf(buf, BUFSIZE, "<li><a href=\"%s/%s\">%s</a> [%s]</li>\n",
url, encName, entries[i].name, format_size(entries[i].size)); url, encName, entries[i].name, format_size(entries[i].size));
} }
strcat(result, buf); result = safe_append(result, &allocated, buf);
} }
strcat(result, "</ul>"); result = safe_append(result, &allocated, "</ul>");
if(uploadEnabled) { if(uploadEnabled) {
strcat(result, "<h2>Upload</h2>"); result = safe_append(result, &allocated, "<h2>Upload</h2>");
strcat(result, "<p>Upload a file to this directory:</p>"); result = safe_append(result, &allocated, "<p>Upload a file to this directory:</p>");
strcat(result, result = safe_append(result, &allocated,
"<p>" "<p>"
" <form method=\"POST\" action=\".\" enctype=\"multipart/form-data\">" " <form method=\"POST\" action=\".\" enctype=\"multipart/form-data\">"
" <input name=\"data\" type=\"file\" size=\"30\">" " <input name=\"data\" type=\"file\" size=\"30\">"
@ -214,7 +184,7 @@ char* gen_html(const char *url, struct Entry *entries, size_t numentries, int up
); );
} }
strcat(result, FOOTER); result = safe_append(result, &allocated, FOOTER);
LOG(LVL_DEBUG, "result string (files) usage: %lu/%lu bytes", strlen(result), allocated); LOG(LVL_DEBUG, "result string (files) usage: %lu/%lu bytes", strlen(result), allocated);

View file

@ -11,8 +11,11 @@
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <malloc.h>
#include <errno.h>
#include "util.h" #include "util.h"
#include "logger.h"
void remove_trailing_slash(char *str) { void remove_trailing_slash(char *str) {
size_t offset = strlen(str)-1; size_t offset = strlen(str)-1;
@ -49,3 +52,34 @@ void urlencode(const char *str, char *result) {
str++; str++;
} }
} }
/*!
* Append src to target, reallocating target on the way if necessary.
*
* \param target The string to append to.
* \param targetsize A pointer to the size of target. Will be updated by this
* function when target is reallocated.
* \param src The string to append to target.
* \returns A pointer to new string (target becomes invalid in the
* event of reallocation) or NULL on a realloc error.
*/
char* safe_append(char *target, size_t *targetsize, const char *src) {
size_t targetlen = strlen(target);
size_t srclen = strlen(src);
size_t newsize = targetlen + 2*srclen + 1;
// check if reallocation is necessary
if((targetlen + srclen) > *targetsize) {
LOG(LVL_DEBUG, "safe_append: reallocating target string: %lu -> %lu characters", *targetsize, newsize);
target = realloc(target, newsize * sizeof(char));
if(target == NULL) {
LOG(LVL_ERR, "safe_append: realloc failed: %s", strerror(errno));
return NULL;
}
*targetsize = newsize;
}
return strcat(target, src);
}