Re: [PATCH v6 2/5] landlock: Support file truncation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




On 08/09/2022 21:58, Günther Noack wrote:
Introduce the LANDLOCK_ACCESS_FS_TRUNCATE flag for file truncation.

[...]

@@ -761,6 +762,47 @@ static bool collect_domain_accesses(
  	return ret;
  }
+/**
+ * get_path_access_rights - Returns the subset of rights in access_request
+ * which are permitted for the given path.
+ *
+ * @domain: The domain that defines the current restrictions.
+ * @path: The path to get access rights for.
+ * @access_request: The rights we are interested in.
+ *
+ * Returns: The access mask of the rights that are permitted on the given path,
+ * which are also a subset of access_request (to save some calculation time).
+ */
+static inline access_mask_t
+get_path_access_rights(const struct landlock_ruleset *const domain,
+		       const struct path *const path,
+		       access_mask_t access_request)
+{
+	layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = {};
+	unsigned long access_bit;
+	unsigned long access_req;
+
+	init_layer_masks(domain, access_request, &layer_masks);
+	if (!check_access_path_dual(domain, path, access_request, &layer_masks,
+				    NULL, 0, NULL, NULL)) {
+		/*
+		 * Return immediately for successful accesses and for cases
+		 * where everything is permitted because the path belongs to an
+		 * internal filesystem.
+		 */
+		return access_request;
+	}
+
+	access_req = access_request;
+	for_each_set_bit(access_bit, &access_req, ARRAY_SIZE(layer_masks)) {
+		if (layer_masks[access_bit]) {
+			/* If any layer vetoed the access right, remove it. */
+			access_request &= ~BIT_ULL(access_bit);
+		}
+	}

This seems to be redundant with the value returned by init_layer_masks(), which should be passed to check_access_path_dual() to avoid useless path walk.

This function is pretty similar to check_access_path(). Can't you change it to use an access_mask_t pointer and get almost the same thing?


+	return access_request;
+}
+
  /**
   * current_check_refer_path - Check if a rename or link action is allowed
   *
@@ -1142,6 +1184,11 @@ static int hook_path_rmdir(const struct path *const dir,
  	return current_check_access_path(dir, LANDLOCK_ACCESS_FS_REMOVE_DIR);
  }
+static int hook_path_truncate(const struct path *const path)
+{
+	return current_check_access_path(path, LANDLOCK_ACCESS_FS_TRUNCATE);
+}
+
  /* File hooks */
static inline access_mask_t get_file_access(const struct file *const file)
@@ -1159,22 +1206,55 @@ static inline access_mask_t get_file_access(const struct file *const file)
  	/* __FMODE_EXEC is indeed part of f_flags, not f_mode. */
  	if (file->f_flags & __FMODE_EXEC)
  		access |= LANDLOCK_ACCESS_FS_EXECUTE;
+
  	return access;
  }
static int hook_file_open(struct file *const file)
  {
+	access_mask_t access_req, access_rights;

"access_request" is used for access_mask_t, and "access_req" for unsigned int. I'd like to stick to this convention.


+	const access_mask_t optional_rights = LANDLOCK_ACCESS_FS_TRUNCATE;

You use "rights" often and I'm having some trouble to find a rational for that (compared to "access")…


  	const struct landlock_ruleset *const dom =
  		landlock_get_current_domain();
- if (!dom)
+	if (!dom) {
+		/* Grant all rights. */
+		landlock_file(file)->rights = LANDLOCK_MASK_ACCESS_FS;
  		return 0;
+	}
+
  	/*
  	 * Because a file may be opened with O_PATH, get_file_access() may
  	 * return 0.  This case will be handled with a future Landlock
  	 * evolution.
  	 */
-	return check_access_path(dom, &file->f_path, get_file_access(file));
+	access_req = get_file_access(file);
+	access_rights = get_path_access_rights(dom, &file->f_path,
+					       access_req | optional_rights);
+	if (access_req & ~access_rights)
+		return -EACCES;

We should add a test to make sure this (optional_rights) logic is correct (and doesn't change), with a matrix of cases involving a ruleset handling either FS_WRITE, FS_TRUNCATE or both. This should be easy to do with test variants.


+
+	/*
+	 * For operations on already opened files (i.e. ftruncate()), it is the
+	 * access rights at the time of open() which decide whether the
+	 * operation is permitted. Therefore, we record the relevant subset of
+	 * file access rights in the opened struct file.
+	 */
+	landlock_file(file)->rights = access_rights;
+
+	return 0;
+}



[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [NTFS 3]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [NTFS 3]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux