[asterisk-commits] res pjsip: Ensure sanitized XML is NULL terminated. (asterisk[master])
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri Aug 7 10:23:49 CDT 2015
Joshua Colp has submitted this change and it was merged.
Change subject: res_pjsip: Ensure sanitized XML is NULL terminated.
......................................................................
res_pjsip: Ensure sanitized XML is NULL terminated.
The ast_sip_sanitize_xml function is used to sanitize
a string for placement into XML. This is done by examining
an input string and then appending values to an output
buffer. The function used by its implementation, strncat,
has specific behavior that was not taken into account.
If the size of the input string exceeded the available
output buffer size it was possible for the sanitization
function to write past the output buffer itself causing
a crash. The crash would either occur because it was
writing into memory it shouldn't be or because the resulting
string was not NULL terminated.
This change keeps count of how much remaining space is
available in the output buffer for text and only allows
strncat to use that amount.
Since this was exposed by the res_pjsip_pidf_digium_body_supplement
module attempting to send a large message the maximum allowed
message size has also been increased in it.
A unit test has also been added which confirms that the
ast_sip_sanitize_xml function is providing NULL terminated
output even when the input length exceeds the output
buffer size.
ASTERISK-25304 #close
Change-Id: I743dd9809d3e13d722df1b0509dfe34621398302
---
M res/res_pjsip.c
M res/res_pjsip/presence_xml.c
M res/res_pjsip_pidf_digium_body_supplement.c
3 files changed, 80 insertions(+), 12 deletions(-)
Approvals:
Mark Michelson: Looks good to me, but someone else must approve
Anonymous Coward #1000019: Verified
Joshua Colp: Looks good to me, approved
diff --git a/res/res_pjsip.c b/res/res_pjsip.c
index 4de0745..25a35c0 100644
--- a/res/res_pjsip.c
+++ b/res/res_pjsip.c
@@ -40,6 +40,8 @@
#include "asterisk/file.h"
#include "asterisk/cli.h"
#include "asterisk/res_pjsip_cli.h"
+#include "asterisk/test.h"
+#include "asterisk/res_pjsip_presence_xml.h"
/*** MODULEINFO
<depend>pjproject</depend>
@@ -3755,6 +3757,57 @@
}
}
+AST_TEST_DEFINE(xml_sanitization_end_null)
+{
+ char sanitized[8];
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "xml_sanitization_end_null";
+ info->category = "/res/res_pjsip/";
+ info->summary = "Ensure XML sanitization works as expected with a long string";
+ info->description = "This test sanitizes a string which exceeds the output\n"
+ "buffer size. Once done the string is confirmed to be NULL terminated.";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ ast_sip_sanitize_xml("aaaaaaaaaaaa", sanitized, sizeof(sanitized));
+ if (sanitized[7] != '\0') {
+ ast_test_status_update(test, "Sanitized XML string is not null-terminated when it should be\n");
+ return AST_TEST_FAIL;
+ }
+
+ return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(xml_sanitization_exceeds_buffer)
+{
+ char sanitized[8];
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "xml_sanitization_exceeds_buffer";
+ info->category = "/res/res_pjsip/";
+ info->summary = "Ensure XML sanitization does not exceed buffer when output won't fit";
+ info->description = "This test sanitizes a string which before sanitization would\n"
+ "fit within the output buffer. After sanitization, however, the string would\n"
+ "exceed the buffer. Once done the string is confirmed to be NULL terminated.";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ ast_sip_sanitize_xml("<><><>&", sanitized, sizeof(sanitized));
+ if (sanitized[7] != '\0') {
+ ast_test_status_update(test, "Sanitized XML string is not null-terminated when it should be\n");
+ return AST_TEST_FAIL;
+ }
+
+ return AST_TEST_PASS;
+}
+
/*!
* \internal
* \brief Reload configuration within a PJSIP thread
@@ -3909,6 +3962,9 @@
ast_res_pjsip_init_options_handling(0);
ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands));
+ AST_TEST_REGISTER(xml_sanitization_end_null);
+ AST_TEST_REGISTER(xml_sanitization_exceeds_buffer);
+
return AST_MODULE_LOAD_SUCCESS;
}
@@ -3950,6 +4006,9 @@
static int unload_module(void)
{
+ AST_TEST_UNREGISTER(xml_sanitization_end_null);
+ AST_TEST_UNREGISTER(xml_sanitization_exceeds_buffer);
+
/* The thread this is called from cannot call PJSIP/PJLIB functions,
* so we have to push the work to the threadpool to handle
*/
diff --git a/res/res_pjsip/presence_xml.c b/res/res_pjsip/presence_xml.c
index 12bfa07..b98ea02 100644
--- a/res/res_pjsip/presence_xml.c
+++ b/res/res_pjsip/presence_xml.c
@@ -30,45 +30,54 @@
{
char *copy = ast_strdupa(input);
char *break_point;
+ size_t remaining = len - 1;
output[0] = '\0';
- while ((break_point = strpbrk(copy, "<>\"&'\n\r"))) {
+ while ((break_point = strpbrk(copy, "<>\"&'\n\r")) && remaining) {
char to_escape = *break_point;
*break_point = '\0';
- strncat(output, copy, len);
+ strncat(output, copy, remaining);
+
+ /* The strncat function will write remaining+1 if the string length is
+ * equal to or greater than the size provided to it. We take this into
+ * account by subtracting 1, which ensures that the NULL byte is written
+ * inside of the provided buffer.
+ */
+ remaining = len - strlen(output) - 1;
switch (to_escape) {
case '<':
- strncat(output, "<", len);
+ strncat(output, "<", remaining);
break;
case '>':
- strncat(output, ">", len);
+ strncat(output, ">", remaining);
break;
case '"':
- strncat(output, """, len);
+ strncat(output, """, remaining);
break;
case '&':
- strncat(output, "&", len);
+ strncat(output, "&", remaining);
break;
case '\'':
- strncat(output, "'", len);
+ strncat(output, "'", remaining);
break;
case '\r':
- strncat(output, "
", len);
+ strncat(output, "
", remaining);
break;
case '\n':
- strncat(output, "
", len);
+ strncat(output, "
", remaining);
break;
};
copy = break_point + 1;
+ remaining = len - strlen(output) - 1;
}
/* Be sure to copy everything after the final bracket */
- if (*copy) {
- strncat(output, copy, len);
+ if (*copy && remaining) {
+ strncat(output, copy, remaining);
}
}
diff --git a/res/res_pjsip_pidf_digium_body_supplement.c b/res/res_pjsip_pidf_digium_body_supplement.c
index b6212ea..93e4982 100644
--- a/res/res_pjsip_pidf_digium_body_supplement.c
+++ b/res/res_pjsip_pidf_digium_body_supplement.c
@@ -40,7 +40,7 @@
{
struct ast_sip_exten_state_data *state_data = data;
pj_xml_node *node;
- char sanitized[256];
+ char sanitized[1024];
if (ast_strlen_zero(state_data->user_agent) ||
!strstr(state_data->user_agent, "digium")) {
--
To view, visit https://gerrit.asterisk.org/1040
To unsubscribe, visit https://gerrit.asterisk.org/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I743dd9809d3e13d722df1b0509dfe34621398302
Gerrit-PatchSet: 2
Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-Owner: Joshua Colp <jcolp at digium.com>
Gerrit-Reviewer: Anonymous Coward #1000019
Gerrit-Reviewer: Joshua Colp <jcolp at digium.com>
Gerrit-Reviewer: Mark Michelson <mmichelson at digium.com>
More information about the asterisk-commits
mailing list