-
-
Notifications
You must be signed in to change notification settings - Fork 876
repository: single config/config text object (repo version 5) #10377
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -125,7 +125,7 @@ rebuilt the index from it. Rewriting such a pack is repository-level repair, see | |
|
|
||
| ``OBJ_MAGIC`` occurs inside the payloads as well, so the scan accepts a candidate | ||
| only when it validates like any walked header. Validating needs the key, so a | ||
| repair that cannot read the manifest walks without it. | ||
| repair that cannot load the key walks without it. | ||
|
|
||
| In the ``none-*`` modes the tag is an unkeyed checksum, and in the | ||
| ``authenticated-*`` modes it binds a blob to its chunk id and nothing else (see | ||
|
|
@@ -354,22 +354,19 @@ without decrypting any blob and without the repository key. | |
| Repository Version | ||
| ------------------ | ||
|
|
||
| Repositories using pack files require repository version **4**, and the version is the | ||
| only gate for the pack format. | ||
| Repositories using pack files require repository version **4** or later, and the version | ||
| is the only gate for the pack format. | ||
|
Comment on lines
+357
to
+358
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 5 or later |
||
|
|
||
| ``Repository.create()`` stores ``4`` as the ``config/version`` store object. | ||
| ``Repository.save_config()`` stores the version in the repository config (see | ||
| :ref:`repo_config`; currently ``5``, which also introduced the config object itself). | ||
| ``Repository.open()`` reads it back and, if it is not in | ||
| ``Repository.acceptable_repo_versions`` (currently ``(4,)``), closes the store again | ||
| ``Repository.acceptable_repo_versions`` (currently ``(5,)``), closes the store again | ||
| and raises ``InvalidRepositoryConfig`` -- before any repository data is read. A borg | ||
| version that only accepts version 3 rejects a version 4 repository the same way, so | ||
| the version bump alone locks out every client that does not know about packs. | ||
|
Comment on lines
365
to
366
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove this |
||
|
|
||
| Borg does have a feature flag mechanism for locking out clients more selectively | ||
| (``Manifest.check_repository_compatibility()``, fed from a ``feature_flags`` entry in | ||
| the manifest ``config`` -- see :ref:`manifest`), but it currently defines no flags at | ||
| all: ``Manifest.SUPPORTED_REPO_FEATURES`` is the empty set, and no borg code writes a | ||
| ``feature_flags`` entry. On a repository borg creates, the compatibility check is | ||
| therefore a no-op; there is in particular no ``pack_files`` feature flag. | ||
|
|
||
| There is no migration path from version 3 repositories to version 4. Users of the | ||
| version 3 beta format must create a new repository with ``borg repo-create``. | ||
| There is no migration path between the beta repository versions: neither from | ||
| version 3 to 4 (the pack format) nor from version 4 to 5 (the repository config | ||
| object). Users of an older beta format must create a new repository with | ||
| ``borg repo-create`` (and can use ``borg transfer`` with a borg version that | ||
| still reads the old repository to copy their archives over). | ||
|
Comment on lines
+368
to
+372
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove this |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -71,7 +71,7 @@ Above used to be all for borg 1.x and was the reason why it needed the | |
| tertiary authentication mechanism (TAM) for manifest and archives. | ||
|
|
||
| borg 2 now stores the ro_type ("meaning") of a repo object's data into that | ||
| object's metadata (like e.g.: manifest vs. archive vs. user file content data). | ||
| object's metadata (like e.g.: archive metadata vs. user file content data). | ||
| When loading data from the repo, borg verifies that the type of object it got | ||
| matches the type it wanted. borg 2 does not use TAMs any more. | ||
|
|
||
|
|
@@ -87,7 +87,7 @@ carry an unkeyed checksum rather than a MAC, and an attacker who modifies an | |
| object can simply recompute it. What still constrains an attacker there is the | ||
| object ID being the (unkeyed) hash of the plaintext: the content of an existing | ||
| object can not be replaced without the ID no longer matching. But the object's | ||
| metadata, the archives list and the manifest are not anchored to anything secret, | ||
| metadata and the archives list are not anchored to anything secret, | ||
| so a ``none-*`` repository provides no tamper protection - only detection of | ||
| accidental corruption. | ||
|
|
||
|
|
@@ -384,8 +384,29 @@ used: | |
| repository objects, so the pointer object itself only reveals the archive id (a MAC | ||
| over the archive metadata) plus whatever the store records about it, e.g. its | ||
| modification time. | ||
| - ``config/manifest`` (an encrypted repository object), plus the plaintext | ||
| ``config/version``, ``config/id`` and ``config/readme``. | ||
| - ``config/config`` -- the plaintext repository config: version, id and the names of | ||
| the crypto suite (encryption mode, id hash), see :ref:`repo_config`. It is neither | ||
| encrypted nor authenticated, so an attacker with repository access can rewrite the | ||
| crypto suite - just like they could replace the manifest object that used to identify | ||
| the key type in borg 1.x and earlier borg 2 versions, whose type byte was also read | ||
| before anything was authenticated. What protects against a swapped crypto suite is | ||
|
Comment on lines
+390
to
+392
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do not talk about the manifest or borg 1.x |
||
| not this object, but: | ||
|
|
||
| - a swap to a suite that does not encrypt (``none-*``, but also | ||
| ``authenticated-*``: its key blob carries the same key material and no suite | ||
| name, so it loads fine) would make the client write plaintext. That is caught | ||
| by the client's security directory: it records the key type of every | ||
| repository the client accessed, and borg refuses to continue with | ||
| ``EncryptionMethodMismatch`` if the suite changed. A repository that does not | ||
| encrypt and is unknown to the client is only accessed after an explicit | ||
| confirmation (``BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK``). Note that this | ||
| requires the client environment to be persistent, see `Attack model`_. | ||
| - a swap between encrypting suites can not expose plaintext: the client | ||
| would write new objects with the same secret key material under the other | ||
| cipher, and merely fail to read the existing objects. On a client that knows | ||
| the repository, the security directory catches this swap as well. The key blobs | ||
| themselves are bound to the repository id and unlocked by the passphrase, so a | ||
| client never ends up using key material of the attacker's choice. | ||
| - ``keys/<store hash>`` -- in ``repokey`` mode, the borg key(s), encrypted with the | ||
| passphrase-derived KEK (see :ref:`key_encryption`). | ||
| - ``locks/*`` and ``cache/*``. Note that the per-archive reference caches | ||
|
|
@@ -492,7 +513,7 @@ Note that the msgpack unpackers of the RPC data channel (``get_limited_unpacker( | |
| kinds ``client`` and ``server``) are deliberately configured with the maximum buffer | ||
| size, because whole repository objects are transferred through them. They therefore | ||
| do not bound the memory a peer can make the other side allocate; the stricter limits | ||
| of that helper apply to manifest, archive and key data. | ||
| of that helper apply to archive and key data. | ||
|
|
||
| The msgpack implementation used (msgpack-python) has a good security track record, | ||
| a large test suite and no issues found by fuzzing. It is based on the msgpack-c implementation, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove this.