[RFC PATCH v2 1/9] landlock: Refactor current_check_access_socket() access right check
Mikhail Ivanov
ivanov.mikhail1 at huawei-partners.com
Tue Aug 20 11:20:55 UTC 2024
8/20/2024 12:37 AM, Günther Noack wrote:
> Hello!
>
> Thanks for sending round 2 of this patch set!
>
> On Wed, Aug 14, 2024 at 11:01:43AM +0800, Mikhail Ivanov wrote:
>> The current_check_access_socket() function contains a set of address
>> validation checks for bind(2) and connect(2) hooks. Separate them from
>> an actual port access right checking. It is required for the (future)
>> hooks that do not perform address validation.
>>
>> Signed-off-by: Mikhail Ivanov <ivanov.mikhail1 at huawei-partners.com>
>> ---
>> security/landlock/net.c | 41 ++++++++++++++++++++++++-----------------
>> 1 file changed, 24 insertions(+), 17 deletions(-)
>>
>> diff --git a/security/landlock/net.c b/security/landlock/net.c
>> index c8bcd29bde09..669ba260342f 100644
>> --- a/security/landlock/net.c
>> +++ b/security/landlock/net.c
>> @@ -2,7 +2,7 @@
>> /*
>> * Landlock LSM - Network management and hooks
>> *
>> - * Copyright © 2022-2023 Huawei Tech. Co., Ltd.
>> + * Copyright © 2022-2024 Huawei Tech. Co., Ltd.
>> * Copyright © 2022-2023 Microsoft Corporation
>> */
>>
>> @@ -61,17 +61,34 @@ static const struct landlock_ruleset *get_current_net_domain(void)
>> return dom;
>> }
>>
>> -static int current_check_access_socket(struct socket *const sock,
>> - struct sockaddr *const address,
>> - const int addrlen,
>> - access_mask_t access_request)
>> +static int check_access_socket(const struct landlock_ruleset *const dom,
>> + __be16 port, access_mask_t access_request)
>
> It might be worth briefly spelling out in documentation that access_request in
> current_check_access_socket() may only have a single bit set. This is different
> to other places where access_mask_t is used, where combinations of these flags
> are possible.
>
> These functions do checks for special cases using "if (access_request ==
> LANDLOCK_ACCESS_NET_CONNECT_TCP)" and the same for "bind". I think it's a
> reasonable way to simplify the implementation here, but we have to be careful to
> not accidentally use it differently.
>
> It is a preexisting issue, so I don't consider it a blocker, but it might be
> worth fixing while we are at it?
I think such comment is not required if we remove
"current_check_access_socket()" as you suggest? In this function
access_request can be a mask with multiple access rights included.
>
>
>> {
>> - __be16 port;
>> layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_NET] = {};
>> const struct landlock_rule *rule;
>> struct landlock_id id = {
>> .type = LANDLOCK_KEY_NET_PORT,
>> };
>> +
>> + id.key.data = (__force uintptr_t)port;
>> + BUILD_BUG_ON(sizeof(port) > sizeof(id.key.data));
>> +
>> + rule = landlock_find_rule(dom, id);
>> + access_request = landlock_init_layer_masks(
>> + dom, access_request, &layer_masks, LANDLOCK_KEY_NET_PORT);
>> + if (landlock_unmask_layers(rule, access_request, &layer_masks,
>> + ARRAY_SIZE(layer_masks)))
>> + return 0;
>> +
>> + return -EACCES;
>> +}
>> +
>> +static int current_check_access_socket(struct socket *const sock,
>
> Re-reading the implementation of this function, it was surprised how specialized
> it is towards the "connect" and "bind" use cases, which it has specific code
> paths for. This does not look like it would extend naturally to additional
> operations.
>
> After your refactoring, current_check_access_socket() is now (a) checking that
> we are looking at a TCP address, and extracting the port, and then (b) doing
> connect- and bind-specific logic, and then (c) calling check_access_socket().
>
> Would it maybe be possible to turn the code logic around by creating a
> "get_tcp_port()" helper function for step (a), and then doing all of (a), (b)
> and (c) directly from hook_socket_bind() and hook_socket_connect()? It would
> have the upside that in step (b) you don't need to distinguish between bind and
> connect because it would be clear from the context which of the two cases we are
> in. It would also remove the need for a function that only supports one bit in
> the access_mask_t, which is potentially surprising.
>
> Thanks,
> —Günther
>
Good idea! But I suggest using "get_port_from_addr_tcp()" naming to
distinguish between extracting a port from an address structure and
from a socket (as performed in hook_listen() in the next patch).
More information about the Linux-security-module-archive
mailing list