@@ -27,6 +27,14 @@ struct landlock_ruleset_attr {
__u64 handled_access_fs;
};
+/*
+ * sys_landlock_create_ruleset() flags:
+ *
+ * - %LANDLOCK_CREATE_RULESET_VERSION: Get the highest supported Landlock ABI
+ * version.
+ */
+#define LANDLOCK_CREATE_RULESET_VERSION (1U << 0)
+
/**
* enum landlock_rule_type - Landlock rule type
*
@@ -128,6 +128,8 @@ static const struct file_operations ruleset_fops = {
.write = fop_dummy_write,
};
+#define LANDLOCK_ABI_VERSION 1
+
/**
* sys_landlock_create_ruleset - Create a new ruleset
*
@@ -135,15 +137,19 @@ static const struct file_operations ruleset_fops = {
* the new ruleset.
* @size: Size of the pointed &struct landlock_ruleset_attr (needed for
* backward and forward compatibility).
- * @flags: Must be 0.
+ * @flags: Supported value: %LANDLOCK_CREATE_RULESET_VERSION.
*
* This system call enables to create a new Landlock ruleset, and returns the
* related file descriptor on success.
*
+ * If @flags is %LANDLOCK_CREATE_RULESET_VERSION and @attr is NULL and @size is
+ * 0, then the returned value is the highest supported Landlock ABI version
+ * (starting at 1).
+ *
* Possible returned errors are:
*
* - EOPNOTSUPP: Landlock is supported by the kernel but disabled at boot time;
- * - EINVAL: @flags is not 0, or unknown access, or too small @size;
+ * - EINVAL: unknown @flags, or unknown access, or too small @size;
* - E2BIG or EFAULT: @attr or @size inconsistencies;
* - ENOMSG: empty &landlock_ruleset_attr.handled_access_fs.
*/
@@ -161,9 +167,12 @@ SYSCALL_DEFINE3(landlock_create_ruleset,
if (!landlock_initialized)
return -EOPNOTSUPP;
- /* No flag for now. */
- if (flags)
+ if (flags) {
+ if ((flags == LANDLOCK_CREATE_RULESET_VERSION)
+ && !attr && !size)
+ return LANDLOCK_ABI_VERSION;
return -EINVAL;
+ }
/* Copies raw user space buffer. */
err = copy_min_struct_from_user(&ruleset_attr, sizeof(ruleset_attr),
@@ -63,6 +63,53 @@ TEST(inconsistent_attr) {
free(buf);
}
+TEST(abi_version) {
+ const struct landlock_ruleset_attr ruleset_attr = {
+ .handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,
+ };
+ ASSERT_EQ(1, landlock_create_ruleset(NULL, 0,
+ LANDLOCK_CREATE_RULESET_VERSION));
+
+ ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0,
+ LANDLOCK_CREATE_RULESET_VERSION));
+ ASSERT_EQ(EINVAL, errno);
+
+ ASSERT_EQ(-1, landlock_create_ruleset(NULL, sizeof(ruleset_attr),
+ LANDLOCK_CREATE_RULESET_VERSION));
+ ASSERT_EQ(EINVAL, errno);
+
+ ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr,
+ sizeof(ruleset_attr),
+ LANDLOCK_CREATE_RULESET_VERSION));
+ ASSERT_EQ(EINVAL, errno);
+
+ ASSERT_EQ(-1, landlock_create_ruleset(NULL, 0,
+ LANDLOCK_CREATE_RULESET_VERSION | 1 << 31));
+ ASSERT_EQ(EINVAL, errno);
+}
+
+TEST(inval_create_ruleset_flags) {
+ const int last_flag = LANDLOCK_CREATE_RULESET_VERSION;
+ const int invalid_flag = last_flag << 1;
+ const struct landlock_ruleset_attr ruleset_attr = {
+ .handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,
+ };
+
+ ASSERT_EQ(-1, landlock_create_ruleset(NULL, 0, invalid_flag));
+ ASSERT_EQ(EINVAL, errno);
+
+ ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0, invalid_flag));
+ ASSERT_EQ(EINVAL, errno);
+
+ ASSERT_EQ(-1, landlock_create_ruleset(NULL, sizeof(ruleset_attr),
+ invalid_flag));
+ ASSERT_EQ(EINVAL, errno);
+
+ ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr,
+ sizeof(ruleset_attr), invalid_flag));
+ ASSERT_EQ(EINVAL, errno);
+}
+
TEST(empty_path_beneath_attr) {
const struct landlock_ruleset_attr ruleset_attr = {
.handled_access_fs = LANDLOCK_ACCESS_FS_EXECUTE,