Skip to content

7.6.x in a Linux chroot: FileSystem root drive is created with Name / but Root /proc, breaking all drive-qualified paths (/root -> /:/oot) and module discovery (works in 7.5.4) #27678

Description

@blancmangit

Steps to reproduce

Official powershell-7.6.3-linux-arm64.tar.gz (also repros with 7.6.2), extracted to /opt/microsoft/powershell/7, run inside a Debian 12 (bookworm, glibc 2.36) arm64 chroot on an OpenWrt host (kernel 5.4.213, aarch64), with /proc bind-mounted into the chroot.

$ pwsh -NoProfile
PS Temp:/> Set-Location /root
Set-Location: Cannot find path '/:/oot' because it does not exist.
PS Temp:/> (Get-Module -ListAvailable).Count
0

Expected behavior

Session starts at / (as 7.5.4 does on the same box); Set-Location /root works; modules are discovered.

Actual behavior

  • Initial location falls back to Temp:/ (setting the startup location apparently fails the same way).
  • Any drive-qualified path fails with one character eaten after the root: /root is reported as /:/oot — consistent with Substring(drive.Name.Length + 1) applied to a drive literally named /, i.e. assuming an X:-style separator that Unix root drives don't have.
  • Invoking a native command (e.g. bash) from the Temp:/ fallback fails with OperationStopped: startIndex cannot be larger than length of string. (Parameter 'startIndex') — consistent with the same substring arithmetic applied to a 1-character path.
  • Get-Module -ListAvailable returns 0 (module discovery resolves every PSModulePath entry through the same machinery), so Utility/Management never autoload and the shell is effectively unusable.

Isolation (same box, same invocation for every test)

  • PowerShell 7.5.4: everything works. 7.6.2 and 7.6.3: broken identically.
  • The .NET layer is fine in the broken build: [IO.Path]::IsPathRooted("/root")True; [IO.Path]::GetFullPath("/root")/root; [IO.Directory]::GetDirectories("$PSHOME/Modules").Count10.
  • Import-Module "$PSHOME/Modules/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1" (explicit path) works, and after it, provider-qualified paths work: Set-Location "Microsoft.PowerShell.Core\FileSystem::/root" succeeds. Only the drive-qualified branch is broken.
  • strace diff between 7.5.4 and 7.6.3 startup shows identical ENOSYS profiles (get_mempolicy, rseq only) — no syscall-availability difference.
  • Clean HOME and redirected POWERSHELL_MODULE_ANALYSIS_CACHE_PATH: no change.
  • FileSystem drive table, 7.5.4: / => [/], Temp => [/tmp/]. 7.6.3: / => [/proc], Temp => [/tmp/] — the root drive is created with the wrong Root. This mechanically explains every symptom above: drive-qualified resolution and module discovery both resolve against /proc, while explicit-path imports and provider-qualified paths bypass the drive and work.
  • The same 7.6.3 tarball works on macOS arm64. Not yet tested on a non-chroot Linux install.

Drive-table probe used on the broken build:

Import-Module $PSHOME/Modules/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1
Get-PSDrive -PSProvider FileSystem | ForEach-Object { $_.Name + " => [" + $_.Root + "]" }

Trigger (confirmed on this box)

Inside the chroot, /proc/self/mounts contains exactly one entry — the /proc bind itself; mounts outside the chroot are not visible:

proc /proc proc rw,nosuid,nodev,noexec,noatime 0 0

and in the broken build [System.IO.DriveInfo]::GetDrives() returns exactly one drive: /proc. There is no / entry in the visible mount table. 7.5.4 on the same box still creates the root FileSystem drive with Root /; 7.6.x creates it with Name / but Root /proc — i.e. 7.6.x appears to derive the root drive's Root from mount/drive enumeration instead of using / unconditionally. This should reproduce on any Linux with a plain chroot where /proc is bind-mounted and no / entry is visible in the mount table.

Workaround (confirmed)

Creating a / entry in the chroot's visible mount table fixes 7.6.x completely — bind-mount the chroot root onto itself before entering:

mount --bind "$CHROOT" "$CHROOT"

After this, /proc/self/mounts inside gains a / line, and the same 7.6.3 build starts at /, Set-Location /root works, and Get-Module -ListAvailable finds all 10 modules.

Error details (Get-Error)

ItemNotFoundException, ItemName /:/oot, SessionStateCategory Drive:

at System.Management.Automation.LocationGlobber.ExpandMshGlobPath(String path, Boolean allowNonexistingPaths, PSDriveInfo drive, ContainerCmdletProvider provider, CmdletProviderContext context)
at System.Management.Automation.LocationGlobber.ResolveDriveQualifiedPath(String path, CmdletProviderContext context, Boolean allowNonexistingPaths, CmdletProvider& providerInstance)
at System.Management.Automation.LocationGlobber.GetGlobbedMonadPathsFromMonadPath(String path, Boolean allowNonexistingPaths, CmdletProviderContext context, CmdletProvider& providerInstance)
at System.Management.Automation.SessionStateInternal.SetLocation(String path, CmdletProviderContext context, Boolean literalPath)
at Microsoft.PowerShell.Commands.SetLocationCommand.ProcessRecord()

Possibly related territory: #15497 (root-drive path arithmetic in the same ExpandMshGlobPath/GetChildName machinery).

Environment

  • Broken: PowerShell 7.6.3 and 7.6.2 (official GitHub release tarballs, linux-arm64)
  • Working: PowerShell 7.5.4 on the same system
  • OS: Debian 12 (bookworm) arm64 chroot, glibc 2.36, on OpenWrt host, Linux 5.4.213 aarch64

Happy to run any further diagnostics on this box.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions