-
Notifications
You must be signed in to change notification settings - Fork 158
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Blocking from a hook is not stopping code execution #2836
base: master
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
--TEST-- | ||
Push address gets blocked even when within a hook | ||
--INI-- | ||
extension=ddtrace.so | ||
datadog.appsec.enabled=1 | ||
--FILE-- | ||
<?php | ||
use function datadog\appsec\testing\{rinit,rshutdown}; | ||
use function datadog\appsec\push_address; | ||
|
||
include __DIR__ . '/inc/mock_helper.php'; | ||
|
||
$helper = Helper::createInitedRun([ | ||
response_list(response_request_init([[['ok', []]]])), | ||
response_list(response_request_exec([[['block', ['status_code' => '404', 'type' => 'html']]], ['{"found":"attack"}','{"another":"attack"}']])), | ||
]); | ||
rinit(); | ||
|
||
class SomeIntegration { | ||
public function init() | ||
{ | ||
DDTrace\install_hook("ltrim", self::hooked_function(), null); | ||
} | ||
|
||
private static function hooked_function() | ||
{ | ||
return static function (DDTrace\HookData $hook) { | ||
push_address("server.request.path_params", ["some" => "params", "more" => "parameters"]); | ||
var_dump("This should be executed"); | ||
}; | ||
} | ||
} | ||
|
||
$integration = new SomeIntegration(); | ||
$integration->init(); | ||
echo "Something here to force partially booking"; | ||
var_dump(ltrim(" Calling wrapped function")); | ||
var_dump("THIS SHOULD NOT GET IN THE OUTPUT"); | ||
?> | ||
--EXPECTHEADERS-- | ||
Content-type: text/html; charset=UTF-8 | ||
--EXPECTF-- | ||
Something here to force partially booking |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -76,7 +76,9 @@ | |
* | ||
* This function should be invoked when a bailout has been caught. | ||
* | ||
* It will restore engine state and continue in all but the case of a timeout | ||
* It will restore engine state and continue in all cases except: | ||
* - Timeout | ||
* - Request is blocked by the extension | ||
*/ | ||
|
||
/* ######### Timeout ########## | ||
|
@@ -218,8 +220,25 @@ inline bool zai_sandbox_timed_out(void) { | |
return false; | ||
} | ||
|
||
inline bool zai_is_request_blocked(void) | ||
{ | ||
if (!PG(last_error_message)) { | ||
return false; | ||
} | ||
|
||
if (strcmp("Datadog blocked the request and presented a static error page", ZSTR_VAL(PG(last_error_message))) == 0) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My main concern with this approach is that if someone changes the error message in appsec, it would stop working. Can you make changes on the appsec side to:
|
||
return true; | ||
} | ||
|
||
if (strcmp("Datadog blocked the request, but the response has already been partially committed", ZSTR_VAL(PG(last_error_message))) == 0) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Alternatively you could check the prefix, which is always |
||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
inline void zai_sandbox_bailout(zai_sandbox *sandbox) { | ||
if (!zai_sandbox_timed_out()) { | ||
if (!zai_sandbox_timed_out() && !zai_is_request_blocked()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know why sandbox.h is written this way, with just C inline functions, but I guess that in the context of its strangeness it's fine. |
||
zai_sandbox_engine_state_restore(&sandbox->engine_state); | ||
|
||
return; | ||
|
@@ -356,8 +375,25 @@ inline bool zai_sandbox_timed_out(void) { | |
return false; | ||
} | ||
|
||
inline bool zai_is_request_blocked(void) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Both implementations of this function are exactly the same, perhaps you can define it only once? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. They are the same yes. However, this file is full of this duplication. I did it that way so follow the same approach There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unless there's a good technical reason, don't duplicate the function. |
||
{ | ||
if (!PG(last_error_message)) { | ||
return false; | ||
} | ||
|
||
if (strcmp("Datadog blocked the request and presented a static error page", ZSTR_VAL(PG(last_error_message))) == 0) { | ||
return true; | ||
} | ||
|
||
if (strcmp("Datadog blocked the request, but the response has already been partially committed", ZSTR_VAL(PG(last_error_message))) == 0) { | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
inline void zai_sandbox_bailout(zai_sandbox *sandbox) { | ||
if (!zai_sandbox_timed_out()) { | ||
if (!zai_sandbox_timed_out() && !zai_is_request_blocked()) { | ||
zai_sandbox_engine_state_restore(&sandbox->engine_state); | ||
|
||
return; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is missing the redirection message as well.