Skip to content

Commit 14ca9e9

Browse files
cataphractbwoebi
authored andcommitted
Fix several bugs and potential bugs in appsec
* Fix free on possibly invalid pointer (the pointer might have been advanced in rare circumstances) * Remove limit enforcing on the helper. If a limit was violated, it would invalidate the full message. * Improve limits on the extension. * Avoid using malloc on the extension when possible; make the mpack library use Zend's emalloc. * Increase max message size on the helper from 64k to 700k. This should be able to accomodate msgpack-serialized json messages of 512k. (The limit on the extension is 4 MB and it was not changed) (cherry picked from commit c826df2)
1 parent fd66c98 commit 14ca9e9

File tree

19 files changed

+455
-381
lines changed

19 files changed

+455
-381
lines changed

appsec/src/extension/commands/config_sync.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
#include "../logging.h"
1313
#include "../msgpack_helpers.h"
1414
#include "config_sync.h"
15-
#include <mpack.h>
1615

1716
static dd_result _request_pack(mpack_writer_t *nonnull w, void *nonnull ctx);
1817
dd_result dd_command_process_config_sync(

appsec/src/extension/commands/request_exec.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,13 @@ static dd_result _pack_command(mpack_writer_t *nonnull w, void *nonnull _ctx)
5050
struct ctx *ctx = _ctx;
5151

5252
dd_mpack_write_nullable_zstr(w, ctx->rasp_rule);
53-
dd_mpack_write_zval(w, ctx->data);
53+
54+
dd_mpack_limits limits = dd_mpack_def_limits;
55+
dd_mpack_write_zval_lim(w, ctx->data, &limits);
56+
57+
if (dd_mpack_limits_reached(&limits)) {
58+
mlog(dd_log_info, "Limits reched when serializing request exec data");
59+
}
5460

5561
return dd_success;
5662
}

appsec/src/extension/commands/request_init.c

Lines changed: 62 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,12 @@
99

1010
#include "../commands_helpers.h"
1111
#include "../configuration.h"
12-
#include "../ddappsec.h"
13-
#include "../ddtrace.h"
12+
#include "../ddappsec.h" // NOLINT(unused-includes)
1413
#include "../entity_body.h"
15-
#include "../ip_extraction.h"
1614
#include "../logging.h"
1715
#include "../msgpack_helpers.h"
18-
#include "../php_compat.h"
16+
#include "../php_compat.h" // NOLINT(unused-includes)
17+
#include "../php_helpers.h"
1918
#include "../string_helpers.h"
2019
#include "request_init.h"
2120
#include <mpack.h>
@@ -31,7 +30,8 @@ static void _pack_files_field_names(
3130
static void _pack_path_params(
3231
mpack_writer_t *nonnull w, const zend_string *nullable uri_raw);
3332
static void _pack_request_body(mpack_writer_t *nonnull w,
34-
struct req_info_init *nonnull ctx, const zend_array *nonnull server);
33+
struct req_info_init *nonnull ctx, const zend_array *nonnull server,
34+
dd_mpack_limits *nonnull limits);
3535

3636
static const dd_command_spec _spec = {
3737
.name = "request_init",
@@ -64,20 +64,27 @@ static dd_result _request_pack(mpack_writer_t *nonnull w, void *nonnull _ctx)
6464
// Pack data from SAPI request_info
6565
sapi_request_info *request_info = &SG(request_info);
6666

67+
// Limits applied to query, cookies and request body
68+
dd_mpack_limits limits = dd_mpack_def_limits;
69+
6770
// 1.
6871
dd_mpack_write_lstr(w, "server.request.query");
69-
dd_mpack_write_array(w, dd_get_superglob_or_equiv(ZEND_STRL("_GET"),
70-
TRACK_VARS_GET, ctx->superglob_equiv));
72+
dd_mpack_write_array_lim(w,
73+
dd_get_superglob_or_equiv(
74+
ZEND_STRL("_GET"), TRACK_VARS_GET, ctx->superglob_equiv),
75+
&limits);
7176

7277
// 2.
7378
const zend_array *nonnull server = dd_get_superglob_or_equiv(
7479
ZEND_STRL("_SERVER"), TRACK_VARS_SERVER, ctx->superglob_equiv);
7580
dd_mpack_write_lstr(w, "server.request.method");
7681
if (ctx->superglob_equiv) {
77-
dd_mpack_write_nullable_zstr(w,
78-
dd_php_get_string_elem_cstr(server, ZEND_STRL("REQUEST_METHOD")));
82+
dd_mpack_write_nullable_zstr_lim(w,
83+
dd_php_get_string_elem_cstr(server, ZEND_STRL("REQUEST_METHOD")),
84+
limits.max_string_length);
7985
} else {
80-
mpack_write(w, request_info->request_method);
86+
dd_mpack_write_nullable_cstr_lim(
87+
w, request_info->request_method, limits.max_string_length);
8188
}
8289

8390
// Pack data from server global
@@ -87,22 +94,24 @@ static dd_result _request_pack(mpack_writer_t *nonnull w, void *nonnull _ctx)
8794

8895
// 3.
8996
dd_mpack_write_lstr(w, "server.request.cookies");
90-
dd_mpack_write_array(w, dd_get_superglob_or_equiv(ZEND_STRL("_COOKIE"),
91-
TRACK_VARS_COOKIE, ctx->superglob_equiv));
97+
dd_mpack_write_array_lim(w,
98+
dd_get_superglob_or_equiv(
99+
ZEND_STRL("_COOKIE"), TRACK_VARS_COOKIE, ctx->superglob_equiv),
100+
&limits);
92101

93102
// 4.
94103
const zend_string *nullable request_uri =
95104
dd_php_get_string_elem_cstr(server, ZEND_STRL("REQUEST_URI"));
96105
dd_mpack_write_lstr(w, "server.request.uri.raw");
97-
dd_mpack_write_nullable_zstr(w, request_uri);
106+
dd_mpack_write_nullable_zstr_lim(w, request_uri, limits.max_string_length);
98107

99108
// 5.
100109
dd_mpack_write_lstr(w, "server.request.headers.no_cookies");
101110
_pack_headers(w, server);
102111

103112
// 6.
104113
dd_mpack_write_lstr(w, "server.request.body");
105-
_pack_request_body(w, ctx, server);
114+
_pack_request_body(w, ctx, server, &limits);
106115

107116
// 7.
108117
const zend_array *nonnull files = dd_get_superglob_or_equiv(
@@ -130,6 +139,10 @@ static dd_result _request_pack(mpack_writer_t *nonnull w, void *nonnull _ctx)
130139

131140
mpack_finish_map(w);
132141

142+
if (dd_mpack_limits_reached(&limits)) {
143+
mlog(dd_log_info, "Limits reched when serializing request init");
144+
}
145+
133146
return dd_success;
134147
}
135148

@@ -163,6 +176,9 @@ static void _pack_headers(
163176
{
164177
mpack_build_map(w);
165178

179+
// apply limits to part of the headers map
180+
dd_mpack_limits limits = dd_mpack_def_limits;
181+
166182
// Pack headers
167183
zend_string *key;
168184
zval *val;
@@ -172,12 +188,17 @@ static void _pack_headers(
172188
continue;
173189
}
174190

191+
if (limits.elements_remaining == 0) {
192+
mlog(dd_log_warning, "Headers map is full, stopping");
193+
break;
194+
}
195+
175196
if (zend_string_equals_literal(key, "CONTENT_TYPE")) {
176197
dd_mpack_write_lstr(w, "content-type");
177-
dd_mpack_write_zval(w, val);
198+
dd_mpack_write_zval_lim(w, val, &limits);
178199
} else if (zend_string_equals_literal(key, "CONTENT_LENGTH")) {
179200
dd_mpack_write_lstr(w, "content-length");
180-
dd_mpack_write_zval(w, val);
201+
dd_mpack_write_zval_lim(w, val, &limits);
181202
} else if (zend_string_equals_literal(key, "PHP_AUTH_DIGEST")) {
182203
if (Z_TYPE_P(val) == IS_STRING && Z_STRLEN_P(val) > 0) {
183204
dd_mpack_write_lstr(w, "authorization");
@@ -186,14 +207,16 @@ static void _pack_headers(
186207
memcpy(auth_str, "digest ", sizeof("digest ") - 1);
187208
memcpy(auth_str + sizeof("digest ") - 1, Z_STRVAL_P(val),
188209
Z_STRLEN_P(val));
189-
mpack_write_str(w, auth_str, auth_len);
210+
dd_mpack_write_nullable_str_lim(
211+
w, auth_str, auth_len, limits.max_string_length);
190212
efree(auth_str);
191213
}
192-
} else if (_is_relevant_header(key)) {
214+
} else if (_is_relevant_header(key)) { // i.e. not a cookie header
193215
zend_string *transf_header_name = _transform_header_name(key);
194-
dd_mpack_write_zstr(w, transf_header_name);
216+
dd_mpack_write_zstr_lim(
217+
w, transf_header_name, limits.max_string_length);
195218
zend_string_efree(transf_header_name);
196-
dd_mpack_write_zval(w, val);
219+
dd_mpack_write_zval_lim(w, val, &limits);
197220
}
198221
}
199222
ZEND_HASH_FOREACH_END();
@@ -290,29 +313,31 @@ static void _pack_path_params(
290313
}
291314

292315
static void _pack_request_body(mpack_writer_t *nonnull w,
293-
struct req_info_init *nonnull ctx, const zend_array *nonnull server)
316+
struct req_info_init *nonnull ctx, const zend_array *nonnull server,
317+
dd_mpack_limits *nonnull limits)
294318
{
295319
const zend_array *post = dd_get_superglob_or_equiv(
296320
ZEND_STRL("_POST"), TRACK_VARS_POST, ctx->superglob_equiv);
297321
if (zend_hash_num_elements(post) != 0) {
298322
dd_mpack_write_array(w, post);
299-
} else {
300-
bool written = false;
301-
if (ctx->entity) {
302-
zend_string *ct =
303-
dd_php_get_string_elem_cstr(server, ZEND_STRL("CONTENT_TYPE"));
304-
if (ct) {
305-
zval body_zv = dd_entity_body_convert(
306-
ZSTR_VAL(ct), ZSTR_LEN(ct), ctx->entity);
307-
if (Z_TYPE(body_zv) != IS_NULL) {
308-
dd_mpack_write_zval(w, &body_zv);
309-
zval_ptr_dtor(&body_zv);
310-
written = true;
311-
}
323+
return;
324+
}
325+
326+
bool written = false;
327+
if (ctx->entity) {
328+
zend_string *ct =
329+
dd_php_get_string_elem_cstr(server, ZEND_STRL("CONTENT_TYPE"));
330+
if (ct) {
331+
zval body_zv =
332+
dd_entity_body_convert(ZSTR_VAL(ct), ZSTR_LEN(ct), ctx->entity);
333+
if (Z_TYPE(body_zv) != IS_NULL) {
334+
dd_mpack_write_zval_lim(w, &body_zv, limits);
335+
zval_ptr_dtor(&body_zv);
336+
written = true;
312337
}
313338
}
314-
if (!written) {
315-
dd_mpack_write_array(w, &zend_empty_array);
316-
}
339+
}
340+
if (!written) {
341+
dd_mpack_write_array(w, &zend_empty_array);
317342
}
318343
}

appsec/src/extension/commands/request_shutdown.c

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,15 @@ static dd_result _request_pack(mpack_writer_t *nonnull w, void *nonnull ctx)
8282

8383
// 1.3.?
8484
if (Z_TYPE(resp_body) != IS_NULL) {
85+
dd_mpack_limits limits = dd_mpack_def_limits;
86+
8587
dd_mpack_write_lstr(w, "server.response.body");
86-
dd_mpack_write_zval(w, &resp_body);
88+
dd_mpack_write_zval_lim(w, &resp_body, &limits);
8789
zval_ptr_dtor_nogc(&resp_body);
90+
91+
if (dd_mpack_limits_reached(&limits)) {
92+
mlog(dd_log_info, "Limits reched when serializing response body");
93+
}
8894
}
8995

9096
mpack_finish_map(w);
@@ -157,13 +163,14 @@ static void _pack_headers_no_cookies_llist(
157163
zend_llist *coll;
158164
ZEND_HASH_FOREACH_STR_KEY_PTR(&headers_map, key, coll)
159165
{
160-
mpack_write_str(w, ZSTR_VAL(key), ZSTR_LEN(key));
161-
mpack_start_array(w, zend_llist_count(coll));
166+
dd_mpack_write_zstr(w, key);
162167

168+
mpack_start_array(w, zend_llist_count(coll));
163169
zend_llist_position p;
164170
for (struct _header_val *hv = zend_llist_get_first_ex(coll, &p); hv;
165171
hv = zend_llist_get_next_ex(coll, &p)) {
166-
mpack_write_str(w, hv->val, hv->len);
172+
dd_mpack_write_nullable_str_lim(
173+
w, hv->val, hv->len, DD_MPACK_DEF_STRING_LIMIT);
167174
}
168175
mpack_finish_array(w);
169176
}
@@ -217,15 +224,16 @@ static void _pack_headers_no_cookies_map(
217224
zend_string_addref(key);
218225
}
219226

220-
mpack_write_str(w, ZSTR_VAL(key), ZSTR_LEN(key));
227+
dd_mpack_write_zstr(w, key);
221228

222229
if (Z_TYPE_P(val) == IS_ARRAY) {
223230
mpack_start_array(w, zend_array_count(Z_ARRVAL_P(val)));
224231
zval *zv;
225232
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(val), zv)
226233
{
227234
if (Z_TYPE_P(zv) == IS_STRING) {
228-
mpack_write_str(w, Z_STRVAL_P(zv), Z_STRLEN_P(zv));
235+
dd_mpack_write_zstr_lim(
236+
w, Z_STR_P(zv), DD_MPACK_DEF_STRING_LIMIT);
229237
} else {
230238
mpack_write_str(w, ZEND_STRL("(invalid value)"));
231239
mlog(dd_log_warning,
@@ -237,7 +245,7 @@ static void _pack_headers_no_cookies_map(
237245
ZEND_HASH_FOREACH_END();
238246
} else if (Z_TYPE_P(val) == IS_STRING) {
239247
mpack_start_array(w, 1);
240-
mpack_write_str(w, Z_STRVAL_P(val), Z_STRLEN_P(val));
248+
dd_mpack_write_zstr_lim(w, Z_STR_P(val), DD_MPACK_DEF_STRING_LIMIT);
241249
} else {
242250
mpack_start_array(w, 1);
243251
mpack_write_str(w, ZEND_STRL("(invalid value)"));

appsec/src/extension/commands_helpers.c

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,8 @@ static dd_result _dd_command_exec(dd_conn *nonnull conn,
9999
dd_imsg imsg = {0};
100100
res = _imsg_recv(&imsg, conn);
101101
if (res) {
102-
if (res != dd_helper_error) {
103-
mlog(dd_log_warning,
104-
"Error receiving reply for command %.*s: %s", NAME_L,
105-
dd_result_to_string(res));
106-
}
102+
mlog(dd_log_warning, "Error receiving reply for command %.*s: %s",
103+
NAME_L, dd_result_to_string(res));
107104
return res;
108105
}
109106

@@ -283,7 +280,7 @@ static ATTR_WARN_UNUSED dd_result _imsg_recv(
283280
static inline ATTR_WARN_UNUSED mpack_error_t _imsg_destroy(
284281
dd_imsg *nonnull imsg)
285282
{
286-
free(imsg->_data);
283+
efree(imsg->_data);
287284
imsg->_data = NULL;
288285
imsg->_size = 0;
289286
return mpack_tree_destroy(&imsg->_tree);
@@ -825,7 +822,7 @@ void _handle_telemetry_metric(const char *nonnull key_str, size_t key_len,
825822
if (key_len == LSTRLEN(name) && memcmp(key_str, name, key_len) == 0) { \
826823
static zend_string *_Atomic key_zstr; \
827824
_init_zstr(&key_zstr, name, LSTRLEN(name)); \
828-
zend_string *tags_zstr = zend_string_init(tags_str, tags_len, 1); \
825+
zend_string *tags_zstr = zend_string_init(tags_str, tags_len, 0); \
829826
dd_telemetry_add_metric(key_zstr, value, tags_zstr, type); \
830827
zend_string_release(tags_zstr); \
831828
mlog_g(dd_log_debug, \
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#pragma once
2+
3+
#include <Zend/zend.h>
4+
5+
#define MPACK_MALLOC emalloc
6+
#define MPACK_REALLOC erealloc
7+
#define MPACK_FREE efree

0 commit comments

Comments
 (0)