mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
landlock: Transpose the layer masks data structure
The layer masks data structure tracks the requested but unfulfilled access rights during an operation's security check. It stores one bit for each combination of access right and layer index. If the bit is set, that access right is not granted (yet) in the given layer and we have to traverse the path further upwards to grant it. Previously, the layer masks were stored as arrays mapping from access right indices to layer_mask_t. The layer_mask_t value then indicates all layers in which the given access right is still (tentatively) denied. This patch introduces struct layer_access_masks instead: This struct contains an array with the access_mask_t of each (tentatively) denied access right in that layer. The hypothesis of this patch is that this simplifies the code enough so that the resulting code will run faster: * We can use bitwise operations in multiple places where we previously looped over bits individually with macros. (Should require less branch speculation and lends itself to better loop unrolling.) * Code is ~75 lines smaller. Other noteworthy changes: * In no_more_access(), call a new helper function may_refer(), which only solves the asymmetric case. Previously, the code interleaved the checks for the two symmetric cases in RENAME_EXCHANGE. It feels that the code is clearer when renames without RENAME_EXCHANGE are more obviously the normal case. Tradeoffs: This change improves performance, at a slight size increase to the layer masks data structure. This fixes the size of the data structure at 32 bytes for all types of access rights. (64, once we introduce a 17th filesystem access right). For filesystem access rights, at the moment, the data structure has the same size as before, but once we introduce the 17th filesystem access right, it will double in size (from 32 to 64 bytes), as access_mask_t grows from 16 to 32 bit [1]. Link: https://lore.kernel.org/all/20260120.haeCh4li9Vae@digikod.net/ [1] Signed-off-by: Günther Noack <gnoack3000@gmail.com> Link: https://lore.kernel.org/r/20260206151154.97915-5-gnoack3000@gmail.com [mic: Cosmetic fixes, moved struct layer_access_masks definition] Signed-off-by: Mickaël Salaün <mic@digikod.net>
This commit is contained in:
@@ -61,14 +61,30 @@ union access_masks_all {
|
||||
static_assert(sizeof(typeof_member(union access_masks_all, masks)) ==
|
||||
sizeof(typeof_member(union access_masks_all, all)));
|
||||
|
||||
typedef u16 layer_mask_t;
|
||||
|
||||
/* Makes sure all layers can be checked. */
|
||||
static_assert(BITS_PER_TYPE(layer_mask_t) >= LANDLOCK_MAX_NUM_LAYERS);
|
||||
/**
|
||||
* struct layer_access_masks - A boolean matrix of layers and access rights
|
||||
*
|
||||
* This has a bit for each combination of layer numbers and access rights.
|
||||
* 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_access_masks {
|
||||
/**
|
||||
* @access: The unfulfilled access rights for each layer.
|
||||
*/
|
||||
access_mask_t access[LANDLOCK_MAX_NUM_LAYERS];
|
||||
};
|
||||
|
||||
/*
|
||||
* Tracks domains responsible of a denied access. This is required to avoid
|
||||
* storing in each object the full layer_masks[] required by update_request().
|
||||
* 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;
|
||||
|
||||
|
||||
+25
-56
@@ -180,38 +180,21 @@ static void test_get_hierarchy(struct kunit *const test)
|
||||
|
||||
#endif /* CONFIG_SECURITY_LANDLOCK_KUNIT_TEST */
|
||||
|
||||
/* Get the youngest layer that denied the access_request. */
|
||||
static size_t get_denied_layer(const struct landlock_ruleset *const domain,
|
||||
access_mask_t *const access_request,
|
||||
const layer_mask_t (*const layer_masks)[],
|
||||
const size_t layer_masks_size)
|
||||
const struct layer_access_masks *masks)
|
||||
{
|
||||
const unsigned long access_req = *access_request;
|
||||
unsigned long access_bit;
|
||||
access_mask_t missing = 0;
|
||||
long youngest_layer = -1;
|
||||
|
||||
for_each_set_bit(access_bit, &access_req, layer_masks_size) {
|
||||
const layer_mask_t mask = (*layer_masks)[access_bit];
|
||||
long layer;
|
||||
|
||||
if (!mask)
|
||||
continue;
|
||||
|
||||
/* __fls(1) == 0 */
|
||||
layer = __fls(mask);
|
||||
if (layer > youngest_layer) {
|
||||
youngest_layer = layer;
|
||||
missing = BIT(access_bit);
|
||||
} else if (layer == youngest_layer) {
|
||||
missing |= BIT(access_bit);
|
||||
for (ssize_t i = ARRAY_SIZE(masks->access) - 1; i >= 0; i--) {
|
||||
if (masks->access[i] & *access_request) {
|
||||
*access_request &= masks->access[i];
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
*access_request = missing;
|
||||
if (youngest_layer == -1)
|
||||
return domain->num_layers - 1;
|
||||
|
||||
return youngest_layer;
|
||||
/* Not found - fall back to default values */
|
||||
*access_request = 0;
|
||||
return domain->num_layers - 1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SECURITY_LANDLOCK_KUNIT_TEST
|
||||
@@ -221,50 +204,39 @@ static void test_get_denied_layer(struct kunit *const test)
|
||||
const struct landlock_ruleset dom = {
|
||||
.num_layers = 5,
|
||||
};
|
||||
const layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = {
|
||||
[BIT_INDEX(LANDLOCK_ACCESS_FS_EXECUTE)] = BIT(0),
|
||||
[BIT_INDEX(LANDLOCK_ACCESS_FS_READ_FILE)] = BIT(1),
|
||||
[BIT_INDEX(LANDLOCK_ACCESS_FS_READ_DIR)] = BIT(1) | BIT(0),
|
||||
[BIT_INDEX(LANDLOCK_ACCESS_FS_REMOVE_DIR)] = BIT(2),
|
||||
const struct layer_access_masks masks = {
|
||||
.access[0] = LANDLOCK_ACCESS_FS_EXECUTE |
|
||||
LANDLOCK_ACCESS_FS_READ_DIR,
|
||||
.access[1] = LANDLOCK_ACCESS_FS_READ_FILE |
|
||||
LANDLOCK_ACCESS_FS_READ_DIR,
|
||||
.access[2] = LANDLOCK_ACCESS_FS_REMOVE_DIR,
|
||||
};
|
||||
access_mask_t access;
|
||||
|
||||
access = LANDLOCK_ACCESS_FS_EXECUTE;
|
||||
KUNIT_EXPECT_EQ(test, 0,
|
||||
get_denied_layer(&dom, &access, &layer_masks,
|
||||
sizeof(layer_masks)));
|
||||
KUNIT_EXPECT_EQ(test, 0, get_denied_layer(&dom, &access, &masks));
|
||||
KUNIT_EXPECT_EQ(test, access, LANDLOCK_ACCESS_FS_EXECUTE);
|
||||
|
||||
access = LANDLOCK_ACCESS_FS_READ_FILE;
|
||||
KUNIT_EXPECT_EQ(test, 1,
|
||||
get_denied_layer(&dom, &access, &layer_masks,
|
||||
sizeof(layer_masks)));
|
||||
KUNIT_EXPECT_EQ(test, 1, get_denied_layer(&dom, &access, &masks));
|
||||
KUNIT_EXPECT_EQ(test, access, LANDLOCK_ACCESS_FS_READ_FILE);
|
||||
|
||||
access = LANDLOCK_ACCESS_FS_READ_DIR;
|
||||
KUNIT_EXPECT_EQ(test, 1,
|
||||
get_denied_layer(&dom, &access, &layer_masks,
|
||||
sizeof(layer_masks)));
|
||||
KUNIT_EXPECT_EQ(test, 1, get_denied_layer(&dom, &access, &masks));
|
||||
KUNIT_EXPECT_EQ(test, access, LANDLOCK_ACCESS_FS_READ_DIR);
|
||||
|
||||
access = LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_READ_DIR;
|
||||
KUNIT_EXPECT_EQ(test, 1,
|
||||
get_denied_layer(&dom, &access, &layer_masks,
|
||||
sizeof(layer_masks)));
|
||||
KUNIT_EXPECT_EQ(test, 1, get_denied_layer(&dom, &access, &masks));
|
||||
KUNIT_EXPECT_EQ(test, access,
|
||||
LANDLOCK_ACCESS_FS_READ_FILE |
|
||||
LANDLOCK_ACCESS_FS_READ_DIR);
|
||||
|
||||
access = LANDLOCK_ACCESS_FS_EXECUTE | LANDLOCK_ACCESS_FS_READ_DIR;
|
||||
KUNIT_EXPECT_EQ(test, 1,
|
||||
get_denied_layer(&dom, &access, &layer_masks,
|
||||
sizeof(layer_masks)));
|
||||
KUNIT_EXPECT_EQ(test, 1, get_denied_layer(&dom, &access, &masks));
|
||||
KUNIT_EXPECT_EQ(test, access, LANDLOCK_ACCESS_FS_READ_DIR);
|
||||
|
||||
access = LANDLOCK_ACCESS_FS_WRITE_FILE;
|
||||
KUNIT_EXPECT_EQ(test, 4,
|
||||
get_denied_layer(&dom, &access, &layer_masks,
|
||||
sizeof(layer_masks)));
|
||||
KUNIT_EXPECT_EQ(test, 4, get_denied_layer(&dom, &access, &masks));
|
||||
KUNIT_EXPECT_EQ(test, access, 0);
|
||||
}
|
||||
|
||||
@@ -370,9 +342,6 @@ static bool is_valid_request(const struct landlock_request *const request)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (WARN_ON_ONCE(!!request->layer_masks ^ !!request->layer_masks_size))
|
||||
return false;
|
||||
|
||||
if (request->deny_masks) {
|
||||
if (WARN_ON_ONCE(!request->all_existing_optional_access))
|
||||
return false;
|
||||
@@ -406,12 +375,12 @@ void landlock_log_denial(const struct landlock_cred_security *const subject,
|
||||
if (missing) {
|
||||
/* Gets the nearest domain that denies the request. */
|
||||
if (request->layer_masks) {
|
||||
youngest_layer = get_denied_layer(
|
||||
subject->domain, &missing, request->layer_masks,
|
||||
request->layer_masks_size);
|
||||
youngest_layer = get_denied_layer(subject->domain,
|
||||
&missing,
|
||||
request->layer_masks);
|
||||
} else {
|
||||
youngest_layer = get_layer_from_deny_masks(
|
||||
&missing, request->all_existing_optional_access,
|
||||
&missing, _LANDLOCK_ACCESS_FS_OPTIONAL,
|
||||
request->deny_masks);
|
||||
}
|
||||
youngest_denied =
|
||||
|
||||
@@ -43,8 +43,7 @@ struct landlock_request {
|
||||
access_mask_t access;
|
||||
|
||||
/* Required fields for requests with layer masks. */
|
||||
const layer_mask_t (*layer_masks)[];
|
||||
size_t layer_masks_size;
|
||||
const struct layer_access_masks *layer_masks;
|
||||
|
||||
/* Required fields for requests with deny masks. */
|
||||
const access_mask_t all_existing_optional_access;
|
||||
|
||||
+24
-20
@@ -182,32 +182,36 @@ static void test_get_layer_deny_mask(struct kunit *const test)
|
||||
deny_masks_t
|
||||
landlock_get_deny_masks(const access_mask_t all_existing_optional_access,
|
||||
const access_mask_t optional_access,
|
||||
const layer_mask_t (*const layer_masks)[],
|
||||
const size_t layer_masks_size)
|
||||
const struct layer_access_masks *const masks)
|
||||
{
|
||||
const unsigned long access_opt = optional_access;
|
||||
unsigned long access_bit;
|
||||
deny_masks_t deny_masks = 0;
|
||||
access_mask_t all_denied = 0;
|
||||
|
||||
/* This may require change with new object types. */
|
||||
WARN_ON_ONCE(access_opt !=
|
||||
(optional_access & all_existing_optional_access));
|
||||
WARN_ON_ONCE(!access_mask_subset(optional_access,
|
||||
all_existing_optional_access));
|
||||
|
||||
if (WARN_ON_ONCE(!layer_masks))
|
||||
if (WARN_ON_ONCE(!masks))
|
||||
return 0;
|
||||
|
||||
if (WARN_ON_ONCE(!access_opt))
|
||||
return 0;
|
||||
|
||||
for_each_set_bit(access_bit, &access_opt, layer_masks_size) {
|
||||
const layer_mask_t mask = (*layer_masks)[access_bit];
|
||||
for (ssize_t i = ARRAY_SIZE(masks->access) - 1; i >= 0; i--) {
|
||||
const access_mask_t denied = masks->access[i] & optional_access;
|
||||
const unsigned long newly_denied = denied & ~all_denied;
|
||||
|
||||
if (!mask)
|
||||
if (!newly_denied)
|
||||
continue;
|
||||
|
||||
/* __fls(1) == 0 */
|
||||
deny_masks |= get_layer_deny_mask(all_existing_optional_access,
|
||||
access_bit, __fls(mask));
|
||||
for_each_set_bit(access_bit, &newly_denied,
|
||||
8 * sizeof(access_mask_t)) {
|
||||
deny_masks |= get_layer_deny_mask(
|
||||
all_existing_optional_access, access_bit, i);
|
||||
}
|
||||
all_denied |= denied;
|
||||
}
|
||||
return deny_masks;
|
||||
}
|
||||
@@ -216,28 +220,28 @@ landlock_get_deny_masks(const access_mask_t all_existing_optional_access,
|
||||
|
||||
static void test_landlock_get_deny_masks(struct kunit *const test)
|
||||
{
|
||||
const layer_mask_t layers1[BITS_PER_TYPE(access_mask_t)] = {
|
||||
[BIT_INDEX(LANDLOCK_ACCESS_FS_EXECUTE)] = BIT_ULL(0) |
|
||||
BIT_ULL(9),
|
||||
[BIT_INDEX(LANDLOCK_ACCESS_FS_TRUNCATE)] = BIT_ULL(1),
|
||||
[BIT_INDEX(LANDLOCK_ACCESS_FS_IOCTL_DEV)] = BIT_ULL(2) |
|
||||
BIT_ULL(0),
|
||||
const struct layer_access_masks layers1 = {
|
||||
.access[0] = LANDLOCK_ACCESS_FS_EXECUTE |
|
||||
LANDLOCK_ACCESS_FS_IOCTL_DEV,
|
||||
.access[1] = LANDLOCK_ACCESS_FS_TRUNCATE,
|
||||
.access[2] = LANDLOCK_ACCESS_FS_IOCTL_DEV,
|
||||
.access[9] = LANDLOCK_ACCESS_FS_EXECUTE,
|
||||
};
|
||||
|
||||
KUNIT_EXPECT_EQ(test, 0x1,
|
||||
landlock_get_deny_masks(_LANDLOCK_ACCESS_FS_OPTIONAL,
|
||||
LANDLOCK_ACCESS_FS_TRUNCATE,
|
||||
&layers1, ARRAY_SIZE(layers1)));
|
||||
&layers1));
|
||||
KUNIT_EXPECT_EQ(test, 0x20,
|
||||
landlock_get_deny_masks(_LANDLOCK_ACCESS_FS_OPTIONAL,
|
||||
LANDLOCK_ACCESS_FS_IOCTL_DEV,
|
||||
&layers1, ARRAY_SIZE(layers1)));
|
||||
&layers1));
|
||||
KUNIT_EXPECT_EQ(
|
||||
test, 0x21,
|
||||
landlock_get_deny_masks(_LANDLOCK_ACCESS_FS_OPTIONAL,
|
||||
LANDLOCK_ACCESS_FS_TRUNCATE |
|
||||
LANDLOCK_ACCESS_FS_IOCTL_DEV,
|
||||
&layers1, ARRAY_SIZE(layers1)));
|
||||
&layers1));
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SECURITY_LANDLOCK_KUNIT_TEST */
|
||||
|
||||
@@ -122,8 +122,7 @@ struct landlock_hierarchy {
|
||||
deny_masks_t
|
||||
landlock_get_deny_masks(const access_mask_t all_existing_optional_access,
|
||||
const access_mask_t optional_access,
|
||||
const layer_mask_t (*const layer_masks)[],
|
||||
size_t layer_masks_size);
|
||||
const struct layer_access_masks *const masks);
|
||||
|
||||
int landlock_init_hierarchy_log(struct landlock_hierarchy *const hierarchy);
|
||||
|
||||
|
||||
+157
-191
File diff suppressed because it is too large
Load Diff
@@ -47,7 +47,7 @@ static int current_check_access_socket(struct socket *const sock,
|
||||
access_mask_t access_request)
|
||||
{
|
||||
__be16 port;
|
||||
layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_NET] = {};
|
||||
struct layer_access_masks layer_masks = {};
|
||||
const struct landlock_rule *rule;
|
||||
struct landlock_id id = {
|
||||
.type = LANDLOCK_KEY_NET_PORT,
|
||||
@@ -191,8 +191,10 @@ static int current_check_access_socket(struct socket *const sock,
|
||||
access_request = landlock_init_layer_masks(subject->domain,
|
||||
access_request, &layer_masks,
|
||||
LANDLOCK_KEY_NET_PORT);
|
||||
if (landlock_unmask_layers(rule, access_request, &layer_masks,
|
||||
ARRAY_SIZE(layer_masks)))
|
||||
if (!access_request)
|
||||
return 0;
|
||||
|
||||
if (landlock_unmask_layers(rule, &layer_masks))
|
||||
return 0;
|
||||
|
||||
audit_net.family = address->sa_family;
|
||||
@@ -203,7 +205,6 @@ static int current_check_access_socket(struct socket *const sock,
|
||||
.audit.u.net = &audit_net,
|
||||
.access = access_request,
|
||||
.layer_masks = &layer_masks,
|
||||
.layer_masks_size = ARRAY_SIZE(layer_masks),
|
||||
});
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
+34
-55
@@ -612,22 +612,24 @@ landlock_find_rule(const struct landlock_ruleset *const ruleset,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* @layer_masks is read and may be updated according to the access request and
|
||||
* the matching rule.
|
||||
* @masks_array_size must be equal to ARRAY_SIZE(*layer_masks).
|
||||
/**
|
||||
* landlock_unmask_layers - Remove the access rights in @masks
|
||||
* which are granted in @rule
|
||||
*
|
||||
* Returns true if the request is allowed (i.e. relevant layer masks for the
|
||||
* request are empty).
|
||||
* Updates the set of (per-layer) unfulfilled access rights @masks
|
||||
* so that all the access rights granted in @rule are removed from it
|
||||
* (because they are now fulfilled).
|
||||
*
|
||||
* @rule: A rule that grants a set of access rights for each layer
|
||||
* @masks: A matrix of unfulfilled access rights for each layer
|
||||
*
|
||||
* Returns true if the request is allowed (i.e. the access rights granted all
|
||||
* remaining unfulfilled access rights and masks has no leftover set bits).
|
||||
*/
|
||||
bool landlock_unmask_layers(const struct landlock_rule *const rule,
|
||||
const access_mask_t access_request,
|
||||
layer_mask_t (*const layer_masks)[],
|
||||
const size_t masks_array_size)
|
||||
struct layer_access_masks *masks)
|
||||
{
|
||||
size_t layer_level;
|
||||
|
||||
if (!access_request || !layer_masks)
|
||||
if (!masks)
|
||||
return true;
|
||||
if (!rule)
|
||||
return false;
|
||||
@@ -642,28 +644,18 @@ bool landlock_unmask_layers(const struct landlock_rule *const rule,
|
||||
* by only one rule, but by the union (binary OR) of multiple rules.
|
||||
* E.g. /a/b <execute> + /a <read> => /a/b <execute + read>
|
||||
*/
|
||||
for (layer_level = 0; layer_level < rule->num_layers; layer_level++) {
|
||||
const struct landlock_layer *const layer =
|
||||
&rule->layers[layer_level];
|
||||
const layer_mask_t layer_bit = BIT_ULL(layer->level - 1);
|
||||
const unsigned long access_req = access_request;
|
||||
unsigned long access_bit;
|
||||
bool is_empty;
|
||||
for (size_t i = 0; i < rule->num_layers; i++) {
|
||||
const struct landlock_layer *const layer = &rule->layers[i];
|
||||
|
||||
/*
|
||||
* Records in @layer_masks which layer grants access to each requested
|
||||
* access: bit cleared if the related layer grants access.
|
||||
*/
|
||||
is_empty = true;
|
||||
for_each_set_bit(access_bit, &access_req, masks_array_size) {
|
||||
if (layer->access & BIT_ULL(access_bit))
|
||||
(*layer_masks)[access_bit] &= ~layer_bit;
|
||||
is_empty = is_empty && !(*layer_masks)[access_bit];
|
||||
}
|
||||
if (is_empty)
|
||||
return true;
|
||||
/* Clear the bits where the layer in the rule grants access. */
|
||||
masks->access[layer->level - 1] &= ~layer->access;
|
||||
}
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(masks->access); i++) {
|
||||
if (masks->access[i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef access_mask_t
|
||||
@@ -673,13 +665,12 @@ get_access_mask_t(const struct landlock_ruleset *const ruleset,
|
||||
/**
|
||||
* landlock_init_layer_masks - Initialize layer masks from an access request
|
||||
*
|
||||
* Populates @layer_masks such that for each access right in @access_request,
|
||||
* Populates @masks such that for each access right in @access_request,
|
||||
* the bits for all the layers are set where this access right is handled.
|
||||
*
|
||||
* @domain: The domain that defines the current restrictions.
|
||||
* @access_request: The requested access rights to check.
|
||||
* @layer_masks: It must contain %LANDLOCK_NUM_ACCESS_FS or
|
||||
* %LANDLOCK_NUM_ACCESS_NET elements according to @key_type.
|
||||
* @masks: Layer access masks to populate.
|
||||
* @key_type: The key type to switch between access masks of different types.
|
||||
*
|
||||
* Returns: An access mask where each access right bit is set which is handled
|
||||
@@ -688,23 +679,20 @@ get_access_mask_t(const struct landlock_ruleset *const ruleset,
|
||||
access_mask_t
|
||||
landlock_init_layer_masks(const struct landlock_ruleset *const domain,
|
||||
const access_mask_t access_request,
|
||||
layer_mask_t (*const layer_masks)[],
|
||||
struct layer_access_masks *const masks,
|
||||
const enum landlock_key_type key_type)
|
||||
{
|
||||
access_mask_t handled_accesses = 0;
|
||||
size_t layer_level, num_access;
|
||||
get_access_mask_t *get_access_mask;
|
||||
|
||||
switch (key_type) {
|
||||
case LANDLOCK_KEY_INODE:
|
||||
get_access_mask = landlock_get_fs_access_mask;
|
||||
num_access = LANDLOCK_NUM_ACCESS_FS;
|
||||
break;
|
||||
|
||||
#if IS_ENABLED(CONFIG_INET)
|
||||
case LANDLOCK_KEY_NET_PORT:
|
||||
get_access_mask = landlock_get_net_access_mask;
|
||||
num_access = LANDLOCK_NUM_ACCESS_NET;
|
||||
break;
|
||||
#endif /* IS_ENABLED(CONFIG_INET) */
|
||||
|
||||
@@ -713,27 +701,18 @@ landlock_init_layer_masks(const struct landlock_ruleset *const domain,
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(layer_masks, 0,
|
||||
array_size(sizeof((*layer_masks)[0]), num_access));
|
||||
|
||||
/* An empty access request can happen because of O_WRONLY | O_RDWR. */
|
||||
if (!access_request)
|
||||
return 0;
|
||||
|
||||
/* Saves all handled accesses per layer. */
|
||||
for (layer_level = 0; layer_level < domain->num_layers; layer_level++) {
|
||||
const unsigned long access_req = access_request;
|
||||
const access_mask_t access_mask =
|
||||
get_access_mask(domain, layer_level);
|
||||
unsigned long access_bit;
|
||||
for (size_t i = 0; i < domain->num_layers; i++) {
|
||||
const access_mask_t handled = get_access_mask(domain, i);
|
||||
|
||||
for_each_set_bit(access_bit, &access_req, num_access) {
|
||||
if (BIT_ULL(access_bit) & access_mask) {
|
||||
(*layer_masks)[access_bit] |=
|
||||
BIT_ULL(layer_level);
|
||||
handled_accesses |= BIT_ULL(access_bit);
|
||||
}
|
||||
}
|
||||
masks->access[i] = access_request & handled;
|
||||
handled_accesses |= masks->access[i];
|
||||
}
|
||||
for (size_t i = domain->num_layers; i < ARRAY_SIZE(masks->access); i++)
|
||||
masks->access[i] = 0;
|
||||
|
||||
return handled_accesses;
|
||||
}
|
||||
|
||||
@@ -302,14 +302,12 @@ landlock_get_scope_mask(const struct landlock_ruleset *const ruleset,
|
||||
}
|
||||
|
||||
bool landlock_unmask_layers(const struct landlock_rule *const rule,
|
||||
const access_mask_t access_request,
|
||||
layer_mask_t (*const layer_masks)[],
|
||||
const size_t masks_array_size);
|
||||
struct layer_access_masks *masks);
|
||||
|
||||
access_mask_t
|
||||
landlock_init_layer_masks(const struct landlock_ruleset *const domain,
|
||||
const access_mask_t access_request,
|
||||
layer_mask_t (*const layer_masks)[],
|
||||
struct layer_access_masks *masks,
|
||||
const enum landlock_key_type key_type);
|
||||
|
||||
#endif /* _SECURITY_LANDLOCK_RULESET_H */
|
||||
|
||||
Reference in New Issue
Block a user