landlock: fix narrow file grants silently dropped on regular files

ober

b37dd197a895873c652e02771cf9ae816b4dbc37

diff --git a/support/landlock-shim.c b/support/landlock-shim.c
index 7eed4b4..6529833 100644
--- a/support/landlock-shim.c
+++ b/support/landlock-shim.c
@@ -12,6 +12,7 @@
 
 #include <sys/types.h>
 #include <sys/prctl.h>
+#include <sys/stat.h>
 #include <sys/syscall.h>
 #include <unistd.h>
 #include <fcntl.h>
@@ -94,6 +95,19 @@ struct landlock_net_port_attr {
     LANDLOCK_ACCESS_FS_MAKE_BLOCK  | \
     LANDLOCK_ACCESS_FS_MAKE_SYM)
 
+/* Access bits valid for regular (non-directory) files. Landlock rejects
+ * landlock_add_rule with EINVAL if any directory-only bit (READ_DIR,
+ * MAKE_*, REMOVE_*, REFER) appears in a rule targeting a regular file,
+ * silently dropping the entire grant. Mask requested access against
+ * this set when the target is a file. IOCTL_DEV is included because
+ * it is valid on character/block device files (e.g. /dev/tty). */
+#define ACCESS_FS_FILE_BITS ( \
+    LANDLOCK_ACCESS_FS_EXECUTE    | \
+    LANDLOCK_ACCESS_FS_WRITE_FILE | \
+    LANDLOCK_ACCESS_FS_READ_FILE  | \
+    LANDLOCK_ACCESS_FS_TRUNCATE   | \
+    LANDLOCK_ACCESS_FS_IOCTL_DEV)
+
 /* ========== API Functions ========== */
 
 int jerboa_landlock_sandbox_ex(const char *packed_read,
@@ -196,11 +210,20 @@ int jerboa_landlock_sandbox_ex(const char *packed_read,
         const char *target = resolved ? resolved : (path); \
         int fd = open(target, O_PATH | O_CLOEXEC); \
         if (fd >= 0) { \
+            uint64_t eff = (access); \
+            struct stat st; \
+            if (fstat(fd, &st) == 0 && !S_ISDIR(st.st_mode)) { \
+                /* Regular file (or device/socket/etc): strip dir-only bits \
+                 * to avoid EINVAL silently dropping the entire grant. */ \
+                eff &= ACCESS_FS_FILE_BITS; \
+            } \
             struct landlock_path_beneath_attr pb; \
-            pb.allowed_access = (access) & handled; \
+            pb.allowed_access = eff & handled; \
             pb.parent_fd = fd; \
-            syscall(__NR_landlock_add_rule, ruleset_fd, \
-                    LANDLOCK_RULE_PATH_BENEATH, &pb, 0); \
+            if (pb.allowed_access) { \
+                syscall(__NR_landlock_add_rule, ruleset_fd, \
+                        LANDLOCK_RULE_PATH_BENEATH, &pb, 0); \
+            } \
             close(fd); \
         } \
         free(resolved); \