salt: The win_dism module does not work on a 64-bit architecture when running inside a 32-bit process

Description of Issue/Question

On a 64-bit windows system, there are two versions of the DISM.exe binary. The first one (64-bit) is /Windows/System32/Dism.exe and the second one (32-bit) is /Windows/SysWOW64/Dism.exe. The win_dism module simply trusts that the PATH is set correctly as it just tries to execute “dism”.

It is prudent to note that on 64-bit versions of windows, the directories for /Windows/System32 and /Windows/SysWOW64 have different semantics depending on the architecture of the application that is being used. So the path to the correct instance of Dism.exe is different depending on the Python interpreter that is running the salt process.

Normally it is assumed that /Windows/SysWOW64 contains the 32-bit binaries (such as Dism.exe) and /Windows/System32 contains the 64-bit binaries. However, when running a 32-bit application (such as the 32-bit version of Python) both the /Windows/SysWOW64 and /Windows/System32 directories point to the 32-bit binaries for the platform. This is done for compatibility reasons as historically the /Windows/System32 directory contains the system tools available for the platform.

Unfortunately this means that via a 32-bit process, it would normally be impossible to call the correct 64-bit version of Dism.exe. However, on a 32-bit process windows creates a file-system redirection to the 64-bit platform tools at /Windows/Sysnative. So depending on the process architecture, the correct path can be either /Windows/System32 or /Windows/Sysnative.

In summary, if one is running salt on a 32-bit version of Windows. Nothing matters, everything is okay. If one is running salt on a 64-bit version of Windows, then the correct path to Dism.exe depends on the architecture of the Python interpreter that is running.

If salt is running in a 32-bit interpreter, then the path to the 64-bit Dism.exe is at /Windows/Sysnative/Dism.exe. If salt is running in a 64-bit interpreter, then the path to the 64-bit Dism.exe is at /Windows/System32.

Symptom (in minion log file)

2019-02-27 09:29:52,104 [salt.minion      :1667][WARNING ][2740] The minion function caused an exception
2019-02-27 09:30:02,510 [salt.loaded.int.module.cmdmod:774 ][ERROR   ][3132] Command '[u'DISM', u'/English', u'/Online', u'/Get-Features']' failed with return code: 11
2019-02-27 09:30:02,510 [salt.loaded.int.module.cmdmod:776 ][ERROR   ][3132] stdout: 
Deployment Image Servicing and Management tool
Version: 6.2.9200.16384


Error: 11

You cannot service a running 64-bit operating system with a 32-bit version of DISM. 
Please use the version of DISM that corresponds to your computer's architecture.

The DISM log file can be found at C:\Windows\Logs\DISM\dism.log
2019-02-27 09:30:02,510 [salt.loaded.int.module.cmdmod:780 ][ERROR   ][3132] retcode: 11

Setup

Install a 64-bit version of Windows that is newer than Vista (inclusive), and then use the 32-bit salt-minion so that a 32-bit version of Python gets installed.

Steps to Reproduce Issue

Try to use anything in the win_dism module such as get_features or something… Another way to prove that the wrong one is being executed would be to use cmd.which as so:

$ salt $target cmd.which Dism
bX_nxPEVRyWOcIDBECwW:
    C:\Windows\system32\dism.EXE

-------------------------------------------
Summary
-------------------------------------------
# of minions targeted: 1
# of minions returned: 1
# of minions that did not return: 0
# of minions with errors: 0
-------------------------------------------

If the path to the System32 Dism.exe is returned, then the win_dism module will not work despite the tool being available

Notes

Really this will happen with all the platform tools on Windows. If one wants to avoid smashing gophers related to calling the wrong tool, there should be a utility to locate platform-specific tools. It’s really not safe/reliable to explicitly trust the PATH environment to locate these types of tools.

Versions Report

This is independant of the version as none of the commits try to do anything funny with /Windows/System32/Sysnative

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 22 (22 by maintainers)

Most upvoted comments

lol, that first case that tests for Windows should be inverted. but i think you get it…

Although using .get() is useful in some cases, it tends to hide errors.

Rather than changing the semantics of which, which is well-defined, wouldn’t it be safer to modify the dism module to call %windir%\Sysnative\Dism.exe, and then on failure call %windir%\System32\Dism.exe?