[pgpool-hackers: 4575] BUG: json_writer doesn't properly encode special characters

Martijn van Duren pgpool at list.imperialat.at
Thu Apr 10 07:26:44 JST 2025


Hello all,

I'm new to pgpool and am currently playing around with it to see if it
suits my needs. While playing around with it (on OpenBSD) I noticed that
pgpool crashed when enabling watchdog. Looking at the logs I found:
WARNING:  authentication failed
DETAIL:  invalid IPC key
which made me make a ktrace, where I saw that the backslash that I added
to my (randomly generated) wd_authkey wasn't escaped inside the json
object, resulting in it being consumed by json.c's json_parse_ex().

The diff adds all the cases as defined in json_parse_ex()' flag_escaped
case, with the addition of '\' and '"', and the exception of \u, because
I don't have nor see the need. Quickly spun together and lightly tested,
but I expect it to be okay.

Test was done with a locally updated package of 4.6.0, and not OpenBSD's
default package, which currently is still at 3.7.18. I plan to push the
update once I'm comfortable enough with the tools. There's also a couple
of local diffs to make things build on OpenBSD, which could probably be
upstreamed as well. But let's first get this all platform bug out of the
way.

Sincerely,

Martijn van Duren

diff /home/martijn/src/pgpool2
path + /home/martijn/src/pgpool2
commit - d766e4a812f2aa78bfc946449620c31e416958a4
blob - 1f7133843f2ea1cfdb17857e2e8068a1c8fb3f24
file + src/utils/json_writer.c
--- src/utils/json_writer.c
+++ src/utils/json_writer.c
@@ -26,6 +26,7 @@
 #include "utils/palloc.h"
 #include "utils/json_writer.h"
 
+static void jw_put_string_escape(JsonNode * jNode, char *string);
 static inline int jw_get_current_element_count(JsonNode * jNode);
 static inline void jw_inc_current_element_count(JsonNode * jNode);
 static inline JWElementType jw_get_current_element_type(JsonNode * jNode);
@@ -67,11 +68,50 @@ jw_put_string(JsonNode * jNode, char *key, char *value
 
 	if (jw_get_current_element_count(jNode) > 0)
 		appendStringInfoChar(jNode->buf, ',');
-	appendStringInfo(jNode->buf, "\"%s\":\"%s\"", key, value);
+	jw_put_string_escape(jNode, key);
+	appendStringInfoChar(jNode->buf, ':');
+	jw_put_string_escape(jNode, value);
 	jw_inc_current_element_count(jNode);
 	return true;
 }
 
+static void
+jw_put_string_escape(JsonNode * jNode, char *string)
+{
+	int i;
+
+	appendStringInfoChar(jNode->buf, '"');
+	for (i = 0; string[i] != '\0'; i++) {
+		switch (string[i]) {
+		case '\"':
+			appendStringInfo(jNode->buf, "\\\"");
+			break;
+		case '\\':
+			appendStringInfo(jNode->buf, "\\\\");
+			break;
+		case '\b':
+			appendStringInfo(jNode->buf, "\\b");
+			break;
+		case '\f':
+			appendStringInfo(jNode->buf, "\\f");
+			break;
+		case '\n':
+			appendStringInfo(jNode->buf, "\\n");
+			break;
+		case '\r':
+			appendStringInfo(jNode->buf, "\\r");
+			break;
+		case '\t':
+			appendStringInfo(jNode->buf, "\\t");
+			break;
+		default:
+			appendStringInfoChar(jNode->buf, string[i]);
+			break;
+		}
+	}
+	appendStringInfoChar(jNode->buf, '"');
+}
+
 /* for compatibility reasons we pack bool in int*/
 bool
 jw_put_bool(JsonNode * jNode, char *key, bool value)



More information about the pgpool-hackers mailing list