summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuca BRUNO <luca.bruno@coreos.com>2022-03-02 16:45:00 +0000
committerLuca BRUNO <luca.bruno@coreos.com>2022-03-02 16:45:00 +0000
commit08e98e904289464e00cd68ac7aa675d23d78971f (patch)
tree1eb454a0a3443aa17850a24f8adf9fbe75e87299
parent2c60f302f91e3aa9ba343261b09b5a0e3d188b28 (diff)
downloadostree-08e98e904289464e00cd68ac7aa675d23d78971f.tar.gz
lib/core: introduce 'bare-split-xattrs' mode
-rw-r--r--Makefile-tests.am1
-rw-r--r--docs/formats.md24
-rw-r--r--docs/repo.md32
-rw-r--r--src/libostree/ostree-core-private.h3
-rw-r--r--src/libostree/ostree-core.c1
-rw-r--r--src/libostree/ostree-core.h2
-rw-r--r--src/libostree/ostree-repo.c5
-rwxr-xr-xtests/test-basic-bare-split-xattrs.sh25
8 files changed, 82 insertions, 11 deletions
diff --git a/Makefile-tests.am b/Makefile-tests.am
index 6bae65cf..5c97bd84 100644
--- a/Makefile-tests.am
+++ b/Makefile-tests.am
@@ -59,6 +59,7 @@ test_programs = \
$(NULL)
_installed_or_uninstalled_test_scripts = \
tests/test-basic.sh \
+ tests/test-basic-bare-split-xattrs.sh \
tests/test-basic-user.sh \
tests/test-basic-user-only.sh \
tests/test-basic-root.sh \
diff --git a/docs/formats.md b/docs/formats.md
index 0943aafa..c3723279 100644
--- a/docs/formats.md
+++ b/docs/formats.md
@@ -63,18 +63,32 @@ Other disadvantages of `archive`:
- One doesn't know the total size (compressed or uncompressed) of content
before downloading everything
-## Aside: the bare and bare-user formats
+## Aside: bare formats
-The most common operation is to pull from an `archive` repository
-into a `bare` or `bare-user` formatted repository. These latter two
-are not compressed on disk. In other words, pulling to them is
-similar to unpacking (but not installing) an RPM/deb package.
+The most common operation is to pull from a remote `archive` repository
+into a local one. This latter is not compressed on disk. In other
+words, pulling to a local repository is similar to unpacking (but not
+installing) the content of an RPM/deb package.
+
+The `bare` repository format is the simplest one. In this mode regular files
+are directly stored to disk, and all metadata (e.g. uid/gid and xattrs) is
+reflected to the filesystem.
+It allows further direct access to content and metadata, but it may require
+elevated privileges when writing objects to the repository.
The `bare-user` format is a bit special in that the uid/gid and xattrs
from the content are ignored. This is primarily useful if you want to
have the same OSTree-managed content that can be run on a host system
or an unprivileged container.
+Similarly, the `bare-split-xattrs` format is a special mode where xattrs
+are stored as separate repository objects, and not directly reflected to
+the filesystem.
+This is primarily useful when transporting xattrs through lossy environments
+(e.g. tar streams and containerized environments). It also allows carrying
+security-sensitive xattrs (e.g. SELinux labels) out-of-band without involving
+OS filesystem logic.
+
## Static deltas
OSTree itself was originally focused on a continuous delivery model, where
diff --git a/docs/repo.md b/docs/repo.md
index 69f26172..580281ca 100644
--- a/docs/repo.md
+++ b/docs/repo.md
@@ -81,15 +81,37 @@ warnings such as GNU Tar emitting "implausibly old time stamp" with 0; however,
until we have a mechanism to transition cleanly to 1, for compatibilty OSTree
is reverted to use zero again.
+### Xattrs objects
+
+In some repository modes (e.g. `bare-split-xattrs`), xattrs are stored on the
+side of the content objects they refer to. This is done via two dedicated
+object types, `file-xattrs` and `file-xattrs-link`.
+
+`file-xattrs` store xattrs data, encoded as GVariant. Each object is keyed by
+the checksum of the xattrs content, allowing for multiple references.
+
+`file-xattrs-link` are hardlinks which are associated to file objects.
+Each object is keyed by the same checksum of the corresponding file
+object. The target of the hardlink is an existing `file-xattrs` object.
+In case of reaching the limit of too many links, this object could be
+a plain file too.
+
# Repository types and locations
-Also unlike git, an OSTree repository can be in one of four separate
-modes: `bare`, `bare-user`, `bare-user-only`, and `archive`. A bare repository is
-one where content files are just stored as regular files; it's
-designed to be the source of a "hardlink farm", where each operating
-system checkout is merely links into it. If you want to store files
+Also unlike git, an OSTree repository can be in one of five separate
+modes: `bare`, `bare-split-xattrs, ``bare-user`, `bare-user-only`, and
+`archive`.
+
+A `bare` repository is one where content files are just stored as regular
+files; it's designed to be the source of a "hardlink farm", where each
+operating system checkout is merely links into it. If you want to store files
owned by e.g. root in this mode, you must run OSTree as root.
+The `bare-split-xattrs` mode is similar to the above one, but it does store
+xattrs as separate objects. This is meant to avoid conflicts with
+kernel-enforced constraints (e.g. on SELinux labels) and with other softwares
+that may perform ephemeral changes to xattrs (e.g. container runtimes).
+
The `bare-user` mode is a later addition that is like `bare` in that
files are unpacked, but it can (and should generally) be created as
non-root. In this mode, extended metadata such as owner uid, gid, and
diff --git a/src/libostree/ostree-core-private.h b/src/libostree/ostree-core-private.h
index 34f86a6c..2bd2f984 100644
--- a/src/libostree/ostree-core-private.h
+++ b/src/libostree/ostree-core-private.h
@@ -197,7 +197,8 @@ _ostree_repo_mode_is_bare (OstreeRepoMode mode)
return
mode == OSTREE_REPO_MODE_BARE ||
mode == OSTREE_REPO_MODE_BARE_USER ||
- mode == OSTREE_REPO_MODE_BARE_USER_ONLY;
+ mode == OSTREE_REPO_MODE_BARE_USER_ONLY ||
+ mode == OSTREE_REPO_MODE_BARE_SPLIT_XATTRS;
}
#ifndef OSTREE_DISABLE_GPGME
diff --git a/src/libostree/ostree-core.c b/src/libostree/ostree-core.c
index 2ff72086..f0d0e698 100644
--- a/src/libostree/ostree-core.c
+++ b/src/libostree/ostree-core.c
@@ -39,6 +39,7 @@ G_STATIC_ASSERT(OSTREE_REPO_MODE_ARCHIVE_Z2 == 1);
G_STATIC_ASSERT(OSTREE_REPO_MODE_ARCHIVE == OSTREE_REPO_MODE_ARCHIVE_Z2);
G_STATIC_ASSERT(OSTREE_REPO_MODE_BARE_USER == 2);
G_STATIC_ASSERT(OSTREE_REPO_MODE_BARE_USER_ONLY == 3);
+G_STATIC_ASSERT(OSTREE_REPO_MODE_BARE_SPLIT_XATTRS == 4);
static GBytes *variant_to_lenprefixed_buffer (GVariant *variant);
diff --git a/src/libostree/ostree-core.h b/src/libostree/ostree-core.h
index 638c40ac..9a14192d 100644
--- a/src/libostree/ostree-core.h
+++ b/src/libostree/ostree-core.h
@@ -193,6 +193,7 @@ typedef enum {
* @OSTREE_REPO_MODE_ARCHIVE_Z2: Legacy alias for `OSTREE_REPO_MODE_ARCHIVE`
* @OSTREE_REPO_MODE_BARE_USER: Files are stored as themselves, except ownership; can be written by user. Hardlinks work only in user checkouts.
* @OSTREE_REPO_MODE_BARE_USER_ONLY: Same as BARE_USER, but all metadata is not stored, so it can only be used for user checkouts. Does not need xattrs.
+ * @OSTREE_REPO_MODE_BARE_SPLIT_XATTRS: Same as BARE_USER, but xattrs are stored separately from file content, with dedicated object types.
*
* See the documentation of #OstreeRepo for more information about the
* possible modes.
@@ -203,6 +204,7 @@ typedef enum {
OSTREE_REPO_MODE_ARCHIVE_Z2 = OSTREE_REPO_MODE_ARCHIVE,
OSTREE_REPO_MODE_BARE_USER,
OSTREE_REPO_MODE_BARE_USER_ONLY,
+ OSTREE_REPO_MODE_BARE_SPLIT_XATTRS,
} OstreeRepoMode;
/**
diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c
index 6c541029..71a01d59 100644
--- a/src/libostree/ostree-repo.c
+++ b/src/libostree/ostree-repo.c
@@ -2704,6 +2704,9 @@ ostree_repo_mode_to_string (OstreeRepoMode mode,
/* Legacy alias */
ret_mode ="archive-z2";
break;
+ case OSTREE_REPO_MODE_BARE_SPLIT_XATTRS:
+ ret_mode = "bare-split-xattrs";
+ break;
default:
return glnx_throw (error, "Invalid mode '%d'", mode);
}
@@ -2734,6 +2737,8 @@ ostree_repo_mode_from_string (const char *mode,
else if (strcmp (mode, "archive-z2") == 0 ||
strcmp (mode, "archive") == 0)
ret_mode = OSTREE_REPO_MODE_ARCHIVE;
+ else if (strcmp (mode, "bare-split-xattrs") == 0)
+ ret_mode = OSTREE_REPO_MODE_BARE_SPLIT_XATTRS;
else
return glnx_throw (error, "Invalid mode '%s' in repository configuration", mode);
diff --git a/tests/test-basic-bare-split-xattrs.sh b/tests/test-basic-bare-split-xattrs.sh
new file mode 100755
index 00000000..8bd6430d
--- /dev/null
+++ b/tests/test-basic-bare-split-xattrs.sh
@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+#
+# SPDX-License-Identifier: LGPL-2.0+
+
+set -euo pipefail
+
+. $(dirname $0)/libtest.sh
+
+mode="bare-split-xattrs"
+OSTREE="${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo"
+
+cd ${test_tmpdir}
+${OSTREE} init --mode "${mode}"
+${OSTREE} config get core.mode > mode.txt
+assert_file_has_content mode.txt "${mode}"
+tap_ok "repo init"
+rm -rf -- repo mode.txt
+
+cd ${test_tmpdir}
+${OSTREE} init --mode "${mode}"
+${OSTREE} fsck --all
+tap_ok "repo fsck"
+rm -rf -- repo
+
+tap_end