Streamline hardening helpers and expand coverage
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
#define PCRE2_CODE_UNIT_WIDTH 8
|
||||
#include <pcre2.h>
|
||||
#include <cctype>
|
||||
#include <stdexcept>
|
||||
|
||||
String var_dump(StringMap map, String prefix, String postfix)
|
||||
@@ -47,14 +48,14 @@ u8 hex_to_u8(String src)
|
||||
String to_lower(String s)
|
||||
{
|
||||
String result = s;
|
||||
std::transform(result.begin(), result.end(),result.begin(), ::tolower);
|
||||
std::transform(result.begin(), result.end(), result.begin(), [](unsigned char c) { return((char)std::tolower(c)); });
|
||||
return(result);
|
||||
}
|
||||
|
||||
String to_upper(String s)
|
||||
{
|
||||
String result = s;
|
||||
std::transform(result.begin(), result.end(),result.begin(), ::toupper);
|
||||
std::transform(result.begin(), result.end(), result.begin(), [](unsigned char c) { return((char)std::toupper(c)); });
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
+6
-8
@@ -496,14 +496,12 @@ String socket_read(u64 sockfd, u32 max_length, u32 timeout)
|
||||
tv.tv_sec = timeout;
|
||||
tv.tv_usec = 0;
|
||||
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);
|
||||
char buf[max_length+1];
|
||||
auto byte_count = recv(sockfd, buf, sizeof(buf), 0);
|
||||
if(max_length == 0)
|
||||
return("");
|
||||
std::vector<char> buf(max_length);
|
||||
auto byte_count = recv(sockfd, buf.data(), buf.size(), 0);
|
||||
if(byte_count > 0)
|
||||
{
|
||||
buf[byte_count] = 0;
|
||||
String result(buf, byte_count+1);
|
||||
return(result);
|
||||
}
|
||||
return(String(buf.data(), byte_count));
|
||||
return("");
|
||||
}
|
||||
|
||||
@@ -512,7 +510,7 @@ String memcache_escape_key(String key)
|
||||
String result;
|
||||
for(auto c : key)
|
||||
{
|
||||
if(isspace(c))
|
||||
if(isspace((unsigned char)c))
|
||||
c = '_';
|
||||
result.append(1, c);
|
||||
}
|
||||
|
||||
+1
-1
@@ -222,7 +222,7 @@ struct Request {
|
||||
bool websocket_is_binary = false;
|
||||
bool websocket_is_text = false;
|
||||
String current_unit_file = "";
|
||||
std::string params_buffer;
|
||||
String params_buffer;
|
||||
} resources;
|
||||
|
||||
void ob_start();
|
||||
|
||||
+37
-4
@@ -1,5 +1,6 @@
|
||||
#include "uri.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -174,7 +175,7 @@ String uri_decode(String q)
|
||||
for(u32 i = 0; i < q.length(); i++)
|
||||
{
|
||||
char c = q[i];
|
||||
if(c == '%' && q[i+1] != '%')
|
||||
if(c == '%' && i + 2 < q.length() && isxdigit((unsigned char)q[i + 1]) && isxdigit((unsigned char)q[i + 2]))
|
||||
{
|
||||
result.append(1, hex_to_u8(q.substr(i+1, 2)));
|
||||
i += 2;
|
||||
@@ -197,12 +198,12 @@ String uri_encode(String q)
|
||||
for(u32 i = 0; i < q.length(); i++)
|
||||
{
|
||||
char c = q[i];
|
||||
if(isalnum(c) || c == '~' || c == '.' || c == '_' || c == '-')
|
||||
if(isalnum((unsigned char)c) || c == '~' || c == '.' || c == '_' || c == '-')
|
||||
result.append(1, c);
|
||||
else
|
||||
{
|
||||
result.append(1, '%');
|
||||
result.append(to_hex(c));
|
||||
result.append(to_hex((u8)c, 2));
|
||||
}
|
||||
}
|
||||
return(result);
|
||||
@@ -259,7 +260,17 @@ String encode_query(StringMap map)
|
||||
return(result);
|
||||
}
|
||||
|
||||
namespace {
|
||||
bool http_header_name_valid(String name)
|
||||
{
|
||||
if(name == "")
|
||||
return(false);
|
||||
for(char c : name)
|
||||
{
|
||||
if(!(std::isalnum((unsigned char)c) || c == '-' || c == '_'))
|
||||
return(false);
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
String http_header_value_clean(String value)
|
||||
{
|
||||
@@ -271,6 +282,22 @@ String http_header_value_clean(String value)
|
||||
return(value);
|
||||
}
|
||||
|
||||
bool http_set_cookie_header_valid(String header)
|
||||
{
|
||||
if(header.find('\r') != String::npos || header.find('\n') != String::npos)
|
||||
return(false);
|
||||
return(str_starts_with(to_lower(header), "set-cookie: "));
|
||||
}
|
||||
|
||||
String http_status_line_clean(String status_line)
|
||||
{
|
||||
if(status_line.find('\r') != String::npos || status_line.find('\n') != String::npos)
|
||||
return("Status: 500 Internal Server Error");
|
||||
return(status_line);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
String cookie_attribute_value_clean(String value)
|
||||
{
|
||||
for(char& c : value)
|
||||
@@ -410,6 +437,12 @@ URI parse_uri(String uri_String)
|
||||
{
|
||||
URI result;
|
||||
|
||||
if(uri_String == "")
|
||||
{
|
||||
result.parts["raw"] = "";
|
||||
return(result);
|
||||
}
|
||||
|
||||
u8 state = 0;
|
||||
String current = "";
|
||||
char expect = 0;
|
||||
|
||||
+12
-1
@@ -40,6 +40,12 @@ bool zip_entry_name_safe(String name)
|
||||
if(name.find(":") != String::npos)
|
||||
return(false);
|
||||
|
||||
for(char c : name)
|
||||
{
|
||||
if(c == '\0' || (unsigned char)c < 0x20)
|
||||
return(false);
|
||||
}
|
||||
|
||||
auto parts = split(replace(name, "\\", "/"), "/");
|
||||
for(auto part : parts)
|
||||
{
|
||||
@@ -330,7 +336,12 @@ String gz_uncompress(String compressed)
|
||||
if(!out)
|
||||
throw std::runtime_error("gz_uncompress(): decompression failed");
|
||||
|
||||
archive_check_size("gz_uncompress", "output", out_len, "ARCHIVE_MAX_OUTPUT_BYTES", 64 * 1024 * 1024);
|
||||
u64 output_limit = archive_config_u64("ARCHIVE_MAX_OUTPUT_BYTES", 64 * 1024 * 1024);
|
||||
if(output_limit > 0 && out_len > output_limit)
|
||||
{
|
||||
mz_free(out);
|
||||
throw std::runtime_error("gz_uncompress(): output exceeds configured limit");
|
||||
}
|
||||
String result((char*)out, out_len);
|
||||
mz_free(out);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user