dorssel / usbipd-win

Windows software for sharing locally connected USB devices to other machines, including Hyper-V guests and WSL 2.
GNU General Public License v3.0
3.77k stars 234 forks source link

Error running `modprobe` for `vhci_hcd` kernel module #1050

Open pdietl opened 2 weeks ago

pdietl commented 2 weeks ago

So I built my own WSL kernel and accidentally set some kernel modules to M instead of Y and so they became modules rather than built directly into the kernel. Thus, I stumbled upon the code here https://github.com/dorssel/usbipd-win/blob/4ac11d413ed9b44ec55532156394c7de83defb5e/Usbipd/Wsl.cs#L345 that tries to remedy the situation by calling modprobe. I kept getting this error:

PS C:\Users\peted> usbipd.exe attach --wsl --busid 7-1
usbipd: info: Using WSL distribution 'Ubuntu-24.04' to attach; the device will be available in all WSL 2 distributions.
usbipd: info: Loading vhci_hcd module.
usbipd: error: Loading vhci_hcd failed.

To investigate this, I tried running C:\Windows\System32\wsl.exe --distribution Ubuntu-24.04 --user root --cd / --exec modprobe and got this result: <3>WSL (77192) ERROR: CreateProcessCommon:559: execvpe(modprobe) failed: No such file or directory. From there, I tried running C:\Windows\System32\wsl.exe --distribution Ubuntu-24.04 --user root --cd / -- ls and curiously, that worked just fine.

After some fiddling around, I finally found my answer in the documentation for execvpe:

p - execlp(), execvp(), execvpe() These functions duplicate the actions of the shell in searching for an executable file if the specified filename does not contain a slash (/) character. The file is sought in the colon-separated list of directory pathnames specified in the PATH environment variable. If this variable isn't defined, the path list defaults to a list that includes the directories returned by confstr(_CS_PATH) (which typically returns the value "/bin:/usr/bin") and possibly also the current working directory; see VERSIONS for further details.

   execvpe() searches for the program using the value of PATH from
   the caller's environment, not from the envp argument.

   If the specified filename includes a slash character, then PATH
   is ignored, and the file at the specified pathname is executed.

So, the command after the --exec argument is indeed executed with an environ containing no PATH entry, but because of how execvpe works, the argument gets looked for in /bin and in /usr/bin. Crucially in Ubuntu at least, modprobe is installed in /usr/sbin/modprobe, and thus was not found.

As for how to go about fixing this, there are several possibilities:

  1. Also try executing /usr/sbin/modprobe explicitly.
  2. Execute modprobe with the --exec argument, which runs it in a shell which probably has its PATH variable set properly.
  3. Something else
pdietl commented 3 days ago

@dorssel could you take a look at this? I can do all of the work; I just would like your input on my approach.