|
| 1 | +From https://gitlab.alpinelinux.org/alpine/apk-tools/-/merge_requests/292.patch |
| 2 | +From 716fe84f69137b59dd12b3b4fa90710e5f4ed911 Mon Sep 17 00:00:00 2001 |
| 3 | +From: Justin Vreeland <vreeland.justin@gmail.com> |
| 4 | +Date: Tue, 18 Mar 2025 10:25:33 -0700 |
| 5 | +Subject: [PATCH] db: Explicitly clean st on fstatat failure to workaround |
| 6 | + rosetta2 |
| 7 | + |
| 8 | +We've discovered an issue with in apk when using Rosetta2 with wolfi that was surfaced |
| 9 | +by f3f239a: apk, db: rework dbopts cache_max_age default handling. With the new |
| 10 | +settings apk now hits an fstatat conditional where it didn't before. As far as I can tell |
| 11 | +this failure is expected and shouldn't be a problem. It only is because the code |
| 12 | +continues to rely out the buffer that was passed in to contain clean |
| 13 | +values. On Rosetta2 with wolfi the st buffer is no longer clean out after the call to fstatat. |
| 14 | + |
| 15 | +This issue only occurs if cache_max_age is positive, and `/var/cache/apk` |
| 16 | +is empty. This issue can be seen below: |
| 17 | + |
| 18 | +``` |
| 19 | +a549fa77b74f:/apk-tools# apk --help | head -1 |
| 20 | +apk-tools 2.14.10, compiled for x86_64. |
| 21 | +a549fa77b74f:/apk-tools# apk update |
| 22 | +fetch https://packages.wolfi.dev/os/x86_64/APKINDEX.tar.gz |
| 23 | +WARNING: opening from cache https://packages.wolfi.dev/os: No such file or directory |
| 24 | +2 unavailable, 0 stale; 83 distinct packages available |
| 25 | + |
| 26 | +a549fa77b74f:/apk-tools# apk update --cache-max-age 0 |
| 27 | +fetch https://packages.wolfi.dev/os/x86_64/APKINDEX.tar.gz |
| 28 | + [https://packages.wolfi.dev/os] |
| 29 | +OK: 144415 distinct packages available |
| 30 | + |
| 31 | +a549fa77b74f:/apk-tools# apk update |
| 32 | + [https://packages.wolfi.dev/os] |
| 33 | +OK: 144415 distinct packages available |
| 34 | + |
| 35 | +a549fa77b74f:/apk-tools# apk update --cache-max-age 1 |
| 36 | + [https://packages.wolfi.dev/os] |
| 37 | +OK: 144415 distinct packages available |
| 38 | + |
| 39 | +a549fa77b74f:/apk-tools# rm /var/cache/apk/* |
| 40 | + |
| 41 | +a549fa77b74f:/apk-tools# apk update |
| 42 | +fetch https://packages.wolfi.dev/os/x86_64/APKINDEX.tar.gz |
| 43 | +WARNING: opening from cache https://packages.wolfi.dev/os: No such file or directory |
| 44 | +2 unavailable, 0 stale; 83 distinct packages available |
| 45 | +``` |
| 46 | + |
| 47 | +Some debug output with Rosetta2 |
| 48 | + |
| 49 | +``` |
| 50 | +a549fa77b74f:/apk-tools# LD_PRELOAD=`pwd`/src/libapk.so ./src/apk update --cache-max-age 1 |
| 51 | +st_mtime pre fstat: 0 |
| 52 | +cache_max_age=60 |
| 53 | +ferr: -1, tmperr: 2 |
| 54 | +st_mtime post fstat: 140737472955232 |
| 55 | +fetch https://packages.wolfi.dev/os/x86_64/APKINDEX.tar.gz |
| 56 | +WARNING: opening from cache https://packages.wolfi.dev/os: No such file or directory |
| 57 | +2 unavailable, 0 stale; 83 distinct packages available |
| 58 | +a549fa77b74f:/apk-tools# git diff > /test.patch |
| 59 | +a549fa77b74f:/apk-tools# ps aux | grep rosetta |
| 60 | + 1 root 0:02 {sh} /run/rosetta/rosetta /bin/sh /bin/sh -l |
| 61 | +15816 root 0:00 {grep} /run/rosetta/rosetta /usr/bin/grep grep rosetta |
| 62 | +``` |
| 63 | + |
| 64 | +Some debug output without Rosetta2 |
| 65 | + |
| 66 | +``` |
| 67 | +/apk-tools # LD_PRELOAD=`pwd`/src/libapk.so ./src/apk update --cache-max-age 1 |
| 68 | +st_mtime pre fstat: 0 |
| 69 | +cache_max_age=60 |
| 70 | +ferr: -1, tmperr: 2 |
| 71 | +st_mtime post fstat: 0 |
| 72 | +fetch https://packages.wolfi.dev/os/x86_64/APKINDEX.tar.gz |
| 73 | + [https://packages.wolfi.dev/os] |
| 74 | +OK: 144391 distinct packages available |
| 75 | +/apk-tools # ps aux | grep rosetta |
| 76 | + 2438 root 0:00 grep rosetta |
| 77 | +``` |
| 78 | + |
| 79 | +I cannot reproduce this with Alpine. In fact the st buffer remains clean |
| 80 | +with Alpine. I believe the real issue is with rosetta2 & glibc not |
| 81 | +actually apk but it seems reasonable not to rely on the buffer from |
| 82 | +a failed system call as a solution for now. |
| 83 | +--- |
| 84 | + src/database.c | 6 +++++- |
| 85 | + 1 file changed, 5 insertions(+), 1 deletion(-) |
| 86 | + |
| 87 | +diff --git a/src/database.c b/src/database.c |
| 88 | +index dc5e4fd4..b7353221 100644 |
| 89 | +--- a/src/database.c |
| 90 | ++++ b/src/database.c |
| 91 | +@@ -654,7 +654,11 @@ int apk_cache_download(struct apk_database *db, struct apk_repository *repo, |
| 92 | + if (r < 0) return r; |
| 93 | + |
| 94 | + if (autoupdate && db->cache_max_age > 0 && !(apk_force & APK_FORCE_REFRESH)) { |
| 95 | +- if (fstatat(db->cache_fd, cacheitem, &st, 0) == 0 && |
| 96 | ++ int ferr = fstatat(db->cache_fd, cacheitem, &st, 0); |
| 97 | ++ if (ferr == -1) { |
| 98 | ++ memset(&st, 0, sizeof(struct stat)); |
| 99 | ++ } |
| 100 | ++ if (ferr == 0 && |
| 101 | + now - st.st_mtime <= db->cache_max_age) |
| 102 | + return -EALREADY; |
| 103 | + } |
| 104 | +-- |
| 105 | +GitLab |
| 106 | + |
0 commit comments