landlock-rs: fix narrow file grants silently dropped on regular files

ober

ab92be0fbf65a01f93520348fceddf002e68ac60

diff --git a/jerboa-native-rs/src/landlock.rs b/jerboa-native-rs/src/landlock.rs
index f70b09c..c8105e3 100644
--- a/jerboa-native-rs/src/landlock.rs
+++ b/jerboa-native-rs/src/landlock.rs
@@ -146,8 +146,32 @@ pub extern "C" fn jerboa_landlock_add_path_rule(
             return -1;
         }
 
+        // Landlock rejects landlock_add_rule with EINVAL if any
+        // directory-only access bit (READ_DIR, MAKE_*, REMOVE_*, REFER)
+        // appears in a rule whose parent_fd refers to a regular file —
+        // silently dropping the entire grant. When the target is not a
+        // directory, mask access_mask down to file-applicable bits
+        // (EXECUTE | WRITE_FILE | READ_FILE | TRUNCATE | IOCTL_DEV).
+        let mut effective_access = access_mask;
+        let mut st: libc::stat = unsafe { std::mem::zeroed() };
+        if unsafe { libc::fstat(parent_fd, &mut st) } == 0
+            && (st.st_mode & libc::S_IFMT) != libc::S_IFDIR
+        {
+            const FILE_BITS: u64 =
+                (1u64 << 0)  | // EXECUTE
+                (1u64 << 1)  | // WRITE_FILE
+                (1u64 << 2)  | // READ_FILE
+                (1u64 << 14) | // TRUNCATE
+                (1u64 << 15);  // IOCTL_DEV
+            effective_access &= FILE_BITS;
+        }
+        if effective_access == 0 {
+            unsafe { libc::close(parent_fd); }
+            return 0;
+        }
+
         let attr = LandlockPathBeneathAttr {
-            allowed_access: access_mask,
+            allowed_access: effective_access,
             parent_fd,
         };
         let rc = unsafe {