lib/repo: Ensure min-free-space* config value doesn't overflow
authorUmang Jain <umang@endlessm.com>
Fri, 31 Aug 2018 14:14:22 +0000 (19:44 +0530)
committerAtomic Bot <atomic-devel@projectatomic.io>
Tue, 4 Sep 2018 21:31:33 +0000 (21:31 +0000)
when converted to bytes

In a subsequent commit, we add a public API to read the value of
min-free-space-* value in bytes. The value for free space check
is enforced in terms of block size instead of bytes. Therefore,
for consistency we check while preparing the transaction that the
value doesn't overflow when converted to bytes.

https://phabricator.endlessm.com/T23694

Closes: #1715
Approved by: cgwalters

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

index d464cd0adea71546a383dbf5837ee4e463660306..1336d28239128acf0917ffd547d2d07828caa364 100644 (file)
@@ -1536,23 +1536,28 @@ devino_cache_lookup (OstreeRepo           *self,
   return dev_ino_val->checksum;
 }
 
-static guint64
-min_free_space_calculate_reserved_blocks (OstreeRepo *self, struct statvfs *stvfsbuf)
+static gboolean
+min_free_space_calculate_reserved_blocks (OstreeRepo *self, struct statvfs *stvfsbuf, GError **error)
 {
-  guint64 reserved_blocks = 0;
+  self->reserved_blocks = 0;
 
   if (self->min_free_space_mb > 0)
     {
-      reserved_blocks = (self->min_free_space_mb << 20) / stvfsbuf->f_bsize;
+      if (self->min_free_space_mb > (G_MAXUINT64 >> 20) ||
+          self->txn.blocksize > (1 << 20))
+        return glnx_throw (error, "min-free-space value is greater than the maximum allowed value of %" G_GUINT64_FORMAT " bytes",
+                           G_MAXUINT64 / stvfsbuf->f_bsize);
+
+      self->reserved_blocks = (self->min_free_space_mb << 20) / self->txn.blocksize;
     }
   else if (self->min_free_space_percent > 0)
     {
       /* Convert fragment to blocks to compute the total */
       guint64 total_blocks = (stvfsbuf->f_frsize * stvfsbuf->f_blocks) / stvfsbuf->f_bsize;
-      reserved_blocks = ((double)total_blocks) * (self->min_free_space_percent/100.0);
+      self->reserved_blocks = ((double)total_blocks) * (self->min_free_space_percent/100.0);
     }
 
-  return reserved_blocks;
+  return TRUE;
 }
 
 /**
@@ -1650,11 +1655,16 @@ ostree_repo_prepare_transaction (OstreeRepo     *self,
 
   g_mutex_lock (&self->txn_lock);
   self->txn.blocksize = stvfsbuf.f_bsize;
-  guint64 reserved_blocks = min_free_space_calculate_reserved_blocks (self, &stvfsbuf);
+  if (!min_free_space_calculate_reserved_blocks (self, &stvfsbuf, error))
+    {
+      g_mutex_unlock (&self->txn_lock);
+      return FALSE;
+    }
+
   /* Use the appropriate free block count if we're unprivileged */
   guint64 bfree = (getuid () != 0 ? stvfsbuf.f_bavail : stvfsbuf.f_bfree);
-  if (bfree > reserved_blocks)
-    self->txn.max_blocks = bfree - reserved_blocks;
+  if (bfree > self->reserved_blocks)
+    self->txn.max_blocks = bfree - self->reserved_blocks;
   else
     {
       self->cleanup_stagedir = TRUE;
index 99eaf49401812298d0a478bddd7940e81e1784ae..3cc4aba0b4cfe5566ce9d06c18cd54c84b6db1b4 100644 (file)
@@ -153,6 +153,7 @@ struct OstreeRepo {
   gid_t target_owner_gid;
   guint min_free_space_percent; /* See the min-free-space-percent config option */
   guint64 min_free_space_mb; /* See the min-free-space-size config option */
+  guint64 reserved_blocks;
   gboolean cleanup_stagedir;
 
   guint test_error_flags; /* OstreeRepoTestErrorFlags */