[PATCH 8/8] tests: Add add_key, keyctl, request_key tests

Eugene Syromyatnikov evgsyr at gmail.com
Thu Sep 29 12:58:05 UTC 2016


* tests/Makefile.am (DECODER_TESTS): Add add_key.test, keyctl.test,
  request_key.test.
  (check_PROGRAMS): Add add_key, keyctl, request_key.
* tests/.gitignore: Likewise.
* tests/add_key.c: New file.
* tests/add_key.test: Likewise.
* tests/keyctl.c: Likewise.
* tests/keyctl.test: Likewise.
* tests/request_key.c: Likewise.
* tests/request_key.test: Likewise.
---
 tests/.gitignore       |    3 +
 tests/Makefile.am      |    6 +
 tests/add_key.c        |  128 +++++++++
 tests/add_key.test     |    6 +
 tests/keyctl.c         |  713 ++++++++++++++++++++++++++++++++++++++++++++++++
 tests/keyctl.test      |    6 +
 tests/request_key.c    |  124 +++++++++
 tests/request_key.test |    6 +
 8 files changed, 992 insertions(+)
 create mode 100644 tests/add_key.c
 create mode 100755 tests/add_key.test
 create mode 100644 tests/keyctl.c
 create mode 100755 tests/keyctl.test
 create mode 100644 tests/request_key.c
 create mode 100755 tests/request_key.test

diff --git a/tests/.gitignore b/tests/.gitignore
index 9ee036b..5b33416 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -10,6 +10,7 @@ accept
 accept4
 access
 acct
+addkey
 adjtimex
 aio
 alarm
@@ -117,6 +118,7 @@ ipc_msg
 ipc_msgbuf
 ipc_sem
 ipc_shm
+keyctl
 kill
 ksysent
 ksysent.h
@@ -208,6 +210,7 @@ remap_file_pages
 rename
 renameat
 renameat2
+request_key
 restart_syscall
 rmdir
 rt_sigpending
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 86672fc..0c24969 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -69,6 +69,7 @@ check_PROGRAMS = \
 	accept4 \
 	access \
 	acct \
+	add_key \
 	adjtimex \
 	aio \
 	alarm \
@@ -176,6 +177,7 @@ check_PROGRAMS = \
 	ipc_msgbuf \
 	ipc_sem \
 	ipc_shm \
+	keyctl \
 	kill \
 	ksysent \
 	lchown \
@@ -265,6 +267,7 @@ check_PROGRAMS = \
 	rename \
 	renameat \
 	renameat2 \
+	request_key \
 	restart_syscall \
 	rmdir \
 	rt_sigpending \
@@ -414,6 +417,7 @@ DECODER_TESTS = \
 	accept4.test \
 	access.test \
 	acct.test \
+	add_key.test \
 	adjtimex.test \
 	aio.test \
 	alarm.test \
@@ -518,6 +522,7 @@ DECODER_TESTS = \
 	ipc_msgbuf.test \
 	ipc_sem.test \
 	ipc_shm.test \
+	keyctl.test \
 	kill.test \
 	lchown.test \
 	lchown32.test \
@@ -601,6 +606,7 @@ DECODER_TESTS = \
 	rename.test \
 	renameat.test \
 	renameat2.test \
+	request_key.test \
 	rmdir.test \
 	rt_sigpending.test \
 	rt_sigprocmask.test \
diff --git a/tests/add_key.c b/tests/add_key.c
new file mode 100644
index 0000000..0773823
--- /dev/null
+++ b/tests/add_key.c
@@ -0,0 +1,128 @@
+#include "tests.h"
+
+#include <asm/unistd.h>
+
+#ifdef __NR_add_key
+
+# include <inttypes.h>
+# include <stdio.h>
+# include <unistd.h>
+
+void
+print_val_str(const void *ptr, const char *str)
+{
+	if (str)
+		printf("%s, ", str);
+	else
+		printf("%p, ", ptr);
+}
+
+void
+do_add_key(const char *type, const char *type_str, const char *desc,
+	const char *desc_str, const char *payload, const char *payload_str,
+	size_t plen, int32_t keyring, const char *keyring_str)
+{
+	long rc;
+
+	rc = syscall(__NR_add_key, type, desc, payload, plen, keyring);
+	printf("add_key(");
+	print_val_str(type, type_str);
+	print_val_str(desc, desc_str);
+	print_val_str(payload, payload_str);
+	printf("%zu, ", plen);
+	if (keyring_str)
+		printf("%s", keyring_str);
+	else
+		printf("%d", keyring);
+	printf(") = %s\n", sprintrc(rc));
+}
+
+# define _STR(_arg) #_arg
+# define ARG_STR(_arg) (_arg), #_arg
+
+int
+main(void)
+{
+	static const char unterminated1[] = { '\1', '\2', '\3', '\4', '\5' };
+	static const char unterminated2[] = { '\6', '\7', '\10', '\11', '\12' };
+	static const char unterminated3[] =
+		{ '\16', '\17', '\20', '\21', '\22' };
+
+	char *bogus_type = tail_memdup(unterminated1, sizeof(unterminated1));
+	char *bogus_desc = tail_memdup(unterminated2, sizeof(unterminated2));
+	char *bogus_payload = tail_memdup(unterminated3, sizeof(unterminated3));
+
+	unsigned i;
+	unsigned j;
+	unsigned k;
+	unsigned l;
+
+	struct {
+		const char *type;
+		const char *str;
+	} types[] = {
+		{ ARG_STR(NULL) },
+		{ (const char *) 0xfffffee1fffffbadULL, NULL },
+		{ bogus_type, NULL },
+		{ ARG_STR("\20\21\22\23\24") },
+		{ ARG_STR("user") },
+	};
+
+	struct {
+		const char *desc;
+		const char *str;
+	} descs[] = {
+		{ ARG_STR(NULL) },
+		{ (const char *) 0xfffff00dfffffca7ULL, NULL },
+		{ bogus_desc, NULL },
+		{ ARG_STR("\25\26\27\30\31") },
+		{ ARG_STR("desc") },
+		{ "overly long description", _STR("overly long ") "..." },
+	};
+
+	struct {
+		const char *pload;
+		const char *str;
+		size_t plen;
+	} payloads[] = {
+		{ ARG_STR(NULL), 0 },
+		{ (const char *) 0xfffffacefffff157ULL, NULL,
+			(size_t) 0xdeadbeefbadc0dedULL },
+		{ bogus_payload, _STR(""), 0 },
+		{ bogus_payload, _STR("\16\17\20\21\22"), 5 },
+		{ bogus_payload, NULL, 10 },
+		{ "overly long payload", _STR("overly long ") "...", 15 },
+	};
+
+	struct {
+		uint32_t keyring;
+		const char *str;
+	} keyrings[] = {
+		{ ARG_STR(0) },
+		{ ARG_STR(1234567890) },
+		{ ARG_STR(-1234567890) },
+		{ -1, "KEY_SPEC_THREAD_KEYRING" },
+	};
+
+	for (i = 0; i < ARRAY_SIZE(types); i++)
+		for (j = 0; j < ARRAY_SIZE(descs); j++)
+			for (k = 0; k < ARRAY_SIZE(payloads); k++)
+				for (l = 0; l < ARRAY_SIZE(keyrings); l++)
+					do_add_key(types[i].type, types[i].str,
+						descs[j].desc, descs[j].str,
+						payloads[k].pload,
+						payloads[k].str,
+						payloads[k].plen,
+						keyrings[l].keyring,
+						keyrings[l].str);
+
+	puts("+++ exited with 0 +++");
+
+	return 0;
+}
+
+#else
+
+SKIP_MAIN_UNDEFINED("__NR_add_key");
+
+#endif
diff --git a/tests/add_key.test b/tests/add_key.test
new file mode 100755
index 0000000..574c91d
--- /dev/null
+++ b/tests/add_key.test
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+# Check add_key syscall decoding.
+
+. "${srcdir=.}/init.sh"
+run_strace_match_diff -a1 -s12
diff --git a/tests/keyctl.c b/tests/keyctl.c
new file mode 100644
index 0000000..3351c97
--- /dev/null
+++ b/tests/keyctl.c
@@ -0,0 +1,713 @@
+#include "tests.h"
+
+#include <asm/unistd.h>
+
+#ifdef __NR_keyctl
+
+# include <linux/types.h>
+# include <linux/keyctl.h>
+
+# include <errno.h>
+# include <inttypes.h>
+# include <stdarg.h>
+# include <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+# include <unistd.h>
+
+#include <sys/uio.h>
+
+
+# if !defined(HAVE___KERNEL_ULONG_T) || !HAVE___KERNEL_ULONG_T
+typedef unsigned long __kernel_ulong_t;
+# endif
+
+/* This check should be before #include "xlat/keyctl_commands.h" */
+# ifndef KEYCTL_DH_COMPUTE
+struct keyctl_dh_params {
+	int32_t private;
+	int32_t prime;
+	int32_t base;
+};
+# endif
+
+# include "xlat.h"
+# include "xlat/keyctl_commands.h"
+
+# ifndef KEY_SPEC_REQKEY_AUTH_KEY
+#  define KEY_SPEC_REQKEY_AUTH_KEY   -7
+# endif
+
+# ifndef KEY_SPEC_REQUESTOR_KEYRING
+#  define KEY_SPEC_REQUESTOR_KEYRING -8
+# endif
+
+static const size_t limit = 10;
+
+void
+print_quoted_string_limit(const char *str, ssize_t size, long rc)
+{
+	size_t abs_size = abs(size);
+	size_t limited_size = abs_size > limit ? limit : abs_size;
+
+	if ((rc == -1) && (size > 0)) {
+		printf("%p", str);
+		return;
+	}
+
+	if (strnlen(str, limited_size) == limited_size) {
+		printf("\"");
+		print_quoted_memory(str, limited_size);
+		if (abs_size > limit)
+			printf("\"...");
+		else
+			printf("\"");
+	} else {
+		printf("\"");
+		print_quoted_string(str);
+		printf("\"");
+	}
+}
+
+static void
+print_arg(__kernel_ulong_t arg, const char *str, const char *fmt, ssize_t size,
+	long rc)
+{
+	if (str) {
+		printf("%s", str);
+	} else {
+		if (size == sizeof(uint64_t))
+			printf(fmt, (uint64_t)arg);
+		else if (size == sizeof(uint32_t))
+			printf(fmt, (uint32_t)arg);
+		else
+			print_quoted_string_limit((void *)arg, size, rc);
+	}
+}
+
+/*
+ * Arguments are passed as sz, val, str, fmt. Arguments are read until 4
+ * arguments are retrieved or size of 0 is occurred.
+ *
+ * str == NULL && fmt == NULL && sz not in {4, 8} - print_quoted_string_limit is
+ *   used for argument printing. If sz is negative, in argument is assumed, out
+ *   otherwise.
+ */
+void
+do_keyctl(__kernel_ulong_t cmd, const char *cmd_str, ...)
+{
+	__kernel_ulong_t args[4] = {
+		(__kernel_ulong_t) 0xdeadfee1badc0de5ULL,
+		(__kernel_ulong_t) 0xdeadfee2badc0de6ULL,
+		(__kernel_ulong_t) 0xdeadfee3badc0de7ULL,
+		(__kernel_ulong_t) 0xdeadfee4badc0de8ULL,
+	};
+	const char *arg_str[4] = { NULL };
+	const char *arg_fmt[4] = { "%llu", "%llu", "%llu", "%llu" };
+	ssize_t arg_sz[4] = {
+		sizeof(__kernel_ulong_t),
+		sizeof(__kernel_ulong_t),
+		sizeof(__kernel_ulong_t),
+		sizeof(__kernel_ulong_t),
+	};
+	long rc;
+	unsigned i;
+	unsigned cnt = 0;
+
+	va_list ap;
+
+	va_start(ap, cmd_str);
+
+	do {
+		arg_sz[cnt] = va_arg(ap, size_t);
+		if (!arg_sz[cnt])
+			break;
+
+		if (arg_sz[cnt] == sizeof(uint64_t))
+			args[cnt] = va_arg(ap, uint64_t);
+		else if (arg_sz[cnt] == sizeof(uint32_t))
+			args[cnt] = va_arg(ap, uint32_t);
+		else
+			args[cnt] = (uintptr_t) va_arg(ap, void *);
+
+		arg_str[cnt] = va_arg(ap, char *);
+		arg_fmt[cnt] = va_arg(ap, char *);
+	} while (++cnt < 4);
+
+	rc = syscall(__NR_keyctl, cmd, args[0], args[1], args[2], args[3]);
+	printf("keyctl(%s", cmd_str);
+	for (i = 0; i < cnt; i++) {
+		printf(", ");
+		print_arg(args[i], arg_str[i], arg_fmt[i], arg_sz[i], rc);
+	}
+	printf(") = %s\n", sprintrc(rc));
+}
+
+# define _STR(_arg) #_arg
+# define ARG_STR(_arg) (_arg), #_arg
+
+int
+main(void)
+{
+	enum { PR_LIMIT = 10, IOV_SIZE = 11, IOV_STR_SIZE = 4096 };
+
+	static const char *kulong_fmt =
+		sizeof(__kernel_ulong_t) == sizeof(uint64_t) ? "%#llx" : "%#x";
+	static const char *ksize_fmt =
+		sizeof(__kernel_ulong_t) == sizeof(uint64_t) ? "%llu" : "%u";
+	static const char *ptr_fmt =
+		sizeof(void *) == sizeof(uint64_t) ? "%#llx" : "%#x";
+	static const char unterminated1[] = { '\1', '\2', '\3', '\4', '\5' };
+	static const char unterminated2[] = { '\6', '\7', '\10', '\11', '\12' };
+	static const char short_type_str[] = "shrt type";
+	static const char short_desc_str[] = "shrt desc";
+	static const char long_type_str[] = "overly long key type";
+	static const char long_desc_str[] = "overly long key description";
+	static const int32_t bogus_key1 = 0xdeadf00d;
+	static const int32_t bogus_key2 = 0x1eefdead;
+	static const __kernel_ulong_t bogus_key3 =
+		(__kernel_ulong_t) 0xdec0ded1dec0ded2ULL;
+	static const char *bogus_key3_str = "-557785390";
+
+	static const struct keyctl_dh_params kcdhp_data = {
+		KEY_SPEC_GROUP_KEYRING, 1234567890, 3141592653U };
+	static const char *kcdhp_str = "{private=KEY_SPEC_GROUP_KEYRING, "
+		"prime=1234567890, base=-1153374643}";
+
+	char *bogus_str = tail_memdup(unterminated1, sizeof(unterminated1));
+	char *bogus_desc = tail_memdup(unterminated2, sizeof(unterminated2));
+	char *short_type = tail_memdup(short_type_str, sizeof(short_type_str));
+	char *short_desc = tail_memdup(short_desc_str, sizeof(short_desc_str));
+	char *long_type = tail_memdup(long_type_str, sizeof(long_type_str));
+	char *long_desc = tail_memdup(long_desc_str, sizeof(long_desc_str));
+	char *kcdhp = tail_memdup(&kcdhp_data, sizeof(kcdhp_data));
+	struct iovec *key_iov = tail_alloc(sizeof(*key_iov) * IOV_SIZE);
+	char *bogus_buf1 = tail_alloc(9);
+	char *bogus_buf2 = tail_alloc(256);
+	char *key_iov_str1;
+	char *key_iov_str2 = malloc(4096);
+	ssize_t ret;
+	ssize_t kis_size = 0;
+	int i;
+
+	key_iov[0].iov_base = short_type;
+	key_iov[0].iov_len = sizeof(short_type_str);
+	key_iov[1].iov_base = long_type;
+	key_iov[1].iov_len = sizeof(long_type_str);
+	key_iov[2].iov_base = short_desc;
+	key_iov[2].iov_len = sizeof(short_desc_str);
+	key_iov[3].iov_base = long_desc;
+	key_iov[3].iov_len = sizeof(long_desc_str);
+	key_iov[4].iov_base = bogus_str;
+	key_iov[4].iov_len = 32;
+
+	for (i = 5; i < IOV_SIZE; i++) {
+		key_iov[i].iov_base =
+			(void *) (uintptr_t) (0xfffffacefffff00dULL +
+			0x100000001ULL * i);
+		key_iov[i].iov_len = (size_t) (0xcaffeeeddefaced7ULL +
+			0x100000001ULL * i);
+	}
+
+	asprintf(&key_iov_str1, "[{iov_base=%p, iov_len=%zu}, "
+		"{iov_base=%p, iov_len=%zu}, {iov_base=%p, iov_len=%zu}, "
+		"{iov_base=%p, iov_len=%zu}]",
+		key_iov[IOV_SIZE - 4].iov_base, key_iov[IOV_SIZE - 4].iov_len,
+		key_iov[IOV_SIZE - 3].iov_base, key_iov[IOV_SIZE - 3].iov_len,
+		key_iov[IOV_SIZE - 2].iov_base, key_iov[IOV_SIZE - 2].iov_len,
+		key_iov[IOV_SIZE - 1].iov_base, key_iov[IOV_SIZE - 1].iov_len);
+
+	ret = snprintf(key_iov_str2, IOV_STR_SIZE,
+		"[{iov_base=\"%s\\0\", iov_len=%zu}, "
+		"{iov_base=\"%.10s\"..., iov_len=%zu}, "
+		"{iov_base=\"%s\\0\", iov_len=%zu}, "
+		"{iov_base=\"%.10s\"..., iov_len=%zu}, ",
+		(char *) key_iov[0].iov_base, key_iov[0].iov_len,
+		(char *) key_iov[1].iov_base, key_iov[1].iov_len,
+		(char *) key_iov[2].iov_base, key_iov[2].iov_len,
+		(char *) key_iov[3].iov_base, key_iov[3].iov_len);
+
+	if ((ret < 0) || (ret >= IOV_STR_SIZE))
+		error_msg_and_fail("snprintf");
+
+	for (i = 4; i < PR_LIMIT; i++) {
+		kis_size += ret;
+
+		ret = snprintf(key_iov_str2 + kis_size, IOV_STR_SIZE - kis_size,
+			"{iov_base=%p, iov_len=%zu}, ",
+			key_iov[i].iov_base, key_iov[i].iov_len);
+
+		if ((ret < 0) || (ret >= (IOV_STR_SIZE - kis_size)))
+			error_msg_and_fail("snprintf");
+	}
+
+	kis_size += ret;
+	snprintf(key_iov_str2 + kis_size, IOV_STR_SIZE - kis_size, "...]");
+
+
+	/* Invalid command */
+	do_keyctl((__kernel_ulong_t) 0xbadc0dedfacefeedULL,
+		"0xfacefeed /* KEYCTL_??? */",
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 0xdeadfee1badc0de5ULL, NULL, kulong_fmt,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 0xdeadfee2badc0de6ULL, NULL, kulong_fmt,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 0xdeadfee3badc0de7ULL, NULL, kulong_fmt,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 0xdeadfee4badc0de8ULL, NULL, kulong_fmt);
+
+
+	/* GET_KEYRING_ID */
+	do_keyctl(ARG_STR(KEYCTL_GET_KEYRING_ID),
+		sizeof(int32_t), bogus_key1, NULL, "%d",
+		sizeof(int), (__kernel_ulong_t) 0xbadc0dedffffffffLLU, "-1",
+		NULL, 0UL);
+	do_keyctl(ARG_STR(KEYCTL_GET_KEYRING_ID),
+		sizeof(int32_t), ARG_STR(KEY_SPEC_THREAD_KEYRING), "%d",
+		sizeof(int), 3141592653U, NULL, "%d",
+		NULL, 0UL);
+
+
+	/* KEYCTL_JOIN_SESSION_KEYRING */
+	do_keyctl(ARG_STR(KEYCTL_JOIN_SESSION_KEYRING),
+		sizeof(char *), ARG_STR(NULL), NULL, 0UL);
+	do_keyctl(ARG_STR(KEYCTL_JOIN_SESSION_KEYRING),
+		sizeof(char *), (char *) 0xfffffacefffffeedULL, NULL, ptr_fmt,
+		0UL);
+	do_keyctl(ARG_STR(KEYCTL_JOIN_SESSION_KEYRING),
+		sizeof(char *), bogus_str, NULL, ptr_fmt, 0UL);
+	do_keyctl(ARG_STR(KEYCTL_JOIN_SESSION_KEYRING),
+		sizeof(char *), ARG_STR("bogus name"), NULL, 0UL);
+	do_keyctl(ARG_STR(KEYCTL_JOIN_SESSION_KEYRING),
+		sizeof(char *), "very long keyring name", "\"very long \"...",
+		NULL, 0UL);
+
+
+	/* KEYCTL_UPDATE */
+	do_keyctl(ARG_STR(KEYCTL_UPDATE),
+		sizeof(int32_t), ARG_STR(KEY_SPEC_REQUESTOR_KEYRING), NULL,
+		sizeof(char *), ARG_STR(NULL), NULL,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 0, NULL, ksize_fmt, 0UL);
+	do_keyctl(ARG_STR(KEYCTL_UPDATE),
+		sizeof(int32_t), bogus_key1, NULL, "%d",
+		sizeof(char *), (char *) 0xfffffacefffffeedULL, NULL, ptr_fmt,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 0xdeadfee4badc0de8ULL, NULL, ksize_fmt, 0UL);
+	do_keyctl(ARG_STR(KEYCTL_UPDATE),
+		sizeof(int32_t), bogus_key2, NULL, "%d",
+		sizeof(char *), bogus_str, NULL, ptr_fmt,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 0xdeadfee4badc0de8ULL, NULL, ksize_fmt, 0UL);
+	do_keyctl(ARG_STR(KEYCTL_UPDATE),
+		sizeof(__kernel_ulong_t), bogus_key3, bogus_key3_str, NULL,
+		-sizeof(short_desc_str), short_desc, NULL, NULL,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) sizeof(short_desc_str) - 1, NULL, ksize_fmt,
+		0UL);
+
+
+	/* KEYCTL_REVOKE */
+	do_keyctl(ARG_STR(KEYCTL_REVOKE),
+		sizeof(int32_t), ARG_STR(KEY_SPEC_GROUP_KEYRING), NULL, 0UL);
+	do_keyctl(ARG_STR(KEYCTL_REVOKE),
+		sizeof(int32_t), bogus_key1, NULL, "%d", 0UL);
+	do_keyctl(ARG_STR(KEYCTL_REVOKE),
+		sizeof(int32_t), bogus_key2, NULL, "%d", 0UL);
+	do_keyctl(ARG_STR(KEYCTL_REVOKE),
+		sizeof(__kernel_ulong_t), bogus_key3, bogus_key3_str, NULL,
+		0UL);
+
+
+	/* KEYCTL_CHOWN */
+	do_keyctl(ARG_STR(KEYCTL_CHOWN),
+		sizeof(int32_t), ARG_STR(KEY_SPEC_REQUESTOR_KEYRING), NULL,
+		sizeof(uid_t), ARG_STR(-1), NULL,
+		sizeof(gid_t), ARG_STR(-1), NULL, 0UL);
+	do_keyctl(ARG_STR(KEYCTL_CHOWN),
+		sizeof(int32_t), bogus_key1, NULL, "%d",
+		sizeof(uid_t), 2718281828U, NULL, "%u",
+		sizeof(gid_t), 3141592653U, NULL, "%u", 0UL);
+
+
+	/* KEYCTL_SETPERM */
+	do_keyctl(ARG_STR(KEYCTL_SETPERM),
+		sizeof(int32_t), ARG_STR(KEY_SPEC_REQKEY_AUTH_KEY), NULL,
+		sizeof(uint32_t), 0xffffffffU,
+		"KEY_POS_VIEW|KEY_POS_READ|KEY_POS_WRITE|"
+		"KEY_POS_SEARCH|KEY_POS_LINK|KEY_POS_SETATTR|"
+		"KEY_USR_VIEW|KEY_USR_READ|KEY_USR_WRITE|"
+		"KEY_USR_SEARCH|KEY_USR_LINK|KEY_USR_SETATTR|"
+		"KEY_GRP_VIEW|KEY_GRP_READ|KEY_GRP_WRITE|"
+		"KEY_GRP_SEARCH|KEY_GRP_LINK|KEY_GRP_SETATTR|"
+		"KEY_OTH_VIEW|KEY_OTH_READ|KEY_OTH_WRITE|"
+		"KEY_OTH_SEARCH|KEY_OTH_LINK|KEY_OTH_SETATTR|"
+		"0xc0c0c0c0", NULL, 0UL);
+	do_keyctl(ARG_STR(KEYCTL_SETPERM),
+		sizeof(int32_t), bogus_key1, NULL, "%d",
+		sizeof(uint32_t), 0, NULL, "%#x", 0UL);
+	do_keyctl(ARG_STR(KEYCTL_SETPERM),
+		sizeof(__kernel_ulong_t), bogus_key3, bogus_key3_str, NULL,
+		sizeof(uint32_t), 0xc0c0c0c0, "0xc0c0c0c0 /* KEY_??? */", NULL,
+		0UL);
+
+
+	/* KEYCTL_DESCRIBE */
+	do_keyctl(ARG_STR(KEYCTL_DESCRIBE),
+		sizeof(int32_t), bogus_key1, NULL, "%d",
+		sizeof(char *), ARG_STR(NULL), ptr_fmt,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 0xfeedf157badc0dedLLU, NULL, ksize_fmt, 0UL);
+	do_keyctl(ARG_STR(KEYCTL_DESCRIBE),
+		sizeof(__kernel_ulong_t), bogus_key3, bogus_key3_str, NULL,
+		sizeof(char *), ARG_STR(NULL), ptr_fmt,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 0xfeedf157badc0dedLLU, NULL, ksize_fmt, 0UL);
+	do_keyctl(ARG_STR(KEYCTL_DESCRIBE),
+		sizeof(int32_t), ARG_STR(KEY_SPEC_THREAD_KEYRING), NULL,
+		9, (uintptr_t) bogus_buf1, NULL, NULL,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 9, NULL, ksize_fmt, 0UL);
+	do_keyctl(ARG_STR(KEYCTL_DESCRIBE),
+		sizeof(int32_t), ARG_STR(KEY_SPEC_THREAD_KEYRING), NULL,
+		256, (uintptr_t) bogus_buf2, NULL, NULL,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 256, NULL, ksize_fmt, 0UL);
+
+
+	/* KEYCTL_CLEAR */
+	do_keyctl(ARG_STR(KEYCTL_CLEAR),
+		sizeof(int32_t), ARG_STR(KEY_SPEC_GROUP_KEYRING), NULL, 0UL);
+	do_keyctl(ARG_STR(KEYCTL_CLEAR),
+		sizeof(int32_t), bogus_key1, NULL, "%d", 0UL);
+	do_keyctl(ARG_STR(KEYCTL_CLEAR),
+		sizeof(int32_t), bogus_key2, NULL, "%d", 0UL);
+	do_keyctl(ARG_STR(KEYCTL_CLEAR),
+		sizeof(__kernel_ulong_t), bogus_key3, bogus_key3_str, NULL,
+		0UL);
+
+
+	/* KEYCTL_LINK */
+	do_keyctl(ARG_STR(KEYCTL_LINK),
+		sizeof(int32_t), bogus_key1, NULL, "%d",
+		sizeof(int32_t), ARG_STR(KEY_SPEC_GROUP_KEYRING), NULL, 0UL);
+	do_keyctl(ARG_STR(KEYCTL_LINK),
+		sizeof(int32_t), ARG_STR(KEY_SPEC_REQUESTOR_KEYRING), NULL,
+		sizeof(int32_t), bogus_key2, NULL, "%d", 0UL);
+	do_keyctl(ARG_STR(KEYCTL_LINK),
+		sizeof(int32_t), ARG_STR(KEY_SPEC_REQUESTOR_KEYRING), NULL,
+		sizeof(__kernel_ulong_t), bogus_key3, bogus_key3_str, NULL,
+		0UL);
+
+
+	/* KEYCTL_UNLINK */
+	do_keyctl(ARG_STR(KEYCTL_UNLINK),
+		sizeof(int32_t), bogus_key1, NULL, "%d",
+		sizeof(int32_t), ARG_STR(KEY_SPEC_GROUP_KEYRING), NULL,
+		0UL);
+	do_keyctl(ARG_STR(KEYCTL_UNLINK),
+		sizeof(int32_t), ARG_STR(KEY_SPEC_REQUESTOR_KEYRING), NULL,
+		sizeof(int32_t), bogus_key2, NULL, "%d", 0UL);
+	do_keyctl(ARG_STR(KEYCTL_UNLINK),
+		sizeof(int32_t), ARG_STR(KEY_SPEC_REQUESTOR_KEYRING), NULL,
+		sizeof(__kernel_ulong_t), bogus_key3, bogus_key3_str, NULL,
+		0UL);
+
+
+	/* KEYCTL_SEARCH */
+	do_keyctl(ARG_STR(KEYCTL_SEARCH),
+		sizeof(int32_t), ARG_STR(KEY_SPEC_REQUESTOR_KEYRING), NULL,
+		sizeof(char *), ARG_STR(NULL), NULL,
+		sizeof(char *), ARG_STR(NULL), NULL,
+		sizeof(int32_t), 0, NULL, "%d");
+	do_keyctl(ARG_STR(KEYCTL_SEARCH),
+		sizeof(int32_t), bogus_key1, NULL, "%d",
+		sizeof(char *), (char *) 0xfffffacefffffeedULL, NULL, ptr_fmt,
+		sizeof(char *), (char *) 0xfffff00dfffff157ULL, NULL, ptr_fmt,
+		sizeof(int32_t), ARG_STR(KEY_SPEC_USER_SESSION_KEYRING), NULL);
+	do_keyctl(ARG_STR(KEYCTL_SEARCH),
+		sizeof(int32_t), bogus_key2, NULL, "%d",
+		sizeof(char *), bogus_str, NULL, ptr_fmt,
+		sizeof(char *), bogus_desc, NULL, ptr_fmt,
+		sizeof(int32_t), bogus_key1, NULL, "%d");
+	do_keyctl(ARG_STR(KEYCTL_SEARCH),
+		sizeof(__kernel_ulong_t), bogus_key3, bogus_key3_str, NULL,
+		-sizeof(short_type_str), short_type, NULL, NULL,
+		-sizeof(short_desc_str), short_desc, NULL, NULL,
+		sizeof(int32_t), bogus_key2, NULL, "%d");
+	do_keyctl(ARG_STR(KEYCTL_SEARCH),
+		sizeof(int32_t), 0, NULL, "%d",
+		-sizeof(long_type_str), long_type, NULL, NULL,
+		-sizeof(long_type_str), long_desc, NULL, NULL,
+		sizeof(__kernel_ulong_t), bogus_key3, bogus_key3_str, NULL);
+
+
+	/* KEYCTL_READ */
+
+	/* Empty result is expected for these */
+	bogus_buf1[0] = '\0';
+	bogus_buf2[0] = '\0';
+
+	do_keyctl(ARG_STR(KEYCTL_READ),
+		sizeof(int32_t), bogus_key1, NULL, "%d",
+		sizeof(char *), ARG_STR(NULL), ptr_fmt,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 0xfeedf157badc0dedLLU, NULL, ksize_fmt, 0UL);
+	do_keyctl(ARG_STR(KEYCTL_READ),
+		sizeof(__kernel_ulong_t), bogus_key3, bogus_key3_str, NULL,
+		sizeof(char *), ARG_STR(NULL), ptr_fmt,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 0xfeedf157badc0dedLLU, NULL, ksize_fmt, 0UL);
+	do_keyctl(ARG_STR(KEYCTL_READ),
+		sizeof(int32_t), ARG_STR(KEY_SPEC_THREAD_KEYRING), NULL,
+		9, (uintptr_t) bogus_buf1, NULL, NULL,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 9, NULL, ksize_fmt, 0UL);
+	do_keyctl(ARG_STR(KEYCTL_READ),
+		sizeof(int32_t), ARG_STR(KEY_SPEC_THREAD_KEYRING), NULL,
+		256, (uintptr_t) bogus_buf2, NULL, NULL,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 256, NULL, ksize_fmt, 0UL);
+
+
+	/* KEYCTL_INSTANTIATE */
+	do_keyctl(ARG_STR(KEYCTL_INSTANTIATE),
+		sizeof(int32_t), 0, NULL, "%d",
+		sizeof(char *), ARG_STR(NULL), ptr_fmt,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 0xfeedf157badc0dedLLU, NULL, ksize_fmt,
+		sizeof(int32_t), 0, NULL, "%d");
+	do_keyctl(ARG_STR(KEYCTL_INSTANTIATE),
+		sizeof(int32_t), bogus_key1, NULL, "%d",
+		sizeof(char *), (char *) 0xfffffacefffffeedULL, NULL, ptr_fmt,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 0xdeadfeedLLU, NULL, ksize_fmt,
+		sizeof(int32_t), bogus_key1, NULL, "%d");
+	do_keyctl(ARG_STR(KEYCTL_INSTANTIATE),
+		sizeof(int32_t), bogus_key2, NULL, "%d",
+		sizeof(char *), bogus_str, NULL, ptr_fmt,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 32LLU, NULL, ksize_fmt,
+		sizeof(int32_t), bogus_key2, NULL, "%d");
+	do_keyctl(ARG_STR(KEYCTL_INSTANTIATE),
+		sizeof(__kernel_ulong_t), bogus_key3, bogus_key3_str, NULL,
+		-sizeof(short_type_str), short_desc, NULL, NULL,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) sizeof(short_type_str) - 1, NULL, ksize_fmt,
+		sizeof(__kernel_ulong_t), bogus_key3, bogus_key3_str, NULL);
+	do_keyctl(ARG_STR(KEYCTL_INSTANTIATE),
+		sizeof(int32_t), ARG_STR(KEY_SPEC_GROUP_KEYRING), NULL,
+		-sizeof(long_type_str), long_desc, NULL, NULL,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) sizeof(long_type_str), NULL, ksize_fmt,
+		sizeof(int32_t), ARG_STR(KEY_SPEC_GROUP_KEYRING), NULL);
+
+
+	/* KEYCTL_NEGATE */
+	do_keyctl(ARG_STR(KEYCTL_NEGATE),
+		sizeof(int32_t), 0, NULL, "%d",
+		sizeof(uint32_t), 0, NULL, "%u",
+		sizeof(int32_t), 0, NULL, "%d", 0UL);
+	do_keyctl(ARG_STR(KEYCTL_NEGATE),
+		sizeof(int32_t), bogus_key1, NULL, "%d",
+		sizeof(uint32_t), 3141592653U, NULL, "%u",
+		sizeof(int32_t), bogus_key1, NULL, "%d", 0UL);
+	do_keyctl(ARG_STR(KEYCTL_NEGATE),
+		sizeof(int32_t), bogus_key2, NULL, "%d",
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 0xfeedf157badc0dedLLU, "3134983661", NULL,
+		sizeof(int32_t), bogus_key2, NULL, "%d", 0UL);
+	do_keyctl(ARG_STR(KEYCTL_NEGATE),
+		sizeof(__kernel_ulong_t), bogus_key3, bogus_key3_str, NULL,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 0xfeedf157badc0dedLLU, "3134983661", NULL,
+		sizeof(__kernel_ulong_t), bogus_key3, bogus_key3_str, NULL,
+		0UL);
+
+
+	/* KEYCTL_SET_REQKEY_KEYRING */
+	do_keyctl(ARG_STR(KEYCTL_SET_REQKEY_KEYRING),
+		sizeof(int32_t), ARG_STR(KEY_REQKEY_DEFL_NO_CHANGE), NULL, 0UL);
+	/* do_keyctl(ARG_STR(KEYCTL_SET_REQKEY_KEYRING),
+		sizeof(int32_t),
+		ARG_STR(KEY_REQKEY_DEFL_REQUESTOR_KEYRING), NULL, 0UL); */
+	do_keyctl(ARG_STR(KEYCTL_SET_REQKEY_KEYRING),
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 0xfeedf157badc0dedLLU,
+		"0xbadc0ded /* KEY_REQKEY_DEFL_??? */", NULL, 0UL);
+
+
+	/* KEYCTL_SET_TIMEOUT */
+	do_keyctl(ARG_STR(KEYCTL_SET_TIMEOUT),
+		sizeof(int32_t), 0, NULL, "%d",
+		sizeof(uint32_t), 0, NULL, "%u", 0UL);
+	do_keyctl(ARG_STR(KEYCTL_SET_TIMEOUT),
+		sizeof(int32_t), bogus_key1, NULL, "%d",
+		sizeof(uint32_t), 3141592653U, NULL, "%u", 0UL);
+	do_keyctl(ARG_STR(KEYCTL_SET_TIMEOUT),
+		sizeof(__kernel_ulong_t), bogus_key3, bogus_key3_str, NULL,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 0xfeedf157badc0dedLLU, "3134983661", NULL,
+		0UL);
+
+
+	/* KEYCTL_ASSUME_AUTHORITY */
+	do_keyctl(ARG_STR(KEYCTL_ASSUME_AUTHORITY),
+		sizeof(int32_t), ARG_STR(KEY_SPEC_GROUP_KEYRING), NULL, 0UL);
+	do_keyctl(ARG_STR(KEYCTL_ASSUME_AUTHORITY),
+		sizeof(int32_t), bogus_key1, NULL, "%d", 0UL);
+	do_keyctl(ARG_STR(KEYCTL_ASSUME_AUTHORITY),
+		sizeof(int32_t), bogus_key2, NULL, "%d", 0UL);
+	do_keyctl(ARG_STR(KEYCTL_ASSUME_AUTHORITY),
+		sizeof(__kernel_ulong_t), bogus_key3, bogus_key3_str, NULL,
+		0UL);
+
+
+	/* KEYCTL_GET_SECURITY */
+
+	/* Empty result is expected for these */
+	bogus_buf1[0] = '\0';
+	bogus_buf2[0] = '\0';
+
+	do_keyctl(ARG_STR(KEYCTL_GET_SECURITY),
+		sizeof(int32_t), bogus_key1, NULL, "%d",
+		sizeof(char *), ARG_STR(NULL), ptr_fmt,
+		sizeof(uint32_t), 0xbadc0dedU, NULL, "%u", 0UL);
+	do_keyctl(ARG_STR(KEYCTL_GET_SECURITY),
+		sizeof(__kernel_ulong_t), bogus_key3, bogus_key3_str, NULL,
+		sizeof(char *), ARG_STR(NULL), ptr_fmt,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 0xfeedf157badc0dedLLU, NULL, ksize_fmt, 0UL);
+	do_keyctl(ARG_STR(KEYCTL_GET_SECURITY),
+		sizeof(int32_t), ARG_STR(KEY_SPEC_THREAD_KEYRING), NULL,
+		9, (uintptr_t) bogus_buf1, NULL, NULL,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 9, NULL, ksize_fmt, 0UL);
+	do_keyctl(ARG_STR(KEYCTL_GET_SECURITY),
+		sizeof(int32_t), ARG_STR(KEY_SPEC_THREAD_KEYRING), NULL,
+		256, (uintptr_t) bogus_buf2, NULL, NULL,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 256, NULL, ksize_fmt, 0UL);
+
+
+	/* KEYCTL_SESSION_TO_PARENT */
+	do_keyctl(ARG_STR(KEYCTL_SESSION_TO_PARENT), 0UL);
+
+
+	/* KEYCTL_REJECT */
+	do_keyctl(ARG_STR(KEYCTL_REJECT),
+		sizeof(int32_t), 0, NULL, "%d",
+		sizeof(uint32_t), 0, NULL, "%u",
+		sizeof(uint32_t), 0, NULL, "%u",
+		sizeof(int32_t), 0, NULL, "%d");
+	do_keyctl(ARG_STR(KEYCTL_REJECT),
+		sizeof(int32_t), bogus_key1, NULL, "%d",
+		sizeof(uint32_t), 3141592653U, NULL, "%u",
+		sizeof(uint32_t), 2718281828U, NULL, "%u",
+		sizeof(int32_t), bogus_key1, NULL, "%d");
+	do_keyctl(ARG_STR(KEYCTL_REJECT),
+		sizeof(int32_t), bogus_key2, NULL, "%d",
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 0xdeadca75facef157LLU, "4207866199", NULL,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 0xfeedf157badc0dedLLU, "3134983661", NULL,
+		sizeof(int32_t), bogus_key2, NULL, "%d");
+	do_keyctl(ARG_STR(KEYCTL_REJECT),
+		sizeof(__kernel_ulong_t), bogus_key3, bogus_key3_str, NULL,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 0xfeedf157badc0dedLLU, "3134983661", NULL,
+		sizeof(uint32_t), ARG_STR(ENODEV), NULL,
+		sizeof(__kernel_ulong_t), bogus_key3, bogus_key3_str, NULL);
+
+
+	/* KEYCTL_INSTANTIATE_IOV */
+	do_keyctl(ARG_STR(KEYCTL_INSTANTIATE_IOV),
+		sizeof(int32_t), 0, NULL, "%d",
+		sizeof(char *), ARG_STR(NULL), ptr_fmt,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 0xfeedf157badc0dedLLU, NULL, ksize_fmt,
+		sizeof(int32_t), 0, NULL, "%d");
+	do_keyctl(ARG_STR(KEYCTL_INSTANTIATE_IOV),
+		sizeof(int32_t), bogus_key1, NULL, "%d",
+		sizeof(char *), (char *) 0xfffffacefffffeedULL, NULL, ptr_fmt,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 0xdeadfeedLLU, NULL, ksize_fmt,
+		sizeof(int32_t), bogus_key1, NULL, "%d");
+	do_keyctl(ARG_STR(KEYCTL_INSTANTIATE_IOV),
+		sizeof(int32_t), bogus_key2, NULL, "%d",
+		sizeof(char *), key_iov + IOV_SIZE, NULL, ptr_fmt,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 32LLU, NULL, ksize_fmt,
+		sizeof(int32_t), bogus_key2, NULL, "%d");
+	do_keyctl(ARG_STR(KEYCTL_INSTANTIATE_IOV),
+		sizeof(__kernel_ulong_t), bogus_key3, bogus_key3_str, NULL,
+		sizeof(key_iov), key_iov + IOV_SIZE - 4, key_iov_str1, NULL,
+		sizeof(__kernel_ulong_t), (__kernel_ulong_t) 4, NULL, ksize_fmt,
+		sizeof(__kernel_ulong_t), bogus_key3, bogus_key3_str, NULL);
+	do_keyctl(ARG_STR(KEYCTL_INSTANTIATE_IOV),
+		sizeof(int32_t), ARG_STR(KEY_SPEC_GROUP_KEYRING), NULL,
+		sizeof(key_iov), key_iov, key_iov_str2, NULL,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) IOV_SIZE, NULL, ksize_fmt,
+		sizeof(int32_t), ARG_STR(KEY_SPEC_GROUP_KEYRING), NULL);
+
+
+	/* KEYCTL_INVALIDATE */
+	do_keyctl(ARG_STR(KEYCTL_INVALIDATE),
+		sizeof(int32_t), ARG_STR(KEY_SPEC_GROUP_KEYRING), NULL, 0UL);
+	do_keyctl(ARG_STR(KEYCTL_INVALIDATE),
+		sizeof(int32_t), bogus_key1, NULL, "%d", 0UL);
+	do_keyctl(ARG_STR(KEYCTL_INVALIDATE),
+		sizeof(int32_t), bogus_key2, NULL, "%d", 0UL);
+	do_keyctl(ARG_STR(KEYCTL_INVALIDATE),
+		sizeof(__kernel_ulong_t), bogus_key3, bogus_key3_str, NULL,
+		0UL);
+
+
+	/* KEYCTL_GET_PERSISTENT */
+	do_keyctl(ARG_STR(KEYCTL_GET_PERSISTENT),
+		sizeof(uid_t), ARG_STR(-1), NULL,
+		sizeof(int32_t), ARG_STR(KEY_SPEC_GROUP_KEYRING), NULL, 0UL);
+	do_keyctl(ARG_STR(KEYCTL_GET_PERSISTENT),
+		sizeof(uid_t), 2718281828U, NULL, "%u",
+		sizeof(int32_t), bogus_key1, NULL, "%d", 0UL);
+	do_keyctl(ARG_STR(KEYCTL_GET_PERSISTENT),
+		sizeof(uid_t), 2718281828U, NULL, "%u",
+		sizeof(__kernel_ulong_t), bogus_key3, bogus_key3_str, NULL,
+		0UL);
+
+
+	/* KEYCTL_DH_COMPUTE */
+	do_keyctl(ARG_STR(KEYCTL_DH_COMPUTE),
+		sizeof(char *), ARG_STR(NULL), ptr_fmt,
+		sizeof(char *), ARG_STR(NULL), ptr_fmt,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 0xfeedf157badc0dedLLU, NULL, ksize_fmt, 0UL);
+	do_keyctl(ARG_STR(KEYCTL_DH_COMPUTE),
+		sizeof(char *), kcdhp + 1, NULL, ptr_fmt,
+		sizeof(char *), (char *) 0xfffff157ffffdeadULL, NULL, ptr_fmt,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 0xfeedf157badc0dedLLU, NULL, ksize_fmt, 0UL);
+	do_keyctl(ARG_STR(KEYCTL_DH_COMPUTE),
+		sizeof(kcdhp), kcdhp, kcdhp_str, NULL,
+		9, (uintptr_t) bogus_buf1, NULL, NULL,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 9, NULL, ksize_fmt, 0UL);
+	do_keyctl(ARG_STR(KEYCTL_DH_COMPUTE),
+		sizeof(kcdhp), kcdhp, kcdhp_str, NULL,
+		256, (uintptr_t) bogus_buf2, NULL, NULL,
+		sizeof(__kernel_ulong_t),
+		(__kernel_ulong_t) 256, NULL, ksize_fmt, 0UL);
+
+
+	puts("+++ exited with 0 +++");
+
+	return 0;
+}
+
+#else
+
+SKIP_MAIN_UNDEFINED("__NR_keyctl");
+
+#endif
diff --git a/tests/keyctl.test b/tests/keyctl.test
new file mode 100755
index 0000000..59b4713
--- /dev/null
+++ b/tests/keyctl.test
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+# Check keyctl syscall decoding.
+
+. "${srcdir=.}/init.sh"
+run_strace_match_diff -a1 -s10
diff --git a/tests/request_key.c b/tests/request_key.c
new file mode 100644
index 0000000..457e446
--- /dev/null
+++ b/tests/request_key.c
@@ -0,0 +1,124 @@
+#include "tests.h"
+
+#include <asm/unistd.h>
+
+#ifdef __NR_request_key
+
+# include <inttypes.h>
+# include <stdio.h>
+# include <unistd.h>
+
+void
+print_val_str(const void *ptr, const char *str)
+{
+	if (str)
+		printf("%s, ", str);
+	else
+		printf("%p, ", ptr);
+}
+
+void
+do_request_key(const char *type, const char *type_str, const char *desc,
+	const char *desc_str, const char *info, const char *info_str,
+	int32_t keyring, const char *keyring_str)
+{
+	long rc;
+
+	rc = syscall(__NR_request_key, type, desc, info, keyring);
+	printf("request_key(");
+	print_val_str(type, type_str);
+	print_val_str(desc, desc_str);
+	print_val_str(info, info_str);
+	if (keyring_str)
+		printf("%s", keyring_str);
+	else
+		printf("%d", keyring);
+	printf(") = %s\n", sprintrc(rc));
+}
+
+# define _STR(_arg) #_arg
+# define ARG_STR(_arg) (_arg), #_arg
+
+int
+main(void)
+{
+	static const char unterminated1[] = { '\1', '\2', '\3', '\4', '\5' };
+	static const char unterminated2[] = { '\6', '\7', '\10', '\11', '\12' };
+	static const char unterminated3[] =
+		{ '\16', '\17', '\20', '\21', '\22' };
+
+	char *bogus_type = tail_memdup(unterminated1, sizeof(unterminated1));
+	char *bogus_desc = tail_memdup(unterminated2, sizeof(unterminated2));
+	char *bogus_info = tail_memdup(unterminated3, sizeof(unterminated3));
+
+	unsigned i;
+	unsigned j;
+	unsigned k;
+	unsigned l;
+
+	struct {
+		const char *type;
+		const char *str;
+	} types[] = {
+		{ ARG_STR(NULL) },
+		{ (const char *) 0xfffffee1fffffbadULL, NULL },
+		{ bogus_type, NULL },
+		{ ARG_STR("\20\21\22\23\24") },
+		{ ARG_STR("user") },
+	};
+
+	struct {
+		const char *desc;
+		const char *str;
+	} descs[] = {
+		{ ARG_STR(NULL) },
+		{ (const char *) 0xfffff00dfffffca7ULL, NULL },
+		{ bogus_desc, NULL },
+		{ ARG_STR("\25\26\27\30\31") },
+		{ ARG_STR("desc") },
+		{ "overly long description", _STR("overly long ") "..." },
+	};
+
+	struct {
+		const char *info;
+		const char *str;
+	} infos[] = {
+		{ ARG_STR(NULL) },
+		{ (const char *) 0xfffffacefffff157ULL, NULL },
+		{ bogus_info, NULL },
+		{ ARG_STR("\32\33\34\35\36") },
+		{ ARG_STR("info") },
+		{ "overly long info", _STR("overly long ") "..." },
+	};
+
+	struct {
+		uint32_t keyring;
+		const char *str;
+	} keyrings[] = {
+		{ ARG_STR(0) },
+		{ ARG_STR(1234567890) },
+		{ ARG_STR(-1234567890) },
+		{ -1, "KEY_SPEC_THREAD_KEYRING" },
+	};
+
+	for (i = 0; i < ARRAY_SIZE(types); i++)
+		for (j = 0; j < ARRAY_SIZE(descs); j++)
+			for (k = 0; k < ARRAY_SIZE(infos); k++)
+				for (l = 0; l < ARRAY_SIZE(keyrings); l++)
+					do_request_key(
+						types[i].type, types[i].str,
+						descs[j].desc, descs[j].str,
+						infos[k].info, infos[k].str,
+						keyrings[l].keyring,
+						keyrings[l].str);
+
+	puts("+++ exited with 0 +++");
+
+	return 0;
+}
+
+#else
+
+SKIP_MAIN_UNDEFINED("__NR_request_key");
+
+#endif
diff --git a/tests/request_key.test b/tests/request_key.test
new file mode 100755
index 0000000..c5a1629
--- /dev/null
+++ b/tests/request_key.test
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+# Check request_key syscall decoding.
+
+. "${srcdir=.}/init.sh"
+run_strace_match_diff -a1 -s12
-- 
1.7.10.4





More information about the Strace-devel mailing list