Skip to content

Commit b4a3419

Browse files
Merge pull request NoiseByNorthwest#255 from NoiseByNorthwest/fix/251
Web UI: easier to reason about SPX_UI_URI confinement check
2 parents 9e5765c + 77ea779 commit b4a3419

21 files changed

+159
-49
lines changed

src/php_spx.c

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -924,24 +924,29 @@ static void http_ui_handler_shutdown(void)
924924
ui_uri = "/index.html";
925925
}
926926

927-
if (ui_uri[0] != '/' || strstr(ui_uri, "/../") != NULL) {
927+
if (ui_uri[0] != '/') {
928928
goto error_404;
929929
}
930930

931931
if (0 == http_ui_handler_data(SPX_G(data_dir), ui_uri)) {
932932
goto finish;
933933
}
934934

935-
char local_file_name[512];
936-
snprintf(
937-
local_file_name,
938-
sizeof(local_file_name),
939-
"%s%s",
940-
SPX_G(http_ui_assets_dir),
941-
ui_uri
942-
);
935+
char local_file_absolute_path[PATH_MAX];
936+
937+
if (
938+
spx_utils_resolve_confined_file_absolute_path(
939+
SPX_G(http_ui_assets_dir),
940+
ui_uri,
941+
NULL,
942+
local_file_absolute_path,
943+
sizeof(local_file_absolute_path)
944+
) == NULL
945+
) {
946+
goto error_404;
947+
}
943948

944-
if (0 == http_ui_handler_output_file(local_file_name)) {
949+
if (0 == http_ui_handler_output_file(local_file_absolute_path)) {
945950
goto finish;
946951
}
947952

@@ -1029,26 +1034,34 @@ static int http_ui_handler_data(const char * data_dir, const char *relative_path
10291034

10301035
const char * get_report_metadata_uri = "/data/reports/metadata/";
10311036
if (spx_utils_str_starts_with(relative_path, get_report_metadata_uri)) {
1032-
char file_name[512];
1033-
spx_reporter_full_build_metadata_file_name(
1034-
data_dir,
1035-
relative_path + strlen(get_report_metadata_uri),
1036-
file_name,
1037-
sizeof(file_name)
1038-
);
1037+
char file_name[PATH_MAX];
1038+
if (
1039+
spx_reporter_full_build_metadata_file_name(
1040+
data_dir,
1041+
relative_path + strlen(get_report_metadata_uri),
1042+
file_name,
1043+
sizeof(file_name)
1044+
) == NULL
1045+
) {
1046+
return -1;
1047+
}
10391048

10401049
return http_ui_handler_output_file(file_name);
10411050
}
10421051

10431052
const char * get_report_uri = "/data/reports/get/";
10441053
if (spx_utils_str_starts_with(relative_path, get_report_uri)) {
1045-
char file_name[512];
1046-
spx_reporter_full_build_file_name(
1047-
data_dir,
1048-
relative_path + strlen(get_report_uri),
1049-
file_name,
1050-
sizeof(file_name)
1051-
);
1054+
char file_name[PATH_MAX];
1055+
if (
1056+
spx_reporter_full_build_file_name(
1057+
data_dir,
1058+
relative_path + strlen(get_report_uri),
1059+
file_name,
1060+
sizeof(file_name)
1061+
) == NULL
1062+
) {
1063+
return -1;
1064+
}
10521065

10531066
return http_ui_handler_output_file(file_name);
10541067
}

src/spx_reporter_full.c

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ typedef struct {
6767
typedef struct {
6868
spx_profiler_reporter_t base;
6969

70-
char metadata_file_name[512];
70+
char metadata_file_name[PATH_MAX];
7171
metadata_t * metadata;
7272
spx_output_stream_t * output;
7373

@@ -99,7 +99,7 @@ size_t spx_reporter_full_metadata_list_files(
9999
return 0;
100100
}
101101

102-
char file_path[512];
102+
char file_path[PATH_MAX];
103103
size_t count = 0;
104104
const struct dirent * entry;
105105
while ((entry = readdir(dir)) != NULL) {
@@ -124,33 +124,33 @@ size_t spx_reporter_full_metadata_list_files(
124124
return count;
125125
}
126126

127-
int spx_reporter_full_build_metadata_file_name(
127+
char * spx_reporter_full_build_metadata_file_name(
128128
const char * data_dir,
129129
const char * key,
130130
char * file_name,
131131
size_t size
132132
) {
133-
return snprintf(
134-
file_name,
135-
size,
136-
"%s/%s.json",
133+
return spx_utils_resolve_confined_file_absolute_path(
137134
data_dir,
138-
key
135+
key,
136+
".json",
137+
file_name,
138+
size
139139
);
140140
}
141141

142-
int spx_reporter_full_build_file_name(
142+
char * spx_reporter_full_build_file_name(
143143
const char * data_dir,
144144
const char * key,
145145
char * file_name,
146146
size_t size
147147
) {
148-
return snprintf(
149-
file_name,
150-
size,
151-
"%s/%s.txt.gz",
148+
return spx_utils_resolve_confined_file_absolute_path(
152149
data_dir,
153-
key
150+
key,
151+
".txt.gz",
152+
file_name,
153+
size
154154
);
155155
}
156156

@@ -173,19 +173,21 @@ spx_profiler_reporter_t * spx_reporter_full_create(const char * data_dir)
173173
goto error;
174174
}
175175

176-
char file_name[512];
177-
spx_reporter_full_build_file_name(
178-
data_dir,
179-
reporter->metadata->key,
176+
char file_name[PATH_MAX];
177+
snprintf(
180178
file_name,
181-
sizeof(file_name)
179+
sizeof(file_name),
180+
"%s/%s.txt.gz",
181+
data_dir,
182+
reporter->metadata->key
182183
);
183184

184-
spx_reporter_full_build_metadata_file_name(
185-
data_dir,
186-
reporter->metadata->key,
185+
snprintf(
187186
reporter->metadata_file_name,
188-
sizeof(reporter->metadata_file_name)
187+
sizeof(reporter->metadata_file_name),
188+
"%s/%s.json",
189+
data_dir,
190+
reporter->metadata->key
189191
);
190192

191193
(void) mkdir(data_dir, 0777);

src/spx_reporter_full.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,14 @@ size_t spx_reporter_full_metadata_list_files(
2626
void (*callback) (const char *, size_t)
2727
);
2828

29-
int spx_reporter_full_build_metadata_file_name(
29+
char * spx_reporter_full_build_metadata_file_name(
3030
const char * data_dir,
3131
const char * key,
3232
char * file_name,
3333
size_t size
3434
);
3535

36-
int spx_reporter_full_build_file_name(
36+
char * spx_reporter_full_build_file_name(
3737
const char * data_dir,
3838
const char * key,
3939
char * file_name,

src/spx_utils.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,52 @@
2121
#include <string.h>
2222
#include "spx_utils.h"
2323

24+
char * spx_utils_resolve_confined_file_absolute_path(
25+
const char * root_dir,
26+
const char * relative_path,
27+
const char * suffix,
28+
char * dst,
29+
size_t size
30+
) {
31+
if (size < PATH_MAX) {
32+
spx_utils_die("size < PATH_MAX");
33+
}
34+
35+
char absolute_file_path[PATH_MAX];
36+
37+
snprintf(
38+
absolute_file_path,
39+
sizeof(absolute_file_path),
40+
"%s%s%s",
41+
root_dir,
42+
relative_path,
43+
suffix == NULL ? "" : suffix
44+
);
45+
46+
if (realpath(absolute_file_path, dst) == NULL) {
47+
return NULL;
48+
}
49+
50+
char root_dir_real_path[PATH_MAX];
51+
if (realpath(root_dir, root_dir_real_path) == NULL) {
52+
return NULL;
53+
}
54+
55+
char expected_path_prefix[PATH_MAX + 1];
56+
snprintf(
57+
expected_path_prefix,
58+
sizeof(expected_path_prefix),
59+
"%s/",
60+
root_dir_real_path
61+
);
62+
63+
if (! spx_utils_str_starts_with(dst, expected_path_prefix)) {
64+
return NULL;
65+
}
66+
67+
return dst;
68+
}
69+
2470
char * spx_utils_json_escape(char * dst, const char * src, size_t limit)
2571
{
2672
size_t i = 0;

src/spx_utils.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#define SPX_UTILS_H_DEFINED
2121

2222
#include <stddef.h>
23+
#include <limits.h> /* PATH_MAX */
2324

2425
#define SPX_UTILS_TOKENIZE_STRING(str, delim, token, size, block) \
2526
do { \
@@ -49,6 +50,14 @@ do { \
4950
} \
5051
} while (0)
5152

53+
char * spx_utils_resolve_confined_file_absolute_path(
54+
const char * root_dir,
55+
const char * relative_path,
56+
const char * suffix,
57+
char * dst,
58+
size_t size
59+
);
60+
5261
char * spx_utils_json_escape(char * dst, const char * src, size_t limit);
5362
int spx_utils_str_starts_with(const char * str, const char * prefix);
5463
int spx_utils_str_ends_with(const char * str, const char * suffix);

tests/spx_auth_ip_ko.phpt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Authentication: KO (invalid IP address)
55
spx.http_enabled=1
66
spx.http_key="dev"
77
spx.http_ip_whitelist="127.0.0.1,127.0.0.2,127.0.0.3"
8+
spx.http_ui_assets_dir="{PWD}/../assets/web-ui"
89
log_errors=on
910
--ENV--
1011
return <<<END

tests/spx_auth_ip_ok.phpt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Authentication: OK (valid IP address)
55
spx.http_enabled=1
66
spx.http_key="dev"
77
spx.http_ip_whitelist="127.0.0.1,127.0.0.2,127.0.0.3"
8+
spx.http_ui_assets_dir="{PWD}/../assets/web-ui"
89
log_errors=on
910
--ENV--
1011
return <<<END

tests/spx_auth_ip_trusted_proxy_ko.phpt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ spx.http_key="dev"
77
spx.http_ip_var="HTTP_X_FORWARDED_FOR"
88
spx.http_trusted_proxies="127.0.0.2,127.0.0.3,127.0.0.4"
99
spx.http_ip_whitelist="127.0.0.5"
10+
spx.http_ui_assets_dir="{PWD}/../assets/web-ui"
1011
log_errors=on
1112
--ENV--
1213
return <<<END

tests/spx_auth_ip_trusted_proxy_ok.phpt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ spx.http_key="dev"
77
spx.http_ip_var="HTTP_X_FORWARDED_FOR"
88
spx.http_trusted_proxies="127.0.0.2,127.0.0.3,127.0.0.4"
99
spx.http_ip_whitelist="127.0.0.5"
10+
spx.http_ui_assets_dir="{PWD}/../assets/web-ui"
1011
log_errors=on
1112
--ENV--
1213
return <<<END

tests/spx_auth_ipv6_ko.phpt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Authentication: KO (invalid IPv6 address)
55
spx.http_enabled=1
66
spx.http_key="dev"
77
spx.http_ip_whitelist="0000:0000:0000:0000:0000:ffff:127.0.0.1,0000:0000:0000:0000:0000:ffff:127.0.0.2,0000:0000:0000:0000:0000:ffff:127.0.0.3"
8+
spx.http_ui_assets_dir="{PWD}/../assets/web-ui"
89
log_errors=on
910
--ENV--
1011
return <<<END

0 commit comments

Comments
 (0)