Skip to content

Commit

Permalink
syscalls/keyctl02: wait for last key to be garbage collected
Browse files Browse the repository at this point in the history
Fixes: #409

This tests creates a lot of keys, which are revoked, but they may
not all be destroyed by the time test finishes. This can create
problems for subsequent tests which will hit quota limit and fail.

This patch adds loop, that periodically sleeps and checks if last
test key has been garbage collected yet.

Signed-off-by: Jan Stancek <jstancek@redhat.com>
Acked-by: Cyril Hrubis <chrubis@suse.cz>
  • Loading branch information
jstancek committed Oct 17, 2018
1 parent 0cd48d1 commit 75dd92c
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 3 deletions.
4 changes: 4 additions & 0 deletions include/lapi/keyctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,10 @@ static inline key_serial_t keyctl_join_session_keyring(const char *name) {
# define KEYCTL_SET_TIMEOUT 15
#endif

#ifndef KEYCTL_INVALIDATE
# define KEYCTL_INVALIDATE 21
#endif

/* key permissions */
#ifndef KEY_POS_VIEW
# define KEY_POS_VIEW 0x01000000
Expand Down
40 changes: 37 additions & 3 deletions testcases/kernel/syscalls/keyctl/keyctl02.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include "lapi/keyctl.h"

#define LOOPS 20000
#define MAX_WAIT_FOR_GC_MS 5000
#define PATH_KEY_COUNT_QUOTA "/proc/sys/kernel/keys/root_maxkeys"

static int orig_maxkeys;
Expand All @@ -69,8 +70,8 @@ static void *do_revoke(void *arg)

static void do_test(void)
{
int i;
key_serial_t key;
int i, ret;
key_serial_t key, key_inv;
pthread_t pth[4];

for (i = 0; i < LOOPS; i++) {
Expand All @@ -94,13 +95,46 @@ static void do_test(void)
SAFE_PTHREAD_JOIN(pth[3], NULL);
}

/*
* Kernel should start garbage collect when last reference to key
* is removed (see key_put()). Since we are adding keys with identical
* description and type, each replacement should schedule a gc run,
* see comment at __key_link().
*
* We create extra key here, to remove reference to last revoked key.
*/
key_inv = add_key("user", "ltptestkey", "foo", 3,
KEY_SPEC_PROCESS_KEYRING);
if (key_inv == -1)
tst_brk(TBROK | TERRNO, "Failed to add key");

/*
* If we have invalidate, we can drop extra key immediately as well,
* which also schedules gc.
*/
if (keyctl(KEYCTL_INVALIDATE, key_inv) == -1 && errno != EOPNOTSUPP)
tst_brk(TBROK | TERRNO, "Failed to invalidate key");

/*
* At this point we are quite confident that gc has been scheduled,
* so we wait and periodically check for last test key to be removed.
*/
for (i = 0; i < MAX_WAIT_FOR_GC_MS; i += 100) {
ret = keyctl(KEYCTL_REVOKE, key);
if (ret == -1 && errno == ENOKEY)
break;
usleep(100*1000);
}

if (i)
tst_res(TINFO, "waiting for key gc took: %d ms", i);
tst_res(TPASS, "Bug not reproduced");
}

static void setup(void)
{
SAFE_FILE_SCANF(PATH_KEY_COUNT_QUOTA, "%d", &orig_maxkeys);
SAFE_FILE_PRINTF(PATH_KEY_COUNT_QUOTA, "%d", orig_maxkeys + LOOPS);
SAFE_FILE_PRINTF(PATH_KEY_COUNT_QUOTA, "%d", orig_maxkeys + LOOPS + 1);
}

static void cleanup(void)
Expand Down

0 comments on commit 75dd92c

Please sign in to comment.