summaryrefslogtreecommitdiff
path: root/security/landlock/syscalls.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/landlock/syscalls.c')
-rw-r--r--security/landlock/syscalls.c72
1 files changed, 63 insertions, 9 deletions
diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c
index e87f572e0251..898358f57fa0 100644
--- a/security/landlock/syscalls.c
+++ b/security/landlock/syscalls.c
@@ -29,6 +29,7 @@
#include "cred.h"
#include "fs.h"
#include "limits.h"
+#include "net.h"
#include "ruleset.h"
#include "setup.h"
@@ -74,7 +75,8 @@ static void build_check_abi(void)
{
struct landlock_ruleset_attr ruleset_attr;
struct landlock_path_beneath_attr path_beneath_attr;
- size_t ruleset_size, path_beneath_size;
+ struct landlock_net_port_attr net_port_attr;
+ size_t ruleset_size, path_beneath_size, net_port_size;
/*
* For each user space ABI structures, first checks that there is no
@@ -82,13 +84,19 @@ static void build_check_abi(void)
* struct size.
*/
ruleset_size = sizeof(ruleset_attr.handled_access_fs);
+ ruleset_size += sizeof(ruleset_attr.handled_access_net);
BUILD_BUG_ON(sizeof(ruleset_attr) != ruleset_size);
- BUILD_BUG_ON(sizeof(ruleset_attr) != 8);
+ BUILD_BUG_ON(sizeof(ruleset_attr) != 16);
path_beneath_size = sizeof(path_beneath_attr.allowed_access);
path_beneath_size += sizeof(path_beneath_attr.parent_fd);
BUILD_BUG_ON(sizeof(path_beneath_attr) != path_beneath_size);
BUILD_BUG_ON(sizeof(path_beneath_attr) != 12);
+
+ net_port_size = sizeof(net_port_attr.allowed_access);
+ net_port_size += sizeof(net_port_attr.port);
+ BUILD_BUG_ON(sizeof(net_port_attr) != net_port_size);
+ BUILD_BUG_ON(sizeof(net_port_attr) != 16);
}
/* Ruleset handling */
@@ -129,7 +137,7 @@ static const struct file_operations ruleset_fops = {
.write = fop_dummy_write,
};
-#define LANDLOCK_ABI_VERSION 3
+#define LANDLOCK_ABI_VERSION 4
/**
* sys_landlock_create_ruleset - Create a new ruleset
@@ -188,8 +196,14 @@ SYSCALL_DEFINE3(landlock_create_ruleset,
LANDLOCK_MASK_ACCESS_FS)
return -EINVAL;
+ /* Checks network content (and 32-bits cast). */
+ if ((ruleset_attr.handled_access_net | LANDLOCK_MASK_ACCESS_NET) !=
+ LANDLOCK_MASK_ACCESS_NET)
+ return -EINVAL;
+
/* Checks arguments and transforms to kernel struct. */
- ruleset = landlock_create_ruleset(ruleset_attr.handled_access_fs);
+ ruleset = landlock_create_ruleset(ruleset_attr.handled_access_fs,
+ ruleset_attr.handled_access_net);
if (IS_ERR(ruleset))
return PTR_ERR(ruleset);
@@ -282,7 +296,7 @@ static int add_rule_path_beneath(struct landlock_ruleset *const ruleset,
int res, err;
access_mask_t mask;
- /* Copies raw user space buffer, only one type for now. */
+ /* Copies raw user space buffer. */
res = copy_from_user(&path_beneath_attr, rule_attr,
sizeof(path_beneath_attr));
if (res)
@@ -312,13 +326,46 @@ static int add_rule_path_beneath(struct landlock_ruleset *const ruleset,
return err;
}
+static int add_rule_net_port(struct landlock_ruleset *ruleset,
+ const void __user *const rule_attr)
+{
+ struct landlock_net_port_attr net_port_attr;
+ int res;
+ access_mask_t mask;
+
+ /* Copies raw user space buffer. */
+ res = copy_from_user(&net_port_attr, rule_attr, sizeof(net_port_attr));
+ if (res)
+ return -EFAULT;
+
+ /*
+ * Informs about useless rule: empty allowed_access (i.e. deny rules)
+ * are ignored by network actions.
+ */
+ if (!net_port_attr.allowed_access)
+ return -ENOMSG;
+
+ /* Checks that allowed_access matches the @ruleset constraints. */
+ mask = landlock_get_net_access_mask(ruleset, 0);
+ if ((net_port_attr.allowed_access | mask) != mask)
+ return -EINVAL;
+
+ /* Denies inserting a rule with port greater than 65535. */
+ if (net_port_attr.port > U16_MAX)
+ return -EINVAL;
+
+ /* Imports the new rule. */
+ return landlock_append_net_rule(ruleset, net_port_attr.port,
+ net_port_attr.allowed_access);
+}
+
/**
* sys_landlock_add_rule - Add a new rule to a ruleset
*
* @ruleset_fd: File descriptor tied to the ruleset that should be extended
* with the new rule.
- * @rule_type: Identify the structure type pointed to by @rule_attr (only
- * %LANDLOCK_RULE_PATH_BENEATH for now).
+ * @rule_type: Identify the structure type pointed to by @rule_attr:
+ * %LANDLOCK_RULE_PATH_BENEATH or %LANDLOCK_RULE_NET_PORT.
* @rule_attr: Pointer to a rule (only of type &struct
* landlock_path_beneath_attr for now).
* @flags: Must be 0.
@@ -329,9 +376,13 @@ static int add_rule_path_beneath(struct landlock_ruleset *const ruleset,
* Possible returned errors are:
*
* - %EOPNOTSUPP: Landlock is supported by the kernel but disabled at boot time;
+ * - %EAFNOSUPPORT: @rule_type is %LANDLOCK_RULE_NET_PORT but TCP/IP is not
+ * supported by the running kernel;
* - %EINVAL: @flags is not 0, or inconsistent access in the rule (i.e.
- * &landlock_path_beneath_attr.allowed_access is not a subset of the
- * ruleset handled accesses);
+ * &landlock_path_beneath_attr.allowed_access or
+ * &landlock_net_port_attr.allowed_access is not a subset of the
+ * ruleset handled accesses), or &landlock_net_port_attr.port is
+ * greater than 65535;
* - %ENOMSG: Empty accesses (e.g. &landlock_path_beneath_attr.allowed_access);
* - %EBADF: @ruleset_fd is not a file descriptor for the current thread, or a
* member of @rule_attr is not a file descriptor as expected;
@@ -363,6 +414,9 @@ SYSCALL_DEFINE4(landlock_add_rule, const int, ruleset_fd,
case LANDLOCK_RULE_PATH_BENEATH:
err = add_rule_path_beneath(ruleset, rule_attr);
break;
+ case LANDLOCK_RULE_NET_PORT:
+ err = add_rule_net_port(ruleset, rule_attr);
+ break;
default:
err = -EINVAL;
break;