Skip to content

Conversation

@picnixz
Copy link
Member

@picnixz picnixz commented Dec 31, 2025

@picnixz
Copy link
Member Author

picnixz commented Dec 31, 2025

Mmh. This is tricky for Windows. I don't have a Windows machine to know what happened there.

@picnixz
Copy link
Member Author

picnixz commented Dec 31, 2025

@chris-eibl I know you're on Windows, so could you help me there please?

@chris-eibl
Copy link
Member

Will have a closer look tomorrow

@picnixz picnixz force-pushed the fix/os/uaf-in-os-execve-143309 branch from 17b706f to be3bd3d Compare January 1, 2026 11:48
@picnixz picnixz requested a review from sobolevn January 1, 2026 11:48
@chris-eibl
Copy link
Member

chris-eibl commented Jan 1, 2026

@chris-eibl I know you're on Windows, so could you help me there please?

Ups, really tricky on Windows. I've found two different issues:

Edit: Created #143327

Details

The test case boils down to this smallest reproducer I can get:

import os, sys
import subprocess

code = """
import os, sys
args = [sys.executable, '-c', 'print(4711)']
os.execve(args[0], args, {})
"""

cmd_line = [sys.executable, '-X', 'faulthandler', '-c', code]
env_1 = os.environ.copy()
env_2 = {}
env_2['SYSTEMROOT'] = os.environ['SYSTEMROOT']
proc = subprocess.Popen(
    cmd_line, stdin=subprocess.PIPE,
    stdout=subprocess.PIPE, stderr=subprocess.PIPE,
    env=env_1)
with proc:
    try:
        out, err = proc.communicate()
    finally:
        proc.kill()
        subprocess._cleanup()
print("rc", proc.returncode)
print("out", out)
print("err", err)

Using env_1 crashes for me like in CI, interestingly the "smaller" env_2 works. It seems to be the combination of subprocess and os.execve. Without subprocess, I do not see this problem.

@picnixz
Copy link
Member Author

picnixz commented Jan 1, 2026

Oh, so the problem is subprocess but not my fix?

@chris-eibl
Copy link
Member

chris-eibl commented Jan 1, 2026

Secondly, the os.execv* family has problems with strings on Windows:

Edit: created #143328

Details

import os
import sys

args = [sys.executable, '-c', 'print("hello from execve")']
os.execve(args[0], args, {})

This results in

    print(hello from execve)
                ^^^^
SyntaxError: invalid syntax

And using "print('hello from execve')" results in

    print('hello
          ^
SyntaxError: unterminated string literal (detected at line 1)

Both work like expected in WSL. The only thing that somewhat works is omitting the spaces "print('hellofromexecve')" :-o

@chris-eibl
Copy link
Member

I haven't found these two things reported as issues, yet, I think I should create two new issues?

With the above in mind, changing your test slightly to:

        args = [sys.executable, '-c', "print('hellofromexecve')"]
        os.execve(args[0], args, MyEnv())
        """

        env = {}
        env['__cleanenv'] = True  # signal to assert_python not to do a copy
                                  # of os.environ on its own

        rc, out, _ = assert_python_ok('-c', code, **env)
        self.assertEqual(rc, 0)
        self.assertIn(b"hellofromexecve", out)

let's it pass for me. Without your fix applied, it will fail with an access violation, due to the UAF 🚀

@picnixz
Copy link
Member Author

picnixz commented Jan 1, 2026

I haven't found these two things reported as issues, yet, I think I should create two new issues?

Please do so and thank you for all this investigation!

@chris-eibl
Copy link
Member

Oh, Win x64 now almost green in CI like for me. Unfortunately, arm64 and Win32 still crash. I will look at Win32, do not have an Arm machine ...

@chris-eibl
Copy link
Member

Sorry, didn't want to also apply my suggestion - just suggest. Misclicked, hangover from yesterday ...

@picnixz
Copy link
Member Author

picnixz commented Jan 1, 2026

You're hijacking my code! 😨

@picnixz
Copy link
Member Author

picnixz commented Jan 1, 2026

Could the issue on Windows and general be caused by this:

        PyObject *keyval = PyUnicode_FromFormat("%U=%U", key2, val2);

@chris-eibl
Copy link
Member

chris-eibl commented Jan 1, 2026

You're hijacking my code! 😨

And already apologized. Misclicked. Sorry again.

arm64 and Win32 still crash

Win32 is green for me. I've run

python -m test.test_os.test_os ExecTests.test_execve_env_concurrent_mutation_with_fspath

5 times sucessfully ...

@picnixz
Copy link
Member Author

picnixz commented Jan 1, 2026

And already apologized. Misclicked. Sorry again.

Don't worry! I was overreacting but I wasn't offended :)

@chris-eibl
Copy link
Member

5 times sucessfully ...

... and crashed after trying a 6th time. But I could not crash x64 after 20 invocations ...

PyObject *keyval = PyUnicode_FromFormat("%U=%U", key2, val2);

IDKN. Looks ok at a first glance?

@picnixz
Copy link
Member Author

picnixz commented Jan 1, 2026

I actually wonder whether the issue is because of execve in general or the environment we build.

@picnixz
Copy link
Member Author

picnixz commented Jan 1, 2026

Could it be actually because we're not forwarding env['SYSTEMROOT'] = os.environ['SYSTEMROOT']? For Windows, if we are lacking SYSTEMROOT, wouldn't it be an issue? maybe execve & co must also inherit SYSTEMROOT in this case?

@chris-eibl
Copy link
Member

It get's autofilled here

if sys.platform == 'win32':
# Windows requires at least the SYSTEMROOT environment variable to
# start Python.
env['SYSTEMROOT'] = os.environ['SYSTEMROOT']

@picnixz
Copy link
Member Author

picnixz commented Jan 1, 2026

Yes, but not when calling execve. The environment I'm passing to execve is an environment that gets mutated.

@picnixz picnixz force-pushed the fix/os/uaf-in-os-execve-143309 branch from 194fa14 to 73e3f79 Compare January 1, 2026 14:50
@picnixz picnixz force-pushed the fix/os/uaf-in-os-execve-143309 branch from 73e3f79 to 5bd7d39 Compare January 1, 2026 14:52
@picnixz picnixz force-pushed the fix/os/uaf-in-os-execve-143309 branch from a7d9e74 to 7b6e2db Compare January 1, 2026 15:34
@picnixz
Copy link
Member Author

picnixz commented Jan 1, 2026

Ok I give up, I have no idea why this crashes but I'm pretty sure the issue is after we call os.execve and not before. I also that changing the command to something that is not Python may work but I don't know which program to use that would always be available on Windows.

@chris-eibl
Copy link
Member

after we call os.execve

Yes, definitely. Was always the case when I was debugging it, but cannot crash it anymore in x64 when the env is "lightweight" ...

@picnixz
Copy link
Member Author

picnixz commented Jan 1, 2026

I think we should debug what the environment passed to execve (that is, after parse_envlist) is called. Would you be willing to check what the contents of the array is (with the patch) please? Also, x64 crashes with FT mode but not in regular build.

@picnixz
Copy link
Member Author

picnixz commented Jan 1, 2026

Considering #137934, I think we will, for now, just skip the test on Windows. If even os.execve is buggy in plain C, then there is nothing we can do on our side.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants