1 #include "php_snuffleupagus.h"
2
PHP_FUNCTION(sp_serialize)3 PHP_FUNCTION(sp_serialize) {
4 zif_handler orig_handler;
5
6 /* Call the original `serialize` function. */
7 orig_handler =
8 zend_hash_str_find_ptr(SNUFFLEUPAGUS_G(sp_internal_functions_hook),
9 "serialize", sizeof("serialize") - 1);
10 orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU);
11
12 /* Compute the HMAC of the textual representation of the serialized data*/
13 zval func_name;
14 zval hmac;
15 zval params[3];
16
17 ZVAL_STRING(&func_name, "hash_hmac");
18 ZVAL_STRING(¶ms[0], "sha256");
19 params[1] = *return_value;
20 ZVAL_STRING(
21 ¶ms[2],
22 ZSTR_VAL(SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key));
23 call_user_function(CG(function_table), NULL, &func_name, &hmac, 3, params);
24
25 size_t len = Z_STRLEN_P(return_value) + Z_STRLEN(hmac);
26 if (len < Z_STRLEN_P(return_value)) {
27 // LCOV_EXCL_START
28 sp_log_err("overflow_error",
29 "Overflow tentative detected in sp_serialize.");
30 zend_bailout();
31 // LCOV_EXCL_STOP
32 }
33 zend_string *res = zend_string_alloc(len, 0);
34
35 memcpy(ZSTR_VAL(res), Z_STRVAL_P(return_value), Z_STRLEN_P(return_value));
36 memcpy(ZSTR_VAL(res) + Z_STRLEN_P(return_value), Z_STRVAL(hmac),
37 Z_STRLEN(hmac));
38
39 /* Append the computed HMAC to the serialized data. */
40 return_value->value.str = res;
41 return;
42 }
43
PHP_FUNCTION(sp_unserialize)44 PHP_FUNCTION(sp_unserialize) {
45 zif_handler orig_handler;
46
47 char *buf = NULL;
48 char *serialized_str = NULL;
49 char *hmac = NULL;
50 zval expected_hmac;
51 size_t buf_len = 0;
52 zval *opts = NULL;
53
54 const sp_config_unserialize *config_unserialize =
55 SNUFFLEUPAGUS_G(config).config_unserialize;
56
57 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|a", &buf, &buf_len, &opts) ==
58 FAILURE) {
59 RETURN_FALSE;
60 }
61
62 /* 64 is the length of HMAC-256 */
63 if (buf_len < 64) {
64 sp_log_drop("unserialize", "The serialized object is too small.");
65 }
66
67 hmac = buf + buf_len - 64;
68 serialized_str = ecalloc(buf_len - 64 + 1, 1);
69 memcpy(serialized_str, buf, buf_len - 64);
70
71 zval func_name;
72 ZVAL_STRING(&func_name, "hash_hmac");
73
74 zval params[3];
75 ZVAL_STRING(¶ms[0], "sha256");
76 ZVAL_STRING(¶ms[1], serialized_str);
77 ZVAL_STRING(
78 ¶ms[2],
79 ZSTR_VAL(SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key));
80 call_user_function(CG(function_table), NULL, &func_name, &expected_hmac, 3,
81 params);
82
83 unsigned int status = 0;
84 for (uint8_t i = 0; i < 64; i++) {
85 status |= (hmac[i] ^ (Z_STRVAL(expected_hmac))[i]);
86 }
87
88 if (0 == status) {
89 if ((orig_handler = zend_hash_str_find_ptr(
90 SNUFFLEUPAGUS_G(sp_internal_functions_hook), "unserialize",
91 sizeof("unserialize") - 1))) {
92 orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU);
93 }
94 } else {
95 if (config_unserialize->dump) {
96 sp_log_request(config_unserialize->dump,
97 config_unserialize->textual_representation,
98 SP_TOKEN_UNSERIALIZE_HMAC);
99 }
100 if (true == config_unserialize->simulation) {
101 sp_log_simulation("unserialize", "Invalid HMAC for %s", serialized_str);
102 if ((orig_handler = zend_hash_str_find_ptr(
103 SNUFFLEUPAGUS_G(sp_internal_functions_hook), "unserialize",
104 sizeof("unserialize") - 1))) {
105 orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU);
106 }
107 } else {
108 sp_log_drop("unserialize", "Invalid HMAC for %s", serialized_str);
109 }
110 }
111 efree(serialized_str);
112 return;
113 }
114
hook_serialize(void)115 int hook_serialize(void) {
116 TSRMLS_FETCH();
117
118 HOOK_FUNCTION("serialize", sp_internal_functions_hook, PHP_FN(sp_serialize));
119 HOOK_FUNCTION("unserialize", sp_internal_functions_hook,
120 PHP_FN(sp_unserialize));
121
122 return SUCCESS;
123 }
124