From 99975c0e42e1ee8f2172cd94c408296b42d5f85d Mon Sep 17 00:00:00 2001
From: 4lDO2 <4lDO2@protonmail.com>
Date: Thu, 29 Jun 2023 11:47:52 +0200
Subject: [PATCH] WIP: Ensure that Grant::borrow does not borrow nonpresent
 grants.

---
 src/context/memory.rs | 26 +++++++++++++++++++++-----
 src/lib.rs            |  1 +
 2 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/src/context/memory.rs b/src/context/memory.rs
index ffc61415..2c649285 100644
--- a/src/context/memory.rs
+++ b/src/context/memory.rs
@@ -644,7 +644,7 @@ impl Grant {
         dst_mapper: &mut PageMapper,
         dst_flusher: impl Flusher<RmmA>,
         eager: bool,
-    ) -> Result<Vec<Grant>, Enomem> {
+    ) -> Result<Vec<Grant>> {
         /*
         if eager {
             for page in PageSpan::new(src_base, page_count) {
@@ -653,16 +653,22 @@ impl Grant {
         }
         */
 
-        // TODO: If grants are missing for certain ranges specified, fill with Provider::External
-        // grants anyway, which will in turn fill the host address space will zeroed grants. This
-        // is required before schemes can be safe.
-
         let mut dst_grants = Vec::with_capacity(1);
 
         let src_span = PageSpan::new(src_base, page_count);
+        let mut prev_span = None;
 
         for (src_grant_base, src_grant) in src_address_space.grants.conflicts(src_span) {
             let grant_span = PageSpan::new(src_grant_base, src_grant.page_count);
+            let prev_span = prev_span.replace(grant_span);
+
+            if prev_span.is_none() && src_grant_base > src_base {
+                log::warn!("Grant too far away, prev_span {:?} src_base {:?} grant base {:?} grant {:#?}", prev_span, src_base, src_grant_base, src_grant);
+                return Err(Error::new(EINVAL));
+            } else if let Some(prev) = prev_span && prev.end() != src_grant_base {
+                log::warn!("Hole between grants, prev_span {:?} src_base {:?} grant base {:?} grant {:#?}", prev_span, src_base, src_grant_base, src_grant);
+                return Err(Error::new(EINVAL));
+            }
 
             let common_span = src_span.intersection(grant_span);
             let offset_from_src_base = common_span.base.offset_from(src_base);
@@ -690,6 +696,16 @@ impl Grant {
             });
         }
 
+        let Some(last_span) = prev_span else {
+            log::warn!("Called Grant::borrow, but no grants were there!");
+            return Err(Error::new(EINVAL));
+        };
+
+        if last_span.end() < src_span.end() {
+            log::warn!("Requested end page too far away from last grant");
+            return Err(Error::new(EINVAL));
+        }
+
         Ok(dst_grants)
     }
     // TODO: This is limited to one grant. Should it be (if some magic new proc: API is introduced)?
diff --git a/src/lib.rs b/src/lib.rs
index 94be6424..b6312060 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -50,6 +50,7 @@
 #![feature(const_option)]
 #![feature(arbitrary_self_types)]
 #![feature(int_roundings)]
+#![feature(let_chains)]
 #![feature(naked_functions)]
 #![feature(slice_ptr_get, slice_ptr_len)]
 #![feature(sync_unsafe_cell)]
-- 
GitLab