munki / munki

Managed software installation for macOS —

Home Page:https://www.munki.org/munki/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Update Python to Version 3.12

skargbo opened this issue · comments

It appears that the current Python version used in the MSC project is vulnerable to a number of high severity security issues that have been disclosed to the public. To address these vulnerabilities, I propose bumping the Python version 3.12, which includes patches for these CVEs.

The following CVEs have been identified in the current version 3.10 of the Python framework used by MSC

This is more difficult than you might think, due to some breakage in the Mac builds of the Python frameworks, making relocation difficult. If anyone wants to dig in and figure the issues out, I'd appreciate the help.

Specifically: If I just use the existing build scripts (but update the Python version to 3.12.2), the Python framework is subtly broken:

$ munki-python
Could not find platform dependent libraries <exec_prefix>
Python 3.12.2 (v3.12.2:6abddd9f6a, Feb  6 2024, 17:02:06) [Clang 13.0.0 (clang-1300.0.29.30)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 
$ managedsoftwareupdate 
Could not find platform dependent libraries <exec_prefix>
Traceback (most recent call last):
  File "/usr/local/munki/.managedsoftwareupdate.py", line 30, in <module>
    import subprocess
  File "/usr/local/munki/Python.framework/Versions/3.12/lib/python3.12/subprocess.py", line 104, in <module>
    from _posixsubprocess import fork_exec as _fork_exec
ModuleNotFoundError: No module named '_posixsubprocess'

This is almost certainly the same issue as this: gregneagle/relocatable-python#31 and is why munki-python has remained on 3.10.x for so long.

Once you work around the issue with a shell script replacing /usr/local/munki/munki-python (which means yet another layer of wrapping and redirection, and yet another process layer), you find that Munki makes use of at least one standard lib module that's been removed in 3.12:

$ managedsoftwareupdate 
Traceback (most recent call last):
  File "/usr/local/munki/.managedsoftwareupdate.py", line 63, in <module>
    from munkilib import appleupdates
  File "/usr/local/munki/munkilib/appleupdates/__init__.py", line 5, in <module>
    from .core import *
  File "/usr/local/munki/munkilib/appleupdates/core.py", line 23, in <module>
    from . import au
  File "/usr/local/munki/munkilib/appleupdates/au.py", line 43, in <module>
    from . import sync
  File "/usr/local/munki/munkilib/appleupdates/sync.py", line 56, in <module>
    from .. import fetch
  File "/usr/local/munki/munkilib/fetch.py", line 27, in <module>
    import imp
ModuleNotFoundError: No module named 'imp'

The imp module is used to import middleware and repo-plugins. So we'll need to figure out the current replacement for this.

imp fix is here: 1850dbe

I posted a potential workaround for gregneagle/relocatable-python#31 (comment).

What if instead of relying on a symlink, we just incorporated the tiny shell script and use that for invoking Python?

It could even be signed, in order to ensure compliance with macOS PPPC expectations for running Python interpreters (have not tested that at all).

FWIW we have discovered that VMware's embedded Munki is using 3.11 so it begs the question - what did they do, why did they do it, and why didn't they send a PR to help the community.

Betting they are just using the actual/normalized path to the actual Python 3.11 binary as the shebang, which avoids the platform libraries issue.

$ /usr/local/hub/python3 -V
Python 3.11.6
$ /usr/local/hub/python3
Python 3.11.6 (tags/v3.11.6-dirty:8b6ee5ba3b, Nov 23 2023, 18:37:49) [Clang 14.0.0 (clang-1400.0.29.202)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import subprocess
>>> exit()
$ file /usr/local/hub/python3
/usr/local/hub/python3: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64:Mach-O 64-bit executable arm64]
/usr/local/hub/python3 (for architecture x86_64):	Mach-O 64-bit executable x86_64
/usr/local/hub/python3 (for architecture arm64):	Mach-O 64-bit executable arm64

So it looks like they went the route of a compiled binary shim...

$ strings /usr/local/hub/python3
realpath: %s
__PYVENV_LAUNCHER__
posix_spawn: %s
Resources/Python.app/Contents/MacOS/Python
posix_spawnattr_int
posix_spawnattr_setbinpref
posix_spawnattr_setbinpref failed to copy
posix_spawnattr_setflags
realpath: %s
__PYVENV_LAUNCHER__
posix_spawn: %s
Resources/Python.app/Contents/MacOS/Python
posix_spawnattr_int
posix_spawnattr_setbinpref
posix_spawnattr_setbinpref failed to copy
posix_spawnattr_setflags

I wish I had contacts over there still. It really sucks that they solved this and didn't help the community.

Most of the needed work is done as of this commit: 9e541a8

we have some installcheck_scripts using the distutils module (https://github.com/autopkg/dataJAR-recipes/blob/master/Firefox-locale/Firefox.munki.recipe#L109.. with distutils being removed with Python 3.12, what's the recommended path to overcome this?

I'm hoping/guessing that we can import another module to use in it's place?

Looking at a8494ab I guess we can:
from munkilib.pkgutils import MunkiLooseVersion as LooseVersion and on an import error revert to from distutils.version import LooseVersion?

So something like:

try:
    from munkilib.pkgutils import MunkiLooseVersion as LooseVersion
except ModuleNotFoundError:
    from distutils.version import LooseVersion

Python moves forward and deprecates and removes things. If your scripts use things that have been removed, yes, you must adapt.

@gregneagle true!

Can MunkiLooseVersion be seen as a drop in replacement for LooseVersion, for simple comparisons?

Just wanted to clarify as will then test and move to that.

I would think so, but there are slight differences in behavior (which is why MunkiLooseVersion was created)

Munki 6.5 has been released, and includes Python 3.12.2.