http_static: sanitize path before file read
Romove dot segments from requested target path before start reading file in file handler to prevent path traversal. Type: fix Change-Id: I3bdd3e9d7fffd33c9c8c608169c1dc73423b7078 Signed-off-by: Matus Fabian <matfabia@cisco.com>
This commit is contained in:
committed by
Florin Coras
parent
a93c85a579
commit
5409d33002
@@ -277,6 +277,74 @@ http_state_is_tx_valid (http_conn_t *hc)
|
||||
state == HTTP_STATE_WAIT_APP_METHOD);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove dot segments from path (RFC3986 section 5.2.4)
|
||||
*
|
||||
* @param path Path to sanitize.
|
||||
*
|
||||
* @return New vector with sanitized path.
|
||||
*
|
||||
* The caller is always responsible to free the returned vector.
|
||||
*/
|
||||
always_inline u8 *
|
||||
http_path_remove_dot_segments (u8 *path)
|
||||
{
|
||||
u32 *segments = 0, *segments_len = 0, segment_len;
|
||||
u8 *new_path = 0;
|
||||
int i, ii;
|
||||
|
||||
if (!path)
|
||||
return vec_new (u8, 0);
|
||||
|
||||
segments = vec_new (u32, 1);
|
||||
/* first segment */
|
||||
segments[0] = 0;
|
||||
/* find all segments */
|
||||
for (i = 1; i < (vec_len (path) - 1); i++)
|
||||
{
|
||||
if (path[i] == '/')
|
||||
vec_add1 (segments, i + 1);
|
||||
}
|
||||
/* dummy tail */
|
||||
vec_add1 (segments, vec_len (path));
|
||||
|
||||
/* scan all segments for "." and ".." */
|
||||
segments_len = vec_new (u32, vec_len (segments) - 1);
|
||||
for (i = 0; i < vec_len (segments_len); i++)
|
||||
{
|
||||
segment_len = segments[i + 1] - segments[i];
|
||||
if (segment_len == 2 && path[segments[i]] == '.')
|
||||
segment_len = 0;
|
||||
else if (segment_len == 3 && path[segments[i]] == '.' &&
|
||||
path[segments[i] + 1] == '.')
|
||||
{
|
||||
segment_len = 0;
|
||||
/* remove parent (if any) */
|
||||
for (ii = i - 1; ii >= 0; ii--)
|
||||
{
|
||||
if (segments_len[ii])
|
||||
{
|
||||
segments_len[ii] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
segments_len[i] = segment_len;
|
||||
}
|
||||
|
||||
/* we might end with empty path, so return at least empty vector */
|
||||
new_path = vec_new (u8, 0);
|
||||
/* append all valid segments */
|
||||
for (i = 0; i < vec_len (segments_len); i++)
|
||||
{
|
||||
if (segments_len[i])
|
||||
vec_add (new_path, path + segments[i], segments_len[i]);
|
||||
}
|
||||
vec_free (segments);
|
||||
vec_free (segments_len);
|
||||
return new_path;
|
||||
}
|
||||
|
||||
#endif /* SRC_PLUGINS_HTTP_HTTP_H_ */
|
||||
|
||||
/*
|
||||
|
||||
@@ -357,7 +357,7 @@ try_file_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt,
|
||||
u8 *request)
|
||||
{
|
||||
http_status_code_t sc = HTTP_STATUS_OK;
|
||||
u8 *path;
|
||||
u8 *path, *sanitized_path;
|
||||
u32 ce_index;
|
||||
http_content_type_t type;
|
||||
|
||||
@@ -367,6 +367,9 @@ try_file_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt,
|
||||
|
||||
type = content_type_from_request (request);
|
||||
|
||||
/* Remove dot segments to prevent path traversal */
|
||||
sanitized_path = http_path_remove_dot_segments (request);
|
||||
|
||||
/*
|
||||
* Construct the file to open
|
||||
* Browsers are capable of sporadically including a leading '/'
|
||||
@@ -374,9 +377,9 @@ try_file_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt,
|
||||
if (!request)
|
||||
path = format (0, "%s%c", hsm->www_root, 0);
|
||||
else if (request[0] == '/')
|
||||
path = format (0, "%s%s%c", hsm->www_root, request, 0);
|
||||
path = format (0, "%s%s%c", hsm->www_root, sanitized_path, 0);
|
||||
else
|
||||
path = format (0, "%s/%s%c", hsm->www_root, request, 0);
|
||||
path = format (0, "%s/%s%c", hsm->www_root, sanitized_path, 0);
|
||||
|
||||
if (hsm->debug_level > 0)
|
||||
clib_warning ("%s '%s'", (rt == HTTP_REQ_GET) ? "GET" : "POST", path);
|
||||
@@ -419,7 +422,7 @@ try_file_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt,
|
||||
hs->cache_pool_index = ce_index;
|
||||
|
||||
done:
|
||||
|
||||
vec_free (sanitized_path);
|
||||
hs->content_type = type;
|
||||
start_send_data (hs, sc);
|
||||
if (!hs->data)
|
||||
|
||||
Reference in New Issue
Block a user