Forráskód Böngészése

Force string length limits for vsnprintf operations (#175)

See 1+2 of https://github.com/civetweb/civetweb/issues/175#issuecomment-139703181
bel 10 éve
szülő
commit
cc4747c1e3
1 módosított fájl, 70 hozzáadás és 1 törlés
  1. 70 1
      src/civetweb.c

+ 70 - 1
src/civetweb.c

@@ -1162,12 +1162,14 @@ struct de {
 	struct file file;
 };
 
+
 #if defined(USE_WEBSOCKET)
 static int is_websocket_protocol(const struct mg_connection *conn);
 #else
 #define is_websocket_protocol(conn) (0)
 #endif
 
+
 static int mg_atomic_inc(volatile int *addr)
 {
 	int ret;
@@ -1184,6 +1186,7 @@ static int mg_atomic_inc(volatile int *addr)
 	return ret;
 }
 
+
 static int mg_atomic_dec(volatile int *addr)
 {
 	int ret;
@@ -1200,6 +1203,7 @@ static int mg_atomic_dec(volatile int *addr)
 	return ret;
 }
 
+
 #if !defined(NO_THREAD_NAME)
 #if defined(_WIN32) && defined(_MSC_VER)
 /* Set the thread name for debugging purposes in Visual Studio
@@ -1218,6 +1222,7 @@ typedef struct tagTHREADNAME_INFO {
 #include <sys/sendfile.h>
 #endif
 
+
 static void mg_set_thread_name(const char *name)
 {
 	char threadName[16 + 1]; /* 16 = Max. thread length in Linux/OSX/.. */
@@ -1262,6 +1267,7 @@ void mg_set_thread_name(const char *threadName)
 }
 #endif
 
+
 #if defined(MG_LEGACY_INTERFACE)
 const char **mg_get_valid_option_names(void)
 {
@@ -1279,11 +1285,13 @@ const char **mg_get_valid_option_names(void)
 }
 #endif
 
+
 const struct mg_option *mg_get_valid_options(void)
 {
 	return config_options;
 }
 
+
 static int is_file_in_memory(struct mg_connection *conn,
                              const char *path,
                              struct file *filep)
@@ -1306,6 +1314,7 @@ static int is_file_in_memory(struct mg_connection *conn,
 	return filep->membuf != NULL;
 }
 
+
 static int is_file_opened(const struct file *filep)
 {
 	if (!filep) {
@@ -1315,6 +1324,7 @@ static int is_file_opened(const struct file *filep)
 	return filep->membuf != NULL || filep->fp != NULL;
 }
 
+
 static int mg_fopen(struct mg_connection *conn,
                     const char *path,
                     const char *mode,
@@ -1345,6 +1355,7 @@ static void mg_fclose(struct file *filep)
 	}
 }
 
+
 static void mg_strlcpy(register char *dst, register const char *src, size_t n)
 {
 	for (; *src != '\0' && n > 1; n--) {
@@ -1353,11 +1364,13 @@ static void mg_strlcpy(register char *dst, register const char *src, size_t n)
 	*dst = '\0';
 }
 
+
 static int lowercase(const char *s)
 {
 	return tolower(*(const unsigned char *)s);
 }
 
+
 int mg_strncasecmp(const char *s1, const char *s2, size_t len)
 {
 	int diff = 0;
@@ -1371,6 +1384,7 @@ int mg_strncasecmp(const char *s1, const char *s2, size_t len)
 	return diff;
 }
 
+
 static int mg_strcasecmp(const char *s1, const char *s2)
 {
 	int diff;
@@ -1382,6 +1396,7 @@ static int mg_strcasecmp(const char *s1, const char *s2)
 	return diff;
 }
 
+
 static char *mg_strndup(const char *ptr, size_t len)
 {
 	char *p;
@@ -1393,11 +1408,13 @@ static char *mg_strndup(const char *ptr, size_t len)
 	return p;
 }
 
+
 static char *mg_strdup(const char *str)
 {
 	return mg_strndup(str, strlen(str));
 }
 
+
 static const char *mg_strcasestr(const char *big_str, const char *small_str)
 {
 	size_t i, big_len = strlen(big_str), small_len = strlen(small_str);
@@ -1413,6 +1430,7 @@ static const char *mg_strcasestr(const char *big_str, const char *small_str)
 	return NULL;
 }
 
+
 /* Return null terminated string of given maximum length.
  * Report errors if length is exceeded. */
 static void mg_vsnprintf(const struct mg_connection *conn,
@@ -1452,13 +1470,14 @@ static void mg_vsnprintf(const struct mg_connection *conn,
 		}
 		mg_cry(conn,
 		       "truncating vsnprintf buffer: [%.*s]",
-		       n > 200 ? 200 : n,
+		       buflen > 200 ? 200 : buflen - 1,
 		       buf);
 		n = (int)buflen - 1;
 	}
 	buf[n] = '\0';
 }
 
+
 static void mg_snprintf(const struct mg_connection *conn,
                         int *truncated,
                         char *buf,
@@ -1473,6 +1492,7 @@ static void mg_snprintf(const struct mg_connection *conn,
 	va_end(ap);
 }
 
+
 static int get_option_index(const char *name)
 {
 	int i;
@@ -1485,6 +1505,7 @@ static int get_option_index(const char *name)
 	return -1;
 }
 
+
 const char *mg_get_option(const struct mg_context *ctx, const char *name)
 {
 	int i;
@@ -1497,16 +1518,19 @@ const char *mg_get_option(const struct mg_context *ctx, const char *name)
 	}
 }
 
+
 struct mg_context *mg_get_context(const struct mg_connection *conn)
 {
 	return (conn == NULL) ? (struct mg_context *)NULL : (conn->ctx);
 }
 
+
 void *mg_get_user_data(const struct mg_context *ctx)
 {
 	return (ctx == NULL) ? NULL : ctx->user_data;
 }
 
+
 void mg_set_user_connection_data(const struct mg_connection *conn, void *data)
 {
 	if (conn != NULL) {
@@ -1514,6 +1538,7 @@ void mg_set_user_connection_data(const struct mg_connection *conn, void *data)
 	}
 }
 
+
 void *mg_get_user_connection_data(const struct mg_connection *conn)
 {
 	if (conn != NULL) {
@@ -1522,6 +1547,7 @@ void *mg_get_user_connection_data(const struct mg_connection *conn)
 	return NULL;
 }
 
+
 size_t
 mg_get_ports(const struct mg_context *ctx, size_t size, int *ports, int *ssl)
 {
@@ -1536,6 +1562,7 @@ mg_get_ports(const struct mg_context *ctx, size_t size, int *ports, int *ssl)
 	return i;
 }
 
+
 static void sockaddr_to_string(char *buf, size_t len, const union usa *usa)
 {
 	buf[0] = '\0';
@@ -1566,6 +1593,7 @@ static void sockaddr_to_string(char *buf, size_t len, const union usa *usa)
 #endif
 }
 
+
 /* Convert time_t to a string. According to RFC2616, Sec 14.18, this must be
  * included in all responses other than 100, 101, 5xx. */
 static void gmt_time_string(char *buf, size_t buf_len, time_t *t)
@@ -1581,6 +1609,7 @@ static void gmt_time_string(char *buf, size_t buf_len, time_t *t)
 	}
 }
 
+
 /* difftime for struct timespec. Return value is in seconds. */
 static double mg_difftimespec(const struct timespec *ts_now,
                               const struct timespec *ts_before)
@@ -1589,6 +1618,7 @@ static double mg_difftimespec(const struct timespec *ts_now,
 	       (double)(ts_now->tv_sec - ts_before->tv_sec);
 }
 
+
 /* Print error message to the opened error log stream. */
 void mg_cry(const struct mg_connection *conn, const char *fmt, ...)
 {
@@ -1600,6 +1630,7 @@ void mg_cry(const struct mg_connection *conn, const char *fmt, ...)
 	va_start(ap, fmt);
 	IGNORE_UNUSED_RESULT(vsnprintf_impl(buf, sizeof(buf), fmt, ap));
 	va_end(ap);
+	buf[sizeof(buf) - 1] = 0;
 
 	/* Do not lock when getting the callback value, here and below.
 	 * I suppose this is fine, since function cannot disappear in the
@@ -1635,6 +1666,7 @@ void mg_cry(const struct mg_connection *conn, const char *fmt, ...)
 	}
 }
 
+
 /* Return fake connection structure. Used for logging, if connection
  * is not applicable at the moment of logging. */
 static struct mg_connection *fc(struct mg_context *ctx)
@@ -1644,11 +1676,13 @@ static struct mg_connection *fc(struct mg_context *ctx)
 	return &fake_connection;
 }
 
+
 const char *mg_version(void)
 {
 	return CIVETWEB_VERSION;
 }
 
+
 const struct mg_request_info *
 mg_get_request_info(const struct mg_connection *conn)
 {
@@ -1658,6 +1692,7 @@ mg_get_request_info(const struct mg_connection *conn)
 	return &conn->request_info;
 }
 
+
 /* Skip the characters until one of the delimiters characters found.
  * 0-terminate resulting word. Skip the delimiter and following whitespaces.
  * Advance pointer to buffer to the next word. Return found 0-terminated word.
@@ -1711,6 +1746,7 @@ static char *skip_quoted(char **buf,
 	return begin_word;
 }
 
+
 /* Simplified version of skip_quoted without quote char
  * and whitespace == delimiters */
 static char *skip(char **buf, const char *delimiters)
@@ -1718,6 +1754,7 @@ static char *skip(char **buf, const char *delimiters)
 	return skip_quoted(buf, delimiters, delimiters, 0);
 }
 
+
 /* Return HTTP header value, or NULL if not found. */
 static const char *get_header(const struct mg_request_info *ri,
                               const char *name)
@@ -1734,6 +1771,7 @@ static const char *get_header(const struct mg_request_info *ri,
 	return NULL;
 }
 
+
 const char *mg_get_header(const struct mg_connection *conn, const char *name)
 {
 	if (!conn) {
@@ -1743,6 +1781,7 @@ const char *mg_get_header(const struct mg_connection *conn, const char *name)
 	return get_header(&conn->request_info, name);
 }
 
+
 /* A helper function for traversing a comma separated list of values.
  * It returns a list pointer shifted to the next value, or NULL if the end
  * of the list found.
@@ -1783,6 +1822,7 @@ next_option(const char *list, struct vec *val, struct vec *eq_val)
 	return list;
 }
 
+
 /* Perform case-insensitive match of string against pattern */
 static int
 match_prefix(const char *pattern, size_t pattern_len, const char *str)
@@ -1826,6 +1866,7 @@ match_prefix(const char *pattern, size_t pattern_len, const char *str)
 	return j;
 }
 
+
 /* HTTP 1.1 assumes keep alive if "Connection:" header is not set
  * This function must tolerate situations when connection info is not
  * set up, for example if request parsing failed. */
@@ -1847,6 +1888,7 @@ static int should_keep_alive(const struct mg_connection *conn)
 	return 0;
 }
 
+
 static int should_decode_url(const struct mg_connection *conn)
 {
 	if (!conn || !conn->ctx) {
@@ -1856,17 +1898,20 @@ static int should_decode_url(const struct mg_connection *conn)
 	return (mg_strcasecmp(conn->ctx->config[DECODE_URL], "yes") == 0);
 }
 
+
 static const char *suggest_connection_header(const struct mg_connection *conn)
 {
 	return should_keep_alive(conn) ? "keep-alive" : "close";
 }
 
+
 static void handle_file_based_request(struct mg_connection *conn,
                                       const char *path,
                                       struct file *filep);
 static int
 mg_stat(struct mg_connection *conn, const char *path, struct file *filep);
 
+
 static const char *mg_get_response_code_text(int response_code,
                                              struct mg_connection *conn)
 {
@@ -2044,6 +2089,7 @@ static const char *mg_get_response_code_text(int response_code,
 	}
 }
 
+
 static void send_http_error(struct mg_connection *,
                             int,
                             PRINTF_FORMAT_STRING(const char *fmt),
@@ -2178,6 +2224,7 @@ send_http_error(struct mg_connection *conn, int status, const char *fmt, ...)
 #pragma GCC diagnostic ignored "-Wunused-function"
 #endif
 
+
 static int pthread_mutex_init(pthread_mutex_t *mutex, void *unused)
 {
 	(void)unused;
@@ -2185,16 +2232,19 @@ static int pthread_mutex_init(pthread_mutex_t *mutex, void *unused)
 	return *mutex == NULL ? -1 : 0;
 }
 
+
 static int pthread_mutex_destroy(pthread_mutex_t *mutex)
 {
 	return CloseHandle(*mutex) == 0 ? -1 : 0;
 }
 
+
 static int pthread_mutex_lock(pthread_mutex_t *mutex)
 {
 	return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0 ? 0 : -1;
 }
 
+
 #ifdef ENABLE_UNUSED_PTHREAD_FUNCTIONS
 static int pthread_mutex_trylock(pthread_mutex_t *mutex)
 {
@@ -3389,6 +3439,7 @@ static int pull_all(FILE *fp, struct mg_connection *conn, char *buf, int len)
 	return nread;
 }
 
+
 static void discard_unread_request_data(struct mg_connection *conn)
 {
 	char buf[MG_BUF_LEN];
@@ -3427,6 +3478,7 @@ static void discard_unread_request_data(struct mg_connection *conn)
 	}
 }
 
+
 static int mg_read_inner(struct mg_connection *conn, void *buf, size_t len)
 {
 	int64_t n, buffered_len, nread;
@@ -3484,6 +3536,7 @@ static int mg_read_inner(struct mg_connection *conn, void *buf, size_t len)
 	return (int)nread;
 }
 
+
 static char mg_getc(struct mg_connection *conn)
 {
 	char c;
@@ -3497,6 +3550,7 @@ static char mg_getc(struct mg_connection *conn)
 	return c;
 }
 
+
 int mg_read(struct mg_connection *conn, void *buf, size_t len)
 {
 	if (len > INT_MAX) {
@@ -3575,6 +3629,7 @@ int mg_read(struct mg_connection *conn, void *buf, size_t len)
 	return mg_read_inner(conn, buf, len);
 }
 
+
 int mg_write(struct mg_connection *conn, const void *buf, size_t len)
 {
 	time_t now;
@@ -3631,6 +3686,7 @@ int mg_write(struct mg_connection *conn, const void *buf, size_t len)
 	return (int)total;
 }
 
+
 /* Alternative alloc_vprintf() for non-compliant C runtimes */
 static int alloc_vprintf2(char **buf, const char *fmt, va_list ap)
 {
@@ -3655,6 +3711,7 @@ static int alloc_vprintf2(char **buf, const char *fmt, va_list ap)
 	return len;
 }
 
+
 /* Print message to buffer. If buffer is large enough to hold the message,
  * return buffer. If buffer is to small, allocate large enough buffer on heap,
  * and return allocated buffer. */
@@ -3692,6 +3749,7 @@ static int alloc_vprintf(char **buf, size_t size, const char *fmt, va_list ap)
 	return len;
 }
 
+
 static int mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap)
 {
 	char mem[MG_BUF_LEN], *buf = mem;
@@ -3707,6 +3765,7 @@ static int mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap)
 	return len;
 }
 
+
 int mg_printf(struct mg_connection *conn, const char *fmt, ...)
 {
 	va_list ap;
@@ -3719,6 +3778,7 @@ int mg_printf(struct mg_connection *conn, const char *fmt, ...)
 	return result;
 }
 
+
 int mg_url_decode(const char *src,
                   int src_len,
                   char *dst,
@@ -3748,6 +3808,7 @@ int mg_url_decode(const char *src,
 	return i >= src_len ? j : -1;
 }
 
+
 int mg_get_var(const char *data,
                size_t data_len,
                const char *name,
@@ -3757,6 +3818,7 @@ int mg_get_var(const char *data,
 	return mg_get_var2(data, data_len, name, dst, dst_len, 0);
 }
 
+
 int mg_get_var2(const char *data,
                 size_t data_len,
                 const char *name,
@@ -3812,6 +3874,7 @@ int mg_get_var2(const char *data,
 	return len;
 }
 
+
 int mg_get_cookie(const char *cookie_header,
                   const char *var_name,
                   char *dst,
@@ -3856,6 +3919,7 @@ int mg_get_cookie(const char *cookie_header,
 	return len;
 }
 
+
 #if defined(USE_WEBSOCKET) || defined(USE_LUA)
 static void base64_encode(const unsigned char *src, int src_len, char *dst)
 {
@@ -3884,6 +3948,7 @@ static void base64_encode(const unsigned char *src, int src_len, char *dst)
 }
 #endif
 
+
 #if defined(USE_LUA)
 static unsigned char b64reverse(char letter)
 {
@@ -3908,6 +3973,7 @@ static unsigned char b64reverse(char letter)
 	return 254; /* error */
 }
 
+
 static int
 base64_decode(const unsigned char *src, int src_len, char *dst, size_t *dst_len)
 {
@@ -3949,6 +4015,7 @@ base64_decode(const unsigned char *src, int src_len, char *dst, size_t *dst_len)
 }
 #endif
 
+
 static int is_put_or_delete_method(const struct mg_connection *conn)
 {
 	if (conn) {
@@ -3959,6 +4026,7 @@ static int is_put_or_delete_method(const struct mg_connection *conn)
 	return 0;
 }
 
+
 static void
 interpret_uri(struct mg_connection *conn,   /* in: request */
               char *filename,               /* out: filename */
@@ -4169,6 +4237,7 @@ interpret_cleanup:
 #endif
 }
 
+
 /* Check whether full request is buffered. Return:
  * -1  if request is malformed
  *  0  if request is not yet fully buffered