Python-nopie: rychlejší Python jako novinka v Debianu a Ubuntu

1. 3. 2023
Doba čtení: 5 minut

Sdílet

 Autor: Python
Nedávno jsem si všiml, že v Ubuntu Jammy jsou nějaké nové balíčky se zvláštními názvy python3-nopie, python3.10-nopie a python3.11-nopie. Co je to za novinky a k čemu by to mohlo být?

Tyto balíčky najdete také v Debianu Bookworm (12) a Sid (unstable). Odsud se dostaly do Ubuntu Jammy (22.04). V popisu balíčků najdeme:

Python interpreter linked without PIE (default python3 version)
This package contains the interpreter not built as position independent executable. This interpreter is diverting the python3 executable, and making the interpreter built with PIE available as python3-pie.

Tedy jde o binární soubory slinkované bez PIE (Position independent executable). Pokud si balíček nainstalujete, dostanete jak binární soubor bez PIE, tak s PIE, ten bude končit na  -pie.

PIE

Co to ten PIE vlastně je a k čemu je dobrý? Spustitelný soubor nezávislý na umístění může použít ASLR (Address Space Layout Randomization), tedy náhodně vybranou adresu a tím ztížit některé útoky. PIE se používá v OpenBSD od roku 2014, OpenSUSE a Fedora jej používá od roku 2015, Ubuntu, Debian a Gentoo pak od roku 2017.

Problém je, že například instrukce skoků musí být v PIE relativní místo absolutních v kódu bez PIE. To přináší jisté zpomalení. Toto zpomalení bylo měřeno například testem SPEC CPU2006 v roce 2012 a na x86 dosáhlo asi 10 %. Na architektuře x86 je obecně málo registrů a jeden musel být použit na relativní adresování. Pro amd64 bylo naměřeno zpomalení jen asi 2 %. Zpomalení tedy závisí na architektuře.

Zajímavé na tom je, že v Debianu a Ubuntu byl až do verze 3.9 Python kompilován bez PIE. Již v roce 2019 byl otevřen požadavek na kompilaci Pythonu s PIE. Požadavek byl však splněn až loni.

Tak se v březnu loňského roku objevil balíček python3.10-nopie a v červnu python3.11-nopie pro ty, co by chtěli Python jako dříve, tedy bez PIE. Zde příklad z arm64:

$ ls -l /usr/bin/python3.1*
-rwxr-xr-x 1 root root 5299528 Nov 14 17:10 /usr/bin/python3.10
-rwxr-xr-x 1 root root 5671928 Nov 14 17:10 /usr/bin/python3.10-pie
-rwxr-xr-x 1 root root 6570216 Aug 12  2022 /usr/bin/python3.11
-rwxr-xr-x 1 root root 6586600 Aug 12  2022 /usr/bin/python3.11-pie

Je vidět, že verze PIE je nepatrně větší. Dá se nějak zkontrolovat, že binární soubory obsahují PIE? Ano, například pomocí  file

$ file /usr/bin/python3.1*
/usr/bin/python3.10:        ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, BuildID[sha1]=db81120a97aab4adf89c723630362ac64b5966dd, for GNU/Linux 3.7.0, stripped
/usr/bin/python3.10-pie:    ELF 64-bit LSB pie executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, BuildID[sha1]=a1841de4f4ec9445a10bff638afa4c72deace9e0, for GNU/Linux 3.7.0, stripped
/usr/bin/python3.11:        ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, BuildID[sha1]=b65600555215df881c09d0544cb410340acc38e8, for GNU/Linux 3.7.0, stripped
/usr/bin/python3.11-pie:    ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, BuildID[sha1]=65f319d75fa662120654ed39ed608b11774bec9b, for GNU/Linux 3.7.0, stripped

Tady vidíme, že python3.11-pie jako by PIE neměl. Zkusíme tedy ještě pro jistotu hardening-checks z balíčku devscripts:

$ hardening-check /usr/bin/python3.11-pie
/usr/bin/python3.11-pie:
 Position Independent Executable: no, normal executable!
 Stack protected: yes
 Fortify Source functions: yes (some protected functions found)
 Read-only relocations: yes
 Immediate binding: no, not found!
 Stack clash protection: unknown, no -fstack-clash-protection instructions found
 Control flow integrity: no, not found!

Takže asi došlo k nějaké chybce při výrobě a python3.11-pie není PIE, i když by měl být. Já jsem celkem rád, protože mi nevycházely testy rychlosti. Ale tato chybka vše vysvětluje.

Toto byly soubory z Ubuntu, ale zkontroloval jsem i Debian Bookworm amd64 i arm64 a v obou případech balíčekpython3.11-minimal_3.11.1-2 obsahuje Python 3.11 bez PIE, i když by ho měl mít.

Ještě poznámka pro ty, co si sami kompilují. Kompilátor gcc může být nastaven, aby ve výchozím stavu produkoval spustitelné soubory s PIE. Debian i Ubuntu to tak mají. Pokud si to nepřejete, je potřeba použít při linkování  -no-pie.

V Gentoo, kde si kompilujete i GCC je k tomuto účelu určen přepínač USE=pie případně  USE=-pie.

Benchmark

Pro získání představy o rychlosti Pythonu s PIE a bez PIE použijeme oficiální benchmark pyperformance a nainstalujeme si ho jako uživatelé pomocí  pip:

python3.10 -m pip install pyperformance
python3.11 -m pip install pyperformance

Tady při instalaci je jedno, jestli použijete Python s PIE nebo bez PIE. Při vlastním testu už to ale samozřejmě jedno není. Testoval jsem na Odroidu M1 s aktuálním Ubuntu 22.04. Odroid M1 má čtyřjádrový Cortex-A55 na téměř 2 GHz. Testy však většinou využívají jen jedno jádro a tak jeden test pyperformance tu trvá asi čtyři hodiny.  Testy spustíme následovně:

python3.10     -m pyperformance run -o py310-nopie.json
python3.10-pie -m pyperformance run -o py310-pie.json
python3.11     -m pyperformance run -o py311-nopie.json
python3.11-pie -m pyperformance run -o py311-pie.json

Příklad běžícího testu pyperformance

Autor: J. Fikar

Na relativní výsledky se můžeme podívat pomocí:

pyperf compare_to py310-pie.json py310-nopie.json --table

Ještě taková maličkost. Aby byly výsledky reprodukovatelnější, dá se k testování naladit systém pomocí sudo pyperf system tune. Po skončení testu se k původním hodnotám vrátíte pomocí sudo pyperf system reset. Bohužel nastavení potřebuje práva roota, je tedy potřeba nainstalovat ještě pyperformance přes pip i pro roota.

Výsledky 310-pie 310-nopie

Autor: J. Fikar

Výsledky 311-pie 311-nopie

Autor: J. Fikar

Výsledky 310-nopie 311-nopie

Autor: J. Fikar

V průměru přes všech 62 testů v pyperformance jsem naměřil, že PIE verze 3.10 je pomalejší o 6 %. Největší rozdíl byl v testu bench_mp_pool a to 38 %. Všechny testy bez PIE byly rychlejší, kromě jediného telco, který byl jen o 1 % pomalejší. V případě 3.11 jsem dostal neočekávaný výsledek, že PIE verze je v průměru o 1 % rychlejší než bez PIE. To se ale vysvětlilo v předchozí kapitole tím, že binární soubor, který měl mít PIE, ho ve skutečnosti nemá.

Ještě by mohlo být zajímavé zajímavé zrychlení mezi 3.10 a 3.11, které by mělo být podle oficiálních měření asi 25 %. Podle mých výsledků mezi verzemi bez PIE je to také průměrně 25 %. Největší zlepšení bylo v testu go a to 1,97×. Naopak největší zhoršení bylo v testu coverage a to 6,35×.

ict ve školství 24

Je to pro mě?

Jsou tedy tyto nové balíčky pyhon3-nopie, python3.10-nopie a python3.11-nopie pro vás? Nainstalujte si je, pokud potřebujete rychlý Python. Ale nezapomeňte udělat benchmark vaší aplikace, výsledek může záviset na architektuře i na vašem programu.

Pokud máte radši bezpečnost, tak je prostě neinstalujte a od verze 3.10 budete mít automaticky Python s PIE. Pokud se tedy problém s PIE u 3.11 vyřeší.

Autor článku

První linux nainstaloval kolem roku 1994 a u něj zůstal. Později vystudoval fyziku a získal doktorát.