From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id Tl8EOBiSQ2rgIR8AWB0awg (envelope-from ) for ; Tue, 30 Jun 2026 05:53:28 -0400 Authentication-Results: simark.ca; dkim=pass (1024-bit key; unprotected) header.d=amd.com header.i=@amd.com header.a=rsa-sha256 header.s=selector1 header.b=LwDazo3y; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id D5E191E024; Tue, 30 Jun 2026 05:53:28 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-6.4 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 58B221E024 for ; Tue, 30 Jun 2026 05:53:27 -0400 (EDT) Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id D66714BA2E10 for ; Tue, 30 Jun 2026 09:53:26 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org D66714BA2E10 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=amd.com header.i=@amd.com header.a=rsa-sha256 header.s=selector1 header.b=LwDazo3y Received: from MW6PR02CU001.outbound.protection.outlook.com (mail-westus2azon11012047.outbound.protection.outlook.com [52.101.48.47]) by sourceware.org (Postfix) with ESMTPS id A31004BA2E07 for ; Tue, 30 Jun 2026 09:52:58 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org A31004BA2E07 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=amd.com Authentication-Results: sourceware.org; spf=fail smtp.mailfrom=amd.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org A31004BA2E07 Authentication-Results: sourceware.org; arc=pass smtp.remote-ip=52.101.48.47 ARC-Seal: i=2; a=rsa-sha256; d=sourceware.org; s=key; t=1782813178; cv=pass; b=HS8CiMBdpnlCBdg9PDvcaG+PziToP7+V9iyik4F7PVVFRpoaY+VFb1NjlKNiCZrqVgaCus7WgUQDyTP2h6NdKNYSpLnUt3kCwXlOZEcJGAJUz2oZTlfoh9kblhMfdgTCkA6DR2QzdsT0T5gY5L4WjzJOBQRKNcKD39OIl0RXSxY= ARC-Message-Signature: i=2; a=rsa-sha256; d=sourceware.org; s=key; t=1782813178; c=relaxed/simple; bh=rsD733IJUnKcU0y9tobraBZa6waGUikq0os49YyEZpY=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=l/7kF8W5LP4TYQC4AAhATlprs9V95VYS152tfioV5xT58SM0bxpqZoNjkTH62OjNZu+XXxawBxiUDJPdnm+O2v/y+JfBpZcsCschN+BqclqqPt6ay/eaLM1GAil+gieSe3oZOGCwnBl0PC8yjsMbbMdrgtG7ElD1wQiT+dKomH8= ARC-Authentication-Results: i=2; sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=amd.com header.i=@amd.com header.a=rsa-sha256 header.s=selector1 header.b=LwDazo3y DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A31004BA2E07 ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=GrmbiZHwkGxXTHgGB/rv7/CfIuI92ZJZDwrSBza4f0kVo29TQnGP8IcVg3iVajgsuf3YEb5CWjyfwttHureN+0m5PN5pc+RRlwnhobOzsyM2SyFflAN2LE8xATRI7TjQqsUZkMOf+MOxP9URDHgxfStl29wAdXRuV0Nf0P3JS1CdVJmBWvLjipEppb7+COy3J+enanucFl52ouY8dCIdrluUWFLq239H/UHJlUS5h0cl29DzJOI/0X4KexKxvGFILQvMwwnPkohnURafHVr+9/gDRt9162YfR7sEaMx8Jak0YT7lgrPTJTGjqqxPvJTO4XuymudMGZ0KwOVY/g4ljg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=h6zKj6c4iniJWoWJpCOz5LMdktBds8xy07j13N3Sb/4=; b=dgL9SC7EElxmjrUeX1oGGO0W45WdMqiCzs+GL6NujgvE/FMfbNLELSl8SDCfAVJUG7B/fTd1NSvYnyGkcr0Osw82eztYegVk60nTZoKxrwmgTN1T6ZHSOiV9d4GSwRH8T/B86xQfmY5CHFaWiBm603yYG48ZC1cStAtj6jYCzZ/1KoRgQuU1yXTA5hzIQMMUdeVDM55xzluqs+9VvVCow/kZEXZJD4W/e6fSNLtsluKneXD0khgDEwgLAGe++/VZ8jXRK7O+si8aymN4DzU9H17dfazPaFHCsQdc5Zm6YT2VK6hx4ajabiT5obG7mL+cSpHX/nwV9sObz8u9Bxiquw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 165.204.84.17) smtp.rcpttodomain=sourceware.org smtp.mailfrom=amd.com; dmarc=pass (p=quarantine sp=quarantine pct=100) action=none header.from=amd.com; dkim=none (message not signed); arc=none (0) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amd.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=h6zKj6c4iniJWoWJpCOz5LMdktBds8xy07j13N3Sb/4=; b=LwDazo3yklXuZLuoylBWpoU+1Wp8Ncm9CLmn/zxf8WxtFeNuVep9ET91+tvIqgFJ88ODR+Jh6YdYX4L9IbNBYzmOE4gxTjAUqg1EoJ+rR+12RQi7GYozSqaG/yLD/QRNkCaNnDl/IeLPaAGDycMOrp7V04wAJoVm8c0cTGd4OMQ= Received: from MN2PR20CA0044.namprd20.prod.outlook.com (2603:10b6:208:235::13) by SJ0PR12MB5610.namprd12.prod.outlook.com (2603:10b6:a03:423::9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.159.19; Tue, 30 Jun 2026 09:52:51 +0000 Received: from BL02EPF00021F6B.namprd02.prod.outlook.com (2603:10b6:208:235:cafe::d) by MN2PR20CA0044.outlook.office365.com (2603:10b6:208:235::13) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.21.181.8 via Frontend Transport; Tue, 30 Jun 2026 09:52:51 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 165.204.84.17) smtp.mailfrom=amd.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=amd.com; Received-SPF: Pass (protection.outlook.com: domain of amd.com designates 165.204.84.17 as permitted sender) receiver=protection.outlook.com; client-ip=165.204.84.17; helo=satlexmb07.amd.com; pr=C Received: from satlexmb07.amd.com (165.204.84.17) by BL02EPF00021F6B.mail.protection.outlook.com (10.167.249.7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.181.6 via Frontend Transport; Tue, 30 Jun 2026 09:52:50 +0000 Received: from ctr-rack32-mi300x-1.amd.com (10.180.168.240) by satlexmb07.amd.com (10.181.42.216) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.41; Tue, 30 Jun 2026 04:52:50 -0500 From: Luis Machado To: Subject: [PATCH] gdb: replace alloca with gdb::char_vector in remote-fileio.c Date: Tue, 30 Jun 2026 04:52:38 -0500 Message-ID: <20260630095238.1700797-1-luis.machado@amd.com> X-Mailer: git-send-email 2.34.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain X-Originating-IP: [10.180.168.240] X-ClientProxiedBy: satlexmb07.amd.com (10.181.42.216) To satlexmb07.amd.com (10.181.42.216) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: BL02EPF00021F6B:EE_|SJ0PR12MB5610:EE_ X-MS-Office365-Filtering-Correlation-Id: 59c46677-ac1f-4253-c752-08ded68d5906 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; ARA:13230040|376014|36860700016|82310400026|23010399003|1800799024|18002099003|11063799006|56012099006|5023799004|6133799003; X-Microsoft-Antispam-Message-Info: BeY1JQFBj8yNVUOpFjtMjXcrA1lHAa/Bmtf4AFmb6UBk+YsL3rXJ7/uwMI5Lf5vmIBIVu3F77KoUOTl0t4GLs67Vjyz87XkO/lpAgMR3LqtuApSBkpXU4uMihoh/SvKGISti2TmScJig/kPp2wkpQ7zOEsAISGBAtrMkUtcAi8JGZ9NN1H7OUGQQSfxdlrhoGy7znQJVeaUC4DMnVdF949XKv9WlCcrh7pWDzf0Llh+XQsqzpz5kON1Bm46U9eOw1CVVd9CJBwHB3injXkXkXjfm/5EPMGjLAyemlJySk8llRE23/UFzAHWYCh6IMCG44zNE2I9PYZbg/w3fXJigzpKkXBHClT3LAGl2qvUG+u6mx+kwkt3YlMNHBmUrvb6gcO1jN6ybiCiOe7Y2ozSpEzy3baOQPfO7SahF2oqxo/NzM5/w+4USkBdl1xku0PoOJRJ0mwi/DMhvgr8KoX/bAvzMFFzwTyiF4D2Kqw8B+1YFYyn6/tM9gecpqwvWXzA/8DuMbtlfCEhhu7/9miw0WWgvkj+QL/2D6UIXjVk8kryVLO5uD3+IdHaTAbdOTr1c8CMd13aeKfR69DpuSeMh5RcFlIKbJ65YlZZg/hllOGT3AAyqAhdZCLEx1hYZQ8Xk/RhLBJ6XweEN9SnohE4mE3AmQhIQrKNp0HVG8PPIEbQDGkTMwqYBp0dm+QNJ5nazMWO3kOM2ezLhT0Xs/cjRaw== X-Forefront-Antispam-Report: CIP:165.204.84.17; CTRY:US; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:satlexmb07.amd.com; PTR:InfoDomainNonexistent; CAT:NONE; SFS:(13230040)(376014)(36860700016)(82310400026)(23010399003)(1800799024)(18002099003)(11063799006)(56012099006)(5023799004)(6133799003); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: zlUkkZWMbLlImgjJnpv/duZoG7yyoAoAi3TAxijQd6HgmrQH4h3FpuX3/Mnb0GfFrgllxeRU9jZyNqBdKZPwl/DwfVxWMRox7naMX7LOHgF3E2CsYdXjRYW8a0sn24xgHZjgtX9Ejm2aveFx1il0zNmWdfrPfkuNV0ybEd+RWhjsfuadbxDWmPeNQ02BRz6LBvAld34v0XzctwBqcY22OKyHIC1tAQSy6U59b9lH1nlAPHWc9I6OItXvxezaAnnxMFa2d7vTxu4FJKDgnfJuGcMl3to0zauorVjNNXlFdX30MQIqDFvKpuHf8ugWGiBadYlO70jAwLfwUp4RQDAVcKqNnDjTaYYspK2bpwU8ipQzcW1L+mn1mfey+fXMEv91dUoXjaZMqQ/ym7d6/PgxfgvsnHx1q72WbyXjpBMV3Kp2wLcum+FrklyPTMjcOl5A X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Jun 2026 09:52:50.5099 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 59c46677-ac1f-4253-c752-08ded68d5906 X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=3dd8961f-e488-4e60-8e11-a82d994e183d; Ip=[165.204.84.17]; Helo=[satlexmb07.amd.com] X-MS-Exchange-CrossTenant-AuthSource: BL02EPF00021F6B.namprd02.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: SJ0PR12MB5610 X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~public-inbox=simark.ca@sourceware.org remote_fileio_extract_ptr_w_len parsed a debuggee-controlled 64-bit length, narrowed it to int with no bounds check, and the value flowed directly into alloca() across RSP File-I/O handlers (Fopen, Frename, Funlink, Fstat, Fsystem). A malicious inferior or remote stub could send a crafted packet with a path-length near INT_MAX, displacing the stack pointer by ~2 GiB and potentially crashing the debugger. remote_fileio_extract_ptr_w_len now rejects negative lengths, zero, and values above PATH_MAX before the int cast. An allow_zero_length flag lets the Fsystem handler opt in to the zero-length sentinel that signals a NULL cmdline query. All other handlers use the default and are protected without any per-call checks. All alloca(length) calls have been replaced with gdb::char_vector. Add a selftest that exercises various problematic cases. Signed-off-by: Luis Machado --- gdb/remote-fileio.c | 150 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 119 insertions(+), 31 deletions(-) diff --git a/gdb/remote-fileio.c b/gdb/remote-fileio.c index ef608cabfab..50c7869a1a5 100644 --- a/gdb/remote-fileio.c +++ b/gdb/remote-fileio.c @@ -31,8 +31,11 @@ #include "target.h" #include "filenames.h" #include "gdbsupport/filestuff.h" +#include "gdbsupport/byte-vector.h" +#include "gdbsupport/selftest.h" #include +#include #include "gdbsupport/gdb_sys_time.h" #ifdef __CYGWIN__ #include @@ -194,7 +197,8 @@ remote_fileio_extract_int (char **buf, long *retint) } static int -remote_fileio_extract_ptr_w_len (char **buf, CORE_ADDR *ptrval, int *length) +remote_fileio_extract_ptr_w_len (char **buf, CORE_ADDR *ptrval, int *length, + bool allow_zero_length = false) { char *c; LONGEST retlong; @@ -211,6 +215,11 @@ remote_fileio_extract_ptr_w_len (char **buf, CORE_ADDR *ptrval, int *length) *buf = c; if (remote_fileio_extract_long (buf, &retlong)) return -1; + /* Reject negative lengths, zero (unless the caller permits it for the + Fsystem NULL-cmdline sentinel), and lengths above PATH_MAX to prevent + out-of-bounds memory reads or oversized heap allocations. */ + if (retlong < 0 || (!allow_zero_length && retlong == 0) || retlong > PATH_MAX) + return -1; *length = (int) retlong; return 0; } @@ -305,7 +314,6 @@ remote_fileio_func_open (remote_target *remote, char *buf) long num; int flags, fd; mode_t mode; - char *pathname; struct stat st; /* 1. Parameter: Ptr to pathname / length incl. trailing zero. */ @@ -339,8 +347,8 @@ remote_fileio_func_open (remote_target *remote, char *buf) } /* Request pathname. */ - pathname = (char *) alloca (length); - if (target_read_memory (ptrval, (gdb_byte *) pathname, length) != 0) + gdb::char_vector pathname (length); + if (target_read_memory (ptrval, (gdb_byte *) pathname.data (), length) != 0) { remote_fileio_ioerror (remote); return; @@ -349,7 +357,7 @@ remote_fileio_func_open (remote_target *remote, char *buf) /* Check if pathname exists and is not a regular file or directory. If so, return an appropriate error code. Same for trying to open directories for writing. */ - if (!stat (pathname, &st)) + if (!stat (pathname.data (), &st)) { if (!S_ISREG (st.st_mode) && !S_ISDIR (st.st_mode)) { @@ -364,7 +372,7 @@ remote_fileio_func_open (remote_target *remote, char *buf) } } - fd = gdb_open_cloexec (pathname, flags, mode).release (); + fd = gdb_open_cloexec (pathname.data (), flags, mode).release (); if (fd < 0) { remote_fileio_return_errno (remote, -1); @@ -659,7 +667,6 @@ remote_fileio_func_rename (remote_target *remote, char *buf) { CORE_ADDR old_ptr, new_ptr; int old_len, new_len; - char *oldpath, *newpath; int ret, of, nf; struct stat ost, nst; @@ -678,24 +685,24 @@ remote_fileio_func_rename (remote_target *remote, char *buf) } /* Request oldpath using 'm' packet */ - oldpath = (char *) alloca (old_len); - if (target_read_memory (old_ptr, (gdb_byte *) oldpath, old_len) != 0) + gdb::char_vector oldpath (old_len); + if (target_read_memory (old_ptr, (gdb_byte *) oldpath.data (), old_len) != 0) { remote_fileio_ioerror (remote); return; } /* Request newpath using 'm' packet */ - newpath = (char *) alloca (new_len); - if (target_read_memory (new_ptr, (gdb_byte *) newpath, new_len) != 0) + gdb::char_vector newpath (new_len); + if (target_read_memory (new_ptr, (gdb_byte *) newpath.data (), new_len) != 0) { remote_fileio_ioerror (remote); return; } /* Only operate on regular files and directories. */ - of = stat (oldpath, &ost); - nf = stat (newpath, &nst); + of = stat (oldpath.data (), &ost); + nf = stat (newpath.data (), &nst); if ((!of && !S_ISREG (ost.st_mode) && !S_ISDIR (ost.st_mode)) || (!nf && !S_ISREG (nst.st_mode) && !S_ISDIR (nst.st_mode))) { @@ -703,7 +710,7 @@ remote_fileio_func_rename (remote_target *remote, char *buf) return; } - ret = rename (oldpath, newpath); + ret = rename (oldpath.data (), newpath.data ()); if (ret == -1) { @@ -726,10 +733,10 @@ remote_fileio_func_rename (remote_target *remote, char *buf) char newfullpath[PATH_MAX]; int len; - cygwin_conv_path (CCP_WIN_A_TO_POSIX, oldpath, oldfullpath, - PATH_MAX); - cygwin_conv_path (CCP_WIN_A_TO_POSIX, newpath, newfullpath, - PATH_MAX); + cygwin_conv_path (CCP_WIN_A_TO_POSIX, oldpath.data (), + oldfullpath, PATH_MAX); + cygwin_conv_path (CCP_WIN_A_TO_POSIX, newpath.data (), + newfullpath, PATH_MAX); len = strlen (oldfullpath); if (IS_DIR_SEPARATOR (newfullpath[len]) && !filename_ncmp (oldfullpath, newfullpath, len)) @@ -752,7 +759,6 @@ remote_fileio_func_unlink (remote_target *remote, char *buf) { CORE_ADDR ptrval; int length; - char *pathname; int ret; struct stat st; @@ -763,8 +769,8 @@ remote_fileio_func_unlink (remote_target *remote, char *buf) return; } /* Request pathname using 'm' packet */ - pathname = (char *) alloca (length); - if (target_read_memory (ptrval, (gdb_byte *) pathname, length) != 0) + gdb::char_vector pathname (length); + if (target_read_memory (ptrval, (gdb_byte *) pathname.data (), length) != 0) { remote_fileio_ioerror (remote); return; @@ -772,13 +778,13 @@ remote_fileio_func_unlink (remote_target *remote, char *buf) /* Only operate on regular files (and directories, which allows to return the correct return code). */ - if (!stat (pathname, &st) && !S_ISREG (st.st_mode) && !S_ISDIR (st.st_mode)) + if (!stat (pathname.data (), &st) && !S_ISREG (st.st_mode) && !S_ISDIR (st.st_mode)) { remote_fileio_reply (remote, -1, FILEIO_ENODEV); return; } - ret = unlink (pathname); + ret = unlink (pathname.data ()); if (ret == -1) remote_fileio_return_errno (remote, -1); @@ -791,7 +797,6 @@ remote_fileio_func_stat (remote_target *remote, char *buf) { CORE_ADDR statptr, nameptr; int ret, namelength; - char *pathname; LONGEST lnum; struct stat st; struct fio_stat fst; @@ -812,14 +817,14 @@ remote_fileio_func_stat (remote_target *remote, char *buf) statptr = (CORE_ADDR) lnum; /* Request pathname using 'm' packet */ - pathname = (char *) alloca (namelength); - if (target_read_memory (nameptr, (gdb_byte *) pathname, namelength) != 0) + gdb::char_vector pathname (namelength); + if (target_read_memory (nameptr, (gdb_byte *) pathname.data (), namelength) != 0) { remote_fileio_ioerror (remote); return; } - ret = stat (pathname, &st); + ret = stat (pathname.data (), &st); if (ret == -1) { @@ -997,24 +1002,28 @@ remote_fileio_func_system (remote_target *remote, char *buf) { CORE_ADDR ptrval; int ret, length; - char *cmdline = NULL; /* Parameter: Ptr to commandline / length incl. trailing zero */ - if (remote_fileio_extract_ptr_w_len (&buf, &ptrval, &length)) + if (remote_fileio_extract_ptr_w_len (&buf, &ptrval, &length, true)) { remote_fileio_ioerror (remote); return; } + gdb::char_vector cmdline_buf; + const char *cmdline = nullptr; + if (length) { /* Request commandline using 'm' packet */ - cmdline = (char *) alloca (length); - if (target_read_memory (ptrval, (gdb_byte *) cmdline, length) != 0) + cmdline_buf.resize (length); + if (target_read_memory (ptrval, (gdb_byte *) cmdline_buf.data (), + length) != 0) { remote_fileio_ioerror (remote); return; } + cmdline = cmdline_buf.data (); } /* Check if system(3) has been explicitly allowed using the @@ -1244,6 +1253,81 @@ show_system_call_allowed (const char *args, int from_tty) remote_fio_system_call_allowed ? "" : "not "); } +#if GDB_SELF_TEST + +namespace selftests { + +/* Verify that remote_fileio_extract_ptr_w_len rejects lengths that are + negative or exceed PATH_MAX, and accepts boundary values. The packet + buffer format is "ptr/len[,...]" with both fields as hex integers. */ + +static void +test_remote_fileio_extract_ptr_w_len () +{ + CORE_ADDR ptrval; + int length; + + /* Build a writable "ptr/len" buffer and parse it, with and without + the Fsystem zero-length allowance. */ + auto parse = [&] (const char *s) -> int + { + std::string buf (s); + char *p = buf.data (); + return remote_fileio_extract_ptr_w_len (&p, &ptrval, &length); + }; + auto parse_allow_zero = [&] (const char *s) -> int + { + std::string buf (s); + char *p = buf.data (); + return remote_fileio_extract_ptr_w_len (&p, &ptrval, &length, true); + }; + + /* Valid: length 1 (minimum positive). Verify both fields are parsed. */ + SELF_CHECK (parse ("deadbeef/1") == 0); + SELF_CHECK (ptrval == 0xdeadbeef); + SELF_CHECK (length == 1); + + /* Valid: packet with trailing fields. */ + SELF_CHECK (parse ("deadbeef/4,0,1a4") == 0); + SELF_CHECK (ptrval == 0xdeadbeef); + SELF_CHECK (length == 4); + + /* Valid: length 0 with allow_zero_length (Fsystem). */ + SELF_CHECK (parse_allow_zero ("0/0") == 0); + SELF_CHECK (length == 0); + + /* Invalid: length 0 without allow_zero_length (pathname handlers). */ + SELF_CHECK (parse ("0/0") == -1); + + /* Valid: length exactly PATH_MAX. */ + { + char hex[32]; + xsnprintf (hex, sizeof (hex), "1/%x", PATH_MAX); + SELF_CHECK (parse (hex) == 0); + SELF_CHECK (length == PATH_MAX); + } + + /* Invalid: length PATH_MAX + 1. */ + { + char hex[32]; + xsnprintf (hex, sizeof (hex), "1/%x", PATH_MAX + 1); + SELF_CHECK (parse (hex) == -1); + } + + /* Invalid: value well above PATH_MAX (INT_MAX as a stress case). */ + SELF_CHECK (parse ("1/7fffffff") == -1); + + /* Invalid: negative length. */ + SELF_CHECK (parse ("1/-1") == -1); + + /* Invalid: missing '/' separator. */ + SELF_CHECK (parse ("deadbeef") == -1); +} + +} /* namespace selftests */ + +#endif /* GDB_SELF_TEST */ + void initialize_remote_fileio (struct cmd_list_element **remote_set_cmdlist, struct cmd_list_element **remote_show_cmdlist) @@ -1256,4 +1340,8 @@ initialize_remote_fileio (struct cmd_list_element **remote_set_cmdlist, show_system_call_allowed, _("Show if the host system(3) call is allowed for the target."), remote_show_cmdlist); +#if GDB_SELF_TEST + selftests::register_test ("remote_fileio_extract_ptr_w_len", + selftests::test_remote_fileio_extract_ptr_w_len); +#endif } -- 2.34.1