From c9d721fea6bd9cce7013c3392378c4abc13a2984 Mon Sep 17 00:00:00 2001 From: Knutwurst <36196269+knutwurst@users.noreply.github.com> Date: Wed, 24 Jun 2026 20:41:26 +0200 Subject: [PATCH] Polish: NOSIGNAL + HTTPS pin on all transports, bounded kill loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The three other curl_easy code paths (downloader, piece pool, net_diag) now set CURLOPT_NOSIGNAL=1L plus PROTOCOLS_STR/REDIR_PROTOCOLS_STR = "https" — matching what patchdl_http_get already does. SIGPIPE on a broken connection in a worker thread previously could crash the process; the protocol pin keeps a redirect from sliding off https. patchdl_proc_kill_others is now bounded to 8 iterations. If kill returns success but the process never exits (zombie / unusual proc-table state), sleep(1) × N would otherwise stall startup indefinitely. lookup_tsv rejects URLs that don't start with https://. The TSV file lives under /data/patchdl and is writable by anyone with /data access; patchdl_http_get's host_allowed gate still applies, but failing earlier keeps a poisoned line from even reaching the network layer. --- src/patchdl_net.c | 9 +++++++++ src/patchdl_proc.c | 5 ++++- src/patchdl_resolve.c | 8 ++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/patchdl_net.c b/src/patchdl_net.c index e6cd0c7..2e37749 100644 --- a/src/patchdl_net.c +++ b/src/patchdl_net.c @@ -452,6 +452,9 @@ http_download_to_file_progress(const char *url, FILE *fp, long long *bytes_out, curl_easy_setopt(curl, CURLOPT_SSL_CIPHER_LIST, "DEFAULT@SECLEVEL=0"); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 5L); + curl_easy_setopt(curl, CURLOPT_PROTOCOLS_STR, "https"); + curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS_STR, "https"); + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L); curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 20L); /* No total timeout (patches can be large); abort only on a long stall. */ curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 1024L); @@ -868,6 +871,9 @@ patchdl_http_download_piece(const char *url, int fd, curl_easy_setopt(curl, CURLOPT_SSL_CIPHER_LIST, "DEFAULT@SECLEVEL=0"); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 5L); + curl_easy_setopt(curl, CURLOPT_PROTOCOLS_STR, "https"); + curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS_STR, "https"); + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L); curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); /* 4xx/5xx -> error, no body written */ curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 20L); curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 1024L); @@ -1060,6 +1066,9 @@ patchdl_net_diag(const char *url, char *out_json, size_t sz) { curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); curl_easy_setopt(curl, CURLOPT_SSL_CIPHER_LIST, "DEFAULT@SECLEVEL=0"); + curl_easy_setopt(curl, CURLOPT_PROTOCOLS_STR, "https"); + curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS_STR, "https"); + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 15L); res = curl_easy_perform(curl); curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); diff --git a/src/patchdl_proc.c b/src/patchdl_proc.c index ae8d7ee..2ca9551 100644 --- a/src/patchdl_proc.c +++ b/src/patchdl_proc.c @@ -65,7 +65,10 @@ patchdl_proc_kill_others(const char *name) { int killed = 0; pid_t pid; - while ((pid = find_pid(name)) > 0) { + /* Bound the loop: at startup we expect 0-1 stale instance. A pathological + proc table (or kill returning success but the process not exiting) would + otherwise stall startup for sleep(1) × N. */ + while (killed < 8 && (pid = find_pid(name)) > 0) { if (kill(pid, SIGKILL)) break; killed++; diff --git a/src/patchdl_resolve.c b/src/patchdl_resolve.c index 5193965..273b0b3 100644 --- a/src/patchdl_resolve.c +++ b/src/patchdl_resolve.c @@ -27,6 +27,14 @@ lookup_tsv(const char *title_id, char *url_out, size_t url_sz) { fclose(fp); return -1; } + /* Defense in depth: the TSV file lives under /data/patchdl, writable + by anyone with /data access. patchdl_http_get also enforces + host_allowed, but rejecting non-https / non-Sony schemes here means + a poisoned line can't even reach the network layer. */ + if (strncmp(url, "https://", 8) != 0) { + fclose(fp); + return -1; + } memcpy(url_out, url, len + 1); fclose(fp); return 0;