Skip to content

Commit efdbc58

Browse files
authored
Merge branch '3.14' into backport-97babb8-3.14
2 parents 4e6db26 + 83ee46c commit efdbc58

16 files changed

+250
-57
lines changed

Android/android.py

Lines changed: 117 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,12 @@
3434
TESTBED_DIR = ANDROID_DIR / "testbed"
3535
CROSS_BUILD_DIR = PYTHON_DIR / "cross-build"
3636

37-
HOSTS = ["aarch64-linux-android", "x86_64-linux-android"]
37+
HOSTS = [
38+
"aarch64-linux-android",
39+
"arm-linux-androideabi",
40+
"i686-linux-android",
41+
"x86_64-linux-android",
42+
]
3843
APP_ID = "org.python.testbed"
3944
DECODE_ARGS = ("UTF-8", "backslashreplace")
4045

@@ -205,38 +210,48 @@ def make_build_python(context):
205210
#
206211
# If you're a member of the Python core team, and you'd like to be able to push
207212
# these tags yourself, please contact Malcolm Smith or Russell Keith-Magee.
208-
def unpack_deps(host, prefix_dir):
213+
def unpack_deps(host, prefix_dir, cache_dir):
209214
os.chdir(prefix_dir)
210215
deps_url = "https://github.com/beeware/cpython-android-source-deps/releases/download"
211216
for name_ver in ["bzip2-1.0.8-3", "libffi-3.4.4-3", "openssl-3.0.19-1",
212-
"sqlite-3.50.4-0", "xz-5.4.6-1", "zstd-1.5.7-1"]:
217+
"sqlite-3.50.4-0", "xz-5.4.6-1", "zstd-1.5.7-2"]:
213218
filename = f"{name_ver}-{host}.tar.gz"
214-
download(f"{deps_url}/{name_ver}/{filename}")
215-
shutil.unpack_archive(filename)
216-
os.remove(filename)
219+
out_path = download(f"{deps_url}/{name_ver}/{filename}", cache_dir)
220+
shutil.unpack_archive(out_path)
217221

218222

219-
def download(url, target_dir="."):
220-
out_path = f"{target_dir}/{basename(url)}"
221-
run(["curl", "-Lf", "--retry", "5", "--retry-all-errors", "-o", out_path, url])
223+
def download(url, cache_dir):
224+
out_path = cache_dir / basename(url)
225+
cache_dir.mkdir(parents=True, exist_ok=True)
226+
if not out_path.is_file():
227+
run(["curl", "-Lf", "--retry", "5", "--retry-all-errors", "-o", out_path, url])
228+
else:
229+
print(f"Using cached version of {basename(url)}")
222230
return out_path
223231

224232

225-
def configure_host_python(context):
233+
def configure_host_python(context, host=None):
234+
if host is None:
235+
host = context.host
226236
if context.clean:
227-
clean(context.host)
237+
clean(host)
228238

229-
host_dir = subdir(context.host, create=True)
239+
host_dir = subdir(host, create=True)
230240
prefix_dir = host_dir / "prefix"
231241
if not prefix_dir.exists():
232242
prefix_dir.mkdir()
233-
unpack_deps(context.host, prefix_dir)
243+
cache_dir = (
244+
Path(context.cache_dir).resolve()
245+
if context.cache_dir
246+
else CROSS_BUILD_DIR / "downloads"
247+
)
248+
unpack_deps(host, prefix_dir, cache_dir)
234249

235250
os.chdir(host_dir)
236251
command = [
237252
# Basic cross-compiling configuration
238253
relpath(PYTHON_DIR / "configure"),
239-
f"--host={context.host}",
254+
f"--host={host}",
240255
f"--build={sysconfig.get_config_var('BUILD_GNU_TYPE')}",
241256
f"--with-build-python={build_python_path()}",
242257
"--without-ensurepip",
@@ -252,14 +267,16 @@ def configure_host_python(context):
252267

253268
if context.args:
254269
command.extend(context.args)
255-
run(command, host=context.host)
270+
run(command, host=host)
256271

257272

258-
def make_host_python(context):
273+
def make_host_python(context, host=None):
274+
if host is None:
275+
host = context.host
259276
# The CFLAGS and LDFLAGS set in android-env include the prefix dir, so
260277
# delete any previous Python installation to prevent it being used during
261278
# the build.
262-
host_dir = subdir(context.host)
279+
host_dir = subdir(host)
263280
prefix_dir = host_dir / "prefix"
264281
for pattern in ("include/python*", "lib/libpython*", "lib/python*"):
265282
delete_glob(f"{prefix_dir}/{pattern}")
@@ -278,20 +295,28 @@ def make_host_python(context):
278295
)
279296

280297

281-
def build_all(context):
282-
steps = [configure_build_python, make_build_python, configure_host_python,
283-
make_host_python]
284-
for step in steps:
285-
step(context)
298+
def build_targets(context):
299+
if context.target in {"all", "build"}:
300+
configure_build_python(context)
301+
make_build_python(context)
302+
303+
for host in HOSTS:
304+
if context.target in {"all", "hosts", host}:
305+
configure_host_python(context, host)
306+
make_host_python(context, host)
286307

287308

288309
def clean(host):
289310
delete_glob(CROSS_BUILD_DIR / host)
290311

291312

292-
def clean_all(context):
293-
for host in HOSTS + ["build"]:
294-
clean(host)
313+
def clean_targets(context):
314+
if context.target in {"all", "build"}:
315+
clean("build")
316+
317+
for host in HOSTS:
318+
if context.target in {"all", "hosts", host}:
319+
clean(host)
295320

296321

297322
def setup_ci():
@@ -853,31 +878,85 @@ def add_parser(*args, **kwargs):
853878

854879
# Subcommands
855880
build = add_parser(
856-
"build", help="Run configure-build, make-build, configure-host and "
857-
"make-host")
881+
"build",
882+
help="Run configure and make for the selected target"
883+
)
858884
configure_build = add_parser(
859885
"configure-build", help="Run `configure` for the build Python")
860-
add_parser(
886+
make_build = add_parser(
861887
"make-build", help="Run `make` for the build Python")
862888
configure_host = add_parser(
863889
"configure-host", help="Run `configure` for Android")
864890
make_host = add_parser(
865891
"make-host", help="Run `make` for Android")
866892

867-
add_parser("clean", help="Delete all build directories")
893+
clean = add_parser(
894+
"clean",
895+
help="Delete build directories for the selected target"
896+
)
897+
868898
add_parser("build-testbed", help="Build the testbed app")
869899
test = add_parser("test", help="Run the testbed app")
870900
package = add_parser("package", help="Make a release package")
871901
ci = add_parser("ci", help="Run build, package and test")
872902
env = add_parser("env", help="Print environment variables")
873903

874904
# Common arguments
905+
# --cross-build-dir argument
906+
for cmd in [
907+
clean,
908+
configure_build,
909+
make_build,
910+
configure_host,
911+
make_host,
912+
build,
913+
package,
914+
test,
915+
ci,
916+
]:
917+
cmd.add_argument(
918+
"--cross-build-dir",
919+
action="store",
920+
default=os.environ.get("CROSS_BUILD_DIR"),
921+
dest="cross_build_dir",
922+
type=Path,
923+
help=(
924+
"Path to the cross-build directory "
925+
f"(default: {CROSS_BUILD_DIR}). Can also be set "
926+
"with the CROSS_BUILD_DIR environment variable."
927+
),
928+
)
929+
930+
# --cache-dir option
931+
for cmd in [configure_host, build, ci]:
932+
cmd.add_argument(
933+
"--cache-dir",
934+
default=os.environ.get("CACHE_DIR"),
935+
help="The directory to store cached downloads.",
936+
)
937+
938+
# --clean option
875939
for subcommand in [build, configure_build, configure_host, ci]:
876940
subcommand.add_argument(
877941
"--clean", action="store_true", default=False, dest="clean",
878942
help="Delete the relevant build directories first")
879943

880-
host_commands = [build, configure_host, make_host, package, ci]
944+
# Allow "all", "build" and "hosts" targets for some commands
945+
for subcommand in [clean, build]:
946+
subcommand.add_argument(
947+
"target",
948+
nargs="?",
949+
default="all",
950+
choices=["all", "build", "hosts"] + HOSTS,
951+
help=(
952+
"The host triplet (e.g., aarch64-linux-android), "
953+
"or 'build' for just the build platform, or 'hosts' for all "
954+
"host platforms, or 'all' for the build platform and all "
955+
"hosts. Defaults to 'all'"
956+
),
957+
)
958+
959+
host_commands = [configure_host, make_host, package, ci]
881960
if in_source_tree:
882961
host_commands.append(env)
883962
for subcommand in host_commands:
@@ -939,13 +1018,19 @@ def main():
9391018
stream.reconfigure(line_buffering=True)
9401019

9411020
context = parse_args()
1021+
1022+
# Set the CROSS_BUILD_DIR if an argument was provided
1023+
if context.cross_build_dir:
1024+
global CROSS_BUILD_DIR
1025+
CROSS_BUILD_DIR = context.cross_build_dir.resolve()
1026+
9421027
dispatch = {
9431028
"configure-build": configure_build_python,
9441029
"make-build": make_build_python,
9451030
"configure-host": configure_host_python,
9461031
"make-host": make_host_python,
947-
"build": build_all,
948-
"clean": clean_all,
1032+
"build": build_targets,
1033+
"clean": clean_targets,
9491034
"build-testbed": build_testbed,
9501035
"test": run_testbed,
9511036
"package": package,

Android/testbed/app/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ val inSourceTree = (
1515

1616
val KNOWN_ABIS = mapOf(
1717
"aarch64-linux-android" to "arm64-v8a",
18+
"arm-linux-androideabi" to "armeabi-v7a",
19+
"i686-linux-android" to "x86",
1820
"x86_64-linux-android" to "x86_64",
1921
)
2022

Doc/conf.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,17 @@
570570
stable_abi_file = 'data/stable_abi.dat'
571571
threadsafety_file = 'data/threadsafety.dat'
572572

573+
# Options for notfound.extension
574+
# -------------------------------
575+
576+
if not os.getenv("READTHEDOCS"):
577+
if language_code:
578+
notfound_urls_prefix = (
579+
f'/{language_code.replace("_", "-").lower()}/{version}/'
580+
)
581+
else:
582+
notfound_urls_prefix = f'/{version}/'
583+
573584
# Options for sphinxext-opengraph
574585
# -------------------------------
575586

Doc/howto/remote_debugging.rst

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,3 +624,58 @@ To inject and execute a Python script in a remote process:
624624
6. Set ``_PY_EVAL_PLEASE_STOP_BIT`` in the ``eval_breaker`` field.
625625
7. Resume the process (if suspended). The script will execute at the next safe
626626
evaluation point.
627+
628+
.. _remote-debugging-threat-model:
629+
630+
Security and threat model
631+
=========================
632+
633+
The remote debugging protocol relies on the same operating system primitives
634+
used by native debuggers such as GDB and LLDB. Attaching to a process
635+
requires the **same privileges** that those debuggers require, for example
636+
``ptrace`` / Yama LSM on Linux, ``task_for_pid`` on macOS, and
637+
``SeDebugPrivilege`` on Windows. Python does not introduce any new privilege
638+
escalation path; if an attacker already possesses the permissions needed to
639+
attach to a process, they could equally use GDB to read memory or inject
640+
code.
641+
642+
The following principles define what is, and is not, considered a security
643+
vulnerability in this feature:
644+
645+
Attaching requires OS-level privileges
646+
On every supported platform the operating system gates cross-process
647+
memory access behind privilege checks (``CAP_SYS_PTRACE``, root, or
648+
administrator rights). A report that demonstrates an issue only after
649+
these privileges have already been obtained is **not** a vulnerability in
650+
CPython, since the OS security boundary was already crossed.
651+
652+
Crashes or memory errors when reading a compromised process are not vulnerabilities
653+
A tool that reads internal interpreter state from a target process must
654+
trust that memory to be well-formed. If the target process has been
655+
corrupted or is controlled by an attacker, the debugger or profiler may
656+
crash, produce garbage output, or behave unpredictably. This is the same
657+
risk accepted by every ``ptrace``-based debugger. Bugs in this category
658+
(buffer overflows, segmentation faults, or undefined behaviour triggered
659+
by reading corrupted state) are **not** treated as security issues, though
660+
fixes that improve robustness are welcome.
661+
662+
Vulnerabilities in the target process are not in scope
663+
If the Python process being debugged has already been compromised, the
664+
attacker already controls execution in that process. Demonstrating further
665+
impact from that starting point does not constitute a vulnerability in the
666+
remote debugging protocol.
667+
668+
When to use ``PYTHON_DISABLE_REMOTE_DEBUG``
669+
-------------------------------------------
670+
671+
The environment variable :envvar:`PYTHON_DISABLE_REMOTE_DEBUG` (and the
672+
equivalent :option:`-X disable_remote_debug` flag) allows operators to disable
673+
the in-process side of the protocol as a **defence-in-depth** measure. This
674+
may be useful in hardened or sandboxed deployment environments where no
675+
debugging or profiling of the process is expected and reducing attack surface
676+
is a priority, even though the OS-level privilege checks already prevent
677+
unprivileged access.
678+
679+
Setting this variable does **not** affect other OS-level debugging interfaces
680+
(``ptrace``, ``/proc``, ``task_for_pid``, etc.), which remain available
681+
according to their own permission models.

Doc/library/argparse.rst

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1111,7 +1111,15 @@ User defined functions can be used as well:
11111111

11121112
The :func:`bool` function is not recommended as a type converter. All it does
11131113
is convert empty strings to ``False`` and non-empty strings to ``True``.
1114-
This is usually not what is desired.
1114+
This is usually not what is desired::
1115+
1116+
>>> parser = argparse.ArgumentParser()
1117+
>>> _ = parser.add_argument('--verbose', type=bool)
1118+
>>> parser.parse_args(['--verbose', 'False'])
1119+
Namespace(verbose=True)
1120+
1121+
See :class:`BooleanOptionalAction` or ``action='store_true'`` for common
1122+
alternatives.
11151123

11161124
In general, the ``type`` keyword is a convenience that should only be used for
11171125
simple conversions that can only raise one of the three supported exceptions.

Doc/library/http.server.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,8 @@ instantiation, of which this module provides three different variants:
287287
specifying its value. Note that, after the send_header calls are done,
288288
:meth:`end_headers` MUST BE called in order to complete the operation.
289289

290+
This method does not reject input containing CRLF sequences.
291+
290292
.. versionchanged:: 3.2
291293
Headers are stored in an internal buffer.
292294

@@ -297,6 +299,8 @@ instantiation, of which this module provides three different variants:
297299
buffered and sent directly the output stream.If the *message* is not
298300
specified, the HTTP message corresponding the response *code* is sent.
299301

302+
This method does not reject *message* containing CRLF sequences.
303+
300304
.. versionadded:: 3.2
301305

302306
.. method:: end_headers()
@@ -622,6 +626,11 @@ Security considerations
622626
requests, this makes it possible for files outside of the specified directory
623627
to be served.
624628

629+
Methods :meth:`BaseHTTPRequestHandler.send_header` and
630+
:meth:`BaseHTTPRequestHandler.send_response_only` assume sanitized input
631+
and does not perform input validation such as checking for the presence of CRLF
632+
sequences. Untrusted input may result in HTTP Header injection attacks.
633+
625634
Earlier versions of Python did not scrub control characters from the
626635
log messages emitted to stderr from ``python -m http.server`` or the
627636
default :class:`BaseHTTPRequestHandler` ``.log_message``

Doc/using/configure.rst

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -838,9 +838,11 @@ See also the :ref:`Python Development Mode <devmode>` and the
838838
:option:`--with-trace-refs` configure option.
839839

840840
.. versionchanged:: 3.8
841-
Release builds and debug builds are now ABI compatible: defining the
841+
Release builds are now ABI compatible with debug builds: defining the
842842
``Py_DEBUG`` macro no longer implies the ``Py_TRACE_REFS`` macro (see the
843-
:option:`--with-trace-refs` option).
843+
:option:`--with-trace-refs` option). However, debug builds still expose
844+
more symbols than release builds and code built against a debug build is not
845+
necessarily compatible with a release build.
844846

845847

846848
Debug options

0 commit comments

Comments
 (0)