lib/commit: autofix permissions for bare-user-only
authorLuca BRUNO <luca.bruno@coreos.com>
Fri, 20 Aug 2021 10:58:24 +0000 (10:58 +0000)
committerLuca BRUNO <luca.bruno@coreos.com>
Fri, 20 Aug 2021 16:11:04 +0000 (16:11 +0000)
This tweaks commit logic to detect bare-user-only repositories and
canonicalize permissions automatically.

src/libostree/ostree-repo-commit.c
src/libostree/ostree-repo.h
tests/basic-test.sh
tests/test-basic-user-only.sh

index c07526fca7d18967a56d3372a3de3b3ebdae8e70..249e792c3b2f8372340e8be7821192a3b4c90131 100644 (file)
@@ -3286,22 +3286,35 @@ _ostree_repo_commit_modifier_apply (OstreeRepo               *self,
                                     GFileInfo                *file_info,
                                     GFileInfo               **out_modified_info)
 {
+  gboolean canonicalize_perms = FALSE;
+  gboolean has_filter = FALSE;
   OstreeRepoCommitFilterResult result = OSTREE_REPO_COMMIT_FILTER_ALLOW;
   GFileInfo *modified_info;
 
-  if (modifier == NULL ||
-      (modifier->filter == NULL &&
-       (modifier->flags & OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CANONICAL_PERMISSIONS) == 0))
+  /* Auto-detect bare-user-only repo, force canonical permissions. */
+  if (self->mode == OSTREE_REPO_MODE_BARE_USER_ONLY)
+    canonicalize_perms = TRUE;
+
+  if (modifier != NULL)
+    {
+      if ((modifier->flags & OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CANONICAL_PERMISSIONS) != 0)
+        canonicalize_perms = TRUE;
+      if (modifier->filter != NULL)
+        has_filter = TRUE;
+    }
+
+  if (!(canonicalize_perms || has_filter))
     {
       *out_modified_info = g_object_ref (file_info);
-      return OSTREE_REPO_COMMIT_FILTER_ALLOW;
+      return OSTREE_REPO_COMMIT_FILTER_ALLOW; /* Note: early return (no actions needed) */
     }
 
   modified_info = g_file_info_dup (file_info);
-  if (modifier->filter)
+
+  if (has_filter)
     result = modifier->filter (self, path, modified_info, modifier->user_data);
 
-  if ((modifier->flags & OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CANONICAL_PERMISSIONS) != 0)
+  if (canonicalize_perms)
     {
       guint mode = g_file_info_get_attribute_uint32 (modified_info, "unix::mode");
       switch (g_file_info_get_file_type (file_info))
@@ -3618,8 +3631,8 @@ write_content_to_mtree_internal (OstreeRepo                  *self,
   /* Load flags into boolean constants for ease of readability (we also need to
    * NULL-check modifier)
    */
-  const gboolean canonical_permissions = modifier &&
-    (modifier->flags & OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CANONICAL_PERMISSIONS);
+  const gboolean canonical_permissions = self->mode == OSTREE_REPO_MODE_BARE_USER_ONLY ||
+    (modifier && (modifier->flags & OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CANONICAL_PERMISSIONS));
   const gboolean devino_canonical = modifier &&
     (modifier->flags & OSTREE_REPO_COMMIT_MODIFIER_FLAGS_DEVINO_CANONICAL);
   /* We currently only honor the CONSUME flag in the dfd_iter case to avoid even
index 08d3d408bec9ac12cde2d5e5f9e9f28869f18aaa..1a9aa325360ffc115cadc244e03b56ce6fc10c56 100644 (file)
@@ -678,10 +678,14 @@ typedef OstreeRepoCommitFilterResult (*OstreeRepoCommitFilter) (OstreeRepo    *r
  * @OSTREE_REPO_COMMIT_MODIFIER_FLAGS_NONE: No special flags
  * @OSTREE_REPO_COMMIT_MODIFIER_FLAGS_SKIP_XATTRS: Do not process extended attributes
  * @OSTREE_REPO_COMMIT_MODIFIER_FLAGS_GENERATE_SIZES: Generate size information.
- * @OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CANONICAL_PERMISSIONS: Canonicalize permissions for bare-user-only mode.
+ * @OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CANONICAL_PERMISSIONS: Canonicalize permissions.
  * @OSTREE_REPO_COMMIT_MODIFIER_FLAGS_ERROR_ON_UNLABELED: Emit an error if configured SELinux policy does not provide a label
  * @OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CONSUME: Delete added files/directories after commit; Since: 2017.13
  * @OSTREE_REPO_COMMIT_MODIFIER_FLAGS_DEVINO_CANONICAL: If a devino cache hit is found, skip modifier filters (non-directories only); Since: 2017.14
+ *
+ * Flags modifying commit behavior. In bare-user-only mode, @OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CANONICAL_PERMISSIONS
+ * is automatically enabled.
+ *
  */
 typedef enum {
   OSTREE_REPO_COMMIT_MODIFIER_FLAGS_NONE = 0,
index 89d352737f7c8a8e7ff30f83ae840a75322e90e2..7946ffa394e05d2a866dfcabf3177afb8dda9f9c 100644 (file)
@@ -31,7 +31,7 @@ if is_bare_user_only_repo repo; then
     # In bare-user-only repos we can only represent files with uid/gid 0, no
     # xattrs and canonical permissions, so we need to commit them as such, or
     # we end up with repos that don't pass fsck
-    COMMIT_ARGS="--canonical-permissions --no-xattrs"
+    COMMIT_ARGS="--no-xattrs"
     DIFF_ARGS="--owner-uid=0 --owner-gid=0 --no-xattrs"
     # Also, since we can't check out uid=0 files we need to check out in user mode
     CHECKOUT_U_ARG="-U"
index 02129b280b8791c1f42b594ac1bb66fbcce9b323..7ef153c38a0635d54cd019221d3467ceec3a0594 100755 (executable)
@@ -25,7 +25,7 @@ set -euo pipefail
 
 mode="bare-user-only"
 setup_test_repository "$mode"
-extra_basic_tests=6
+extra_basic_tests=7
 . $(dirname $0)/basic-test.sh
 
 $CMD_PREFIX ostree --version > version.yaml
@@ -112,3 +112,15 @@ $OSTREE checkout --force-copy perms out
 $OSTREE checkout ${CHECKOUT_H_ARGS} --union-identical perms out
 $OSTREE fsck
 echo "ok checkout checksum with canonical perms"
+
+cd ${test_tmpdir}
+rm repo -rf
+ostree_repo_init repo init --mode=bare-user-only
+rm files -rf && mkdir files
+echo afile > files/afile
+$OSTREE commit ${COMMIT_ARGS} -b perms files
+rm out -rf
+$OSTREE checkout --force-copy perms out
+$OSTREE checkout ${CHECKOUT_H_ARGS} --union-identical perms out
+$OSTREE fsck
+echo "ok automatic canonical perms for bare-user-only"