From nobody Mon Feb 9 15:30:21 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+69056+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+69056+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1608158408; cv=none; d=zohomail.com; s=zohoarc; b=UAV2/ePlSQdfnZjHGgKCx9LvtcCnRKD7Y1L4EwZqHmnRtwYqP0W6hoDi+vLSXlZTnGVGzWfujEYTQiviat/9Hp9zTM8iFSZZAU79FKt/aqf/LcV7N5UxJJRLDWyJAPlWUEpZnNQLAWzCD5t8n15DoGY4LxM1Ve8rM6L+iMA7X+I= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1608158408; 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=7KsP6/78c+6UI7/m3lxNQ1W4mlHlPkxaVu4fiNFetK8=; b=TjEmTSlyV6QMJuOOyr6GmV/6u1Xq5Uwlyw2vONTuP9c96onU1XXES+0OLoyiYP7YBKvzUFOzaMbb/aFKsCd2caHdMTIdPa7nXfWWZ6HsXFdbky41ZAMyUQNQ5n81OnrvXV30BYR30qZH1qJJP/Lmzh4i7Ci8Ch8yCf5+eCSkzmI= 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+69056+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 160815840866351.72386462816269; Wed, 16 Dec 2020 14:40:08 -0800 (PST) Return-Path: X-Received: by 127.0.0.2 with SMTP id stVXYY1788612x2awBD1vGoC; Wed, 16 Dec 2020 14:40:08 -0800 X-Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [63.128.21.124]) by mx.groups.io with SMTP id smtpd.web09.4862.1608158402654984048 for ; Wed, 16 Dec 2020 14:40:02 -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-332-x-UbvzVlOCu972sdkrg86Q-1; Wed, 16 Dec 2020 17:39:59 -0500 X-MC-Unique: x-UbvzVlOCu972sdkrg86Q-1 X-Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 2CF4181441E; Wed, 16 Dec 2020 22:39:54 +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 72DEF62953; Wed, 16 Dec 2020 22:39:52 +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 42/48] OvmfPkg/VirtioFsDxe: add helper for composing rename/move destination path Date: Wed, 16 Dec 2020 22:11:19 +0100 Message-Id: <20201216211125.19496-43-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.79 on 10.5.11.15 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: tcg5ZG9P9T6W65kAcbX4XuGhx1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1608158408; bh=7KsP6/78c+6UI7/m3lxNQ1W4mlHlPkxaVu4fiNFetK8=; h=Cc:Content-Type:Date:From:Reply-To:Subject:To; b=e5VeJC77/XJg9spAvTqkyfXF/t9Qll3muNIKjm84kzvMp+/0lTBH/VoiY+vcp+tFN+k hah7LT+P+I6a5msaGUP1jSRnfBSjZQxjHfqpH4aVpA3d0WqFuDhCGnVxATrFdp+8YFMCd xeNA3Mo7ZO8Djnk0KJhrDXz+fW7F6hMORhA= X-ZohoMail-DKIM: pass (identity @groups.io) Content-Type: text/plain; charset="utf-8" The EFI_FILE_PROTOCOL.SetInfo() member is somewhat under-specified; one of its modes of operation is renaming/moving the file. In order to create the destination pathname in canonical format, 2*2=3D4 cases have to be considered. For the sake of discussion, assume the current canonical pathname of a VIRTIO_FS_FILE is "/home/user/f1.txt". Then, consider the following rename/move requests from EFI_FILE_PROTOCOL.SetInfo(): Destination requested Destination Move into Destination in by SetInfo() relative? directory? canonical format --------------------- ----------- ---------- ----------------------- L"\\dir\\f2.txt" no no "/dir/f2.txt" L"\\dir\\" no yes "/dir/f1.txt" L"dir\\f2.txt" yes no "/home/user/dir/f2.txt" L"dir\\" yes yes "/home/user/dir/f1.txt" Add the VirtioFsComposeRenameDestination() function, for composing the last column from the current canonical pathname and the SetInfo() input. The function works on the following principles: - The prefix of the destination path is "/", if the SetInfo() rename request is absolute. Otherwise, the dest prefix is the "current directory" (the most specific parent directory) of the original pathname (in the above example, "/home/user"). - The suffix of the destination path is precisely the SetInfo() request string, if the "move into directory" convenience format -- the trailing backslash -- is not used. (In the above example, L"\\dir\\f2.txt" and L"dir\\f2.txt".) Otherwise, the suffix is the SetInfo() request, plus the original basename (in the above example, L"\\dir\\f1.txt" and L"dir\\f1.txt"). - The complete destination is created by fusing the dest prefix and the dest suffix, using the VirtioFsAppendPath() function. 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.h | 8 + OvmfPkg/VirtioFsDxe/Helpers.c | 194 ++++++++++++++++++++ 2 files changed, 202 insertions(+) diff --git a/OvmfPkg/VirtioFsDxe/VirtioFsDxe.h b/OvmfPkg/VirtioFsDxe/Virtio= FsDxe.h index 9334e5434c51..a6dfac71f4a7 100644 --- a/OvmfPkg/VirtioFsDxe/VirtioFsDxe.h +++ b/OvmfPkg/VirtioFsDxe/VirtioFsDxe.h @@ -257,16 +257,24 @@ VirtioFsLookupMostSpecificParentDir ( =20 EFI_STATUS VirtioFsGetBasename ( IN CHAR8 *Path, OUT CHAR16 *Basename OPTIONAL, IN OUT UINTN *BasenameSize ); =20 +EFI_STATUS +VirtioFsComposeRenameDestination ( + IN CHAR8 *LhsPath8, + IN CHAR16 *RhsPath16, + OUT CHAR8 **ResultPath8, + OUT BOOLEAN *RootEscape + ); + EFI_STATUS VirtioFsFuseAttrToEfiFileInfo ( IN VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE *FuseAttr, OUT EFI_FILE_INFO *FileInfo ); =20 EFI_STATUS VirtioFsFuseDirentPlusToEfiFileInfo ( diff --git a/OvmfPkg/VirtioFsDxe/Helpers.c b/OvmfPkg/VirtioFsDxe/Helpers.c index cdaa8557a17b..b741cf753495 100644 --- a/OvmfPkg/VirtioFsDxe/Helpers.c +++ b/OvmfPkg/VirtioFsDxe/Helpers.c @@ -1778,16 +1778,210 @@ VirtioFsGetBasename ( } =20 for (Idx =3D LastComponent; Idx < PathSize; Idx++) { Basename[Idx - LastComponent] =3D Path[Idx]; } return EFI_SUCCESS; } =20 +/** + Format the destination of a rename/move operation as a dynamically alloc= ated + canonical pathname. + + 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 The source pathname operand of the rename/move + operation, expressed as a canonical pathname (as + defined in the description of VirtioFsAppendPath= ()). + The root directory "/" cannot be renamed/moved, = and + will be rejected. + + @param[in] RhsPath16 The destination pathname operand expressed as a + UEFI-style CHAR16 pathname. + + If RhsPath16 starts with a backslash, then RhsPa= th16 + is considered absolute. Otherwise, RhsPath16 is + interpreted relative to the most specific parent + directory found in LhsPath8. + + Independently, if RhsPath16 ends with a backslash + (i.e., RhsPath16 is given in the "move into + directory" convenience form), then RhsPath16 is + interpreted with the basename of LhsPath8 append= ed. + Otherwise, the last pathname component of RhsPat= h16 + is taken as the last pathname component of the + rename/move destination. + + An empty RhsPath16 is rejected. + + @param[out] ResultPath8 The POSIX-style, canonical format pathname that + leads to the renamed/moved file. After use, the + caller is responsible for freeing ResultPath8. + + @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 LhsPath8 is "/". + + @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 +VirtioFsComposeRenameDestination ( + IN CHAR8 *LhsPath8, + IN CHAR16 *RhsPath16, + OUT CHAR8 **ResultPath8, + OUT BOOLEAN *RootEscape + ) +{ + // + // Lengths are expressed as numbers of characters (CHAR8 or CHAR16), + // excluding terminating NULs. Sizes are expressed as byte counts, inclu= ding + // the bytes taken up by terminating NULs. + // + UINTN RhsLen; + UINTN LhsBasename16Size; + EFI_STATUS Status; + UINTN LhsBasenameLen; + UINTN DestSuffix16Size; + CHAR16 *DestSuffix16; + CHAR8 *DestPrefix8; + + // + // An empty destination operand for the rename/move operation is not all= owed. + // + 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; + } + + // + // Determine the length of the basename of LhsPath8. + // + LhsBasename16Size =3D 0; + Status =3D VirtioFsGetBasename (LhsPath8, NULL, &LhsBasename16Size); + ASSERT (Status =3D=3D EFI_BUFFER_TOO_SMALL); + ASSERT (LhsBasename16Size >=3D sizeof (CHAR16)); + ASSERT (LhsBasename16Size % sizeof (CHAR16) =3D=3D 0); + LhsBasenameLen =3D LhsBasename16Size / sizeof (CHAR16) - 1; + if (LhsBasenameLen =3D=3D 0) { + // + // The root directory cannot be renamed/moved. + // + return EFI_INVALID_PARAMETER; + } + + // + // Resolve the "move into directory" convenience form in RhsPath16. + // + if (RhsPath16[RhsLen - 1] =3D=3D L'\\') { + // + // Append the basename of LhsPath8 as a CHAR16 string to RhsPath16. + // + DestSuffix16Size =3D RhsLen * sizeof (CHAR16) + LhsBasename16Size; + DestSuffix16 =3D AllocatePool (DestSuffix16Size); + if (DestSuffix16 =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + CopyMem (DestSuffix16, RhsPath16, RhsLen * sizeof (CHAR16)); + Status =3D VirtioFsGetBasename (LhsPath8, DestSuffix16 + RhsLen, + &LhsBasename16Size); + ASSERT_EFI_ERROR (Status); + } else { + // + // Just create a copy of RhsPath16. + // + DestSuffix16Size =3D (RhsLen + 1) * sizeof (CHAR16); + DestSuffix16 =3D AllocateCopyPool (DestSuffix16Size, RhsPath16); + if (DestSuffix16 =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + } + + // + // If the destination operand is absolute, it will be interpreted relati= ve to + // the root directory. + // + // Otherwise (i.e., if the destination operand is relative), then create= the + // canonical pathname that the destination operand is interpreted relati= vely + // to; that is, the canonical pathname of the most specific parent direc= tory + // found in LhsPath8. + // + if (DestSuffix16[0] =3D=3D L'\\') { + DestPrefix8 =3D AllocateCopyPool (sizeof "/", "/"); + if (DestPrefix8 =3D=3D NULL) { + Status =3D EFI_OUT_OF_RESOURCES; + goto FreeDestSuffix16; + } + } else { + UINTN LhsLen; + UINTN DestPrefixLen; + + // + // Strip the basename of LhsPath8. + // + LhsLen =3D AsciiStrLen (LhsPath8); + ASSERT (LhsBasenameLen < LhsLen); + DestPrefixLen =3D LhsLen - LhsBasenameLen; + ASSERT (LhsPath8[DestPrefixLen - 1] =3D=3D '/'); + // + // If we're not at the root directory, strip the slash too. + // + if (DestPrefixLen > 1) { + DestPrefixLen--; + } + DestPrefix8 =3D AllocatePool (DestPrefixLen + 1); + if (DestPrefix8 =3D=3D NULL) { + Status =3D EFI_OUT_OF_RESOURCES; + goto FreeDestSuffix16; + } + CopyMem (DestPrefix8, LhsPath8, DestPrefixLen); + DestPrefix8[DestPrefixLen] =3D '\0'; + } + + // + // Now combine DestPrefix8 and DestSuffix16 into the final canonical + // pathname. + // + Status =3D VirtioFsAppendPath (DestPrefix8, DestSuffix16, ResultPath8, + RootEscape); + + FreePool (DestPrefix8); + // + // Fall through. + // +FreeDestSuffix16: + FreePool (DestSuffix16); + + return Status; +} + /** Convert select fields of a VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE object to corresponding fields in EFI_FILE_INFO. =20 @param[in] FuseAttr The VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE object to convert the relevant fields from. =20 @param[out] FileInfo The EFI_FILE_INFO structure to modify. Importantly= , the --=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 (#69056): https://edk2.groups.io/g/devel/message/69056 Mute This Topic: https://groups.io/mt/79024445/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-