[libsoup/pgriffis/utf8-safe-apis] headers: Ensure untrusted header values are UTF-8
- From: Patrick Griffis <pgriffis src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libsoup/pgriffis/utf8-safe-apis] headers: Ensure untrusted header values are UTF-8
- Date: Sat, 24 Jul 2021 18:51:37 +0000 (UTC)
commit 9a2d4ea1454f210fff8c6889b417238899006137
Author: Patrick Griffis <pgriffis igalia com>
Date: Thu Jul 22 13:51:00 2021 -0500
headers: Ensure untrusted header values are UTF-8
Our API uses `char *` for all headers throughout.
This means that GObject-Introspection assumes it it is valid UTF-8,
so languages assume it is valid UTF-8.
Applications using the C API assume it is valid UTF-8.
Passing along unverified bytes is unsafe and will cause issues.
libsoup/http2/soup-client-message-io-http2.c | 5 ++--
libsoup/soup-headers.c | 3 ++-
libsoup/soup-message-headers-private.h | 3 +++
libsoup/soup-message-headers.c | 15 +++++++++++
tests/misc-test.c | 39 ++++++++++++++++++++++++++++
5 files changed, 62 insertions(+), 3 deletions(-)
---
diff --git a/libsoup/http2/soup-client-message-io-http2.c b/libsoup/http2/soup-client-message-io-http2.c
index 592fde68..5e7f0665 100644
--- a/libsoup/http2/soup-client-message-io-http2.c
+++ b/libsoup/http2/soup-client-message-io-http2.c
@@ -32,6 +32,7 @@
#include "soup-body-input-stream.h"
#include "soup-message-metrics-private.h"
+#include "soup-message-headers-private.h"
#include "soup-message-private.h"
#include "soup-message-io-source.h"
#include "soup-message-queue-item.h"
@@ -544,8 +545,8 @@ on_header_callback (nghttp2_session *session,
return 0;
}
- soup_message_headers_append (soup_message_get_response_headers (data->msg),
- (const char *)name, (const char *)value);
+ soup_message_headers_append_untrusted_data (soup_message_get_response_headers (data->msg),
+ (const char*)name, (const char*)value);
return 0;
}
diff --git a/libsoup/soup-headers.c b/libsoup/soup-headers.c
index e7f843b0..87779fcf 100644
--- a/libsoup/soup-headers.c
+++ b/libsoup/soup-headers.c
@@ -14,6 +14,7 @@
#include "soup-misc.h"
#include "soup-headers.h"
+#include "soup-message-headers-private.h"
#include "soup.h"
/**
@@ -154,7 +155,7 @@ soup_headers_parse (const char *str, int len, SoupMessageHeaders *dest)
for (p = strchr (value, '\r'); p; p = strchr (p, '\r'))
*p = ' ';
- soup_message_headers_append (dest, name, value);
+ soup_message_headers_append_untrusted_data (dest, name, value);
}
success = TRUE;
diff --git a/libsoup/soup-message-headers-private.h b/libsoup/soup-message-headers-private.h
index b606a331..98154645 100644
--- a/libsoup/soup-message-headers-private.h
+++ b/libsoup/soup-message-headers-private.h
@@ -10,6 +10,9 @@
G_BEGIN_DECLS
+void soup_message_headers_append_untrusted_data (SoupMessageHeaders *hdrs,
+ const char *name,
+ const char *value);
void soup_message_headers_append_common (SoupMessageHeaders *hdrs,
SoupHeaderName name,
const char *value);
diff --git a/libsoup/soup-message-headers.c b/libsoup/soup-message-headers.c
index 2dfea525..c602a064 100644
--- a/libsoup/soup-message-headers.c
+++ b/libsoup/soup-message-headers.c
@@ -353,6 +353,21 @@ soup_message_headers_append (SoupMessageHeaders *hdrs,
g_hash_table_remove (hdrs->uncommon_concat, header.name);
}
+/*
+ * Appends a header value ensuring that it is valid UTF8.
+ */
+void
+soup_message_headers_append_untrusted_data (SoupMessageHeaders *hdrs,
+ const char *name,
+ const char *value)
+{
+ char *safe_value = g_utf8_make_valid (value, -1);
+ char *safe_name = g_utf8_make_valid (name, -1);
+ soup_message_headers_append (hdrs, safe_name, safe_value);
+ g_free (safe_value);
+ g_free (safe_name);
+}
+
void
soup_message_headers_replace_common (SoupMessageHeaders *hdrs,
SoupHeaderName name,
diff --git a/tests/misc-test.c b/tests/misc-test.c
index efbe2798..18befd67 100644
--- a/tests/misc-test.c
+++ b/tests/misc-test.c
@@ -6,6 +6,7 @@
#include "test-utils.h"
#include "soup-connection.h"
#include "soup-session-private.h"
+#include "soup-message-headers-private.h"
SoupServer *server;
GUri *base_uri;
@@ -55,6 +56,15 @@ server_callback (SoupServer *server,
g_source_unref (timeout);
}
+ if (!strcmp (path, "/invalid_utf8_headers")) {
+ SoupMessageHeaders *headers = soup_server_message_get_response_headers (msg);
+ const char *invalid_utf8_value = "\xe2\x82\xa0gh\xe2\xffjl";
+
+ /* Purposefully insert invalid utf8 data */
+ g_assert_false (g_utf8_validate (invalid_utf8_value, -1, NULL));
+ soup_message_headers_append (headers, "InvalidValue", invalid_utf8_value);
+ }
+
soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL);
if (!strcmp (g_uri_get_host (uri), "foo")) {
soup_server_message_set_response (msg, "text/plain",
@@ -861,6 +871,34 @@ do_new_request_on_redirect_test (void)
soup_test_session_abort_unref (session);
}
+static void
+do_invalid_utf8_headers_test (void)
+{
+ SoupSession *session;
+ SoupMessage *msg;
+ GUri *uri;
+ SoupMessageHeaders *headers;
+ guint status;
+ const char *header_value;
+
+ session = soup_test_session_new (NULL);
+
+ uri = g_uri_parse_relative (base_uri, "/invalid_utf8_headers", SOUP_HTTP_URI_FLAGS, NULL);
+ msg = soup_message_new_from_uri ("GET", uri);
+
+ status = soup_test_session_send_message (session, msg);
+ g_assert_cmpuint (status, ==, SOUP_STATUS_OK);
+
+ headers = soup_message_get_response_headers (msg);
+ header_value = soup_message_headers_get_one (headers, "InvalidValue");
+ g_assert_nonnull (header_value);
+ g_assert_true (g_utf8_validate (header_value, -1, NULL));
+
+ g_object_unref (msg);
+ g_uri_unref (uri);
+ soup_test_session_abort_unref (session);
+}
+
int
main (int argc, char **argv)
{
@@ -896,6 +934,7 @@ main (int argc, char **argv)
g_test_add_func ("/misc/connection-id", do_connection_id_test);
g_test_add_func ("/misc/remote-address", do_remote_address_test);
g_test_add_func ("/misc/new-request-on-redirect", do_new_request_on_redirect_test);
+ g_test_add_func ("/misc/invalid-utf8-headers", do_invalid_utf8_headers_test);
ret = g_test_run ();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]