diff options
author | Di Chen <dichen@redhat.com> | 2021-08-20 13:03:21 +0800 |
---|---|---|
committer | Mark Wielaard <mark@klomp.org> | 2021-08-27 19:40:55 +0200 |
commit | d3f914023abcd6ae76b168da97518e5e7dbd761a (patch) | |
tree | d5f3ed04d6a459eb858ef0a4906f389b8fcff01a /debuginfod/debuginfod.cxx | |
parent | 610623458b7e98ed3e912e4b7ca8050f6ce4c698 (diff) | |
download | elfutils-d3f914023abcd6ae76b168da97518e5e7dbd761a.tar.gz |
debuginfod: PR27917 - protect against federation loops
If someone misconfigures a debuginfod federation to have loops, and
a nonexistent buildid lookup is attempted, bad things will happen,
as is documented.
This patch aims to reduce the risk by adding an option to debuginfod
that functions kind of like an IP packet's TTL: a limit on the length of
XFF: header that debuginfod is willing to process. If X-Forwarded-For:
exceeds N hops, it will not delegate a local lookup miss to upstream
debuginfods.
Commit ab38d167c40c99 causes federation loops for non-existent resources
to result in multiple temporary deadlocks, each lasting for
$DEBUGINFOD_TIMEOUT seconds. Since concurrent requests for each unique
resource are now serialized, federation loops can result in one server
thread waiting to acquire a lock while the server thread holding the
lock waits for the first thread to respond to an http request.
This PR can help protect against the above multiple temporary deadlocks
behaviour. Ex. if --forwarded-ttl-limit=0 then the timeout behaviour of
local loops should be avoided.
https://sourceware.org/bugzilla/show_bug.cgi?id=27917
Signed-off-by: Di Chen <dichen@redhat.com>
Diffstat (limited to 'debuginfod/debuginfod.cxx')
-rw-r--r-- | debuginfod/debuginfod.cxx | 18 |
1 files changed, 18 insertions, 0 deletions
diff --git a/debuginfod/debuginfod.cxx b/debuginfod/debuginfod.cxx index b560fdcb..6e182a84 100644 --- a/debuginfod/debuginfod.cxx +++ b/debuginfod/debuginfod.cxx @@ -374,6 +374,8 @@ static const struct argp_option options[] = #define ARGP_KEY_FDCACHE_PREFETCH_FDS 0x1006 { "fdcache-prefetch-fds", ARGP_KEY_FDCACHE_PREFETCH_FDS, "NUM", 0,"Number of files allocated to the \ prefetch cache.", 0}, +#define ARGP_KEY_FORWARDED_TTL_LIMIT 0x1007 + {"forwarded-ttl-limit", ARGP_KEY_FORWARDED_TTL_LIMIT, "NUM", 0, "Limit of X-Forwarded-For hops, default 8.", 0}, { NULL, 0, NULL, 0, NULL, 0 }, }; @@ -421,6 +423,7 @@ static long fdcache_prefetch; static long fdcache_mintmp; static long fdcache_prefetch_mbs; static long fdcache_prefetch_fds; +static unsigned forwarded_ttl_limit = 8; static string tmpdir; static void set_metric(const string& key, double value); @@ -553,6 +556,9 @@ parse_opt (int key, char *arg, if( fdcache_mintmp > 100 || fdcache_mintmp < 0 ) argp_failure(state, 1, EINVAL, "fdcache mintmp percent"); break; + case ARGP_KEY_FORWARDED_TTL_LIMIT: + forwarded_ttl_limit = (unsigned) atoi(arg); + break; case ARGP_KEY_ARG: source_paths.insert(string(arg)); break; @@ -1880,6 +1886,17 @@ handle_buildid (MHD_Connection* conn, if (xff != "") xff += string(", "); // comma separated list + unsigned int xff_count = 0; + for (auto&& i : xff){ + if (i == ',') xff_count++; + } + + // if X-Forwarded-For: exceeds N hops, + // do not delegate a local lookup miss to upstream debuginfods. + if (xff_count >= forwarded_ttl_limit) + throw reportable_exception(MHD_HTTP_NOT_FOUND, "not found, --forwared-ttl-limit reached \ +and will not query the upstream servers"); + // Compute the client's numeric IP address only - so can't merge with conninfo() const union MHD_ConnectionInfo *u = MHD_get_connection_info (conn, MHD_CONNECTION_INFO_CLIENT_ADDRESS); @@ -3718,6 +3735,7 @@ main (int argc, char *argv[]) obatched(clog) << "groom time " << groom_s << endl; obatched(clog) << "prefetch fds " << fdcache_prefetch_fds << endl; obatched(clog) << "prefetch mbs " << fdcache_prefetch_mbs << endl; + obatched(clog) << "forwarded ttl limit " << forwarded_ttl_limit << endl; if (scan_archives.size()>0) { |