commit 082c0a94eed6706753e8019ce348be095deb72f9 (HEAD -> main)
Author: Frank Ch. Eigler
Date: Fri Feb 21 14:33:49 2025 -0500
PR31862: debuginfod: client to cache x-debuginfod-* headers
This feature allows the extra http headers from debuginfod to be saved
into the client cache, and also thus replayed to clients. This way
they can perform IMA verification again, if they like, or a federating
caching intermediate debuginfod server can replay the headers it
received previously from upstream to future downstream. The headers
are placed adjacent to the payload files .cache/debuginfod/BUILDID/PAYLOAD
as .cache/debuginfod/BUILDID/hdr-PAYLOAD. They are aged the same
atime-based way.
Testing via an extension of a previous small test, and hand-running both
client & server code under valgrind. No memcheck errors reported.
Signed-off-by: Frank Ch. Eigler
diff --git a/debuginfod/debuginfod-client.c b/debuginfod/debuginfod-client.c
index d89beae93ea1..3ea234abb1a8 100644
--- a/debuginfod/debuginfod-client.c
+++ b/debuginfod/debuginfod-client.c
@@ -569,7 +569,7 @@ debuginfod_clean_cache(debuginfod_client *c,
return -errno;
regex_t re;
- const char * pattern =
".*/(metadata.*|[a-f0-9]+(/debuginfo|/executable|/source.*|))$"; /* include
dirs */
+ const char * pattern =
".*/(metadata.*|[a-f0-9]+(/hdr.*|/debuginfo|/executable|/source.*|))$"; /*
include dirs */
/* NB: also matches .../section/ subdirs, so extracted section files also
get cleaned. */
if (regcomp (&re, pattern, REG_EXTENDED | REG_NOSUB) != 0)
return -ENOMEM;
@@ -1777,7 +1777,9 @@ debuginfod_query_server_by_buildid (debuginfod_client *c,
char *cache_miss_path = NULL;
char *target_cache_dir = NULL;
char *target_cache_path = NULL;
+ char *target_cachehdr_path = NULL;
char *target_cache_tmppath = NULL;
+ char *target_cachehdr_tmppath = NULL;
char suffix[NAME_MAX];
char build_id_bytes[MAX_BUILD_ID_BYTES * 2 + 1];
int vfd = c->verbose_fd;
@@ -1912,6 +1914,8 @@ debuginfod_query_server_by_buildid (debuginfod_client *c,
target_cache_path: $HOME/.cache/0123abcd/debuginfo
target_cache_path: $HOME/.cache/0123abcd/executable-.debug_info
target_cache_path: $HOME/.cache/0123abcd/source-HASH-#PATH#TO#SOURCE
+ target_cachehdr_path: $HOME/.cache/0123abcd/hdr-debuginfo
+ target_cachehdr_path: $HOME/.cache/0123abcd/hdr-executable...
*/
cache_path = make_cache_path();
@@ -1923,11 +1927,15 @@ debuginfod_query_server_by_buildid (debuginfod_client
*c,
xalloc_str (target_cache_dir, "%s/%s", cache_path, build_id_bytes);
(void) mkdir (target_cache_dir, 0700); // failures with this mkdir would be
caught later too
- if (suffix[0] != '\0') /* section, source queries */
+ if (suffix[0] != '\0') { /* section, source queries */
xalloc_str (target_cache_path, "%s/%s-%s", target_cache_dir, type, suffix);
- else
+xalloc_str (target_cachehdr_path, "%s/hdr-%s-%s", target_cache_dir, type,
suffix);
+ } else {
xalloc_str (target_cache_path, "%s/%s", target_cache_dir, type);
+xalloc_str (target_cachehdr_path, "%s/hdr-%s", target_cache_dir, type);
+ }
xalloc_str (target_cache_tmppath, "%s.XX", target_cache_path);
+ xalloc_str (target_cachehdr_tmppath, "%s.XX", target_cachehdr_path);
/* XXX combine these */
xalloc_str (interval_path, "%s/%s", cache_path,
cache_clean_interval_filename);
@@ -1978,6 +1986,50 @@ debuginfod_query_server_by_buildid (debuginfod_client *c,
/* Success */
update_atime(fd);
rc = fd;
+
+ /* Attempt to transcribe saved headers. */
+ int fdh = open (target_cachehdr_path, O_RDONLY);
+ if (fdh >= 0)
+{
+ if (fstat (fdh, &st) == 0)
+if (st.st_size > 0)
+ {
+c->winning_headers = malloc(st.st_size);
+if (NULL != c->winning_headers) {
+
+ // Read all teh bytes, thanks posix.
+ // In case of any error, unlink the file to force a
redownload later.
+ off_t hdr_read = 0;
+ while (hdr_read < st.st_size)
+{
+ ssize_t bytes_read = read (fdh, c->winning_headers +
hdr_read,
+ st.st_size - hdr_read);
+ if (bytes_read < 0)
+{
+ if (errno == EINTR)
+continue;
+ free (c->winning_headers);
+ c->winning_headers = NULL;
+ (void) unlink (target_cachehdr_path);
+ break;
+}
+ if (bytes_read == 0) {
+free (c->winning_headers