blob: 316146745135ce793937d0a9ec778e299c67e682 [file] [log] [blame]
/* Tests built into the keyctl program
*
* Copyright (C) 2019 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#define _GNU_SOURCE
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <errno.h>
#include <sys/stat.h>
#include <asm/unistd.h>
#include "keyutils.h"
#include <limits.h>
#include "keyctl.h"
static nr void act_keyctl_test_limits(int, char *[]);
static nr void act_keyctl_test_limits2(int, char *[]);
static const struct command test_commands[] = {
{ act_keyctl_test_limits, "limits", "" },
{ act_keyctl_test_limits2, "limits2", "" },
{ NULL, NULL, NULL }
};
static void test_format(void) __attribute__((noreturn));
static void test_format(void)
{
const struct command *cmd;
fprintf(stderr, "Format:\n");
for (cmd = test_commands; cmd->name; cmd++)
fprintf(stderr, " keyctl --test %s %s\n", cmd->name, cmd->format);
fprintf(stderr, "\n");
fprintf(stderr, "Key/keyring ID:\n");
fprintf(stderr, " <nnn> numeric keyring ID\n");
fprintf(stderr, " @t thread keyring\n");
fprintf(stderr, " @p process keyring\n");
fprintf(stderr, " @s session keyring\n");
fprintf(stderr, " @u user keyring\n");
fprintf(stderr, " @us user default session keyring\n");
fprintf(stderr, " @g group keyring\n");
fprintf(stderr, " @a assumed request_key authorisation key\n");
fprintf(stderr, "\n");
fprintf(stderr, "<type> can be \"user\" for a user-defined keyring\n");
fprintf(stderr, "If you do this, prefix the description with \"<subtype>:\"\n");
exit(2);
}
/*
* Provide some testing functions for "keyctl --test"
*/
void act_keyctl_test(int argc, char *argv[])
{
if (argc < 2)
test_format();
do_command(argc, argv, test_commands, "test ");
}
/*
* Test the limits of the type and description fields in add_user().
*/
static void act_keyctl_test_limits(int argc, char *argv[])
{
key_serial_t key;
char buf[8192];
int i, nr_fail = 0;
if (argc != 1)
test_format();
setvbuf(stdout, NULL, _IONBF, 0);
for (i = 0; i < sizeof(buf); i++) {
if (i % 32 == 0) {
if (i != 0)
putchar('\n');
printf("TEST SIZE %d", i);
}
buf[i] = 0;
putchar('.');
if (add_key(buf, "wibble", "a", 1, KEY_SPEC_THREAD_KEYRING) == -1) {
if (i == 0 || i >= 32) {
if (errno != EINVAL) {
putchar('\n');
fprintf(stderr, "%d type failed: %m\n", i);
nr_fail++;
}
} else {
if (errno != ENODEV) {
putchar('\n');
fprintf(stderr, "%d type failed: %m\n", i);
nr_fail++;
}
}
} else {
putchar('\n');
fprintf(stderr, "%d type unexpectedly succeeded\n", i);
nr_fail++;
}
putchar('_');
key = add_key("user", buf, "a", 1, KEY_SPEC_THREAD_KEYRING);
if (key == -1) {
if (i == 0 || i >= 4096) {
if (errno != EINVAL) {
putchar('\n');
fprintf(stderr, "%d desc failed: %m\n", i);
nr_fail++;
}
} else {
putchar('\n');
fprintf(stderr, "%d desc wrong error: %m\n", i);
nr_fail++;
}
} else {
if (i == 0 || i >= 4096) {
putchar('\n');
fprintf(stderr, "%d desc unexpectedly succeeded\n", i);
nr_fail++;
}
if (keyctl_unlink(key, KEY_SPEC_THREAD_KEYRING) == -1) {
putchar('\n');
fprintf(stderr, "Unlink failed: %m\n");
nr_fail++;
}
}
buf[i] = 'a';
if (nr_fail > 20) {
fprintf(stderr, "Aborting with too many failures\n");
exit(1);
}
}
putchar('\n');
exit(nr_fail ? 1 : 0);
}
/*
* Test the limits of the payload field in add_user(). The user-type will only
* accept sizes in the range 1-32767 bytes, though add_key() will accept up to
* just shy of 1MiB.
*/
static void act_keyctl_test_limits2(int argc, char *argv[])
{
key_serial_t key;
char buf[1030 * 1024];
int i, nr_fail = 0;
if (argc != 1)
test_format();
setvbuf(stdout, NULL, _IONBF, 0);
memset(buf, 'a', sizeof(buf));
for (i = 0; i < sizeof(buf); i++) {
if (i % 2048 == 0) {
if (i != 0)
putchar('\n');
printf("TEST SIZE %7d ", i);
}
if (i % (2048 / 32) == 0)
putchar('.');
key = add_key("user", "a", buf, i, KEY_SPEC_THREAD_KEYRING);
if (key == -1) {
if (i == 0 || i > 32767) {
if (errno != EINVAL) {
putchar('\n');
fprintf(stderr, "%d desc failed: %m\n", i);
nr_fail++;
}
} else if (errno == EDQUOT) {
/* This might happen due to us creating keys
* really fast.
*/
} else {
putchar('\n');
fprintf(stderr, "%d desc wrong error: %m\n", i);
nr_fail++;
}
} else {
if (i == 0 || i > 32767) {
putchar('\n');
fprintf(stderr, "%d desc unexpectedly succeeded\n", i);
nr_fail++;
}
if (keyctl_unlink(key, KEY_SPEC_THREAD_KEYRING) == -1) {
putchar('\n');
fprintf(stderr, "Unlink failed: %m\n");
nr_fail++;
}
}
if (nr_fail > 20) {
fprintf(stderr, "Aborting with too many failures\n");
exit(1);
}
}
putchar('\n');
exit(nr_fail ? 1 : 0);
}