lib/repo: For bare-user, mask content object modes with 0775
authorColin Walters <walters@verbum.org>
Mon, 5 Jun 2017 15:32:52 +0000 (11:32 -0400)
committerAtomic Bot <atomic-devel@projectatomic.io>
Thu, 8 Jun 2017 06:50:16 +0000 (06:50 +0000)
Having every object in a bare-user repo (and checkouts) be executable
is ugly.  I can't think of a good reason to do that; they should only
be executable if their input is.  This does
for `bare-user` what we did for `bare-user-only` in
https://github.com/ostreedev/ostree/pull/909
It's also a stronger version of what we do with `checkout -U` in suppressing
suid - here we also strip world-writable files and the sticky bit (even though
that's meaningless today, it might not be in the future).

Closes: https://github.com/ostreedev/ostree/issues/907
Closes: #908
Approved by: alexlarsson

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

index 3ecea29da300be759732be38a882754298d48d62..da0a5cdcb87b9c4e2f777bc6188e95ba4df0a39d 100644 (file)
@@ -283,19 +283,19 @@ commit_loose_object_trusted (OstreeRepo        *self,
       if (objtype == OSTREE_OBJECT_TYPE_FILE &&
           self->mode == OSTREE_REPO_MODE_BARE_USER)
         {
+          if (!write_file_metadata_to_xattr (fd, uid, gid, mode, xattrs, error))
+            return FALSE;
+
           if (!object_is_symlink)
             {
-              /* We need to apply at least some mode bits, because the repo file was created
-                 with mode 644, and we need e.g. exec bits to be right when we do a user-mode
-                 checkout. To make this work we apply all user bits and the read bits for
-                 group/other.  Furthermore, setting user xattrs requires write access, so
-                 this makes sure it's at least writable by us.  (O_TMPFILE uses mode 0 by default) */
-              if (fchmod (fd, mode | 0744) < 0)
-                return glnx_throw_errno (error);
+              /* Note that previously this path added `| 0755` which made every
+               * file executable, see
+               * https://github.com/ostreedev/ostree/issues/907
+               */
+              const mode_t content_mode = (mode & (S_IFREG | 0775));
+              if (fchmod (fd, content_mode) < 0)
+                return glnx_throw_errno_prefix (error, "fchmod");
             }
-
-          if (!write_file_metadata_to_xattr (fd, uid, gid, mode, xattrs, error))
-            return FALSE;
         }
       else if (objtype == OSTREE_OBJECT_TYPE_FILE &&
                self->mode == OSTREE_REPO_MODE_BARE_USER_ONLY
index f5af93b19de4ef9c9da0e1312334834f508aaea8..e3e442e9bd22b0ab8573d35319004f43531235b3 100644 (file)
@@ -19,7 +19,7 @@
 
 set -euo pipefail
 
-echo "1..66"
+echo "1..$((66 + ${extra_basic_tests:-0}))"
 
 $CMD_PREFIX ostree --version > version.yaml
 python -c 'import yaml; yaml.safe_load(open("version.yaml"))'
index f1fba4fc201a7f56f2a2119f67d38d161ab785e1..1774a7b6d4690468147e221167a13233cc2f21d8 100755 (executable)
@@ -503,3 +503,21 @@ libtest_cleanup_gpg () {
 is_bare_user_only_repo () {
   grep -q 'mode=bare-user-only' $1/config
 }
+
+# Given a path to a file in a repo for a ref, print its checksum
+ostree_file_path_to_checksum() {
+    repo=$1
+    ref=$2
+    path=$3
+    $CMD_PREFIX ostree --repo=$repo ls -C $ref $path | awk '{ print $5 }'
+}
+
+# Given a path to a file in a repo for a ref, print the path to its object
+ostree_file_path_to_object_path() {
+   repo=$1
+   ref=$2
+   path=$3
+   checksum=$(ostree_file_path_to_checksum $repo $ref $path)
+   test -n "${checksum}"
+   echo ${repo}/objects/${checksum:0:2}/${checksum:2}.file
+}
index 3e11545e382ba83c8896c305e2049ba286faccd3..fa802df67ea97bdbdb865da51640bb698c339f47 100755 (executable)
@@ -25,4 +25,42 @@ skip_without_user_xattrs
 
 setup_test_repository "bare-user"
 
+extra_basic_tests=3
 . $(dirname $0)/basic-test.sh
+
+# Reset things so we don't inherit a lot of state from earlier tests
+rm repo files -rf
+setup_test_repository "bare-user"
+
+cd ${test_tmpdir}
+objpath_nonexec=$(ostree_file_path_to_object_path repo test2 baz/cow)
+# Sigh, umask
+touch testfile
+default_mode=$(stat -c '%a' testfile)
+rm testfile
+assert_file_has_mode ${objpath_nonexec} ${default_mode}
+objpath_ro=$(ostree_file_path_to_object_path repo test2 baz/cowro)
+assert_file_has_mode ${objpath_ro} 600
+objpath_exec=$(ostree_file_path_to_object_path repo test2 baz/deeper/ohyeahx)
+assert_file_has_mode ${objpath_exec} 755
+echo "ok bare-user committed modes"
+
+rm test2-checkout -rf
+$OSTREE checkout -U -H test2 test2-checkout
+cd test2-checkout
+assert_file_has_mode baz/cow ${default_mode}
+assert_file_has_mode baz/cowro 600
+assert_file_has_mode baz/deeper/ohyeahx 755
+echo "ok bare-user checkout modes"
+
+rm test2-checkout -rf
+$OSTREE checkout -U -H test2 test2-checkout
+touch test2-checkout/unwritable
+chmod 0400 test2-checkout/unwritable
+$OSTREE commit -b test2-unwritable --tree=dir=test2-checkout
+chmod 0600 test2-checkout/unwritable
+rm test2-checkout -rf
+$OSTREE checkout -U -H test2-unwritable test2-checkout
+cd test2-checkout
+assert_file_has_mode unwritable 400
+echo "ok bare-user unwritable"