lib/repo: Skip import via hardlink if repo owners don't match
authorColin Walters <walters@verbum.org>
Mon, 12 Jun 2017 17:20:42 +0000 (13:20 -0400)
committerAtomic Bot <atomic-devel@projectatomic.io>
Tue, 13 Jun 2017 12:02:12 +0000 (12:02 +0000)
Before this, if one had repos of matching mode but different owners,
which could happen if one e.g. makes a `bare` non-root repo in
`/ostree/deploy/$stateroot/var/tmp`, every time we tried to call `linkat()`
we'd get `EPERM` and fall back to a copy.

Fix this by saving the repo owner uid, and avoid trying to call `linkat()` if we
know it's going to fail. Of course most commonly in this scenario we'll
immediately fail trying to `chown` the files to `0`, but this is prep for a
future patch to improve `bare-user` → `bare-user-only` imports where we'll be a
bit more sophisticated.

Closes: #922
Approved by: alexlarsson

src/libostree/ostree-repo-private.h
src/libostree/ostree-repo.c

index 556029400e60dd7152a0672d9940d8f4233743be..6cbf9ebeee2d39d59373318688fd9974e4459398 100644 (file)
@@ -116,6 +116,7 @@ struct OstreeRepo {
   GHashTable *updated_uncompressed_dirs;
   GHashTable *object_sizes;
 
+  uid_t owner_uid;
   uid_t target_owner_uid;
   gid_t target_owner_gid;
 
index 1da0621760813b6bfff160c25ad4fce3773709eb..e43d4dcdbcedf6e2a713250406333b9eab4e900f 100644 (file)
@@ -2092,6 +2092,7 @@ ostree_repo_open (OstreeRepo    *self,
 
   if (fstat (self->objects_dir_fd, &stbuf) != 0)
     return glnx_throw_errno (error);
+  self->owner_uid = stbuf.st_uid;
 
   if (stbuf.st_uid != getuid () || stbuf.st_gid != getgid ())
     {
@@ -3168,8 +3169,14 @@ ostree_repo_import_object_from_with_trust (OstreeRepo           *self,
                                            GCancellable         *cancellable,
                                            GError              **error)
 {
-  if (trusted && /* Don't hardlink into untrusted remotes */
-      self->mode == source->mode)
+  /* We try to import via hardlink. If the remote is explicitly not trusted
+   * (i.e.) their checksums may be incorrect, we skip that. Also, we require the
+   * repository modes to match, as well as the owner uid (since we need to be
+   * able to make hardlinks).
+   */
+  if (trusted &&
+      self->mode == source->mode &&
+      self->owner_uid == source->owner_uid)
     {
       gboolean hardlink_was_supported = FALSE;