| 335 | } |
| 336 | |
| 337 | fextl::string RecoverGuestProgramFilename(fextl::string Program, bool ExecFDInterp, int ProgramFDFromEnv) { |
| 338 | // If executed with a FEX FD then the Program argument might be empty. |
| 339 | // In this case we need to scan the FD node to recover the application binary that exists on disk. |
| 340 | // Only do this if the Program argument is empty, since we would prefer the application's expectation |
| 341 | // of application name. |
| 342 | if (ProgramFDFromEnv != -1 && Program.empty()) { |
| 343 | // Get the `dev` node of the execveat fd string. |
| 344 | Program = fextl::fmt::format("/dev/fd/{}", ProgramFDFromEnv); |
| 345 | } |
| 346 | |
| 347 | // If we were provided a relative path then we need to canonicalize it to become absolute. |
| 348 | // If the program name isn't resolved to an absolute path then glibc breaks inside it's `_dl_get_origin` function. |
| 349 | // This is because we rewrite `/proc/self/exe` to the absolute program path calculated in here. |
| 350 | if (!Program.starts_with('/')) { |
| 351 | char ExistsTempPath[PATH_MAX]; |
| 352 | char* RealPath = FHU::Filesystem::Absolute(Program.c_str(), ExistsTempPath); |
| 353 | if (RealPath) { |
| 354 | Program = RealPath; |
| 355 | } |
| 356 | } |
| 357 | |
| 358 | // If FEX was invoked through an FD path (either binfmt_misc or execveat) then we need to check the |
| 359 | // Program to see if it is a symlink to find the real path. |
| 360 | // |
| 361 | // binfmt_misc: Arg[0] is actually the execve `pathname` argument or `/dev/fd/<FD>` path |
| 362 | // - `pathname` with execve (See Side Note) |
| 363 | // - FD path with execveat and FD doesn't have an existing file on the disk |
| 364 | // |
| 365 | // ProgramFDFromEnv: Arg[0] is Application provided data or `/dev/fd/<FD>` from above fix-up. |
| 366 | // - execveat was either passed no arguments (argv=NULL) or the first argument is an empty string (argv[0]=""). |
| 367 | // - FD path with execveat and FD doesn't have an existing file on the disk |
| 368 | // |
| 369 | // Side Note: |
| 370 | // The `execve` syscall doesn't take an FD but binfmt_misc will give FEX an FD to execute still. |
| 371 | // Arg[0] will always contain the `pathname` argument provided to execve. |
| 372 | // It does not resolve symlinks, and it does not convert the path to absolute. |
| 373 | // |
| 374 | // Examples: |
| 375 | // - Regular execve. Application must exist on disk. |
| 376 | // execve binfmt_misc args layout: `FEXInterpreter <Path provided to execve pathname> <user provided argv[0]> <user provided argv[n]>...` |
| 377 | // - Regular execveat with FD. FD is backed by application on disk. |
| 378 | // execveat binfmt_misc args layout: `FEXInterpreter <Path provided to execve pathname> <user provided argv[0]> <user provided argv[n]>...` |
| 379 | // - Regular execveat with FD. FD points to file on disk that has been deleted. |
| 380 | // execveat binfmt_misc args layout: `FEXInterpreter /dev/fd/<FD> <user provided argv[0]> <user provided argv[n]>...` |
| 381 | #ifndef _WIN32 |
| 382 | if (ExecFDInterp || ProgramFDFromEnv != -1) { |
| 383 | // Only in the case that FEX is executing an FD will the program argument potentially be a symlink. |
| 384 | // This symlink will be in the style of `/dev/fd/<FD>`. |
| 385 | // |
| 386 | // If the argument /is/ a symlink then resolve its path to get the original application name. |
| 387 | if (FHU::Symlinks::IsSymlink(Program)) { |
| 388 | char Filename[PATH_MAX]; |
| 389 | auto SymlinkPath = FHU::Symlinks::ResolveSymlink(Program, Filename); |
| 390 | if (SymlinkPath.starts_with('/')) { |
| 391 | // This file was executed through an FD. |
| 392 | // Remove the ` (deleted)` text if the file was deleted after the fact. |
| 393 | // Otherwise just get the symlink without the deleted text. |
| 394 | return fextl::string {SymlinkPath.substr(0, SymlinkPath.rfind(" (deleted)"))}; |
no test coverage detected