[RFC PATCH v3 06/19] selftests/landlock: Test adding a rule for unhandled access
Mikhail Ivanov
ivanov.mikhail1 at huawei-partners.com
Fri Sep 13 16:15:20 UTC 2024
On 9/13/2024 6:04 PM, Günther Noack wrote:
> On Wed, Sep 11, 2024 at 11:19:48AM +0300, Mikhail Ivanov wrote:
>> On 9/10/2024 12:22 PM, Günther Noack wrote:
>>> Hi!
>>>
>>> On Wed, Sep 04, 2024 at 06:48:11PM +0800, Mikhail Ivanov wrote:
>>>> Add test that validates behaviour of Landlock after rule with
>>>> unhandled access is added.
>>>>
>>>> Signed-off-by: Mikhail Ivanov <ivanov.mikhail1 at huawei-partners.com>
>>>> ---
>>>> Changes since v2:
>>>> * Replaces EXPECT_EQ with ASSERT_EQ for close().
>>>> * Refactors commit title and message.
>>>>
>>>> Changes since v1:
>>>> * Refactors commit message.
>>>> ---
>>>> .../testing/selftests/landlock/socket_test.c | 33 +++++++++++++++++++
>>>> 1 file changed, 33 insertions(+)
>>>>
>>>> diff --git a/tools/testing/selftests/landlock/socket_test.c b/tools/testing/selftests/landlock/socket_test.c
>>>> index 811bdaa95a7a..d2fedfca7193 100644
>>>> --- a/tools/testing/selftests/landlock/socket_test.c
>>>> +++ b/tools/testing/selftests/landlock/socket_test.c
>>>> @@ -351,4 +351,37 @@ TEST_F(protocol, rule_with_unknown_access)
>>>> ASSERT_EQ(0, close(ruleset_fd));
>>>> }
>>>> +TEST_F(protocol, rule_with_unhandled_access)
>>>> +{
>>>> + struct landlock_ruleset_attr ruleset_attr = {
>>>> + .handled_access_socket = LANDLOCK_ACCESS_SOCKET_CREATE,
>>>> + };
>>>> + struct landlock_socket_attr protocol = {
>>>> + .family = self->prot.family,
>>>> + .type = self->prot.type,
>>>> + };
>>>> + int ruleset_fd;
>>>> + __u64 access;
>>>> +
>>>> + ruleset_fd =
>>>> + landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
>>>> + ASSERT_LE(0, ruleset_fd);
>>>> +
>>>> + for (access = 1; access > 0; access <<= 1) {
>>>> + int err;
>>>> +
>>>> + protocol.allowed_access = access;
>>>> + err = landlock_add_rule(ruleset_fd, LANDLOCK_RULE_SOCKET,
>>>> + &protocol, 0);
>>>> + if (access == ruleset_attr.handled_access_socket) {
>>>> + EXPECT_EQ(0, err);
>>>> + } else {
>>>> + EXPECT_EQ(-1, err);
>>>> + EXPECT_EQ(EINVAL, errno);
>>>> + }
>>>> + }
>>>> +
>>>> + ASSERT_EQ(0, close(ruleset_fd));
>>>> +}
>>>> +
>>>
>>> I should probably have noticed this on the first review round; you are not
>>> actually exercising any scenario here where a rule with unhandled access is
>>> added.
>>>
>>> To clarify, the notion of an access right being "unhandled" means that the
>>> access right was not listed at ruleset creation time in the ruleset_attr's
>>> .handled_access_* field where it would have belonged. If that is the case,
>>> adding a ruleset with that access right is going to be denied.
>>>
>>> As an example:
>>> If the ruleset only handles LANDLOCK_ACCESS_FS_WRITE_FILE and nothing else,
>>> then, if the test tries to insert a rule for LANDLOCK_ACCESS_SOCKET_CREATE,
>>> that call is supposed to fail -- because the "socket creation" access right is
>>> not handled.
>>
>> This test was added to exercise adding a rule with future possible
>> "unhandled" access rights of "socket" type, but since this patch
>> implements only one, this test is really meaningless. Thank you for
>> this note!
>>
>>>
>>> IMHO the test would become more reasonable if it was more clearly "handling"
>>> something entirely unrelated at ruleset creation time, e.g. one of the file
>>> system access rights. (And we could do the same for the "net" and "fs" tests as
>>> well.)
>>>
>>> Your test is a copy of the same test for the "net" rights, which in turn is a
>>> copy of teh same test for the "fs" rights. When the "fs" test was written, the
>>> "fs" access rights were the only ones that could be used at all to create a
>>> ruleset, but this is not true any more.
>>
>> Good idea! Can I implement such test in the current patchset?
>
> Yes, I think it would be a good idea.
>
> I would, in fact, recommend to turn the rule_with_unhandled_access test into that test.
>
> The test traces its roots clearly to
>
> TEST_F(mini, rule_with_unhandled_access) from net_test.c
>
> and to
>
> TEST_F_FORK(layout1, rule_with_unhandled_access) from fs_test.c
>
>
> and I think all three variants would better be advised to create a ruleset with
>
> struct landlock_ruleset_attr ruleset_attr = {
> .handled_access_something_entirely_different = LANDLOCK_ACCESS_WHATEVER,
> }
>
> and then check their corresponding fs, net and socket access rights using a
> landlock_add_rule() call for the access rights that belong to the respective
> module, so that it exercises the scenario where userspace attempts to use the
> access right in a rule, but the surrounding ruleset did not restrict the same
> access right (it was "unhandled").
Agreed, thanks for the recommendation!
>
> In spirit, it would be nicest if we could create a ruleset where nothing at all
> is handled, but I believe in that case, the landlock_create_ruleset() call would
> already fail.
>
> —Günther
>
> P.S.: I am starting to grow a bit uncomfortable with the amount of duplicated
> test code that we start having across the different types of access rights. If
> you see a way to keep this more in check, while still keeping the tests
> expressive and not over-frameworking them, let's try to move in that direction
> if we can. :)
Yeah, I really want to see patchset dedicated to tests refactoring. I'll
try to finish the description of corresponding issue [1] ASAP.
[1] https://github.com/landlock-lsm/linux/issues/34
More information about the Linux-security-module-archive
mailing list