Commit Graph
55 Commits
Author SHA1 Message Date
libretroadmin 9cd17d57bb cloud sync: allocate the drive folder cache on first use
The Google Drive backend held a 128-entry static folder-id cache,
each entry a full path buffer - 295 kilobytes of load-resident
state on platforms without demand paging, for a backend most
sessions never configure. The cache now allocates on the first
insert and lookups treat an absent cache as a miss; it lives for
the session once syncing has run, exactly the lifetime the static
had. All eleven touch sites sit in the two cache functions,
audited.
2026-07-07 16:30:36 +02:00
libretroadmin 8047c7358f webdav: make cnonce const char* (CXX_BUILD -Wwrite-strings)
webdav_state_t::cnonce is only ever assigned the string literal
"1a2b3c4f" and read from (strlen, MD5_Update input, strlcpy source);
unlike its sibling digest fields (realm/nonce/algo/opaque) it is never
malloc'd, strdup'd or freed. As a plain char* it triggers, under
CXX_BUILD=1:

  warning: ISO C++ forbids converting a string constant to 'char*'
    [-Wwrite-strings]

Type it as const char* to match its actual use. All consumers already
take const (MD5_Update's const void*, strlcpy's const char* source,
strlen), it is valid C, and it is not part of the free path, so the C
build and runtime behaviour are unchanged.

Follow-up to the CXX_BUILD fixes in 059ca26 .. 9f1531a.
2026-06-25 10:39:50 +02:00
libretroadmin 0d3a0645f5 Track running length across strlcpy/strlcat chains (5 sites)
Five non-loop path-build sequences chained strlcpy with one or two
following strlcat calls.  Every strlcat scans its destination from
the start to find the NUL, so an N-call chain pays N strlen scans
on an ever-growing prefix.  The mechanical fix is to capture the
strlcpy return value and use strlcpy-at-offset for subsequent
appends — same end result, but each step is O(strlen(src)) instead
of O(strlen(dst)+strlen(src)).

The sites:

  configuration.c (input_config_save_keybinds_user)
    Three calls to fill_pathname_join_delim built the same
    'prefix_base' stem before each suffix variant ('_btn', '_axis',
    '_mbtn').  Build the stem ONCE, then overwrite just the suffix
    bytes at the known offset via memcpy.  Eliminates two redundant
    full path builds plus three strlcat scans.

  ai/game_ai.c (game_ai_lib_init path)
    strlcpy(lib_path) + strlcat('/data/') + strlcat(game_name) +
    strlen() truncation check.  Replaced with three offset-tracked
    strlcpys; truncation detection moves to a comparison of the
    accumulated _len against sizeof - 1 (same outcome — bail
    before using a truncated path).

  network/cloud_sync/smb.c (smb_sync_build_path helper)
    The 'add trailing slash if missing' branch used strlen(dest)-1
    to peek at the last char; now uses the strlcpy-tracked _len-1.
    Two following strlcats become strlcpys at offset.

  network/cloud_sync/smb.c (cloud_sync subdir builder)
    Same shape, two strlcats off a strlcpy.

  libretro-common/vfs/vfs_implementation_smb.c (smb_path_join)
    Same shape as smb_sync_build_path — including the strlen(dest)-1
    peek that becomes a _len-1 peek.

Correctness verified: 164 cases (4 realistic shapes + 80
truncation boundaries x 2 input shapes) produce byte-identical
output to the prior strlcat-chain form, checked under ASan+UBSan.

Absolute savings per call are modest (each strlcat avoided saves
one O(strlen(dst)) scan, ~3-10 ns for typical path lengths) and
none of these are per-frame paths, so the wall-clock win is small
in any individual call.  The value is shape consistency with the
offset-tracking pattern used elsewhere in the codebase, and the
configuration.c change additionally removes two redundant
fill_pathname_join_delim invocations per keybind unset.

Zero new compiler warnings on any of the four files.
2026-05-19 23:30:53 +02:00
U-DESKTOP-SPFP6AQ\twistedtechre 644d71d8d1 ================================================================
Suggested commit message
================================================================

cloud_sync: fix one-byte heap overflow in HTTP failure loggers

The four cloud-sync HTTP failure loggers (webdav, s3 ×2, google_drive)
all wrote a NUL terminator at data->data[data->len] and then printed
data->data with %s.  The buffer in data->data is owned by net_http
and is sized exactly to data->len: net_http_update() shrinks the
response buffer with realloc(response->data, response->len) on the
P_DONE transition (net_http.c lines 1441, 1501, 1540), and
net_http_data() returns that pointer plus the same length to the
task layer.  The terminator write therefore overflows the heap chunk
by one byte and corrupts the next chunk's metadata.

The corruption is silent at the point of the write.  Glibc detects
it later, on an unrelated free() near the same arena -- in practice
the next task_http_transfer_cleanup() during startup, when cloud
sync issues many HTTP requests in quick succession.  The result is
malloc_printerr / abort with a backtrace through
task_http_transfer_cleanup that does not point at cloud_sync at all.

Switch all four sites from "NUL-and-print-with-%s" to the
length-bounded form RARCH_WARN("%.*s\n", (int)data->len, ...).
This is local to the broken code, requires no producer-side change,
and removes the implicit "consumer must NUL-terminate, allocator
must oversize" handshake that nothing in the codebase documents.
Other consumers of data->data already pass (data->data, data->len)
together and are unaffected.

Reproducer (ASan, distilled from the call chain above):

    char *p = realloc(malloc(64*1024), 57);   /* mimic net_http */
    memcpy(p, body, 57);
    p[57] = 0;                                /* OOB write */

    ==116==ERROR: AddressSanitizer: heap-buffer-overflow
    WRITE of size 1 at 0x506000000059 thread T0
        #0 webdav_log_http_failure
    0 bytes after 57-byte region

Fixes the abort path in #16834, #17474, #17731 (and likely several
other "[CloudSync] crash on startup" reports that share the
task_http_transfer_cleanup → malloc_printerr → abort signature).

================================================================
PR description (for github.com/libretro/RetroArch)
================================================================

Cloud sync triggers a one-byte heap-buffer-overflow on every non-2xx
HTTP response, in the failure logging path shared by webdav, s3, and
google_drive.  Glibc usually catches the resulting heap corruption a
few allocations later, on an unrelated `free()`, with a backtrace
that points at `task_http_transfer_cleanup` and gives no hint that
cloud sync is the source.

```
```

Reproduces reliably at startup with cloud sync enabled; goes away
with cloud sync disabled.  The user-visible repro from #17474
("crashes upon fetching any server file other than manifest.server")
is the same bug -- a server returning anything that hits the failure
logger.

`net_http_update()` shrinks the response buffer to **exactly**
`response->len` bytes when the body is fully received:

  - `libretro-common/net/net_http.c:1441`  `realloc(response->data, response->len)`
  - `libretro-common/net/net_http.c:1501`  same
  - `libretro-common/net/net_http.c:1540`  same

`net_http_data()` returns that pointer plus the same length, and
`task_http_transfer_handler` puts both into `data->data` /
`data->len`.

The four cloud-sync failure loggers then do:

```c
data->data[data->len] = 0;
RARCH_WARN("%s\n", data->data);
```

That's a one-byte write past the end of the heap allocation.  It
corrupts the malloc chunk header of whatever sits next on the
arena.  Glibc only screams when something adjacent gets `free()`d.
At startup with cloud sync, that "something adjacent" is
overwhelmingly `task_http_transfer_cleanup()`'s own
`free(data->data)` or `free(data)`, which is what users see in the
backtrace.

The repeating-substring log spam in #16834
(`"Beetle PCE Fast.opt", PCE Fast/Beetle PCE Fast.opt", config/Beetle..."`)
is the same root cause manifesting as a corrupt-read instead of an
abort -- different chunk geometry, same OOB.

Replace `data->data[data->len] = 0; RARCH_WARN("%s\n", data->data)`
with `RARCH_WARN("%.*s\n", (int)data->len, (const char*)data->data)`
at all four sites:

- `network/cloud_sync/webdav.c` `webdav_log_http_failure`
- `network/cloud_sync/s3.c`     `s3_log_http_failure`
- `network/cloud_sync/s3.c`     `s3_log_multipart_initiate_failure`
- `network/cloud_sync/google_drive.c` `gdrive_log_http_failure`

The fix is local and does not change the producer-side ownership
contract.  All other consumers of `data->data` in the tree already
use `(data->data, data->len)` together and are unaffected.

ASan reproducer of the exact write pattern (pre-patch):

```
==116==ERROR: AddressSanitizer: heap-buffer-overflow
WRITE of size 1 at 0x506000000059 thread T0
    #0 webdav_log_http_failure
0x506000000059 is located 0 bytes after 57-byte region
allocated by realloc / fake_net_http_response
```

Same harness with the patched logger: clean run, no ASan diagnostic.

Closes #17474.  Likely closes #16834, #17731 and other "cloud sync
crash on startup" reports with the same `task_http_transfer_cleanup
→ malloc_printerr → abort` signature; if those reports are actually
the WebDAV "begin failed" / network-down case rather than this one,
they need separate diagnosis but should at least stop crashing.

================================================================
2026-04-25 05:04:14 +02:00
U-DESKTOP-SPFP6AQ\twistedtechre a52ea1b647 Remove unused functions 2026-04-25 03:50:19 +02:00
U-DESKTOP-SPFP6AQ\twistedtechre 1efeddccc1 network/cloud_sync + netplay: fix NULL-deref, OOM crashes, and realloc-to-self leak
Four bugs found in a sweep of network/ alloc sites.

=== network/cloud_sync/s3.c: s3_url_encode / s3_trim_string ===

Both helpers had the same dead-code NULL guard:

    static char* s3_url_encode(const char *input)
    {
       size_t input_len = strlen(input);    /* segfaults on NULL */
       size_t output_pos = 0;

       char *output = malloc(input_len * 3 + 1);

       size_t i;

       if (!output)
          return NULL;

       if (!input)                          /* dead code */
          return NULL;
       ...

The 'if (!input)' check sat after both strlen(input) and the
malloc sized by strlen's result, so a NULL input crashed in
strlen before we ever reached the guard.  s3_trim_string at
line 443 had the identical pattern.

Fix: move the NULL-check to run FIRST, then strlen, then malloc
(also NULL-checked).  Dropped the dead post-strlen guard.

These callers feed arbitrary header values / URL path components
through these helpers; a malformed S3 response or a malformed
user-supplied bucket/path was one NULL away from crashing the
cloud-sync subsystem.

=== network/cloud_sync/s3.c: s3_build_auth_header ===

Straight OOM NULL-deref:

    auth_header = malloc(1024);
    snprintf(auth_header, 1024, ...);     /* NULL-deref on OOM */

Also leaked 'signature' (heap-allocated just above by
s3_calculate_signature_v4_with_time) on the crash path - the
free at the bottom of the function was unreachable.

Fix: NULL-check the malloc, free signature + return NULL on OOM.

=== network/cloud_sync/google_drive.c: gdrive_do_patch ===

    filestream_seek(cb_st->rfile, 0, SEEK_SET);
    len = filestream_get_size(cb_st->rfile);
    buf = malloc((size_t)(len + 1));            /* unchecked */
    filestream_read(cb_st->rfile, buf, len);    /* NULL-deref */
    ...
    task_push_http_transfer_with_content(url, "PATCH",
          buf, (size_t)len, ...);                /* sends NULL */

Two issues folded together:
  - malloc not NULL-checked.
  - filestream_get_size returns int64_t; on file-not-readable /
    error it returns negative.  (size_t)(-1 + 1) == 0, so
    malloc(0) is either NULL or a valid zero-sized pointer
    depending on libc, and the subsequent filestream_read with
    a negative size_t-cast len is undefined at best.

Fix: bail early on len <= 0 (the patch is a PUT of the file's
contents, empty or error both mean nothing to upload), then
NULL-check the malloc.  Function is void-returning, so on OOM
just silently skip this upload and let the next sync poll
retry.

=== network/netplay/netplay_frontend.c: state-buffer growth ===

When a peer sends a state_size larger than ours, all buffer
entries are grown to match:

    netplay->state_size = state_size;
    for (i = 0; i < netplay->buffer_size; i++)
    {
       netplay->buffer[i].state = realloc(netplay->buffer[i].state, netplay->state_size);
       if (!netplay->buffer[i].state)
          return false;
    }

Classic realloc-assign-self leak: on OOM realloc returns NULL
but leaves the prior buffer[i].state allocation intact; the
self-assign overwrites the only pointer to it and leaks the
whole ring entry.

Fix: realloc into a temp, NULL-check, commit to the ivar only on
success.  Still return false on OOM; the caller disconnects the
netplay connection on false return, so the partially-grown
buffer (entries 0..i-1 at new size, i..end at old size) is
about to be torn down anyway and the inconsistency is transient.

=== Thread-safety ===

Unchanged.  s3 and google_drive cloud-sync helpers run on the
task-queue worker thread; netplay state handling runs on the
netplay thread.  No new locks or ordering requirements
introduced.

=== Reachability ===

Cloud-sync helpers fire on every background sync poll
(configurable, default ~5-minute interval).  s3_url_encode and
s3_trim_string are called on every request path / header field.
The netplay realloc is hit when a peer with a different-version
core joins and the two sides disagree on save-state size.  All
four are reachable in realistic runtime conditions.
2026-04-23 23:16:39 +02:00
U-DESKTOP-SPFP6AQ\twistedtechre d03dbbf132 fix another buffer overflow 2026-04-07 23:37:19 +02:00
U-DESKTOP-SPFP6AQ\twistedtechre 60440c2f0a Buildfixes for s3 2026-04-07 22:30:35 +02:00
U-DESKTOP-SPFP6AQ\twistedtechre 494d9de8a1 Warning fixes 2026-04-07 22:19:42 +02:00
U-DESKTOP-SPFP6AQ\twistedtechre b034b8781e Get rid of most string_is_empty calls 2026-04-07 22:09:00 +02:00
U-DESKTOP-SPFP6AQ\twistedtechre 6d07ac41b8 Remove some ISSPACE usage 2026-04-01 21:02:09 +02:00
Eric Warmenhoven 935e6f549c Merge branch 'add_s3' into s3 2026-03-27 00:12:03 -04:00
U-DESKTOP-SPFP6AQ\twistedtechre 0479b8a309 Rename local variables 'len' to '_len' (or '__len' for inner loop) 2026-03-13 16:15:01 +01:00
Russell Parks 9495430305 Fix b2 for path and virtual host styles 2026-03-12 23:31:11 -05:00
Russell Parks 0b2493f2c7 Changed url parsing logic
* Support extra prefix in URL
* Cloudflare should support both virtual-host style and path-based URLs
2026-03-11 19:37:48 -05:00
Russell Parks 666fd497da Fix code review comments 2026-03-10 23:18:44 -05:00
Russell Parks 28f0d1c1ad Remove comments [skip ci] 2026-03-10 22:00:52 -05:00
Russell Parks a1457a1985 Add multipart uploads for S3 2026-03-10 22:00:52 -05:00
Russell Parks 39af5ecf1e Move to task-based non-blocking pattern
Similar to how the WebDAV driver uses async tasks to do network
operations I'm moving the MVP of S3 to do this also.
2026-03-10 22:00:52 -05:00
Russell Parks 64dc2652dd Standards cleanup
* Ensure we're using C89 standards and other libretro standards
* Use more appropriate logging levels so we don't spam the log
* Fix incorrect S3 part size
2026-03-10 22:00:52 -05:00
Russell Parks c7bf80fb72 S3 Implementation 2026-03-10 22:00:52 -05:00
Eric Warmenhoven a0b73dea00 gdrive: fix warnings 2026-02-26 16:26:09 -05:00
Eric Warmenhoven bc868dff49 gdrive: use subdirs, fix url encoding
fixes #18748
2026-02-18 22:52:23 -05:00
Eric Warmenhoven 421ba9efe3 smb cloud sync driver 2026-02-18 15:37:11 -05:00
Eric Warmenhoven 6cf7502a73 google drive cloud sync driver 2026-02-17 23:09:35 -05:00
libretroadmin 5650d91608 Silence warnings 2025-11-13 19:24:27 +01:00
libretroadmin 661e5b55cb Some more malloc/realloc casts for C++ 2025-08-06 00:31:42 +02:00
libretroadmin 151d49311d Some CXX_BUILD buildfixes 2025-08-06 00:12:21 +02:00
libretroadmin ae2465f0db Variable name changes 2025-07-17 23:41:27 +02:00
sonninnos b2ca569521 Logging unification cleanups 2025-07-10 05:59:06 +03:00
Davide Andreoli 2f1ae73dd4 feat: added iCloud Drive Cloud Sync 2025-05-12 08:54:06 -04:00
Eric Warmenhoven 962cc9b033 webdav: workaround for getting 301 redirects 2025-03-01 22:53:11 -05:00
Eric Warmenhoven f55d028ae5 cloud sync: workaround bug of requests being duplicated (#17448) 2025-01-20 22:39:23 +01:00
LibretroAdmin cde82f532c * Naming convention changes for variable names/function arguments
* Try to fit lines within ANSI 80-char limit
2025-01-19 20:19:14 +01:00
LibretroAdmin 047e04ed3e Standardize local len variable naming conventions 2025-01-15 15:00:12 +01:00
Eric Warmenhoven 0e26bea0b2 icloud: properly report errors (#17249) 2024-12-11 22:54:53 -08:00
Eric Warmenhoven 7b29062e96 cloud sync: small bug fixes around handling deleted files (#17236) 2024-12-07 00:59:05 -08:00
libretroadmin 82e4504968 Revert "(pt. 2) static variables are initialized to '0' automatically as per C rules"
This reverts commit 47410df7a3.
2024-11-19 03:03:05 +01:00
libretroadmin 47410df7a3 (pt. 2) static variables are initialized to '0' automatically as per C rules 2024-11-18 15:59:46 +01:00
Eric Warmenhoven a26f6f6b45 webdav: fixes for reauth and parallelism (#17132) 2024-10-29 12:03:46 -07:00
Eric Warmenhoven b955a2ff8b webdav: add logging around http transactions to try to track failures (#17114) 2024-10-26 06:45:17 -07:00
Alex Kiraly d779654068 Disallow Cloud Sync with HTTPs when HAVE_SSL is disabled (#17059) 2024-09-28 23:52:54 -05:00
libretroadmin b8391e233f * PATH_MAX_LENGTH redefined from 4096 to 2048
* Massive reduction in heap space allocation, going from settings struct
264kb to 119Kb
* Use NAME_MAX_LENGTH for base paths/names, etc
* Use DIR_MAX_LENGTH for directory sizes
2024-09-09 05:47:32 +02:00
Eric Warmenhoven d4cb4953a6 iCloud: fix storing variables that don't survive to the async callback (#16849) 2024-08-06 17:03:04 -07:00
Eric Warmenhoven 63799385fc iCloud cloud sync driver (#16794) 2024-07-18 22:02:52 -07:00
libretroadmin 0ced85b91d Get rid of some unnecessary strlcat usage 2024-06-16 15:09:31 +02:00
Alex Kiraly c644487d8f Enable Cloud Sync by default on Linux builds with network (#16456)
* Enable by cloudsync by default on Linux builds with network

* Make WebDAV C89-friendly
2024-04-23 16:57:38 -07:00
Alex Kiraly 5730ac51a5 Fixed SEGFAULT in WebDav task sync + type changes (#16345) 2024-03-18 12:08:40 -07:00
Eric Warmenhoven dfda186985 Fix webdav crash bug in digest auth handling (#16003) 2023-12-12 08:44:29 -08:00
libretroadmin c5088ce2ca Silence some warnings and general cleanups 2023-08-16 22:08:01 +02:00