mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-08-09 06:14:34 +02:00
The quietness behaviour is as documented in the previous patch. For optional accesses, since the existing deny_masks can only store 2x4bit of layer index, with no way to represent "no layer", we need to either expand it or have another field to correctly handle quieting of those. This commit uses the latter approach - we add another field to store which optional access (of the 2) are covered by quiet rules in their respective layers as stored in deny_masks. Assisted-by: GitHub-Copilot:claude-opus-4.8 copilot-review Signed-off-by: Tingmao Wang <m@maowtm.org> Link: https://patch.msgid.link/2510a357a94183683eefc49917dcb2240d67be96.1781228815.git.m@maowtm.org [mic: Cosmetic fixes] Signed-off-by: Mickaël Salaün <mic@digikod.net>
152 lines
4.7 KiB
C
152 lines
4.7 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/*
|
|
* Landlock - Access types and helpers
|
|
*
|
|
* Copyright © 2016-2020 Mickaël Salaün <mic@digikod.net>
|
|
* Copyright © 2018-2020 ANSSI
|
|
* Copyright © 2024-2025 Microsoft Corporation
|
|
*/
|
|
|
|
#ifndef _SECURITY_LANDLOCK_ACCESS_H
|
|
#define _SECURITY_LANDLOCK_ACCESS_H
|
|
|
|
#include <linux/bitops.h>
|
|
#include <linux/build_bug.h>
|
|
#include <linux/kernel.h>
|
|
#include <uapi/linux/landlock.h>
|
|
|
|
#include "limits.h"
|
|
|
|
/*
|
|
* All access rights that are denied by default whether they are handled or not
|
|
* by a ruleset/layer. This must be ORed with all ruleset->access_masks[]
|
|
* entries when we need to get the absolute handled access masks, see
|
|
* landlock_upgrade_handled_access_masks().
|
|
*/
|
|
/* clang-format off */
|
|
#define _LANDLOCK_ACCESS_FS_INITIALLY_DENIED ( \
|
|
LANDLOCK_ACCESS_FS_REFER)
|
|
/* clang-format on */
|
|
|
|
/* clang-format off */
|
|
#define _LANDLOCK_ACCESS_FS_OPTIONAL ( \
|
|
LANDLOCK_ACCESS_FS_TRUNCATE | \
|
|
LANDLOCK_ACCESS_FS_IOCTL_DEV)
|
|
/* clang-format on */
|
|
|
|
typedef u32 access_mask_t;
|
|
|
|
/* Makes sure all filesystem access rights can be stored. */
|
|
static_assert(BITS_PER_TYPE(access_mask_t) >= LANDLOCK_NUM_ACCESS_FS);
|
|
/* Makes sure all network access rights can be stored. */
|
|
static_assert(BITS_PER_TYPE(access_mask_t) >= LANDLOCK_NUM_ACCESS_NET);
|
|
/* Makes sure all scoped rights can be stored. */
|
|
static_assert(BITS_PER_TYPE(access_mask_t) >= LANDLOCK_NUM_SCOPE);
|
|
/* Makes sure for_each_set_bit() and for_each_clear_bit() calls are OK. */
|
|
static_assert(sizeof(unsigned long) >= sizeof(access_mask_t));
|
|
|
|
/* Ruleset access masks. */
|
|
struct access_masks {
|
|
access_mask_t fs : LANDLOCK_NUM_ACCESS_FS;
|
|
access_mask_t net : LANDLOCK_NUM_ACCESS_NET;
|
|
access_mask_t scope : LANDLOCK_NUM_SCOPE;
|
|
} __packed __aligned(sizeof(u32));
|
|
|
|
union access_masks_all {
|
|
struct access_masks masks;
|
|
u32 all;
|
|
};
|
|
|
|
/* Makes sure all fields are covered. */
|
|
static_assert(sizeof(typeof_member(union access_masks_all, masks)) ==
|
|
sizeof(typeof_member(union access_masks_all, all)));
|
|
|
|
/**
|
|
* struct layer_mask - The access rights and rule flags for a layer.
|
|
*
|
|
* This has a bit for each access rights and rule flags. During access checks,
|
|
* it is used to represent the access rights for each layer which still need to
|
|
* be fulfilled. When all bits are 0, the access request is considered to be
|
|
* fulfilled.
|
|
*/
|
|
struct layer_mask {
|
|
/**
|
|
* @access: The unfulfilled access rights for this layer.
|
|
*/
|
|
access_mask_t access : LANDLOCK_NUM_ACCESS_MAX;
|
|
#ifdef CONFIG_AUDIT
|
|
/**
|
|
* @quiet: Whether we have encountered a rule with the quiet flag for
|
|
* this layer. Used to control logging.
|
|
*/
|
|
access_mask_t quiet : 1;
|
|
#endif /* CONFIG_AUDIT */
|
|
} __packed __aligned(sizeof(access_mask_t));
|
|
|
|
/*
|
|
* Make sure that we don't increase the size of struct layer_mask when storing
|
|
* rule flags.
|
|
*/
|
|
static_assert(sizeof(struct layer_mask) == sizeof(access_mask_t));
|
|
|
|
/**
|
|
* struct layer_masks - An array of struct layer_mask, one per layer.
|
|
*/
|
|
struct layer_masks {
|
|
/**
|
|
* @layers: The unfulfilled access rights for each layer.
|
|
*/
|
|
struct layer_mask layers[LANDLOCK_MAX_NUM_LAYERS];
|
|
};
|
|
|
|
/*
|
|
* Tracks domains responsible of a denied access. This avoids storing in each
|
|
* object the full matrix of per-layer unfulfilled access rights, which is
|
|
* required by update_request().
|
|
*
|
|
* Each nibble represents the layer index of the newest layer which denied a
|
|
* certain access right. For file system access rights, the upper four bits are
|
|
* the index of the layer which denies LANDLOCK_ACCESS_FS_IOCTL_DEV and the
|
|
* lower nibble represents LANDLOCK_ACCESS_FS_TRUNCATE.
|
|
*/
|
|
typedef u8 deny_masks_t;
|
|
|
|
/*
|
|
* Makes sure all optional access rights can be tied to a layer index (cf.
|
|
* get_deny_mask).
|
|
*/
|
|
static_assert(BITS_PER_TYPE(deny_masks_t) >=
|
|
(HWEIGHT(LANDLOCK_MAX_NUM_LAYERS - 1) *
|
|
HWEIGHT(_LANDLOCK_ACCESS_FS_OPTIONAL)));
|
|
|
|
/* LANDLOCK_MAX_NUM_LAYERS must be a power of two (cf. deny_masks_t assert). */
|
|
static_assert(HWEIGHT(LANDLOCK_MAX_NUM_LAYERS) == 1);
|
|
|
|
/* Upgrades with all initially denied by default access rights. */
|
|
static inline struct access_masks
|
|
landlock_upgrade_handled_access_masks(struct access_masks access_masks)
|
|
{
|
|
/*
|
|
* All access rights that are denied by default whether they are
|
|
* explicitly handled or not.
|
|
*/
|
|
if (access_masks.fs)
|
|
access_masks.fs |= _LANDLOCK_ACCESS_FS_INITIALLY_DENIED;
|
|
|
|
return access_masks;
|
|
}
|
|
|
|
/* Checks the subset relation between access masks. */
|
|
static inline bool access_mask_subset(access_mask_t subset,
|
|
access_mask_t superset)
|
|
{
|
|
return (subset | superset) == superset;
|
|
}
|
|
|
|
/* A bitmask that is large enough to hold set of optional accesses. */
|
|
typedef u8 optional_access_t;
|
|
static_assert(BITS_PER_TYPE(optional_access_t) >=
|
|
HWEIGHT(_LANDLOCK_ACCESS_FS_OPTIONAL));
|
|
|
|
#endif /* _SECURITY_LANDLOCK_ACCESS_H */
|