Repository navigation
Conversation
… for signed entries.
…MAC tag over the pickle and the cache key and checks the tag before unpickling.
…nce, SECURITY.md and the changelog.
Documentation build overview
|
…stem treats as absolute, which on Windows needs a drive since Python 3.13.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
SafeDisk.with_signing(), an opt-in disk for libraries that cache their own objects, which no allowlist can hold: parsed databases whose pickles call functions, torch models, application objects,requests.Response. Testing diskcache-community 5.8.2 against 42 downstream libraries found five that need it (cantools, pywander, pyjinhx, fluke-fl, holobench). Each one's fallback on 5.8.3 narrows what it caches or puts HMAC code into the library itself. With this disk, the change on their side is a few lines.Nothing existing changes unless
with_signing()is called. No other disk behaves differently, and thecache.dbschema and the file layout are the same. It is new, security-sensitive API in a patch release, and the changelog gives it a section of its own.What it does
UnpicklingError, or reads as missing withon_error='miss'. That includes every unsigned pickle, plain data included, so the allowlist is not used for values on a signing disk.str,bytes,intandfloatvalues are stored as on every disk, unsigned.with_typeswidens what they may hold.filenamepointed at another row's value file.1and1.0, and0.0and-0.0, as one key.TypeError, because SQLite stores them as NULL. That bug exists on every disk today.pushhashes the pickle before its transaction and adds the key once the transaction has chosen it, so the write lock is held only for microseconds.Row format
modestaysMODE_PICKLE.valuecolumn always starts with 45 bytes:b'\xffDCS';header ‖ pickle ‖ key ‖ len(key).0xffis not a pickle opcode, so diskcache 5.6.3 and every existing disk raiseUnpicklingError: invalid load key, '\xff'on a signed row before reading anything else, or delete it underon_error='miss'. A new test intest_golden.pychecks this with a real 5.6.3 interpreter in the coexist job.SafeDiskwithout signing now says the row is a signed entry.Keys
$DISKCACHE_SIGNING_KEY_FILE, otherwisesigning.keyin adiskcache-communityfolder of the user's local data directory:$XDG_DATA_HOMEor~/.local/shareon Linux;~/Library/Application Supporton macOS;%LOCALAPPDATA%on Windows.0600in a0700folder. It is written to a temporary file and hard-linked into place, so processes that start together end up with the same key.ValueError. The check compares device and inode, so another letter case on macOS and symlinks are caught, andFanoutCachealso checks its own root;OSErrorand namesDISKCACHE_SIGNING_KEY_FILE.key=: takes 32 or more bytes held only in memory, for caches that live in one process (fluke-fl). Pickling a cache that uses it raisesTypeError.CacheorFanoutCache, in a repr, or as bytes in an attribute. The disk holds a keyedhmac.HMACobject instead.Changes outside the new module
core.py:fetchcall sites inCachepass the row's key only when the disk signs, and other disks are called exactly as before;pushsigns once the key is chosen;SafeDiskgainswith_signing, and itsput,storeandfetchgain a branch for signing disks;with_numpy()andwith_signing()refuse to combine;SafeJSONDisk.with_signing()raises.fanout.pychecks the key file against the fanout root, since each shard's disk sees only its shard..pylintrcraisesmax-module-linesfrom 4300 to 4400, sincecore.pyis now 4359 lines.Not in this PR
resign()was in an earlier draft and was removed after review, because running it on a shared or restored cache would sign planted rows.Testing
signing.pyis at 100%.tests/typecheck_stubs.py), pylint (10.00/10) and doc8 are clean;-W;gethit,getmiss andsetagainst master is within noise. For a signing disk, a smallgetcosts about 1 µs more. A 1 MiB file row reads in 0.8 ms instead of 0.06 ms, because of the two passes. A smallsetis faster than plainSafeDisk, because it skips the allowlist scan.