From nobody Mon Feb 9 17:05:28 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) client-ip=66.175.222.108; envelope-from=bounce+27952+69030+1787277+3901457@groups.io; helo=mail02.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+69030+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1608155121; cv=none; d=zohomail.com; s=zohoarc; b=m0S+PTAQuEgqErlr62eZVgW4D6IKScoO7Rvw4QUV6p6yeXkS7TxlWNQJWXFuGNi58XYLXPZ16F7CaeBFhHTDzG/aRU+7J1ajE+sKvFPFPVj1w1zUFek4z6jHDWGMs0sRduZM3NwWG7AI83ZElq8k5P7ktrcCsYoNF/K0KM9Uagk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1608155121; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Id:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:References:Sender:Subject:To; bh=iOi9RKotYtjfX2GxfPSl16RRnOgiB6P5mAIsMF5qNTY=; b=BgJTfFfAdSl0DCa9/nlEFnNricwyP3CAEn94kKcYDl0kySNz3U60bFxRB9dtzSymSpxPRgvQKyQwGkwyIbqfXmIsC97i3zuDYBlj7o9qWty4DuV1gKt4nMHgJDEIiQYvkc0+jjWf97IjtmNyuW1LYG9kByAgygk+NujI+qWl2+Y= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+69030+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) header.from= Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by mx.zohomail.com with SMTPS id 1608155121838614.8213185620731; Wed, 16 Dec 2020 13:45:21 -0800 (PST) Return-Path: X-Received: by 127.0.0.2 with SMTP id CXN6YY1788612xFg0QGcc6Wp; Wed, 16 Dec 2020 13:45:21 -0800 X-Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.205.24.124]) by mx.groups.io with SMTP id smtpd.web09.3871.1608155115346989409 for ; Wed, 16 Dec 2020 13:45:15 -0800 X-Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-379-QL2vaVxWO-usxFQy8A3QnA-1; Wed, 16 Dec 2020 16:45:12 -0500 X-MC-Unique: QL2vaVxWO-usxFQy8A3QnA-1 X-Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 76127180E475; Wed, 16 Dec 2020 21:45:11 +0000 (UTC) X-Received: from lacos-laptop-7.usersys.redhat.com (ovpn-114-152.ams2.redhat.com [10.36.114.152]) by smtp.corp.redhat.com (Postfix) with ESMTP id 10458271A4; Wed, 16 Dec 2020 21:45:04 +0000 (UTC) From: "Laszlo Ersek" To: devel@edk2.groups.io, virtio-fs@redhat.com, lersek@redhat.com Cc: Ard Biesheuvel , Jordan Justen , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Subject: [edk2-devel] [edk2 PATCH 16/48] OvmfPkg/VirtioFsDxe: add helper for appending and sanitizing paths Date: Wed, 16 Dec 2020 22:10:53 +0100 Message-Id: <20201216211125.19496-17-lersek@redhat.com> In-Reply-To: <20201216211125.19496-1-lersek@redhat.com> References: <20201216211125.19496-1-lersek@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Precedence: Bulk List-Unsubscribe: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,lersek@redhat.com X-Gm-Message-State: df8ZV2THbKxjqbVizMjg5HMDx1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1608155121; bh=iOi9RKotYtjfX2GxfPSl16RRnOgiB6P5mAIsMF5qNTY=; h=Cc:Content-Type:Date:From:Reply-To:Subject:To; b=UFEvMHl7XFvRdaZASZCodEa1EFCZxIMn+Mz/JLa5ZperdNz/eZL0dnF/pGQCKxJoEwH 6WelXJ9NHXX2s/L6D20V1xEMvzZxiVhpn00XM7WXzU384aTRM8yfCCfFEuTVwIsJFn1dJ bM5YAmMlaagSkbmaI4XNIw4FT/dEmW1dKj0= X-ZohoMail-DKIM: pass (identity @groups.io) Content-Type: text/plain; charset="utf-8" EFI_FILE_PROTOCOL.Open() -- for opening files -- and EFI_FILE_PROTOCOL.SetInfo() -- for renaming files -- will require us to append a relative UEFI pathname to an absolute base pathname. In turn, components of the resultant pathnames will have to be sent to virtiofsd, which does not consume UEFI-style pathnames. We're going to maintain the base pathnames in canonical POSIX format: - absolute (starts with "/"), - dot (.) and dot-dot (..) components resolved/removed, - uses forward slashes, - sequences of slashes collapsed, - printable ASCII character set, - CHAR8 encoding, - no trailing slash except for the root directory itself, - length at most VIRTIO_FS_MAX_PATHNAME_LENGTH. Add a helper function that can append a UEFI pathname to such a base pathname, and produce the result in conformance with the same invariants. Cc: Ard Biesheuvel Cc: Jordan Justen Cc: Philippe Mathieu-Daud=C3=A9 Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3D3097 Signed-off-by: Laszlo Ersek --- OvmfPkg/VirtioFsDxe/VirtioFsDxe.inf | 1 + OvmfPkg/VirtioFsDxe/VirtioFsDxe.h | 32 ++ OvmfPkg/VirtioFsDxe/Helpers.c | 474 ++++++++++++++++++++ 3 files changed, 507 insertions(+) diff --git a/OvmfPkg/VirtioFsDxe/VirtioFsDxe.inf b/OvmfPkg/VirtioFsDxe/Virt= ioFsDxe.inf index 15e21772c8ac..0c92bccdac86 100644 --- a/OvmfPkg/VirtioFsDxe/VirtioFsDxe.inf +++ b/OvmfPkg/VirtioFsDxe/VirtioFsDxe.inf @@ -99,16 +99,17 @@ [Sources] SimpleFsRead.c SimpleFsSetInfo.c SimpleFsSetPosition.c SimpleFsWrite.c VirtioFsDxe.h =20 [LibraryClasses] BaseLib + BaseMemoryLib DebugLib MemoryAllocationLib UefiBootServicesTableLib UefiDriverEntryPoint VirtioLib =20 [Protocols] gEfiComponentName2ProtocolGuid ## PRODUCES diff --git a/OvmfPkg/VirtioFsDxe/VirtioFsDxe.h b/OvmfPkg/VirtioFsDxe/Virtio= FsDxe.h index 1cbd27d8fb52..f4fed64c7217 100644 --- a/OvmfPkg/VirtioFsDxe/VirtioFsDxe.h +++ b/OvmfPkg/VirtioFsDxe/VirtioFsDxe.h @@ -17,16 +17,40 @@ #include // VIRTIO_DEVICE_PROTOCOL #include // EFI_EVENT =20 #define VIRTIO_FS_SIG SIGNATURE_64 ('V', 'I', 'R', 'T', 'I', 'O', 'F', 'S') =20 #define VIRTIO_FS_FILE_SIG \ SIGNATURE_64 ('V', 'I', 'O', 'F', 'S', 'F', 'I', 'L') =20 +// +// The following limit applies to two kinds of pathnames. +// +// - The length of a POSIX-style, canonical pathname *at rest* never excee= ds +// VIRTIO_FS_MAX_PATHNAME_LENGTH. (Length is defined as the number of CH= AR8 +// elements in the canonical pathname, excluding the terminating '\0'.) = This +// is an invariant that is ensured for canonical pathnames created, and = that +// is assumed about canonical pathname inputs (which all originate +// internally). +// +// - If the length of a UEFI-style pathname *argument*, originating direct= ly or +// indirectly from the EFI_FILE_PROTOCOL caller, exceeds +// VIRTIO_FS_MAX_PATHNAME_LENGTH, then the argument is rejected. (Length= is +// defined as the number of CHAR16 elements in the UEFI-style pathname, +// excluding the terminating L'\0'.) This is a restriction that's checke= d on +// external UEFI-style pathname inputs. +// +// The limit is not expected to be a practical limitation; it's only suppo= sed +// to prevent attempts at overflowing size calculations. For both kinds of +// pathnames, separate limits could be used; a common limit is used purely= for +// simplicity. +// +#define VIRTIO_FS_MAX_PATHNAME_LENGTH ((UINTN)65535) + // // Filesystem label encoded in UCS-2, transformed from the UTF-8 represent= ation // in "VIRTIO_FS_CONFIG.Tag", and NUL-terminated. Only the printable ASCII= code // points (U+0020 through U+007E) are supported. // typedef CHAR16 VIRTIO_FS_LABEL[VIRTIO_FS_TAG_BYTES + 1]; =20 // @@ -187,16 +211,24 @@ VirtioFsFuseCheckResponse ( OUT UINTN *TailBufferFill ); =20 EFI_STATUS VirtioFsErrnoToEfiStatus ( IN INT32 Errno ); =20 +EFI_STATUS +VirtioFsAppendPath ( + IN CHAR8 *LhsPath8, + IN CHAR16 *RhsPath16, + OUT CHAR8 **ResultPath8, + OUT BOOLEAN *RootEscape + ); + // // Wrapper functions for FUSE commands (primitives). // =20 EFI_STATUS VirtioFsFuseForget ( IN OUT VIRTIO_FS *VirtioFs, IN UINT64 NodeId diff --git a/OvmfPkg/VirtioFsDxe/Helpers.c b/OvmfPkg/VirtioFsDxe/Helpers.c index 00f762142746..4a7b59332ca9 100644 --- a/OvmfPkg/VirtioFsDxe/Helpers.c +++ b/OvmfPkg/VirtioFsDxe/Helpers.c @@ -1,16 +1,19 @@ /** @file Initialization and helper routines for the Virtio Filesystem device. =20 Copyright (C) 2020, Red Hat, Inc. =20 SPDX-License-Identifier: BSD-2-Clause-Patent **/ =20 +#include // StrLen() +#include // CopyMem() +#include // AllocatePool() #include // Virtio10WriteFeatures() =20 #include "VirtioFsDxe.h" =20 /** Read the Virtio Filesystem device configuration structure in full. =20 @param[in] Virtio The Virtio protocol underlying the VIRTIO_FS object. @@ -1110,8 +1113,479 @@ VirtioFsErrnoToEfiStatus ( return EFI_NOT_STARTED; =20 default: break; } =20 return EFI_DEVICE_ERROR; } + +// +// Parser states for canonicalizing a POSIX pathname. +// +typedef enum { + ParserInit, // just starting + ParserEnd, // finished + ParserSlash, // slash(es) seen + ParserDot, // one dot seen since last slash + ParserDotDot, // two dots seen since last slash + ParserNormal, // a different sequence seen +} PARSER_STATE; + +/** + Strip the trailing slash from the parser's output buffer, unless the tra= iling + slash stands for the root directory. + + @param[in] Buffer The parser's output buffer. Only used for + sanity-checking. + + @param[in,out] Position On entry, points at the next character to produ= ce + (i.e., right past the end of the output written= by + the parser thus far). The last character in the + parser's output buffer is a slash. On return, t= he + slash is stripped, by decrementing Position by = one. + If this action would remove the slash character + standing for the root directory, then the funct= ion + has no effect. +**/ +STATIC +VOID +ParserStripSlash ( + IN CHAR8 *Buffer, + IN OUT UINTN *Position + ) +{ + ASSERT (*Position >=3D 1); + ASSERT (Buffer[*Position - 1] =3D=3D '/'); + if (*Position =3D=3D 1) { + return; + } + (*Position)--; +} + +/** + Produce one character in the parser's output buffer. + + @param[out] Buffer The parser's output buffer. On return, Char8 wi= ll + have been written. + + @param[in,out] Position On entry, points at the next character to produ= ce + (i.e., right past the end of the output written= by + the parser thus far). On return, Position is + incremented by one. + + @param[in] Size Total allocated size of the parser's output buf= fer. + Used for sanity-checking. + + @param[in] Char8 The character to place in the output buffer. +**/ +STATIC +VOID +ParserCopy ( + OUT CHAR8 *Buffer, + IN OUT UINTN *Position, + IN UINTN Size, + IN CHAR8 Char8 + ) +{ + ASSERT (*Position < Size); + Buffer[(*Position)++] =3D Char8; +} + +/** + Rewind the last single-dot in the parser's output buffer. + + @param[in] Buffer The parser's output buffer. Only used for + sanity-checking. + + @param[in,out] Position On entry, points at the next character to produ= ce + (i.e., right past the end of the output written= by + the parser thus far); the parser's output buffer + ends with the characters ('/', '.'). On return,= the + dot is rewound by decrementing Position by one;= a + slash character will reside at the new end of t= he + parser's output buffer. +**/ +STATIC +VOID +ParserRewindDot ( + IN CHAR8 *Buffer, + IN OUT UINTN *Position + ) +{ + ASSERT (*Position >=3D 2); + ASSERT (Buffer[*Position - 1] =3D=3D '.'); + ASSERT (Buffer[*Position - 2] =3D=3D '/'); + (*Position)--; +} + +/** + Rewind the last dot-dot in the parser's output buffer. + + @param[in] Buffer The parser's output buffer. Only used for + sanity-checking. + + @param[in,out] Position On entry, points at the next character to produ= ce + (i.e., right past the end of the output written= by + the parser thus far); the parser's output buffer + ends with the characters ('/', '.', '.'). On re= turn, + the ('.', '.') pair is rewound unconditionally,= by + decrementing Position by two; a slash character + resides at the new end of the parser's output + buffer. + + If this slash character stands for the root + directory, then RootEscape is set to TRUE. + + Otherwise (i.e., if this slash character is not= the + one standing for the root directory), then the = slash + character, and the pathname component preceding= it, + are removed by decrementing Position further. In + this case, the slash character preceding the re= moved + pathname component will reside at the new end o= f the + parser's output buffer. + + @param[out] RootEscape Set to TRUE on output if the dot-dot component = tries + to escape the root directory, as described abov= e. + Otherwise, RootEscape is not modified. +**/ +STATIC +VOID +ParserRewindDotDot ( + IN CHAR8 *Buffer, + IN OUT UINTN *Position, + OUT BOOLEAN *RootEscape + + ) +{ + ASSERT (*Position >=3D 3); + ASSERT (Buffer[*Position - 1] =3D=3D '.'); + ASSERT (Buffer[*Position - 2] =3D=3D '.'); + ASSERT (Buffer[*Position - 3] =3D=3D '/'); + (*Position) -=3D 2; + + if (*Position =3D=3D 1) { + // + // Root directory slash reached; don't try to climb higher. + // + *RootEscape =3D TRUE; + return; + } + + // + // Skip slash. + // + (*Position)--; + // + // Scan until next slash to the left. + // + do { + ASSERT (*Position > 0); + (*Position)--; + } while (Buffer[*Position] !=3D '/'); + (*Position)++; +} + +/** + Append the UEFI-style RhsPath16 to the POSIX-style, canonical format + LhsPath8. Output the POSIX-style, canonical format result in ResultPath,= as a + dynamically allocated string. + + Canonicalization (aka sanitization) establishes the following properties: + - ResultPath is absolute (starts with "/"), + - dot (.) and dot-dot (..) components are resolved/eliminated in ResultP= ath, + with the usual semantics, + - ResultPath uses forward slashes, + - sequences of slashes are squashed in ResultPath, + - the printable ASCII character set covers ResultPath, + - CHAR8 encoding is used in ResultPath, + - no trailing slash present in ResultPath except for the standalone root + directory, + - the length of ResultPath is at most VIRTIO_FS_MAX_PATHNAME_LENGTH. + + Any dot-dot in RhsPath16 that would remove the root directory is dropped= , and + reported through RootEscape, without failing the function call. + + @param[in] LhsPath8 Identifies the base directory. The caller is + responsible for ensuring that LhsPath8 conform = to + the above canonical pathname format on entry. + + @param[in] RhsPath16 Identifies the desired file with a UEFI-style C= HAR16 + pathname. If RhsPath16 starts with a backslash,= then + RhsPath16 is considered absolute, and LhsPath8 = is + ignored; RhsPath16 is sanitized in isolation, f= or + producing ResultPath8. Otherwise (i.e., if RhsP= ath16 + is relative), RhsPath16 is transliterated to CH= AR8, + and naively appended to LhsPath8. The resultant + fused pathname is then sanitized, to produce + ResultPath8. + + @param[out] ResultPath8 The POSIX-style, canonical format pathname that + leads to the file desired by the caller. After = use, + the caller is responsible for freeing ResultPat= h8. + + @param[out] RootEscape Set to TRUE if at least one dot-dot component in + RhsPath16 attempted to escape the root director= y; + set to FALSE otherwise. + + @retval EFI_SUCCESS ResultPath8 has been produced. RootEscape= has + been output. + + @retval EFI_INVALID_PARAMETER RhsPath16 is zero-length. + + @retval EFI_INVALID_PARAMETER RhsPath16 failed the + VIRTIO_FS_MAX_PATHNAME_LENGTH check. + + @retval EFI_OUT_OF_RESOURCES Memory allocation failed. + + @retval EFI_OUT_OF_RESOURCES ResultPath8 would have failed the + VIRTIO_FS_MAX_PATHNAME_LENGTH check. + + @retval EFI_UNSUPPORTED RhsPath16 contains a character that either + falls outside of the printable ASCII set,= or + is a forward slash. +**/ +EFI_STATUS +VirtioFsAppendPath ( + IN CHAR8 *LhsPath8, + IN CHAR16 *RhsPath16, + OUT CHAR8 **ResultPath8, + OUT BOOLEAN *RootEscape + ) +{ + UINTN RhsLen; + CHAR8 *RhsPath8; + UINTN Idx; + EFI_STATUS Status; + UINTN SizeToSanitize; + CHAR8 *BufferToSanitize; + CHAR8 *SanitizedBuffer; + PARSER_STATE State; + UINTN SanitizedPosition; + + // + // Appending an empty pathname is not allowed. + // + RhsLen =3D StrLen (RhsPath16); + if (RhsLen =3D=3D 0) { + return EFI_INVALID_PARAMETER; + } + // + // Enforce length restriction on RhsPath16. + // + if (RhsLen > VIRTIO_FS_MAX_PATHNAME_LENGTH) { + return EFI_INVALID_PARAMETER; + } + + // + // Transliterate RhsPath16 to RhsPath8 by: + // - rejecting RhsPath16 if a character outside of printable ASCII is se= en, + // - rejecting RhsPath16 if a forward slash is seen, + // - replacing backslashes with forward slashes, + // - casting the characters from CHAR16 to CHAR8. + // + RhsPath8 =3D AllocatePool (RhsLen + 1); + if (RhsPath8 =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + for (Idx =3D 0; RhsPath16[Idx] !=3D L'\0'; Idx++) { + if (RhsPath16[Idx] < 0x20 || RhsPath16[Idx] > 0x7E || + RhsPath16[Idx] =3D=3D L'/') { + Status =3D EFI_UNSUPPORTED; + goto FreeRhsPath8; + } + RhsPath8[Idx] =3D (CHAR8)((RhsPath16[Idx] =3D=3D L'\\') ? L'/' : RhsPa= th16[Idx]); + } + RhsPath8[Idx++] =3D '\0'; + + // + // Now prepare the input for the canonicalization (squashing of sequence= s of + // forward slashes, and eliminating . (dot) and .. (dot-dot) pathname + // components). + // + // The sanitized path can never be longer than the naive concatenation o= f the + // left hand side and right hand side paths, so we'll use the catenated = size + // for allocating the sanitized output too. + // + if (RhsPath8[0] =3D=3D '/') { + // + // If the right hand side path is absolute, then it is not appended to= the + // left hand side path -- it *replaces* the left hand side path. + // + SizeToSanitize =3D RhsLen + 1; + BufferToSanitize =3D RhsPath8; + } else { + // + // If the right hand side path is relative, then it is appended (naive= ly) + // to the left hand side. + // + UINTN LhsLen; + + LhsLen =3D AsciiStrLen (LhsPath8); + SizeToSanitize =3D LhsLen + 1 + RhsLen + 1; + BufferToSanitize =3D AllocatePool (SizeToSanitize); + if (BufferToSanitize =3D=3D NULL) { + Status =3D EFI_OUT_OF_RESOURCES; + goto FreeRhsPath8; + } + CopyMem (BufferToSanitize, LhsPath8, LhsLen); + BufferToSanitize[LhsLen] =3D '/'; + CopyMem (BufferToSanitize + LhsLen + 1, RhsPath8, RhsLen + 1); + } + + // + // Allocate the output buffer. + // + SanitizedBuffer =3D AllocatePool (SizeToSanitize); + if (SanitizedBuffer =3D=3D NULL) { + Status =3D EFI_OUT_OF_RESOURCES; + goto FreeBufferToSanitize; + } + + // + // State machine for parsing the input and producing the canonical output + // follows. + // + *RootEscape =3D FALSE; + Idx =3D 0; + State =3D ParserInit; + SanitizedPosition =3D 0; + do { + CHAR8 Chr8; + + ASSERT (Idx < SizeToSanitize); + Chr8 =3D BufferToSanitize[Idx++]; + + switch (State) { + case ParserInit: // just starting + ASSERT (Chr8 =3D=3D '/'); + ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, Chr= 8); + State =3D ParserSlash; + break; + + case ParserSlash: // slash(es) seen + switch (Chr8) { + case '\0': + ParserStripSlash (SanitizedBuffer, &SanitizedPosition); + ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, C= hr8); + State =3D ParserEnd; + break; + case '/': + // + // skip & stay in same state + // + break; + case '.': + ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, C= hr8); + State =3D ParserDot; + break; + default: + ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, C= hr8); + State =3D ParserNormal; + break; + } + break; + + case ParserDot: // one dot seen since last slash + switch (Chr8) { + case '\0': + ParserRewindDot (SanitizedBuffer, &SanitizedPosition); + ParserStripSlash (SanitizedBuffer, &SanitizedPosition); + ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, C= hr8); + State =3D ParserEnd; + break; + case '/': + ParserRewindDot (SanitizedBuffer, &SanitizedPosition); + State =3D ParserSlash; + break; + case '.': + ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, C= hr8); + State =3D ParserDotDot; + break; + default: + ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, C= hr8); + State =3D ParserNormal; + break; + } + break; + + case ParserDotDot: // two dots seen since last slash + switch (Chr8) { + case '\0': + ParserRewindDotDot (SanitizedBuffer, &SanitizedPosition, RootEscap= e); + ParserStripSlash (SanitizedBuffer, &SanitizedPosition); + ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, C= hr8); + State =3D ParserEnd; + break; + case '/': + ParserRewindDotDot (SanitizedBuffer, &SanitizedPosition, RootEscap= e); + State =3D ParserSlash; + break; + case '.': + // + // fall through + // + default: + ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, C= hr8); + State =3D ParserNormal; + break; + } + break; + + case ParserNormal: // a different sequence seen + switch (Chr8) { + case '\0': + ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, C= hr8); + State =3D ParserEnd; + break; + case '/': + ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, C= hr8); + State =3D ParserSlash; + break; + case '.': + // + // fall through + // + default: + // + // copy and stay in same state + // + ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, C= hr8); + break; + } + break; + + default: + ASSERT (FALSE); + break; + } + } while (State !=3D ParserEnd); + + // + // Ensure length invariant on ResultPath8. + // + ASSERT (SanitizedPosition >=3D 2); + if (SanitizedPosition - 1 > VIRTIO_FS_MAX_PATHNAME_LENGTH) { + Status =3D EFI_OUT_OF_RESOURCES; + goto FreeSanitizedBuffer; + } + + *ResultPath8 =3D SanitizedBuffer; + SanitizedBuffer =3D NULL; + Status =3D EFI_SUCCESS; + // + // Fall through. + // +FreeSanitizedBuffer: + if (SanitizedBuffer !=3D NULL) { + FreePool (SanitizedBuffer); + } + +FreeBufferToSanitize: + if (RhsPath8[0] !=3D '/') { + FreePool (BufferToSanitize); + } + +FreeRhsPath8: + FreePool (RhsPath8); + return Status; +} --=20 2.19.1.3.g30247aa5d201 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#69030): https://edk2.groups.io/g/devel/message/69030 Mute This Topic: https://groups.io/mt/79023203/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-