Files
RetroArch/tasks/task_cloudsync_path.h
T
Anthony SchemelandClaude Opus 5.5 4ee62a575f security: validate replay, UPnP and cloud sync input (#19628)
Three places trust data that comes from outside RetroArch:

- replay_set_serialized_data reads the embedded replay length from the
  save state. A negative value, or one shorter than the replay header,
  was passed on to the seek and write that restore the replay. Refuse
  such states.
- natt_parse_desc_node walks the IGD description XML a router serves.
  On a node without children it recursed with a NULL child and then
  read child->next, so a leaf node or an empty root crashed it. It
  also recursed only into childless nodes, so a <service> nested in
  <root>/<device>/<serviceList>, the normal UPnP shape, was never
  found. It now always recurses into children and checks the
  serviceType and controlURL text before using it.
- task_cloud_sync_fetch_server_file took the local path from a
  server-supplied manifest key as strchr(key, '/') + 1. A key without
  '/' read from address 1, and a key containing ".." or an absolute
  path was joined onto the sync directory, so a hostile server could
  write outside it. Such keys are now refused and counted as a
  failure.

The description walk moves to network/natt_desc.c and the key check
to tasks/task_cloudsync_path.c, so the new sample tests
(samples/tasks/natt_desc, and cloudsync_path_safety_test beside the
existing cloudsync test) compile the shipped code directly. Both are
added to Linux-samples-tasks.yml.

Tested on Linux: full build; touched files also compile with
C89_BUILD=1 without warnings. The workflow's commands for both new
steps pass, and the existing cloudsync test still passes under
SANITIZER=address. With the old parser or the old key handling
substituted, each test segfaults.

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-09-26 17:22:37 +02:00

49 lines
1.9 KiB
C

/* RetroArch - A frontend for libretro.
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __TASK_CLOUDSYNC_PATH_H
#define __TASK_CLOUDSYNC_PATH_H
/* Kept dependency-free (only <string.h> in the .c) so the regression test
* samples/tasks/cloudsync/cloudsync_path_safety_test.c can compile the real
* predicate standalone -- no libretro-common include path required. */
#ifdef __cplusplus
extern "C" {
#endif
/**
* cloud_sync_manifest_key_path:
* @key : a manifest key as supplied by the (untrusted) cloud-sync server,
* in "portable" format using '/' separators.
*
* Validates @key and returns the relative path portion -- the substring
* after the first '/' -- suitable for joining onto the local cloud-sync
* base directory. Returns NULL when @key is unsafe to use, i.e. when it is
* NULL, contains no '/', has an empty path portion, has an absolute path
* portion (leading '/'), or contains a ".." anywhere in the path portion.
*
* The NULL return is the traversal/malformed-key reject signal: a hostile
* manifest must not be able to walk out of the cloud-sync directory via
* fill_pathname_join_special. The returned pointer, when non-NULL, points
* into @key (no allocation).
*/
const char *cloud_sync_manifest_key_path(const char *key);
#ifdef __cplusplus
}
#endif
#endif