Skip to content

Commit 212de0b

Browse files
committed
Modify request_exec message
1 parent bc2d796 commit 212de0b

29 files changed

+375
-213
lines changed

appsec/src/extension/commands/request_exec.c

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,17 @@
99
#include "../ddappsec.h"
1010
#include "../logging.h"
1111
#include "../msgpack_helpers.h"
12+
#include <mpack.h>
1213
#include <php.h>
1314
#include <zend_hash.h>
1415
#include <zend_types.h>
1516

1617
struct ctx {
1718
struct req_info req_info; // dd_command_proc_resp_verd_span_data expect it
1819
zend_string *nullable rasp_rule;
19-
zval *nonnull data;
20+
zend_string *nullable subctx_id;
21+
bool subctx_last_call;
22+
zend_array *nonnull data;
2023
};
2124

2225
static dd_result _pack_command(mpack_writer_t *nonnull w, void *nonnull ctx);
@@ -30,16 +33,13 @@ static const dd_command_spec _spec = {
3033
.config_features_cb = dd_command_process_config_features_unexpected,
3134
};
3235

33-
dd_result dd_request_exec(
34-
dd_conn *nonnull conn, zval *nonnull data, zend_string *nullable rasp_rule)
36+
dd_result dd_request_exec(dd_conn *nonnull conn, zend_array *nonnull data,
37+
const struct req_exec_opts *nonnull opts)
3538
{
36-
if (Z_TYPE_P(data) != IS_ARRAY) {
37-
mlog(dd_log_debug, "Invalid data provided to command request_exec, "
38-
"expected hash table.");
39-
return dd_error;
40-
}
41-
42-
struct ctx ctx = {.rasp_rule = rasp_rule, .data = data};
39+
struct ctx ctx = {.data = data,
40+
.rasp_rule = opts->rasp_rule,
41+
.subctx_id = opts->subctx_id,
42+
.subctx_last_call = opts->subctx_last_call};
4343

4444
return dd_command_exec_req_info(conn, &_spec, &ctx.req_info);
4545
}
@@ -49,14 +49,31 @@ static dd_result _pack_command(mpack_writer_t *nonnull w, void *nonnull _ctx)
4949
assert(_ctx != NULL);
5050
struct ctx *ctx = _ctx;
5151

52-
dd_mpack_write_nullable_zstr(w, ctx->rasp_rule);
53-
5452
dd_mpack_limits limits = dd_mpack_def_limits;
55-
dd_mpack_write_zval_lim(w, ctx->data, &limits);
53+
dd_mpack_write_array_lim(w, ctx->data, &limits);
54+
55+
size_t num_map_elems =
56+
(ctx->rasp_rule != NULL) + (ctx->subctx_id != NULL) * 2;
57+
mpack_start_map(w, num_map_elems);
5658

5759
if (dd_mpack_limits_reached(&limits)) {
5860
mlog(dd_log_info, "Limits reched when serializing request exec data");
5961
}
6062

63+
if (ctx->rasp_rule != NULL) {
64+
dd_mpack_write_lstr(w, "rasp_rule");
65+
dd_mpack_write_zstr(w, ctx->rasp_rule);
66+
}
67+
68+
if (ctx->subctx_id != NULL) {
69+
dd_mpack_write_lstr(w, "subctx_id");
70+
dd_mpack_write_nullable_zstr(w, ctx->subctx_id);
71+
72+
dd_mpack_write_lstr(w, "subctx_last_call");
73+
mpack_write_bool(w, ctx->subctx_last_call);
74+
}
75+
76+
mpack_finish_map(w);
77+
6178
return dd_success;
6279
}

appsec/src/extension/commands/request_exec.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,11 @@
99
#include <SAPI.h>
1010
#include <php.h>
1111

12-
dd_result dd_request_exec(
13-
dd_conn *nonnull conn, zval *nonnull data, zend_string *nullable rasp_rule);
12+
struct req_exec_opts {
13+
zend_string *nullable rasp_rule;
14+
zend_string *nullable subctx_id;
15+
bool subctx_last_call;
16+
};
17+
18+
dd_result dd_request_exec(dd_conn *nonnull conn, zend_array *nonnull data,
19+
const struct req_exec_opts *nonnull opts);

appsec/src/extension/ddappsec.c

Lines changed: 76 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55
// (https://www.datadoghq.com/). Copyright 2021 Datadog, Inc.
66
#include <SAPI.h>
77
#include <Zend/zend_extensions.h>
8+
#include <Zend/zend_operators.h>
9+
#include <Zend/zend_string.h>
10+
#include <Zend/zend_types.h>
811
#include <ext/standard/info.h>
12+
#include <json/json.h>
913
#include <php.h>
1014

1115
// for open(2)
@@ -37,14 +41,12 @@
3741
#include "php_objects.h"
3842
#include "request_abort.h"
3943
#include "request_lifecycle.h"
44+
#include "string_helpers.h"
4045
#include "tags.h"
4146
#include "telemetry.h"
4247
#include "user_tracking.h"
4348
#include "version.h"
4449

45-
#include <json/json.h>
46-
#include <zend_string.h>
47-
4850
#if ZTS
4951
static atomic_int _thread_count;
5052
#endif
@@ -468,8 +470,12 @@ static PHP_FUNCTION(datadog_appsec_testing_stop_for_debugger)
468470

469471
static PHP_FUNCTION(datadog_appsec_testing_request_exec)
470472
{
471-
zval *data = NULL;
472-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &data) != SUCCESS) {
473+
zend_array *data;
474+
zend_string *rasp_rule = NULL;
475+
zend_string *subctx_id = NULL;
476+
bool subctx_last_call = false;
477+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "h|SSb", &data, &rasp_rule,
478+
&subctx_id, &subctx_last_call) != SUCCESS) {
473479
RETURN_FALSE;
474480
}
475481

@@ -483,7 +489,13 @@ static PHP_FUNCTION(datadog_appsec_testing_request_exec)
483489
RETURN_FALSE;
484490
}
485491

486-
if (dd_request_exec(conn, data, false) != dd_success) {
492+
struct req_exec_opts opts = {
493+
.rasp_rule = rasp_rule,
494+
.subctx_id = subctx_id,
495+
.subctx_last_call = subctx_last_call,
496+
};
497+
498+
if (dd_request_exec(conn, data, &opts) != dd_success) {
487499
RETURN_FALSE;
488500
}
489501

@@ -503,18 +515,64 @@ static PHP_FUNCTION(datadog_appsec_push_addresses)
503515
return;
504516
}
505517

506-
zval *addresses = NULL;
507-
zend_string *rasp_rule = NULL;
508-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|S", &addresses, &rasp_rule) ==
518+
zend_array *addresses = NULL;
519+
zval *opts_zv = NULL;
520+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "h|z!", &addresses, &opts_zv) ==
509521
FAILURE) {
510522
RETURN_FALSE;
511523
}
512524

513-
if (Z_TYPE_P(addresses) != IS_ARRAY) {
514-
RETURN_FALSE;
525+
if (opts_zv) {
526+
ZVAL_DEREF(opts_zv);
527+
}
528+
529+
struct req_exec_opts opts = {0};
530+
if (opts_zv && Z_TYPE_P(opts_zv) == IS_ARRAY) {
531+
zval *rasp_rule_zv =
532+
zend_hash_str_find(Z_ARR_P(opts_zv), LSTRARG("rasp_rule"));
533+
if (rasp_rule_zv) {
534+
ZVAL_DEREF(rasp_rule_zv);
535+
if (Z_TYPE_P(rasp_rule_zv) != IS_STRING) {
536+
php_error_docref(
537+
NULL, E_WARNING, "Invalid type for option rasp_rule");
538+
RETURN_FALSE;
539+
}
540+
opts.rasp_rule = Z_STR_P(rasp_rule_zv);
541+
}
542+
543+
zval *subctx_id_zv =
544+
zend_hash_str_find(Z_ARR_P(opts_zv), LSTRARG("subctx_id"));
545+
if (subctx_id_zv) {
546+
ZVAL_DEREF(subctx_id_zv);
547+
if (Z_TYPE_P(subctx_id_zv) != IS_STRING) {
548+
php_error_docref(
549+
NULL, E_WARNING, "Invalid type for option subctx_id");
550+
RETURN_FALSE;
551+
}
552+
opts.subctx_id = Z_STR_P(subctx_id_zv);
553+
}
554+
555+
zval *subctx_last_call_zv =
556+
zend_hash_str_find(Z_ARR_P(opts_zv), LSTRARG("subctx_last_call"));
557+
if (subctx_last_call_zv) {
558+
ZVAL_DEREF(subctx_last_call_zv);
559+
if (Z_TYPE_P(subctx_last_call_zv) != IS_TRUE &&
560+
Z_TYPE_P(subctx_last_call_zv) != IS_FALSE) {
561+
php_error_docref(NULL, E_WARNING,
562+
"Invalid type for option subctx_last_call");
563+
RETURN_FALSE;
564+
}
565+
opts.subctx_last_call = Z_TYPE_P(subctx_last_call_zv) == IS_TRUE;
566+
}
567+
} else if (opts_zv) {
568+
// legacy second string argument
569+
if (!try_convert_to_string(opts_zv)) {
570+
RETURN_FALSE;
571+
}
572+
opts.rasp_rule = Z_STR_P(opts_zv);
515573
}
516574

517-
if (rasp_rule && ZSTR_LEN(rasp_rule) > 0 &&
575+
if (opts.rasp_rule && ZSTR_LEN(opts.rasp_rule) > 0 &&
518576
!get_global_DD_APPSEC_RASP_ENABLED()) {
519577
return;
520578
}
@@ -525,9 +583,9 @@ static PHP_FUNCTION(datadog_appsec_push_addresses)
525583
return;
526584
}
527585

528-
dd_result res = dd_request_exec(conn, addresses, rasp_rule);
586+
dd_result res = dd_request_exec(conn, addresses, &opts);
529587

530-
if (rasp_rule && ZSTR_LEN(rasp_rule) > 0) {
588+
if (opts.rasp_rule && ZSTR_LEN(opts.rasp_rule) > 0) {
531589
clock_gettime(CLOCK_MONOTONIC_RAW, &end);
532590
elapsed =
533591
((int64_t)end.tv_sec - (int64_t)start.tv_sec) *
@@ -559,12 +617,15 @@ ZEND_END_ARG_INFO()
559617

560618
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(request_exec_arginfo, 0, 1, _IS_BOOL, 0)
561619
ZEND_ARG_INFO(0, "data")
620+
ZEND_ARG_INFO_WITH_DEFAULT_VALUE(0, "rasp_rule", NULL)
621+
ZEND_ARG_INFO_WITH_DEFAULT_VALUE(0, "subctx_id", NULL)
622+
ZEND_ARG_INFO_WITH_DEFAULT_VALUE(0, "subctx_last_call", false)
562623
ZEND_END_ARG_INFO()
563624

564625
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(
565626
push_addresses_arginfo, 0, 0, IS_VOID, 1)
566627
ZEND_ARG_INFO(0, addresses)
567-
ZEND_ARG_INFO(0, rasp)
628+
ZEND_ARG_INFO_WITH_DEFAULT_VALUE(0, rasp_rule_or_opts, NULL)
568629
ZEND_END_ARG_INFO()
569630

570631
// clang-format off

appsec/src/extension/user_tracking.c

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -233,44 +233,45 @@ void dd_find_and_apply_verdict_for_user(zend_string *nullable user_id,
233233
return;
234234
}
235235

236-
zval data_zv;
237-
size_t data_size = 0;
236+
zend_array *data_array;
237+
uint32_t data_size = 0;
238238
data_size += user_login != NULL && ZSTR_LEN(user_login) > 0 ? 1 : 0;
239239
data_size += user_id != NULL && ZSTR_LEN(user_id) > 0 ? 1 : 0;
240240
data_size += event != user_event_none ? 1 : 0;
241-
array_init_size(&data_zv, data_size);
241+
data_array = zend_new_array(data_size);
242242

243243
if (event == user_event_login_success) {
244-
zend_hash_str_add_empty_element(Z_ARRVAL(data_zv),
245-
LSTRARG("server.business_logic.users.login.success"));
244+
zend_hash_str_add_empty_element(
245+
data_array, LSTRARG("server.business_logic.users.login.success"));
246246
} else if (event == user_event_login_failure) {
247-
zend_hash_str_add_empty_element(Z_ARRVAL(data_zv),
248-
LSTRARG("server.business_logic.users.login.failure"));
247+
zend_hash_str_add_empty_element(
248+
data_array, LSTRARG("server.business_logic.users.login.failure"));
249249
}
250250

251251
if (user_login != NULL && ZSTR_LEN(user_login) > 0) {
252252
zval user_login_zv;
253253
ZVAL_STR_COPY(&user_login_zv, user_login);
254254

255-
zend_hash_str_add_new(Z_ARRVAL(data_zv), "usr.login",
256-
sizeof("usr.login") - 1, &user_login_zv);
255+
zend_hash_str_add_new(
256+
data_array, "usr.login", sizeof("usr.login") - 1, &user_login_zv);
257257
}
258258

259259
if (user_id != NULL && ZSTR_LEN(user_id) > 0) {
260260
zval user_id_zv;
261261
ZVAL_STR_COPY(&user_id_zv, user_id);
262262
zend_hash_str_add_new(
263-
Z_ARRVAL(data_zv), "usr.id", sizeof("usr.id") - 1, &user_id_zv);
263+
data_array, "usr.id", sizeof("usr.id") - 1, &user_id_zv);
264264
}
265265

266-
dd_result res = dd_request_exec(conn, &data_zv, false);
266+
dd_result res =
267+
dd_request_exec(conn, data_array, &(struct req_exec_opts){0});
267268
if (res == dd_network) {
268269
mlog_g(dd_log_info, "request_exec failed with dd_network; closing "
269270
"connection to helper");
270271
dd_helper_close_conn();
271272
}
272273

273-
zval_ptr_dtor(&data_zv);
274+
zend_array_destroy(data_array);
274275

275276
if (user_id != NULL && ZSTR_LEN(user_id) > 0) {
276277
dd_tags_set_event_user_id(user_id);

appsec/src/helper/client.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -230,14 +230,14 @@ template <typename T> bool client::service_guard()
230230

231231
template <typename T>
232232
std::shared_ptr<typename T::response> client::publish(
233-
typename T::request &command, const std::string &rasp_rule)
233+
typename T::request &command, const network::request_exec_options &options)
234234
{
235235
SPDLOG_DEBUG("received command {}", T::name);
236236

237237
auto response = std::make_shared<typename T::response>();
238238
try {
239239
// NOLINTNEXTLINE(bugprone-unchecked-optional-access)
240-
auto res = context_->publish(std::move(command.data), rasp_rule);
240+
auto res = context_->publish(std::move(command.data), options);
241241
if (res) {
242242
bool event_action = false;
243243
bool stack_trace = false;
@@ -319,7 +319,7 @@ bool client::handle_command(network::request_init::request &command)
319319
// During request init we initialize the engine context
320320
context_.emplace(*service_->get_engine());
321321

322-
auto response = publish<network::request_init>(command);
322+
auto response = publish<network::request_init>(command, {});
323323
if (response) {
324324
response->settings["auto_user_instrum"] = to_string_view(
325325
service_->get_service_config()->get_auto_user_intrum_mode());
@@ -338,7 +338,7 @@ bool client::handle_command(network::request_exec::request &command)
338338
context_.emplace(*service_->get_engine());
339339
}
340340

341-
auto response = publish<network::request_exec>(command, command.rasp_rule);
341+
auto response = publish<network::request_exec>(command, command.options);
342342
return send_message<network::request_exec>(response);
343343
}
344344

@@ -465,7 +465,7 @@ bool client::handle_command(network::request_shutdown::request &command)
465465
command.data.add("waf.context.processor", std::move(context_processor));
466466
}
467467

468-
auto response = publish<network::request_shutdown>(command);
468+
auto response = publish<network::request_shutdown>(command, {});
469469
if (!response) {
470470
return false;
471471
}

appsec/src/helper/client.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ class client {
8282
}
8383

8484
template <typename T>
85-
std::shared_ptr<typename T::response> publish(
86-
typename T::request &command, const std::string &rasp_rule = "");
85+
std::shared_ptr<typename T::response> publish(typename T::request &command,
86+
const network::request_exec_options &options);
8787
template <typename T> bool service_guard();
8888
template <typename T, bool actions = true>
8989
bool send_message(const std::shared_ptr<typename T::response> &message);

appsec/src/helper/engine.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ void engine::update(const rapidjson::Document &doc,
8282
}
8383

8484
std::optional<engine::result> engine::context::publish(
85-
parameter &&param, const std::string &rasp_rule)
85+
parameter &&param, const network::request_exec_options &options)
8686
{
8787
// Once the parameter reaches this function, it is guaranteed to be
8888
// owned by the engine.
@@ -113,7 +113,7 @@ std::optional<engine::result> engine::context::publish(
113113
}
114114
try {
115115
const auto &listener = it->second;
116-
listener->call(data, event, rasp_rule);
116+
listener->call(data, event, options);
117117
} catch (std::exception &e) {
118118
SPDLOG_ERROR("subscriber failed: {}", e.what());
119119
}

appsec/src/helper/engine.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include "action.hpp"
99
#include "engine_settings.hpp"
10+
#include "network/proto.hpp"
1011
#include "parameter.hpp"
1112
#include "rate_limit.hpp"
1213
#include "subscriber/base.hpp"
@@ -65,7 +66,7 @@ class engine {
6566
~context() = default;
6667

6768
std::optional<result> publish(
68-
parameter &&param, const std::string &rasp_rule = "");
69+
parameter &&param, const network::request_exec_options &options);
6970
// NOLINTNEXTLINE(google-runtime-references)
7071
void get_metrics(telemetry::telemetry_submitter &msubmitter);
7172

0 commit comments

Comments
 (0)