Skip to main content

Scans Python wheels for abi3 violations and inconsistencies

Project description

abi3audit

Tests PyPI version Packaging status

Read the Trail of Bits blog post about how we find bugs with abi3audit!

abi3audit scans Python extensions for abi3 violations and inconsistencies.

It can scan individual (unpackaged) shared objects, packaged wheels, or entire package version histories.

An animated demonstration of abi3audit in action

This project is maintained in part by Trail of Bits. This is not an official Trail of Bits product.

Index

Motivation

CPython (the reference implementation of Python) defines a stable API and corresponding ABI ("abi3"). In principle, any CPython extension can be built against this API/ABI and will remain forward compatible with future minor versions of CPython. In other words: if you build against the stable ABI for Python 3.5, your extension should work without modification on Python 3.9.

The stable ABI simplifies packaging of CPython extensions, since the packager only needs to build one abi3 wheel that targets the minimum supported Python version.

To signal that a Python wheel contains abi3-compatible extensions, the Python packaging ecosystem uses the abi3 wheel tag, e.g.:

pyrage-1.0.1-cp37-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.whl

Unfortunately, there is no actual enforcement of abi3 compliance in Python extensions at install or runtime: a wheel (or independent shared object) that is tagged as abi3 is assumed to be abi3, but is not validated in any way.

To make matters worse, there is no formal connection between the flag (--py-limited-api) that controls wheel tagging and the build macros (Py_LIMITED_API) that actually lock a Python extension into a specific abi3 version.

As a result: it is very easy to compile a Python extension for the wrong abi3 version, or to tag a Python wheel as abi3 without actually compiling it as abi3-compatible.

This has serious security and reliability implications: non-stable parts of the CPython ABI can change between minor versions, resulting in crashes, unpredictable behavior, or potentially exploitable memory corruption when a Python extension incorrectly assumes the parameters of a function or layout of a structure.

Installation

abi3audit is available via pip:

pip install abi3audit

Usage

You can run abi3audit as a standalone program, or via python -m abi3audit:

abi3audit --help
python -m abi3audit --help

Examples

Audit a single shared object, wheel, or PyPI package:

# audit a local copy of an abi3 extension
abi3audit procmaps.abi3.so

# audit a local copy of an abi3 wheel
abi3audit procmaps-0.5.0-cp36-abi3-manylinux2010_x86_64.whl

# audit every abi3 wheel for the package 'procmaps' on PyPI
abi3audit procmaps

Show additional detail (pretty tables and individual violations) while auditing:

abi3audit procmaps --verbose

yields:

[17:59:46] ๐Ÿ‘Ž procmaps:
           procmaps-0.5.0-cp36-abi3-manylinux2010_x86_64.whl: procmaps.abi3.so
           uses the Python 3.10 ABI, but is tagged for the Python 3.6 ABI
           โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”“
           โ”ƒ Symbol                  โ”ƒ Version โ”ƒ
           โ”กโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ฉ
           โ”‚ PyUnicode_AsUTF8AndSize โ”‚ 3.10    โ”‚
           โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
[17:59:47] ๐Ÿ’ procmaps: 2 extensions scanned; 1 ABI version mismatches and 0
           ABI violations found

Generate a JSON report for each input:

abi3audit procmaps --report | python -m json.tool

yields:

{
  "specs": {
    "procmaps": {
      "kind": "package",
      "package": {
        "procmaps-0.5.0-cp36-abi3-manylinux2010_x86_64.whl": [
          {
            "name": "procmaps.abi3.so",
            "result": {
              "is_abi3": true,
              "is_abi3_baseline_compatible": false,
              "baseline": "3.6",
              "computed": "3.10",
              "non_abi3_symbols": [],
              "future_abi3_objects": {
                "PyUnicode_AsUTF8AndSize": "3.10"
              }
            }
          }
        ],
        "procmaps-0.6.1-cp37-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.whl": [
          {
            "name": "procmaps.abi3.so",
            "result": {
              "is_abi3": true,
              "is_abi3_baseline_compatible": true,
              "baseline": "3.7",
              "computed": "3.7",
              "non_abi3_symbols": [],
              "future_abi3_objects": {}
            }
          }
        ]
      }
    }
  }
}

Limitations

abi3audit is a best-effort tool, with some of the same limitations as auditwheel. In particular:

  • abi3audit cannot check for dynamic abi3 violations, such as an extension that calls dlsym(3) to invoke a non-abi3 function at runtime.

  • abi3audit can confirm the presence of abi3-compatible symbols, but does not have an exhaustive list of abi3-incompatible symbols. Instead, it looks for violations by looking for symbols that start with Py_ or _Py_ that are not in the abi3 compatibility list. This is unlikely to result in false positives, but could if an extension incorrectly uses those reserved prefixes.

  • When auditing a "bare" shared object (e.g. foo.abi3.so), abi3audit cannot assume anything about the minimum intended abi3 version. Instead, it defaults to the lowest known abi3 version (abi3-cp32) and warns on any version mismatches (e.g., a symbol that was only stabilized in 3.6). This can result in false positives, so users are encouraged to audit entire wheels or packages instead (since they contain the sufficient metadata).

  • abi3audit considers the abi3 version when a symbol was stabilized, not introduced. In other words: abi3audit will produce a warning when an abi3-cp36 extension contains a function stabilized in 3.7, even if that function was introduced in 3.6. This is not a false positive (it is an ABI version mismatch), but it's generally not a source of bugs.

  • abi3audit checks both the "local" and "external" symbols for each extension, for formats that support both. It does this to catch symbols that have been inlined, such as _Py_DECREF. However, if the extension's symbol table has been stripped, these may be missed.

Licensing

abi3audit is licensed under the MIT license.

abi3audit includes ASN.1 and Mach-O parsers generated from definitions provided by the Kaitai Struct project. These vendored parsers are licensed by the Kaitai Struct authors under the MIT license.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

abi3audit-0.0.26.tar.gz (29.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

abi3audit-0.0.26-py3-none-any.whl (30.3 kB view details)

Uploaded Python 3

File details

Details for the file abi3audit-0.0.26.tar.gz.

File metadata

  • Download URL: abi3audit-0.0.26.tar.gz
  • Upload date:
  • Size: 29.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for abi3audit-0.0.26.tar.gz
Algorithm Hash digest
SHA256 44b5fa5ddc8acdfdbd221f400d48b8a205df519e8f4c6d57a349837ac88d0ff8
MD5 5bfa21fd3f4cf8634de53d4d7a11f43c
BLAKE2b-256 992dfa16448d36021e36caa71acda36e25be8f6315b9c740b1be8bdae5c76257

See more details on using hashes here.

Provenance

The following attestation bundles were made for abi3audit-0.0.26.tar.gz:

Publisher: release.yml on pypa/abi3audit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file abi3audit-0.0.26-py3-none-any.whl.

File metadata

  • Download URL: abi3audit-0.0.26-py3-none-any.whl
  • Upload date:
  • Size: 30.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for abi3audit-0.0.26-py3-none-any.whl
Algorithm Hash digest
SHA256 b94b774984e50ec03481c1dda88c48079f6baec870b263bf7f5e7415feb8802d
MD5 f3ed026bfa4452b5e015176a85a6bf9b
BLAKE2b-256 75a84bbc458cc2dcb14b0a13be9593bb70f7d424c8244e632e16dbf4aa6cb778

See more details on using hashes here.

Provenance

The following attestation bundles were made for abi3audit-0.0.26-py3-none-any.whl:

Publisher: release.yml on pypa/abi3audit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page