mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 01:32:21 +02:00
landlock: Add API support and docs for the quiet flags
Adds the UAPI for the quiet flags feature (but not the implementation yet). Even though currently LANDLOCK_ADD_RULE_QUIET only affects audit logging, in the future this can also be used as part of a supervisor mechanism, where it will also suppress denial notifications on a per-object basis. Thus the name is deliberately generic, as opposed to e.g. LANDLOCK_ADD_RULE_LOG_QUIET. According to pahole, even after adding the struct access_masks quiet_masks in struct landlock_hierarchy, the u32 log_* bitfield still only has a size of 2 bytes, so there's minimal wasted space. Assisted-by: GitHub-Copilot:claude-opus-4.8 Signed-off-by: Tingmao Wang <m@maowtm.org> [mic: Update date, fix comment formatting] Link: https://patch.msgid.link/031184748a8e74c0bb02f1fa13d7a3f10918c627.1781228815.git.m@maowtm.org Signed-off-by: Mickaël Salaün <mic@digikod.net>
This commit is contained in:
parent
a260c00556
commit
29752205db
|
|
@ -19,8 +19,10 @@ Audit
|
|||
Denied access requests are logged by default for a sandboxed program if `audit`
|
||||
is enabled. This default behavior can be changed with the
|
||||
sys_landlock_restrict_self() flags (cf.
|
||||
Documentation/userspace-api/landlock.rst). Landlock logs can also be masked
|
||||
thanks to audit rules. Landlock can generate 2 audit record types.
|
||||
Documentation/userspace-api/landlock.rst), or suppressed on a per-object
|
||||
basis by using ``LANDLOCK_ADD_RULE_QUIET`` (ABI 10+). Landlock logs can
|
||||
also be masked thanks to audit rules. Landlock can generate 2 audit
|
||||
record types.
|
||||
|
||||
Record types
|
||||
------------
|
||||
|
|
@ -174,7 +176,8 @@ If you get spammed with audit logs related to Landlock, this is either an
|
|||
attack attempt or a bug in the security policy. We can put in place some
|
||||
filters to limit noise with two complementary ways:
|
||||
|
||||
- with sys_landlock_restrict_self()'s flags if we can fix the sandboxed
|
||||
- with sys_landlock_restrict_self()'s flags, or
|
||||
``LANDLOCK_ADD_RULE_QUIET`` (ABI 10+) if we can fix the sandboxed
|
||||
programs,
|
||||
- or with audit rules (see :manpage:`auditctl(8)`).
|
||||
|
||||
|
|
|
|||
|
|
@ -775,6 +775,20 @@ remote port of UDP sockets (via :manpage:`connect(2)`), and sending
|
|||
datagrams to an explicit remote port (ignoring any destination set on
|
||||
UDP sockets, via e.g. :manpage:`sendto(2)`).
|
||||
|
||||
Quiet rule flag (ABI < 10)
|
||||
--------------------------
|
||||
|
||||
Starting with the Landlock ABI version 10, it is possible to selectively
|
||||
suppress logs for specific denied accesses on a per-object basis with
|
||||
the ``LANDLOCK_ADD_RULE_QUIET`` flag of sys_landlock_add_rule(), in
|
||||
combination with the ``quiet_access_fs`` and ``quiet_access_net`` fields
|
||||
of struct landlock_ruleset_attr. It is also now possible to suppress
|
||||
logs for scope accesses via the ``quiet_scoped`` field of struct
|
||||
landlock_ruleset_attr. The object is marked as quiet within a ruleset
|
||||
when at least one sys_landlock_add_rule() call is made for it with the
|
||||
``LANDLOCK_ADD_RULE_QUIET`` flag, additional add-rule calls for the same
|
||||
object without this flag do not clear it.
|
||||
|
||||
.. _kernel_support:
|
||||
|
||||
Kernel support
|
||||
|
|
|
|||
|
|
@ -32,6 +32,19 @@
|
|||
* *handle* a wide range or all access rights that they know about at build time
|
||||
* (and that they have tested with a kernel that supported them all).
|
||||
*
|
||||
* @quiet_access_fs and @quiet_access_net are bitmasks of actions for which a
|
||||
* denial by this layer will not trigger a log if the corresponding object (or
|
||||
* its children, for filesystem rules) is marked with the "quiet" bit via
|
||||
* %LANDLOCK_ADD_RULE_QUIET, even if logging would normally take place per
|
||||
* landlock_restrict_self() flags. @quiet_scoped is similar, except that it
|
||||
* does not require marking any objects as quiet - if the ruleset is created
|
||||
* with any bits set in @quiet_scoped, then denial of such scoped resources will
|
||||
* not trigger any log. These 3 fields are available since Landlock ABI version
|
||||
* 10.
|
||||
*
|
||||
* @quiet_access_fs, @quiet_access_net and @quiet_scoped must be a subset of
|
||||
* @handled_access_fs, @handled_access_net and @scoped respectively.
|
||||
*
|
||||
* This structure can grow in future Landlock versions.
|
||||
*/
|
||||
struct landlock_ruleset_attr {
|
||||
|
|
@ -51,6 +64,20 @@ struct landlock_ruleset_attr {
|
|||
* resources (e.g. IPCs).
|
||||
*/
|
||||
__u64 scoped;
|
||||
/**
|
||||
* @quiet_access_fs: Bitmask of filesystem actions which should not be
|
||||
* logged if per-object quiet flag is set.
|
||||
*/
|
||||
__u64 quiet_access_fs;
|
||||
/**
|
||||
* @quiet_access_net: Bitmask of network actions which should not be
|
||||
* logged if per-object quiet flag is set.
|
||||
*/
|
||||
__u64 quiet_access_net;
|
||||
/**
|
||||
* @quiet_scoped: Bitmask of scoped actions which should not be logged.
|
||||
*/
|
||||
__u64 quiet_scoped;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -69,6 +96,39 @@ struct landlock_ruleset_attr {
|
|||
#define LANDLOCK_CREATE_RULESET_ERRATA (1U << 1)
|
||||
/* clang-format on */
|
||||
|
||||
/**
|
||||
* DOC: landlock_add_rule_flags
|
||||
*
|
||||
* **Flags**
|
||||
*
|
||||
* %LANDLOCK_ADD_RULE_QUIET
|
||||
* Together with the quiet_* fields in struct landlock_ruleset_attr,
|
||||
* this flag controls whether Landlock will log audit messages when
|
||||
* access to the objects covered by this rule is denied by this layer.
|
||||
*
|
||||
* If logging is enabled, when Landlock denies an access, it will
|
||||
* suppress the log if all of the following are true:
|
||||
*
|
||||
* - this layer is the innermost layer that denied the access;
|
||||
* - all accesses denied by this layer are part of the quiet_* fields
|
||||
* in the related struct landlock_ruleset_attr;
|
||||
* - the object (or one of its parents, for filesystem rules) is
|
||||
* marked as "quiet" via %LANDLOCK_ADD_RULE_QUIET.
|
||||
*
|
||||
* Because logging is only suppressed by a layer if the layer denies
|
||||
* access, a sandboxed program cannot use this flag to "hide" access
|
||||
* denials, without denying itself the access in the first place.
|
||||
*
|
||||
* The effect of this flag does not depend on the value of
|
||||
* allowed_access in the passed in rule_attr. When this flag is
|
||||
* present, the caller is also allowed to pass in an empty
|
||||
* allowed_access.
|
||||
*/
|
||||
|
||||
/* clang-format off */
|
||||
#define LANDLOCK_ADD_RULE_QUIET (1U << 0)
|
||||
/* clang-format on */
|
||||
|
||||
/**
|
||||
* DOC: landlock_restrict_self_flags
|
||||
*
|
||||
|
|
|
|||
|
|
@ -111,6 +111,11 @@ struct landlock_hierarchy {
|
|||
* %LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON. Set to false by default.
|
||||
*/
|
||||
log_new_exec : 1;
|
||||
/**
|
||||
* @quiet_masks: Bitmasks of access that should be quieted (i.e. not
|
||||
* logged) if the related object is marked as quiet.
|
||||
*/
|
||||
struct access_masks quiet_masks;
|
||||
#endif /* CONFIG_AUDIT */
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -325,7 +325,7 @@ static struct landlock_object *get_inode_object(struct inode *const inode)
|
|||
*/
|
||||
int landlock_append_fs_rule(struct landlock_ruleset *const ruleset,
|
||||
const struct path *const path,
|
||||
access_mask_t access_rights)
|
||||
access_mask_t access_rights, const u32 flags)
|
||||
{
|
||||
int err;
|
||||
struct landlock_id id = {
|
||||
|
|
@ -346,7 +346,7 @@ int landlock_append_fs_rule(struct landlock_ruleset *const ruleset,
|
|||
if (IS_ERR(id.key.object))
|
||||
return PTR_ERR(id.key.object);
|
||||
mutex_lock(&ruleset->lock);
|
||||
err = landlock_insert_rule(ruleset, id, access_rights);
|
||||
err = landlock_insert_rule(ruleset, id, access_rights, flags);
|
||||
mutex_unlock(&ruleset->lock);
|
||||
/*
|
||||
* No need to check for an error because landlock_insert_rule()
|
||||
|
|
|
|||
|
|
@ -136,6 +136,6 @@ __init void landlock_add_fs_hooks(void);
|
|||
|
||||
int landlock_append_fs_rule(struct landlock_ruleset *const ruleset,
|
||||
const struct path *const path,
|
||||
access_mask_t access_hierarchy);
|
||||
access_mask_t access_hierarchy, const u32 flags);
|
||||
|
||||
#endif /* _SECURITY_LANDLOCK_FS_H */
|
||||
|
|
|
|||
|
|
@ -20,7 +20,8 @@
|
|||
#include "ruleset.h"
|
||||
|
||||
int landlock_append_net_rule(struct landlock_ruleset *const ruleset,
|
||||
const u16 port, access_mask_t access_rights)
|
||||
const u16 port, access_mask_t access_rights,
|
||||
const u32 flags)
|
||||
{
|
||||
int err;
|
||||
const struct landlock_id id = {
|
||||
|
|
@ -35,7 +36,7 @@ int landlock_append_net_rule(struct landlock_ruleset *const ruleset,
|
|||
~landlock_get_net_access_mask(ruleset, 0);
|
||||
|
||||
mutex_lock(&ruleset->lock);
|
||||
err = landlock_insert_rule(ruleset, id, access_rights);
|
||||
err = landlock_insert_rule(ruleset, id, access_rights, flags);
|
||||
mutex_unlock(&ruleset->lock);
|
||||
|
||||
return err;
|
||||
|
|
|
|||
|
|
@ -16,7 +16,8 @@
|
|||
__init void landlock_add_net_hooks(void);
|
||||
|
||||
int landlock_append_net_rule(struct landlock_ruleset *const ruleset,
|
||||
const u16 port, access_mask_t access_rights);
|
||||
const u16 port, access_mask_t access_rights,
|
||||
const u32 flags);
|
||||
#else /* IS_ENABLED(CONFIG_INET) */
|
||||
static inline void landlock_add_net_hooks(void)
|
||||
{
|
||||
|
|
@ -24,7 +25,7 @@ static inline void landlock_add_net_hooks(void)
|
|||
|
||||
static inline int
|
||||
landlock_append_net_rule(struct landlock_ruleset *const ruleset, const u16 port,
|
||||
access_mask_t access_rights)
|
||||
access_mask_t access_rights, const u32 flags)
|
||||
{
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <uapi/linux/landlock.h>
|
||||
|
||||
#include "access.h"
|
||||
#include "domain.h"
|
||||
|
|
@ -255,6 +256,7 @@ static int insert_rule(struct landlock_ruleset *const ruleset,
|
|||
if (WARN_ON_ONCE(this->layers[0].level != 0))
|
||||
return -EINVAL;
|
||||
this->layers[0].access |= (*layers)[0].access;
|
||||
this->layers[0].flags.quiet |= (*layers)[0].flags.quiet;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -305,12 +307,15 @@ static void build_check_layer(void)
|
|||
/* @ruleset must be locked by the caller. */
|
||||
int landlock_insert_rule(struct landlock_ruleset *const ruleset,
|
||||
const struct landlock_id id,
|
||||
const access_mask_t access)
|
||||
const access_mask_t access, const u32 flags)
|
||||
{
|
||||
struct landlock_layer layers[] = { {
|
||||
.access = access,
|
||||
/* When @level is zero, insert_rule() extends @ruleset. */
|
||||
.level = 0,
|
||||
.flags = {
|
||||
.quiet = !!(flags & LANDLOCK_ADD_RULE_QUIET),
|
||||
},
|
||||
} };
|
||||
|
||||
build_check_layer();
|
||||
|
|
@ -351,6 +356,7 @@ static int merge_tree(struct landlock_ruleset *const dst,
|
|||
return -EINVAL;
|
||||
|
||||
layers[0].access = walker_rule->layers[0].access;
|
||||
layers[0].flags = walker_rule->layers[0].flags;
|
||||
|
||||
err = insert_rule(dst, id, &layers, ARRAY_SIZE(layers));
|
||||
if (err)
|
||||
|
|
@ -581,6 +587,10 @@ landlock_merge_ruleset(struct landlock_ruleset *const parent,
|
|||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
#ifdef CONFIG_AUDIT
|
||||
new_dom->hierarchy->quiet_masks = ruleset->quiet_masks;
|
||||
#endif /* CONFIG_AUDIT */
|
||||
|
||||
return no_free_ptr(new_dom);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -156,8 +156,8 @@ struct landlock_ruleset {
|
|||
* @work_free: Enables to free a ruleset within a lockless
|
||||
* section. This is only used by
|
||||
* landlock_put_ruleset_deferred() when @usage reaches zero.
|
||||
* The fields @lock, @usage, @num_rules, @num_layers and
|
||||
* @access_masks are then unused.
|
||||
* The fields @lock, @usage, @num_rules, @num_layers,
|
||||
* @quiet_masks and @access_masks are then unused.
|
||||
*/
|
||||
struct work_struct work_free;
|
||||
struct {
|
||||
|
|
@ -183,6 +183,12 @@ struct landlock_ruleset {
|
|||
* non-merged ruleset (i.e. not a domain).
|
||||
*/
|
||||
u32 num_layers;
|
||||
/**
|
||||
* @quiet_masks: Stores the quiet flags for an unmerged
|
||||
* ruleset. For a merged domain, this is stored in each
|
||||
* layer's struct landlock_hierarchy instead.
|
||||
*/
|
||||
struct access_masks quiet_masks;
|
||||
/**
|
||||
* @access_masks: Contains the subset of filesystem and
|
||||
* network actions that are restricted by a ruleset.
|
||||
|
|
@ -213,7 +219,7 @@ DEFINE_FREE(landlock_put_ruleset, struct landlock_ruleset *,
|
|||
|
||||
int landlock_insert_rule(struct landlock_ruleset *const ruleset,
|
||||
const struct landlock_id id,
|
||||
const access_mask_t access);
|
||||
const access_mask_t access, const u32 flags);
|
||||
|
||||
struct landlock_ruleset *
|
||||
landlock_merge_ruleset(struct landlock_ruleset *const parent,
|
||||
|
|
|
|||
|
|
@ -105,8 +105,11 @@ static void build_check_abi(void)
|
|||
ruleset_size = sizeof(ruleset_attr.handled_access_fs);
|
||||
ruleset_size += sizeof(ruleset_attr.handled_access_net);
|
||||
ruleset_size += sizeof(ruleset_attr.scoped);
|
||||
ruleset_size += sizeof(ruleset_attr.quiet_access_fs);
|
||||
ruleset_size += sizeof(ruleset_attr.quiet_access_net);
|
||||
ruleset_size += sizeof(ruleset_attr.quiet_scoped);
|
||||
BUILD_BUG_ON(sizeof(ruleset_attr) != ruleset_size);
|
||||
BUILD_BUG_ON(sizeof(ruleset_attr) != 24);
|
||||
BUILD_BUG_ON(sizeof(ruleset_attr) != 48);
|
||||
|
||||
path_beneath_size = sizeof(path_beneath_attr.allowed_access);
|
||||
path_beneath_size += sizeof(path_beneath_attr.parent_fd);
|
||||
|
|
@ -193,6 +196,9 @@ const int landlock_abi_version = 10;
|
|||
* - %EOPNOTSUPP: Landlock is supported by the kernel but disabled at boot time;
|
||||
* - %EINVAL: unknown @flags, or unknown access, or unknown scope, or too small
|
||||
* @size;
|
||||
* - %EINVAL: quiet_access_fs, quiet_access_net, or quiet_scoped is not a
|
||||
* subset of the corresponding handled_access_fs, handled_access_net, or
|
||||
* scoped;
|
||||
* - %E2BIG: @attr or @size inconsistencies;
|
||||
* - %EFAULT: @attr or @size inconsistencies;
|
||||
* - %ENOMSG: empty &landlock_ruleset_attr.handled_access_fs.
|
||||
|
|
@ -249,6 +255,21 @@ SYSCALL_DEFINE3(landlock_create_ruleset,
|
|||
if ((ruleset_attr.scoped | LANDLOCK_MASK_SCOPE) != LANDLOCK_MASK_SCOPE)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Check that quiet masks are subsets of the respective handled masks.
|
||||
* Because of the checks above this is sufficient to also ensure that
|
||||
* the quiet masks are valid access masks.
|
||||
*/
|
||||
if ((ruleset_attr.quiet_access_fs | ruleset_attr.handled_access_fs) !=
|
||||
ruleset_attr.handled_access_fs)
|
||||
return -EINVAL;
|
||||
if ((ruleset_attr.quiet_access_net | ruleset_attr.handled_access_net) !=
|
||||
ruleset_attr.handled_access_net)
|
||||
return -EINVAL;
|
||||
if ((ruleset_attr.quiet_scoped | ruleset_attr.scoped) !=
|
||||
ruleset_attr.scoped)
|
||||
return -EINVAL;
|
||||
|
||||
/* Checks arguments and transforms to kernel struct. */
|
||||
ruleset = landlock_create_ruleset(ruleset_attr.handled_access_fs,
|
||||
ruleset_attr.handled_access_net,
|
||||
|
|
@ -256,6 +277,10 @@ SYSCALL_DEFINE3(landlock_create_ruleset,
|
|||
if (IS_ERR(ruleset))
|
||||
return PTR_ERR(ruleset);
|
||||
|
||||
ruleset->quiet_masks.fs = ruleset_attr.quiet_access_fs;
|
||||
ruleset->quiet_masks.net = ruleset_attr.quiet_access_net;
|
||||
ruleset->quiet_masks.scope = ruleset_attr.quiet_scoped;
|
||||
|
||||
/* Creates anonymous FD referring to the ruleset. */
|
||||
ruleset_fd = anon_inode_getfd("[landlock-ruleset]", &ruleset_fops,
|
||||
ruleset, O_RDWR | O_CLOEXEC);
|
||||
|
|
@ -320,7 +345,7 @@ static int get_path_from_fd(const s32 fd, struct path *const path)
|
|||
}
|
||||
|
||||
static int add_rule_path_beneath(struct landlock_ruleset *const ruleset,
|
||||
const void __user *const rule_attr)
|
||||
const void __user *const rule_attr, u32 flags)
|
||||
{
|
||||
struct landlock_path_beneath_attr path_beneath_attr;
|
||||
struct path path;
|
||||
|
|
@ -335,9 +360,10 @@ static int add_rule_path_beneath(struct landlock_ruleset *const ruleset,
|
|||
|
||||
/*
|
||||
* Informs about useless rule: empty allowed_access (i.e. deny rules)
|
||||
* are ignored in path walks.
|
||||
* are ignored in path walks. However, the rule is not useless if it is
|
||||
* there to hold a quiet flag.
|
||||
*/
|
||||
if (!path_beneath_attr.allowed_access)
|
||||
if (!flags && !path_beneath_attr.allowed_access)
|
||||
return -ENOMSG;
|
||||
|
||||
/* Checks that allowed_access matches the @ruleset constraints. */
|
||||
|
|
@ -345,6 +371,10 @@ static int add_rule_path_beneath(struct landlock_ruleset *const ruleset,
|
|||
if ((path_beneath_attr.allowed_access | mask) != mask)
|
||||
return -EINVAL;
|
||||
|
||||
/* Checks for useless quiet flag. */
|
||||
if (flags & LANDLOCK_ADD_RULE_QUIET && !ruleset->quiet_masks.fs)
|
||||
return -EINVAL;
|
||||
|
||||
/* Gets and checks the new rule. */
|
||||
err = get_path_from_fd(path_beneath_attr.parent_fd, &path);
|
||||
if (err)
|
||||
|
|
@ -352,13 +382,13 @@ static int add_rule_path_beneath(struct landlock_ruleset *const ruleset,
|
|||
|
||||
/* Imports the new rule. */
|
||||
err = landlock_append_fs_rule(ruleset, &path,
|
||||
path_beneath_attr.allowed_access);
|
||||
path_beneath_attr.allowed_access, flags);
|
||||
path_put(&path);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int add_rule_net_port(struct landlock_ruleset *ruleset,
|
||||
const void __user *const rule_attr)
|
||||
const void __user *const rule_attr, u32 flags)
|
||||
{
|
||||
struct landlock_net_port_attr net_port_attr;
|
||||
int res;
|
||||
|
|
@ -371,9 +401,10 @@ static int add_rule_net_port(struct landlock_ruleset *ruleset,
|
|||
|
||||
/*
|
||||
* Informs about useless rule: empty allowed_access (i.e. deny rules)
|
||||
* are ignored by network actions.
|
||||
* are ignored by network actions. However, the rule is not useless if
|
||||
* it is there to hold a quiet flag.
|
||||
*/
|
||||
if (!net_port_attr.allowed_access)
|
||||
if (!flags && !net_port_attr.allowed_access)
|
||||
return -ENOMSG;
|
||||
|
||||
/* Checks that allowed_access matches the @ruleset constraints. */
|
||||
|
|
@ -381,13 +412,17 @@ static int add_rule_net_port(struct landlock_ruleset *ruleset,
|
|||
if ((net_port_attr.allowed_access | mask) != mask)
|
||||
return -EINVAL;
|
||||
|
||||
/* Checks for useless quiet flag. */
|
||||
if (flags & LANDLOCK_ADD_RULE_QUIET && !ruleset->quiet_masks.net)
|
||||
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);
|
||||
net_port_attr.allowed_access, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -398,7 +433,7 @@ static int add_rule_net_port(struct landlock_ruleset *ruleset,
|
|||
* @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 (matching the @rule_type).
|
||||
* @flags: Must be 0.
|
||||
* @flags: Must be 0 or %LANDLOCK_ADD_RULE_QUIET.
|
||||
*
|
||||
* This system call enables to define a new rule and add it to an existing
|
||||
* ruleset.
|
||||
|
|
@ -408,20 +443,25 @@ static int add_rule_net_port(struct landlock_ruleset *ruleset,
|
|||
* - %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;
|
||||
* - %EINVAL: @flags is not valid;
|
||||
* - %EINVAL: The rule accesses are inconsistent (i.e.
|
||||
* &landlock_path_beneath_attr.allowed_access or
|
||||
* &landlock_net_port_attr.allowed_access is not a subset of the ruleset
|
||||
* handled accesses)
|
||||
* - %EINVAL: &landlock_net_port_attr.port is greater than 65535;
|
||||
* - %EINVAL: LANDLOCK_ADD_RULE_QUIET is passed but the ruleset has no
|
||||
* quiet access bits set for the corresponding rule type.
|
||||
* - %ENOMSG: Empty accesses (e.g. &landlock_path_beneath_attr.allowed_access is
|
||||
* 0);
|
||||
* 0) and no flags;
|
||||
* - %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;
|
||||
* - %EBADFD: @ruleset_fd is not a ruleset file descriptor, or a member of
|
||||
* @rule_attr is not the expected file descriptor type;
|
||||
* - %EPERM: @ruleset_fd has no write access to the underlying ruleset;
|
||||
* - %EFAULT: @rule_attr was not a valid address.
|
||||
*
|
||||
* .. kernel-doc:: include/uapi/linux/landlock.h
|
||||
* :identifiers: landlock_add_rule_flags
|
||||
*/
|
||||
SYSCALL_DEFINE4(landlock_add_rule, const int, ruleset_fd,
|
||||
const enum landlock_rule_type, rule_type,
|
||||
|
|
@ -432,8 +472,7 @@ SYSCALL_DEFINE4(landlock_add_rule, const int, ruleset_fd,
|
|||
if (!is_initialized())
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* No flag for now. */
|
||||
if (flags)
|
||||
if (flags && flags != LANDLOCK_ADD_RULE_QUIET)
|
||||
return -EINVAL;
|
||||
|
||||
/* Gets and checks the ruleset. */
|
||||
|
|
@ -443,9 +482,9 @@ SYSCALL_DEFINE4(landlock_add_rule, const int, ruleset_fd,
|
|||
|
||||
switch (rule_type) {
|
||||
case LANDLOCK_RULE_PATH_BENEATH:
|
||||
return add_rule_path_beneath(ruleset, rule_attr);
|
||||
return add_rule_path_beneath(ruleset, rule_attr, flags);
|
||||
case LANDLOCK_RULE_NET_PORT:
|
||||
return add_rule_net_port(ruleset, rule_attr);
|
||||
return add_rule_net_port(ruleset, rule_attr, flags);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ TEST(add_rule_checks_ordering)
|
|||
ASSERT_LE(0, ruleset_fd);
|
||||
|
||||
/* Checks invalid flags. */
|
||||
ASSERT_EQ(-1, landlock_add_rule(-1, 0, NULL, 1));
|
||||
ASSERT_EQ(-1, landlock_add_rule(-1, 0, NULL, 100));
|
||||
ASSERT_EQ(EINVAL, errno);
|
||||
|
||||
/* Checks invalid ruleset FD. */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user