Message ID | 023bab16-beca-40d0-a52c-c8c802aea701@gmail.com |
---|---|
State | Committed |
Headers |
Return-Path: <elfutils-devel-bounces~patchwork=sourceware.org@sourceware.org> X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 5EA663858D28 for <patchwork@sourceware.org>; Wed, 4 Dec 2024 23:00:23 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 5EA663858D28 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=CKk9+7Tu X-Original-To: elfutils-devel@sourceware.org Delivered-To: elfutils-devel@sourceware.org Received: from mail-wm1-x333.google.com (mail-wm1-x333.google.com [IPv6:2a00:1450:4864:20::333]) by sourceware.org (Postfix) with ESMTPS id DF1013858D20 for <elfutils-devel@sourceware.org>; Wed, 4 Dec 2024 23:00:03 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org DF1013858D20 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org DF1013858D20 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2a00:1450:4864:20::333 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1733353204; cv=none; b=Op0UvYfSbOifilnDTR45tWBDjsUtz5PFwJxVdkiNgLqmNjtH2NNzzGpmVF5pwpy3BXdVslkRXp2JEv0Y/CJ9Z9EAI6kd+4KQ061kO0t4EJo8+Ww7E8h/YOwr4JFQSP37YjI+eU/xrGkZk2iqpjWIt3ZpFzVSdqGQQq3Y+877VYY= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1733353204; c=relaxed/simple; bh=CZNn8qWjU68E7+NY/6PkSTCWs+Ai/Gly0D9syIdZqD4=; h=DKIM-Signature:Message-ID:Date:MIME-Version:To:From:Subject; b=OHUDLyw+/wovZHuRXwsTRAOpc+gQvsO7lkbB8SKPb56CngvfD81B6o7xCLzdnRVIzn4sN+XjcueVCWfz0eVe7uPHC1/xI9GdlNsUMQfsGiJz+PznFB9962t7K/vCp4cwDpiUHT9s86xn9r73Zv7fWoH44+TWcx4s5ggeiPU5Eew= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org DF1013858D20 Received: by mail-wm1-x333.google.com with SMTP id 5b1f17b1804b1-434a8640763so2116265e9.1 for <elfutils-devel@sourceware.org>; Wed, 04 Dec 2024 15:00:03 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1733353202; x=1733958002; darn=sourceware.org; h=content-transfer-encoding:subject:autocrypt:from:to :content-language:user-agent:mime-version:date:message-id:from:to:cc :subject:date:message-id:reply-to; bh=EbHRXEuoRUrFIfnmAGm3DtbErqtgClFqlpV3EPZt8MA=; b=CKk9+7TuhnFFYFha/LIAOZO99qnvz9N2I3kkMS/TG0wL+kR3b7WjFTwnHD1VY41p+6 0v/5oFOkwLd+5Q+/H0gMevK1+CvcdnXxgJSc0mOYOK6cmH21V8ghmIHmtw0HvinmaL4L /ZUewio40fyRDp73Wc5g0tWoOdMXzFrhtZ5D4giSl6Fc4dUAVZO6FF3JWVTc8zmwhVir yekEhyZxGfyh+SWKslRh0BJcxsTKOvFBwCDjuLRzfK8Emui3Pa+Z4O3yt9lSGGB6W1kl MhmmTH/22VbVdnw7m1KjZ8k3oqfHTMiZBNSHpdhJ07RhdFm06At/dwnwEcYBSgvmTXFX +x+w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733353202; x=1733958002; h=content-transfer-encoding:subject:autocrypt:from:to :content-language:user-agent:mime-version:date:message-id :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=EbHRXEuoRUrFIfnmAGm3DtbErqtgClFqlpV3EPZt8MA=; b=KRGwZRFSLFdD/OabllMfN9MM+H2EzYPBsQBeaQnPf3SUL4NO5QvbNiHxh3rFvOJ+TZ ULwgxW/fXYuNLhCKZhCu1Bd1RSKIVzl1q2ADtPgwpAYSDLdvrb01NzuxYTPVIe8NG39H PJtMJPMOHUFA6lOvnvsbxS4q0+kn+Kve45VIqO09VgB0B7b0M3HBEYN3zjoorSzdfGqo LPh54xQXJ1bzgTrvayAk+DTUpNUBr5/37osQ9s4saefi3VTjxpGRQSFCr17mifCa6kBh CEPvUDSgaCfMpZBN06piRwjrHvCCYERtywn2K9HB88e3FghqtD56YbnRkCmm7+WntzaS T6qA== X-Gm-Message-State: AOJu0Yys57L2DFoFxbvQez4Kba6OAWSiRqimSImc0PdUJ6RW6PVkUpCX /H+jQbxACjh5tMI0g18IylZKn4DZlSRBuKArf6NpaaDgqqU0sj4hhL3Z7Q== X-Gm-Gg: ASbGnctA1TiMqdGdu8q+kHBcGPMQgOfBnoSeD4YcevXuJvuUfprLnMTgGlxWYHeNHwc zFhElg4iH8pazDh+MfrSh4x8YpimyxXglk9E1uWfq5+BOF2XJniRuIuZfeFf4BE4r5hGLMvudZp CBtZobdLCbX2CHj0sg1biexjJVj3QIJgow4ZngDNfiO5j1aZEsF3zav1Yh9EosHjZq3qtMnDPKr X2g+zK9nR5YmTieTEVl32mtScm19KIx8UUPDnNF9po+5EuwK1oTxJcKjar80Mf5VUbwyph9nRa0 1Xjb7TnT0z/0Md1TdTBpI88JRd2l4JHTHu3lg8+K9JdtT6OXYJXu/5SPdyRqVImuXgY008FIA5c ZD7XY X-Google-Smtp-Source: AGHT+IFX1dFtI/yXw6Nv9E+pjo7B36mKXdNMDJyvFAjdTuiYMM/SUMM7caQw9+VO1zOTdGHUggw70Q== X-Received: by 2002:a05:600c:1c0e:b0:434:a802:e99a with SMTP id 5b1f17b1804b1-434d09b1590mr74327365e9.4.1733353202110; Wed, 04 Dec 2024 15:00:02 -0800 (PST) Received: from ?IPV6:2003:f6:171f:7b07:3815:606f:91b1:20d2? (p200300f6171f7b073815606f91b120d2.dip0.t-ipconnect.de. [2003:f6:171f:7b07:3815:606f:91b1:20d2]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-386219095d3sm213655f8f.71.2024.12.04.15.00.00 for <elfutils-devel@sourceware.org> (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Wed, 04 Dec 2024 15:00:01 -0800 (PST) Message-ID: <023bab16-beca-40d0-a52c-c8c802aea701@gmail.com> Date: Wed, 4 Dec 2024 23:59:59 +0100 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Content-Language: en-US To: elfutils-devel@sourceware.org From: Henning Meyer <hmeyer.eu@gmail.com> Autocrypt: addr=hmeyer.eu@gmail.com; keydata= xjMEZwqZDRYJKwYBBAHaRw8BAQdAwyfx2Q1dMlUqYCu9WOrxK2BrKRy6840/omIVBc1218LN I0hlbm5pbmcgTWV5ZXIgPGhtZXllci5ldUBnbWFpbC5jb20+wo8EExYIADcWIQQ/igt3fKmp krPnDwgkX84AHyLf5gUCZwqZDQUJBaOagAIbAwQLCQgHBRUICQoLBRYCAwEAAAoJECRfzgAf It/mbCIA/2L88Y1BZWBE1CYR5nAWq2CBO2zYwxyIZqiq9DXCfWT5AQDVAdVhzadREALsshMU goj/L9DeUUUamTwXCT/IMuTGBs44BGcKmQ4SCisGAQQBl1UBBQEBB0BLPd9lCrj3dNzFR9wp moyy3A77aejCFnqN63Sr6R0cfgMBCAfCfgQYFggAJhYhBD+KC3d8qamSs+cPCCRfzgAfIt/m BQJnCpkOBQkFo5qAAhsMAAoJECRfzgAfIt/m1eMA/jtveXojEN++w0IJ8lnkooGOwB+m81Qp M6wadBAiJFTFAQCednWKYSxS8hqKE4ecCoSbZp+sKEVcVHl/nZYqcGdzCQ== Subject: [PATCH] debuginfod: add CORS support Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-8.2 required=5.0 tests=BAYES_00, BODY_8BITS, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, URIBL_BLOCKED, URIBL_SBL_A autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: elfutils-devel@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Elfutils-devel mailing list <elfutils-devel.sourceware.org> List-Unsubscribe: <https://sourceware.org/mailman/options/elfutils-devel>, <mailto:elfutils-devel-request@sourceware.org?subject=unsubscribe> List-Archive: <https://sourceware.org/pipermail/elfutils-devel/> List-Post: <mailto:elfutils-devel@sourceware.org> List-Help: <mailto:elfutils-devel-request@sourceware.org?subject=help> List-Subscribe: <https://sourceware.org/mailman/listinfo/elfutils-devel>, <mailto:elfutils-devel-request@sourceware.org?subject=subscribe> Errors-To: elfutils-devel-bounces~patchwork=sourceware.org@sourceware.org |
Series |
debuginfod: add CORS support
|
|
Commit Message
Henning Meyer
Dec. 4, 2024, 10:59 p.m. UTC
This is my first attempt at implementing CORS support in debuginfod.
I should probably add or change tests. Since debuginfod-find does not
need this functionality, it would be another test done with curl. I had
a look at the existing tests,
run-debuginfod-webapi-concurrency.sh looks like it would be a good template.
I have confirmed that I can use debuginfod with this patch from my web
application at
https://core-explorer.github.io/cdx-type/
Signed-off-by: Henning Meyer <hmeyer.eu@gmail.com>
---
debuginfod/ChangeLog | 6 ++++++
debuginfod/debuginfod.cxx | 35 +++++++++++++++++++++++++++++++++--
2 files changed, 39 insertions(+), 2 deletions(-)
string header_dup;
@@ -3537,6 +3538,7 @@ handle_metrics (off_t* size)
{
*size = os.size();
add_mhd_response_header (r, "Content-Type", "text/plain");
+ add_mhd_response_header (r, "Access-Control-Allow-Origin", "*");
}
return r;
}
@@ -3763,7 +3765,10 @@ handle_metadata (MHD_Connection* conn,
MHD_RESPMEM_MUST_COPY);
*size = strlen(metadata_str);
if (r)
+ {
add_mhd_response_header(r, "Content-Type", "application/json");
+ add_mhd_response_header (r, "Access-Control-Allow-Origin", "*");
+ }
return r;
}
@@ -3780,11 +3785,28 @@ handle_root (off_t* size)
{
*size = version.size ();
add_mhd_response_header (r, "Content-Type", "text/plain");
+ add_mhd_response_header (r, "Access-Control-Allow-Origin", "*");
}
return r;
}
+static struct MHD_Response*
+handle_options (off_t* size)
+{
+ static char empty_body[] = " ";
+ MHD_Response* r = MHD_create_response_from_buffer (1, empty_body,
+ MHD_RESPMEM_PERSISTENT);
+ if (r != NULL)
+ {
+ *size = 1;
+ add_mhd_response_header (r, "Access-Control-Allow-Origin", "*");
+ add_mhd_response_header (r, "Access-Control-Allow-Methods", "GET,
OPTIONS");
+ add_mhd_response_header (r, "Access-Control-Allow-Headers",
"cache-control");
+ }
+ return r;
+}
+
////////////////////////////////////////////////////////////////////////
@@ -3838,8 +3860,17 @@ handler_cb (void * /*cls*/,
try
{
- if (string(method) != "GET")
- throw reportable_exception(400, "we support GET only");
+ if (method == string("OPTIONS"))
+ {
+ artifacttype = "OPTIONS";
+ inc_metric("http_requests_total", "type", artifacttype);
+ r = handle_options(& http_size);
+ rc = MHD_queue_response (connection, MHD_HTTP_OK, r);
+ http_code = MHD_HTTP_OK;
+ MHD_destroy_response (r);
+ return rc;
+ } else if (method != string("GET"))
+ throw reportable_exception(400, "we only support GET and
OPTIONS");
/* Start decoding the URL. */
size_t slash1 = url_copy.find('/', 1);
Comments
Hi - > This is my first attempt at implementing CORS support in debuginfod. Looks good to me really; will wait for a glance from others. > I should probably add or change tests. [...] I wouldn't overthink it - just add a "-i" to any random curl command and look for ACAO:*. I reconfigured the debuginfod.elfutils.org server (at the reverse proxy level) to emit that header already. This may be enough for your web gadget to start working by default. I'm not sure the OPTIONS part is needed for that. - FChE
Hi Frank, Hi Henning, On Wed, 2024-12-04 at 19:40 -0500, Frank Ch. Eigler wrote: > > This is my first attempt at implementing CORS support in debuginfod. > > Looks good to me really; will wait for a glance from others. So the code looks correct if you want to handle the OPTION command and add a header saying "Access-Control-Allow-Origin: *" to all request replies. But I have to admit I have no idea what that means. Could you include an URL to a quick summary when and why you would add such an header? Thanks, Mark
Hi Mark, it is the Cross-Origin-Resource-Sharing mechanism explained at https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS 1. by default JavaScript code from Website A cannot request arbitrary resources from website B, these are called cross-origin-requests 2. The browser performs what is called a preflight check, this the OPTIONS method 3. the response allows website B fine-grained control over what the web browser should allow 4. Setting "Access-Control-Allow-Origin: *" tells the web browser to allow all access, e.g. the same behavior you get with curl or debuginfod-find The website mentions that the corresponding spec has been changed, such that preflight requests are no longer necessary, but in the browsers I use today (Firefox 132 and Chromium 131) they are still necessary. Regards, Henning On 05.12.24 15:35, Mark Wielaard wrote: Hi Frank, Hi Henning, On Wed, 2024-12-04 at 19:40 -0500, Frank Ch. Eigler wrote: >> This is my first attempt at implementing CORS support in debuginfod. > Looks good to me really; will wait for a glance from others. So the code looks correct if you want to handle the OPTION command and add a header saying "Access-Control-Allow-Origin: *" to all request replies. But I have to admit I have no idea what that means. Could you include an URL to a quick summary when and why you would add such an header? Thanks, Mark
Hi - I'm planning to commit this shortly: From 4ebefc8f3b4b8fb68a55c960e70122fda50a0fb9 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" <fche@redhat.com> Date: Sat, 7 Dec 2024 15:01:54 -0500 Subject: [PATCH] debuginfod: add CORS response headers and OPTIONS method From: Henning Meyer <hmeyer.eu@gmail.com> CORS is the Cross-Origin-Resource-Sharing mechanism explained at https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS 1. by default JavaScript code from Website A cannot request arbitrary resources from website B, these are called cross-origin-requests 2. The browser performs what is called a preflight check, this the OPTIONS method 3. the response allows website B fine-grained control over what the web browser should allow 4. Setting "Access-Control-Allow-Origin: *" tells the web browser to allow all access, e.g. the same behavior you get with curl or debuginfod-find The website mentions that the corresponding spec has been changed, such that preflight requests are no longer necessary, but in the browsers I use today (Firefox 132 and Chromium 131) they are still necessary. I have confirmed that I can use debuginfod with this patch from my web application at https://core-explorer.github.io/cdx-type/ FChE simplified the code and added a few quick "curl -i | grep" tests to confirm the new headers are there. Signed-off-by: Henning Meyer <hmeyer.eu@gmail.com> Signed-off-by: Frank Ch. Eigler <fche@redhat.com> --- debuginfod/debuginfod.cxx | 35 ++++++++++++++++++++-- tests/run-debuginfod-federation-metrics.sh | 3 ++ tests/run-debuginfod-find-metadata.sh | 1 + 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/debuginfod/debuginfod.cxx b/debuginfod/debuginfod.cxx index 4bb517bde80f..fbcd0f627dc8 100644 --- a/debuginfod/debuginfod.cxx +++ b/debuginfod/debuginfod.cxx @@ -3785,6 +3785,23 @@ handle_root (off_t* size) } +static struct MHD_Response* +handle_options (off_t* size) +{ + static char empty_body[] = " "; + MHD_Response* r = MHD_create_response_from_buffer (1, empty_body, + MHD_RESPMEM_PERSISTENT); + if (r != NULL) + { + *size = 1; + add_mhd_response_header (r, "Access-Control-Allow-Origin", "*"); + add_mhd_response_header (r, "Access-Control-Allow-Methods", "GET, OPTIONS"); + add_mhd_response_header (r, "Access-Control-Allow-Headers", "cache-control"); + } + return r; +} + + //////////////////////////////////////////////////////////////////////// @@ -3838,8 +3855,17 @@ handler_cb (void * /*cls*/, try { - if (string(method) != "GET") - throw reportable_exception(400, "we support GET only"); + if (method == string("OPTIONS")) + { + inc_metric("http_requests_total", "type", method); + r = handle_options(& http_size); + rc = MHD_queue_response (connection, MHD_HTTP_OK, r); + http_code = MHD_HTTP_OK; + MHD_destroy_response (r); + return rc; + } + else if (string(method) != "GET") + throw reportable_exception(400, "we support OPTIONS+GET only"); /* Start decoding the URL. */ size_t slash1 = url_copy.find('/', 1); @@ -3887,7 +3913,7 @@ handler_cb (void * /*cls*/, // get the resulting fd so we can report its size int fd; - r = handle_buildid(connection, buildid, artifacttype, suffix, &fd); + r = handle_buildid (connection, buildid, artifacttype, suffix, &fd); if (r) { struct stat fs; @@ -3934,6 +3960,8 @@ handler_cb (void * /*cls*/, throw reportable_exception(406, "File too large, max size=" + std::to_string(maxsize)); } + // add ACAO header for all successful requests + add_mhd_response_header (r, "Access-Control-Allow-Origin", "*"); rc = MHD_queue_response (connection, MHD_HTTP_OK, r); http_code = MHD_HTTP_OK; MHD_destroy_response (r); @@ -4023,6 +4051,7 @@ dwarf_extract_source_paths (Elf *elf, set<string>& debug_sourcefiles) { string artifacttype = "debuginfo"; r = handle_buildid (0, buildid, artifacttype, "", &alt_fd); + // NB: no need for ACAO etc. headers; this is not getting sent to a client } catch (const reportable_exception& e) { diff --git a/tests/run-debuginfod-federation-metrics.sh b/tests/run-debuginfod-federation-metrics.sh index 60fe69ca4f25..eef800010935 100755 --- a/tests/run-debuginfod-federation-metrics.sh +++ b/tests/run-debuginfod-federation-metrics.sh @@ -153,6 +153,8 @@ testrun ${abs_builddir}/debuginfod_build_id_find -e F/prog 1 curl -s http://127.0.0.1:$PORT1/badapi curl -s http://127.0.0.1:$PORT1/metrics curl -s http://127.0.0.1:$PORT2/metrics +curl -i -s http://127.0.0.1:$PORT1/metrics | grep -i access.control.allow.origin: +curl -X OPTIONS -i -s http://127.0.0.1:$PORT1/ | grep -i access.control.allow.origin: curl -s http://127.0.0.1:$PORT1/metrics | grep -q 'http_responses_total.*result.*error' curl -s http://127.0.0.1:$PORT2/metrics | grep -q 'http_responses_total.*result.*upstream' curl -s http://127.0.0.1:$PORT1/metrics | grep 'http_responses_duration_milliseconds_count' @@ -181,6 +183,7 @@ rm -f .client_cache*/$BUILDID/debuginfo testrun ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo $BUILDID testrun ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo $BUILDID testrun ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo $BUILDID +curl -i -s http://127.0.0.1:$PORT2/buildid/$BUILDID/debuginfo | grep -i access.control.allow.origin: rm -f .client_cache*/$BUILDID/debuginfo testrun ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo $BUILDID diff --git a/tests/run-debuginfod-find-metadata.sh b/tests/run-debuginfod-find-metadata.sh index 78a34f09490f..041d08233281 100755 --- a/tests/run-debuginfod-find-metadata.sh +++ b/tests/run-debuginfod-find-metadata.sh @@ -79,6 +79,7 @@ test $N_FOUND -eq 2 # Query via the webapi as well curl http://127.0.0.1:$PORT2'/metadata?key=glob&value=/usr/bin/*hi*' +curl -s -i http://127.0.0.1:$PORT2'/metadata?key=glob&value=/usr/bin/*hi*' | grep -i access.control.allow.origin: test `curl -s http://127.0.0.1:$PORT2'/metadata?key=glob&value=/usr/bin/*hi*' | jq '.results[0].buildid == "f17a29b5a25bd4960531d82aa6b07c8abe84fa66"'` = 'true' test `curl -s http://127.0.0.1:$PORT2'/metadata?key=glob&value=/usr/bin/*hi*' | jq '.results[0].file == "/usr/bin/hithere"'` = 'true' test `curl -s http://127.0.0.1:$PORT2'/metadata?key=glob&value=/usr/bin/*hi*' | jq '.results[0].archive | test(".*hithere.*deb")'` = 'true'
Hi Henning, On Fri, Dec 06, 2024 at 01:01:34AM +0100, Henning Meyer wrote: > it is the Cross-Origin-Resource-Sharing mechanism explained at > https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS Thanks, this might be a good URL to include in a comment so others know what the extra headers are there for. > 1. by default > JavaScript code from Website A cannot request arbitrary resources > from website B, these are called cross-origin-requests 2. The > browser performs what is called a preflight check, this the OPTIONS > method 3. the response allows website B fine-grained control over > what the web browser should allow 4. Setting > "Access-Control-Allow-Origin: *" tells the web browser to allow all > access, e.g. the same behavior you get with curl or debuginfod-find Right and then when the browser sents an OPTION request we reply with Access-Control-Allow-Origin: * to indicate that is fine from everywhere. A Access-Control-Allow-Methods: GET, OPTIONS to allow both request methods. And a Access-Control-Allow-Headers: cache-control to indicate the browser script may use the cache-control header. Is that the only header we want to expose to scripts? Also we only return these three headers for an OPTION request. Why are we setting the Access-Control-Allow-Origin also on GET requests? Is that necessary? Why not the other Access-Control-Allow headers? > The website mentions that the corresponding spec has been changed, > such that preflight requests are no longer necessary, but in the > browsers I use today (Firefox 132 and Chromium 131) they are still > necessary. That is not how I read it. I looks like the OPTION request is always necessary, but some older browsers didn't do it. I do understand now why you would like to see these headers. But might it be an idea to just let a proxy do this for us? Cheers, Mark
* Frank Ch. Eigler: > Hi - > > I'm planning to commit this shortly: > > From 4ebefc8f3b4b8fb68a55c960e70122fda50a0fb9 Mon Sep 17 00:00:00 2001 > From: "Frank Ch. Eigler" <fche@redhat.com> > Date: Sat, 7 Dec 2024 15:01:54 -0500 > Subject: [PATCH] debuginfod: add CORS response headers and OPTIONS method What are the security implications of a shared origin when serving (potentially third-party) debuginfo data? I think it will allow public web clients to exfiltrate debuginfo data from debuginfod servers on private intranets. Previously, the cross-origin restrictions on web content would have prevented that. Thanks, Florian
Hi - > [...] > I think it will allow public web clients to exfiltrate debuginfo data > from debuginfod servers on private intranets. Previously, the > cross-origin restrictions on web content would have prevented that. Yes, this is the flip side of the CORS default coin. ISTM the convenience is a larger benefit than this risk. Users that disagree can do the reverse-proxy header-filtering to defeat it. 'course we can also be more noncomittal and make it a command line option. - FChE
I think Florian is right. I see a scenario where: 1. someone runs a debuginfod service for closed source software in an internal network 2. the names for debuginfod server instances are guessable 3. users in corporate networks don't run adblockers 4. the debuginfod defaults change 5. it is now possible to exfiltrate sensitive debug information I don't think making software insecure by default, even if it is convenient, is appropriate in 2024. I don't want people not to run debuginfod instances because of security considerations. I still think it is a good idea to make it easy to enable this when serving open source software. I am not sure what the best way forward is, usually I would say, make it all configurable, but debuginfod doesn't have a central configuration file. I would not like to add more environment variables. Regards, Henning On 08.12.24 12:06, Florian Weimer wrote: > * Frank Ch. Eigler: > >> Hi - >> >> I'm planning to commit this shortly: >> >> From 4ebefc8f3b4b8fb68a55c960e70122fda50a0fb9 Mon Sep 17 00:00:00 2001 >> From: "Frank Ch. Eigler" <fche@redhat.com> >> Date: Sat, 7 Dec 2024 15:01:54 -0500 >> Subject: [PATCH] debuginfod: add CORS response headers and OPTIONS method > What are the security implications of a shared origin when serving > (potentially third-party) debuginfo data? > > I think it will allow public web clients to exfiltrate debuginfo data > from debuginfod servers on private intranets. Previously, the > cross-origin restrictions on web content would have prevented that. > > Thanks, > Florian >
Hi - > [...] > I am not sure what the best way forward is, > usually I would say, make it all configurable, > but debuginfod doesn't have a central configuration file. Marty, we will not need central configuration files where we're going. > I would not like to add more environment variables. Note that the env vars are used for configuring the *client*, because it sometimes embedded deep into other preexisting applications, so we can't easily add command line options. - FChE From e574f0089a2389267a95417c11ae5aa42a5b8bf8 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" <fche@redhat.com> Date: Sat, 7 Dec 2024 15:01:54 -0500 Subject: [PATCH] debuginfod: in --cors mode, add CORS response headers and OPTIONS method From: Henning Meyer <hmeyer.eu@gmail.com> CORS is the Cross-Origin-Resource-Sharing mechanism explained at https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS 1. by default JavaScript code from Website A cannot request arbitrary resources from website B, these are called cross-origin-requests 2. The browser performs what is called a preflight check, this the OPTIONS method 3. the response allows website B fine-grained control over what the web browser should allow 4. Setting "Access-Control-Allow-Origin: *" tells the web browser to allow all access, e.g. the same behavior you get with curl or debuginfod-find The website mentions that the corresponding spec has been changed, such that preflight requests are no longer necessary, but in the browsers I use today (Firefox 132 and Chromium 131) they are still necessary. I have confirmed that I can use debuginfod with this patch from my web application at https://core-explorer.github.io/cdx-type/ FChE simplified the code and added a few quick "curl -i | grep" tests to confirm the new headers are there. * debuginfod/debuginfod.cxx (handle_options): New function. (handler_cb): Call it for OPTIONS. Add ACAO header for all successful requests. (parse_opt): Parse --cors. * tests/run-debuginfod-federation-metrics.sh, tests/run-debuginfod-find-metadata.sh: Lightly test. * doc/debuginfod.8: Document --cors option, default off. Signed-off-by: Henning Meyer <hmeyer.eu@gmail.com> Signed-off-by: Frank Ch. Eigler <fche@redhat.com> --- NEWS | 4 ++ debuginfod/debuginfod.cxx | 46 ++++++++++++++++++++-- doc/debuginfod.8 | 7 ++++ tests/run-debuginfod-federation-metrics.sh | 7 +++- tests/run-debuginfod-find-metadata.sh | 5 ++- 5 files changed, 62 insertions(+), 7 deletions(-) diff --git a/NEWS b/NEWS index 1189c6037693..4cb5b2260fec 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,7 @@ +Version 0.193 (one after 0.192) + +debuginfod: Add CORS (webapp access) support to webapi. + Version 0.192 "New rules, faster tools" CONDUCT: A new code of conduct has been adopted. See the diff --git a/debuginfod/debuginfod.cxx b/debuginfod/debuginfod.cxx index 4bb517bde80f..cdf05456b41e 100644 --- a/debuginfod/debuginfod.cxx +++ b/debuginfod/debuginfod.cxx @@ -448,6 +448,8 @@ static const struct argp_option options[] = { "include", 'I', "REGEX", 0, "Include files matching REGEX, default=all.", 0 }, { "exclude", 'X', "REGEX", 0, "Exclude files matching REGEX, default=none.", 0 }, { "port", 'p', "NUM", 0, "HTTP port to listen on, default 8002.", 0 }, +#define ARGP_KEY_CORS 0x1000 + { "cors", ARGP_KEY_CORS, NULL, 0, "Add CORS response headers to HTTP queries, default no.", 0 }, { "database", 'd', "FILE", 0, "Path to sqlite database.", 0 }, { "ddl", 'D', "SQL", 0, "Apply extra sqlite ddl/pragma to connection.", 0 }, { "verbose", 'v', NULL, 0, "Increase verbosity.", 0 }, @@ -510,6 +512,7 @@ static volatile sig_atomic_t sigusr1 = 0; static volatile sig_atomic_t forced_groom_count = 0; static volatile sig_atomic_t sigusr2 = 0; static unsigned http_port = 8002; +static bool webapi_cors = false; static unsigned rescan_s = 300; static unsigned groom_s = 86400; static bool maxigroom = false; @@ -614,6 +617,9 @@ parse_opt (int key, char *arg, if (http_port == 0 || http_port > 65535) argp_failure(state, 1, EINVAL, "port number"); break; + case ARGP_KEY_CORS: + webapi_cors = true; + break; case 'F': scan_files = true; break; case 'R': scan_archives[".rpm"]="cat"; // libarchive groks rpm natively @@ -3785,6 +3791,23 @@ handle_root (off_t* size) } +static struct MHD_Response* +handle_options (off_t* size) +{ + static char empty_body[] = " "; + MHD_Response* r = MHD_create_response_from_buffer (1, empty_body, + MHD_RESPMEM_PERSISTENT); + if (r != NULL) + { + *size = 1; + add_mhd_response_header (r, "Access-Control-Allow-Origin", "*"); + add_mhd_response_header (r, "Access-Control-Allow-Methods", "GET, OPTIONS"); + add_mhd_response_header (r, "Access-Control-Allow-Headers", "cache-control"); + } + return r; +} + + //////////////////////////////////////////////////////////////////////// @@ -3838,8 +3861,17 @@ handler_cb (void * /*cls*/, try { - if (string(method) != "GET") - throw reportable_exception(400, "we support GET only"); + if (webapi_cors && method == string("OPTIONS")) + { + inc_metric("http_requests_total", "type", method); + r = handle_options(& http_size); + rc = MHD_queue_response (connection, MHD_HTTP_OK, r); + http_code = MHD_HTTP_OK; + MHD_destroy_response (r); + return rc; + } + else if (string(method) != "GET") + throw reportable_exception(400, "we support OPTIONS+GET only"); /* Start decoding the URL. */ size_t slash1 = url_copy.find('/', 1); @@ -3887,7 +3919,7 @@ handler_cb (void * /*cls*/, // get the resulting fd so we can report its size int fd; - r = handle_buildid(connection, buildid, artifacttype, suffix, &fd); + r = handle_buildid (connection, buildid, artifacttype, suffix, &fd); if (r) { struct stat fs; @@ -3934,6 +3966,9 @@ handler_cb (void * /*cls*/, throw reportable_exception(406, "File too large, max size=" + std::to_string(maxsize)); } + if (webapi_cors) + // add ACAO header for all successful requests + add_mhd_response_header (r, "Access-Control-Allow-Origin", "*"); rc = MHD_queue_response (connection, MHD_HTTP_OK, r); http_code = MHD_HTTP_OK; MHD_destroy_response (r); @@ -4023,6 +4058,7 @@ dwarf_extract_source_paths (Elf *elf, set<string>& debug_sourcefiles) { string artifacttype = "debuginfo"; r = handle_buildid (0, buildid, artifacttype, "", &alt_fd); + // NB: no need for ACAO etc. headers; this is not getting sent to a client } catch (const reportable_exception& e) { @@ -5706,7 +5742,9 @@ main (int argc, char *argv[]) } obatched(clog) << "started http server on" << (d4 != NULL ? " IPv4 " : " IPv4 IPv6 ") - << "port=" << http_port << endl; + << "port=" << http_port + << (webapi_cors ? " with cors" : "") + << endl; // add maxigroom sql if -G given if (maxigroom) diff --git a/doc/debuginfod.8 b/doc/debuginfod.8 index f35ce6c1a9ca..1cf9a18fe2f3 100644 --- a/doc/debuginfod.8 +++ b/doc/debuginfod.8 @@ -154,6 +154,12 @@ listen, to service HTTP requests. Both IPv4 and IPV6 sockets are opened, if possible. The webapi is documented below. The default port number is 8002. +.TP +.B "\-\-cors" +Add CORS-related response headers and OPTIONS method processing. +This allows third-party webapps to query debuginfod data, which may +or may not be desirable. Default is no. + .TP .B "\-I REGEX" "\-\-include=REGEX" "\-X REGEX" "\-\-exclude=REGEX" Govern the inclusion and exclusion of file names under the search @@ -563,3 +569,4 @@ Default database file. .I "debuginfod-find(1)" .I "sqlite3(1)" .I \%https://prometheus.io/docs/instrumenting/exporters/ +.I \%https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS diff --git a/tests/run-debuginfod-federation-metrics.sh b/tests/run-debuginfod-federation-metrics.sh index 60fe69ca4f25..715a575cbc3b 100755 --- a/tests/run-debuginfod-federation-metrics.sh +++ b/tests/run-debuginfod-federation-metrics.sh @@ -37,7 +37,7 @@ base=9000 get_ports # Launch server which will be unable to follow symlinks -env LD_LIBRARY_PATH=$ldpath ${abs_builddir}/../debuginfod/debuginfod $VERBOSE -d ${DB} -F -U -t0 -g0 -p $PORT1 L D F > vlog$PORT1 2>&1 & +env LD_LIBRARY_PATH=$ldpath ${abs_builddir}/../debuginfod/debuginfod $VERBOSE -d ${DB} -F -U -t0 -g0 -p $PORT1 --cors L D F > vlog$PORT1 2>&1 & PID1=$! tempfiles vlog$PORT1 errfiles vlog$PORT1 @@ -75,7 +75,7 @@ wait_ready $PORT1 'thread_busy{role="http-metrics"}' 1 export DEBUGINFOD_CACHE_PATH=${PWD}/.client_cache2 mkdir -p $DEBUGINFOD_CACHE_PATH # NB: run in -L symlink-following mode for the L subdir -env LD_LIBRARY_PATH=$ldpath DEBUGINFOD_URLS=http://127.0.0.1:$PORT1 ${abs_builddir}/../debuginfod/debuginfod $VERBOSE -d ${DB}_2 -F -U -p $PORT2 -L L D > vlog$PORT2 2>&1 & +env LD_LIBRARY_PATH=$ldpath DEBUGINFOD_URLS=http://127.0.0.1:$PORT1 ${abs_builddir}/../debuginfod/debuginfod $VERBOSE -d ${DB}_2 -F -U -p $PORT2 --cors -L L D > vlog$PORT2 2>&1 & PID2=$! tempfiles vlog$PORT2 errfiles vlog$PORT2 @@ -153,6 +153,8 @@ testrun ${abs_builddir}/debuginfod_build_id_find -e F/prog 1 curl -s http://127.0.0.1:$PORT1/badapi curl -s http://127.0.0.1:$PORT1/metrics curl -s http://127.0.0.1:$PORT2/metrics +curl -i -s http://127.0.0.1:$PORT1/metrics | grep -i access.control.allow.origin: +curl -X OPTIONS -i -s http://127.0.0.1:$PORT1/ | grep -i access.control.allow.origin: curl -s http://127.0.0.1:$PORT1/metrics | grep -q 'http_responses_total.*result.*error' curl -s http://127.0.0.1:$PORT2/metrics | grep -q 'http_responses_total.*result.*upstream' curl -s http://127.0.0.1:$PORT1/metrics | grep 'http_responses_duration_milliseconds_count' @@ -181,6 +183,7 @@ rm -f .client_cache*/$BUILDID/debuginfo testrun ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo $BUILDID testrun ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo $BUILDID testrun ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo $BUILDID +curl -i -s http://127.0.0.1:$PORT2/buildid/$BUILDID/debuginfo | grep -i access.control.allow.origin: rm -f .client_cache*/$BUILDID/debuginfo testrun ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo $BUILDID diff --git a/tests/run-debuginfod-find-metadata.sh b/tests/run-debuginfod-find-metadata.sh index 78a34f09490f..99759cff20a8 100755 --- a/tests/run-debuginfod-find-metadata.sh +++ b/tests/run-debuginfod-find-metadata.sh @@ -52,7 +52,7 @@ wait_ready $PORT1 'thread_work_pending{role="scan"}' 0 wait_ready $PORT1 'thread_busy{role="scan"}' 0 env LD_LIBRARY_PATH=$ldpath DEBUGINFOD_URLS="http://127.0.0.1:$PORT1 https://bad/url.web" ${VALGRIND_CMD} ${abs_builddir}/../debuginfod/debuginfod $VERBOSE -U \ - -d ${DB}_2 -p $PORT2 -t0 -g0 D > vlog$PORT2 2>&1 & + -d ${DB}_2 -p $PORT2 -t0 -g0 --cors D > vlog$PORT2 2>&1 & PID2=$! tempfiles vlog$PORT2 errfiles vlog$PORT2 @@ -79,6 +79,9 @@ test $N_FOUND -eq 2 # Query via the webapi as well curl http://127.0.0.1:$PORT2'/metadata?key=glob&value=/usr/bin/*hi*' +# no --cors on $PORT1's debuginfod +test "`curl -s -i http://127.0.0.1:$PORT1'/metadata?key=glob&value=/usr/bin/*hi*' | grep -i access.control.allow.origin: || true`" == "" +curl -s -i http://127.0.0.1:$PORT2'/metadata?key=glob&value=/usr/bin/*hi*' | grep -i access.control.allow.origin: test `curl -s http://127.0.0.1:$PORT2'/metadata?key=glob&value=/usr/bin/*hi*' | jq '.results[0].buildid == "f17a29b5a25bd4960531d82aa6b07c8abe84fa66"'` = 'true' test `curl -s http://127.0.0.1:$PORT2'/metadata?key=glob&value=/usr/bin/*hi*' | jq '.results[0].file == "/usr/bin/hithere"'` = 'true' test `curl -s http://127.0.0.1:$PORT2'/metadata?key=glob&value=/usr/bin/*hi*' | jq '.results[0].archive | test(".*hithere.*deb")'` = 'true'
diff --git a/debuginfod/ChangeLog b/debuginfod/ChangeLog index 0e4810bb..8e2377a0 100644 --- a/debuginfod/ChangeLog +++ b/debuginfod/ChangeLog @@ -1,3 +1,9 @@ +2024-12-04: Henning Meyer <hmeyer.eu@gmail.com> + * debuginfod.cxx: + (handle_options): new_function + (handle_buildid, handle_metrics, handle_root, handle_metadata): + add Access-Control-Allow-Origin header + (handler_cb): handle http OPTIONS method 2023-04-21 Frank Ch. Eigler <fche@redhat.com> * debuginfod.cxx (groom): Fix -r / -X logic. diff --git a/debuginfod/debuginfod.cxx b/debuginfod/debuginfod.cxx index 4bb517bd..7f7d304f 100644 --- a/debuginfod/debuginfod.cxx +++ b/debuginfod/debuginfod.cxx @@ -3365,6 +3365,7 @@ handle_buildid (MHD_Connection* conn, { add_mhd_response_header (r, "Content-Type", "application/octet-stream"); + add_mhd_response_header (r, "Access-Control-Allow-Origin", "*"); // Copy the incoming headers const char * hdrs = debuginfod_get_headers(client);