Hello,
This series adds helper functions for testing AF_ALG (the userspace
interface to algorithms in the Linux kernel's crypto API) to the
Linux Test Project. It then adds a few sample regression tests.
I've had these patches sitting around for a while with the goal of also
writing some "real" tests that test for more than these specific bugs,
but haven't gotten around to it yet. And I now consider further
improving the in-kernel crypto self-tests to be a higher priority. But
I figured I'd send this out as-is in case people are interested in
having this merged, e.g. maybe other people want to add AF_ALG tests to
LTP too and the 'tst_af_alg' lib would be a good starting point.
Changed since v1:
- Define 'AF_ALG' in include/lapi/socket.h if undefined.
Also move 'SOL_ALG' definition to there.
- Add all new tests to runtest/crypto.
- In af_alg01, use .test() and .tcnt rather than a 'for' loop.
- Consistently use 'algfd' rather than 'alg_fd', and similarly for reqfd.
- Make two error messages in tst_af_alg.c clearer.
- Add SPDX license identifier to include/lapi/if_alg.h.
Eric Biggers (6):
lib: add tst_af_alg lib
crypto/af_alg01: new regression test for hmac nesting bug
crypto/af_alg02: new regression test for salsa20 empty message bug
crypto/af_alg03: new regression test for rfc7539 hash alg validation
crypto/af_alg04: new regression test for vmac race conditions
crypto/af_alg05: new regression test for skcipher_walk error bug
configure.ac | 1 +
include/lapi/if_alg.h | 38 ++++++++
include/lapi/socket.h | 8 ++
include/tst_af_alg.h | 136 ++++++++++++++++++++++++++
lib/tst_af_alg.c | 147 +++++++++++++++++++++++++++++
runtest/crypto | 5 +
runtest/cve | 2 +
testcases/kernel/crypto/.gitignore | 5 +
testcases/kernel/crypto/af_alg01.c | 78 +++++++++++++++
testcases/kernel/crypto/af_alg02.c | 29 ++++++
testcases/kernel/crypto/af_alg03.c | 31 ++++++
testcases/kernel/crypto/af_alg04.c | 56 +++++++++++
testcases/kernel/crypto/af_alg05.c | 43 +++++++++
13 files changed, 579 insertions(+)
create mode 100644 include/lapi/if_alg.h
create mode 100644 include/tst_af_alg.h
create mode 100644 lib/tst_af_alg.c
create mode 100644 testcases/kernel/crypto/af_alg01.c
create mode 100644 testcases/kernel/crypto/af_alg02.c
create mode 100644 testcases/kernel/crypto/af_alg03.c
create mode 100644 testcases/kernel/crypto/af_alg04.c
create mode 100644 testcases/kernel/crypto/af_alg05.c
--
2.21.0.225.g810b269d1ac-goog
From: Eric Biggers <[email protected]>
Signed-off-by: Eric Biggers <[email protected]>
---
runtest/crypto | 1 +
runtest/cve | 1 +
testcases/kernel/crypto/.gitignore | 1 +
testcases/kernel/crypto/af_alg01.c | 78 ++++++++++++++++++++++++++++++
4 files changed, 81 insertions(+)
create mode 100644 testcases/kernel/crypto/af_alg01.c
diff --git a/runtest/crypto b/runtest/crypto
index cdbc44cc8..45c8cdd2d 100644
--- a/runtest/crypto
+++ b/runtest/crypto
@@ -1,2 +1,3 @@
+af_alg01 af_alg01
pcrypt_aead01 pcrypt_aead01
crypto_user01 crypto_user01
diff --git a/runtest/cve b/runtest/cve
index 8f38045e9..f46c400cc 100644
--- a/runtest/cve
+++ b/runtest/cve
@@ -27,6 +27,7 @@ cve-2017-15299 request_key03 -b cve-2017-15299
cve-2017-15537 ptrace07
cve-2017-15649 fanout01
cve-2017-15951 request_key03 -b cve-2017-15951
+cve-2017-17806 af_alg01
cve-2017-17807 request_key04
cve-2017-1000364 stack_clash
cve-2017-5754 meltdown
diff --git a/testcases/kernel/crypto/.gitignore b/testcases/kernel/crypto/.gitignore
index 759592fbd..998af1728 100644
--- a/testcases/kernel/crypto/.gitignore
+++ b/testcases/kernel/crypto/.gitignore
@@ -1,2 +1,3 @@
+af_alg01
pcrypt_aead01
crypto_user01
diff --git a/testcases/kernel/crypto/af_alg01.c b/testcases/kernel/crypto/af_alg01.c
new file mode 100644
index 000000000..1ce0e2508
--- /dev/null
+++ b/testcases/kernel/crypto/af_alg01.c
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2019 Google LLC
+ */
+
+/*
+ * Regression test for commit af3ff8045bbf ("crypto: hmac - require that the
+ * underlying hash algorithm is unkeyed"), or CVE-2017-17806. This test
+ * verifies that the hmac template cannot be nested inside itself.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+
+#include "tst_test.h"
+#include "tst_af_alg.h"
+
+static void test_with_hash_alg(const char *hash_algname)
+{
+ char hmac_algname[64];
+ char key[4096] = { 0 };
+
+ if (!tst_have_alg("hash", hash_algname)) {
+ tst_res(TCONF, "kernel doesn't have hash algorithm '%s'",
+ hash_algname);
+ return;
+ }
+ sprintf(hmac_algname, "hmac(%s)", hash_algname);
+ if (!tst_have_alg("hash", hmac_algname)) {
+ tst_res(TCONF, "kernel doesn't have hash algorithm '%s'",
+ hmac_algname);
+ return;
+ }
+
+ sprintf(hmac_algname, "hmac(hmac(%s))", hash_algname);
+ if (tst_have_alg("hash", hmac_algname)) {
+ int algfd;
+
+ tst_res(TFAIL, "instantiated nested hmac algorithm ('%s')!",
+ hmac_algname);
+
+ /*
+ * Be extra annoying; with the bug, setting a key on
+ * "hmac(hmac(sha3-256-generic))" crashed the kernel.
+ */
+ algfd = tst_alg_setup("hash", hmac_algname, NULL, 0);
+ if (setsockopt(algfd, SOL_ALG, ALG_SET_KEY,
+ key, sizeof(key)) == 0) {
+ tst_res(TFAIL,
+ "set key on nested hmac algorithm ('%s')!",
+ hmac_algname);
+ }
+ } else {
+ tst_res(TPASS,
+ "couldn't instantiate nested hmac algorithm ('%s')",
+ hmac_algname);
+ }
+}
+
+/* try several different unkeyed hash algorithms */
+static const char * const hash_algs[] = {
+ "md5", "md5-generic",
+ "sha1", "sha1-generic",
+ "sha224", "sha224-generic",
+ "sha256", "sha256-generic",
+ "sha3-256", "sha3-256-generic",
+ "sha3-512", "sha3-512-generic",
+};
+
+static void do_test(unsigned int i)
+{
+ test_with_hash_alg(hash_algs[i]);
+}
+
+static struct tst_test test = {
+ .test = do_test,
+ .tcnt = ARRAY_SIZE(hash_algs),
+};
--
2.21.0.225.g810b269d1ac-goog
From: Eric Biggers <[email protected]>
Signed-off-by: Eric Biggers <[email protected]>
---
runtest/crypto | 1 +
runtest/cve | 1 +
testcases/kernel/crypto/.gitignore | 1 +
testcases/kernel/crypto/af_alg02.c | 29 +++++++++++++++++++++++++++++
4 files changed, 32 insertions(+)
create mode 100644 testcases/kernel/crypto/af_alg02.c
diff --git a/runtest/crypto b/runtest/crypto
index 45c8cdd2d..758586c19 100644
--- a/runtest/crypto
+++ b/runtest/crypto
@@ -1,3 +1,4 @@
af_alg01 af_alg01
+af_alg02 af_alg02
pcrypt_aead01 pcrypt_aead01
crypto_user01 crypto_user01
diff --git a/runtest/cve b/runtest/cve
index f46c400cc..031bcdc2a 100644
--- a/runtest/cve
+++ b/runtest/cve
@@ -27,6 +27,7 @@ cve-2017-15299 request_key03 -b cve-2017-15299
cve-2017-15537 ptrace07
cve-2017-15649 fanout01
cve-2017-15951 request_key03 -b cve-2017-15951
+cve-2017-17805 af_alg02
cve-2017-17806 af_alg01
cve-2017-17807 request_key04
cve-2017-1000364 stack_clash
diff --git a/testcases/kernel/crypto/.gitignore b/testcases/kernel/crypto/.gitignore
index 998af1728..dc79f3275 100644
--- a/testcases/kernel/crypto/.gitignore
+++ b/testcases/kernel/crypto/.gitignore
@@ -1,3 +1,4 @@
af_alg01
+af_alg02
pcrypt_aead01
crypto_user01
diff --git a/testcases/kernel/crypto/af_alg02.c b/testcases/kernel/crypto/af_alg02.c
new file mode 100644
index 000000000..a9e820423
--- /dev/null
+++ b/testcases/kernel/crypto/af_alg02.c
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2019 Google LLC
+ */
+
+/*
+ * Regression test for commit ecaaab564978 ("crypto: salsa20 - fix
+ * blkcipher_walk API usage"), or CVE-2017-17805. This test verifies that an
+ * empty message can be encrypted with Salsa20 without crashing the kernel.
+ */
+
+#include "tst_test.h"
+#include "tst_af_alg.h"
+
+static void run(void)
+{
+ char buf[16];
+ int reqfd = tst_alg_setup_reqfd("skcipher", "salsa20", NULL, 16);
+
+ /* With the bug the kernel crashed here */
+ if (read(reqfd, buf, 16) == 0)
+ tst_res(TPASS, "Successfully \"encrypted\" an empty message");
+ else
+ tst_res(TBROK, "read() didn't return 0");
+}
+
+static struct tst_test test = {
+ .test_all = run,
+};
--
2.21.0.225.g810b269d1ac-goog
From: Eric Biggers <[email protected]>
Signed-off-by: Eric Biggers <[email protected]>
---
runtest/crypto | 1 +
testcases/kernel/crypto/.gitignore | 1 +
testcases/kernel/crypto/af_alg04.c | 56 ++++++++++++++++++++++++++++++
3 files changed, 58 insertions(+)
create mode 100644 testcases/kernel/crypto/af_alg04.c
diff --git a/runtest/crypto b/runtest/crypto
index 03a49df3a..b6180c417 100644
--- a/runtest/crypto
+++ b/runtest/crypto
@@ -1,5 +1,6 @@
af_alg01 af_alg01
af_alg02 af_alg02
af_alg03 af_alg03
+af_alg04 af_alg04
pcrypt_aead01 pcrypt_aead01
crypto_user01 crypto_user01
diff --git a/testcases/kernel/crypto/.gitignore b/testcases/kernel/crypto/.gitignore
index 3e7936fc9..df6b7e73c 100644
--- a/testcases/kernel/crypto/.gitignore
+++ b/testcases/kernel/crypto/.gitignore
@@ -1,5 +1,6 @@
af_alg01
af_alg02
af_alg03
+af_alg04
pcrypt_aead01
crypto_user01
diff --git a/testcases/kernel/crypto/af_alg04.c b/testcases/kernel/crypto/af_alg04.c
new file mode 100644
index 000000000..b8e494b87
--- /dev/null
+++ b/testcases/kernel/crypto/af_alg04.c
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2019 Google LLC
+ */
+
+/*
+ * Regression test for commit bb2964810233 ("crypto: vmac - separate tfm and
+ * request context"). This test verifies that a VMAC transform can be used by
+ * multiple concurrent hash requests without crashing the kernel. Based on the
+ * reproducer from the commit message.
+ */
+
+#include <sys/wait.h>
+
+#include "tst_test.h"
+#include "tst_af_alg.h"
+
+static void run(void)
+{
+ int algfd, reqfd;
+ char buf[256] = { 0 };
+ pid_t pid;
+ int status;
+ int i;
+
+ if (tst_have_alg("hash", "vmac64(aes)"))
+ algfd = tst_alg_setup("hash", "vmac64(aes)", NULL, 16);
+ else
+ algfd = tst_alg_setup("hash", "vmac(aes)", NULL, 16);
+
+ pid = SAFE_FORK();
+
+ reqfd = tst_alg_accept(algfd);
+
+ for (i = 0; i < 500000; i++)
+ SAFE_WRITE(1, reqfd, buf, sizeof(buf));
+
+ close(reqfd);
+
+ if (pid != 0) {
+ SAFE_WAIT(&status);
+ if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
+ tst_res(TPASS, "didn't crash");
+ else if (WIFSIGNALED(status) && WTERMSIG(status) == SIGKILL)
+ tst_res(TFAIL, "crashed");
+ else
+ tst_brk(TBROK, "child %s", tst_strstatus(status));
+
+ close(algfd);
+ }
+}
+
+static struct tst_test test = {
+ .test_all = run,
+ .forks_child = 1,
+};
--
2.21.0.225.g810b269d1ac-goog
From: Eric Biggers <[email protected]>
Signed-off-by: Eric Biggers <[email protected]>
---
runtest/crypto | 1 +
testcases/kernel/crypto/.gitignore | 1 +
testcases/kernel/crypto/af_alg03.c | 31 ++++++++++++++++++++++++++++++
3 files changed, 33 insertions(+)
create mode 100644 testcases/kernel/crypto/af_alg03.c
diff --git a/runtest/crypto b/runtest/crypto
index 758586c19..03a49df3a 100644
--- a/runtest/crypto
+++ b/runtest/crypto
@@ -1,4 +1,5 @@
af_alg01 af_alg01
af_alg02 af_alg02
+af_alg03 af_alg03
pcrypt_aead01 pcrypt_aead01
crypto_user01 crypto_user01
diff --git a/testcases/kernel/crypto/.gitignore b/testcases/kernel/crypto/.gitignore
index dc79f3275..3e7936fc9 100644
--- a/testcases/kernel/crypto/.gitignore
+++ b/testcases/kernel/crypto/.gitignore
@@ -1,4 +1,5 @@
af_alg01
af_alg02
+af_alg03
pcrypt_aead01
crypto_user01
diff --git a/testcases/kernel/crypto/af_alg03.c b/testcases/kernel/crypto/af_alg03.c
new file mode 100644
index 000000000..240c52835
--- /dev/null
+++ b/testcases/kernel/crypto/af_alg03.c
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2019 Google LLC
+ */
+
+/*
+ * Regression test for commit e57121d08c38 ("crypto: chacha20poly1305 - validate
+ * the digest size"). This test verifies that the rfc7539 template can't be
+ * instantiated with a hash algorithm whose digest size is not 16 bytes.
+ */
+
+#include "tst_test.h"
+#include "tst_af_alg.h"
+
+static void run(void)
+{
+ tst_require_alg("aead", "rfc7539(chacha20,poly1305)");
+ tst_require_alg("hash", "sha256");
+
+ if (tst_have_alg("aead", "rfc7539(chacha20,sha256)")) {
+ tst_res(TFAIL,
+ "instantiated rfc7539 template with wrong digest size");
+ } else {
+ tst_res(TPASS,
+ "couldn't instantiate rfc7539 template with wrong digest size");
+ }
+}
+
+static struct tst_test test = {
+ .test_all = run,
+};
--
2.21.0.225.g810b269d1ac-goog
From: Eric Biggers <[email protected]>
Signed-off-by: Eric Biggers <[email protected]>
---
runtest/crypto | 1 +
testcases/kernel/crypto/.gitignore | 1 +
testcases/kernel/crypto/af_alg05.c | 43 ++++++++++++++++++++++++++++++
3 files changed, 45 insertions(+)
create mode 100644 testcases/kernel/crypto/af_alg05.c
diff --git a/runtest/crypto b/runtest/crypto
index b6180c417..41ea7b81c 100644
--- a/runtest/crypto
+++ b/runtest/crypto
@@ -2,5 +2,6 @@ af_alg01 af_alg01
af_alg02 af_alg02
af_alg03 af_alg03
af_alg04 af_alg04
+af_alg05 af_alg05
pcrypt_aead01 pcrypt_aead01
crypto_user01 crypto_user01
diff --git a/testcases/kernel/crypto/.gitignore b/testcases/kernel/crypto/.gitignore
index df6b7e73c..17faf3eef 100644
--- a/testcases/kernel/crypto/.gitignore
+++ b/testcases/kernel/crypto/.gitignore
@@ -2,5 +2,6 @@ af_alg01
af_alg02
af_alg03
af_alg04
+af_alg05
pcrypt_aead01
crypto_user01
diff --git a/testcases/kernel/crypto/af_alg05.c b/testcases/kernel/crypto/af_alg05.c
new file mode 100644
index 000000000..419c65eab
--- /dev/null
+++ b/testcases/kernel/crypto/af_alg05.c
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2019 Google LLC
+ */
+
+/*
+ * Regression test for commit 8088d3dd4d7c ("crypto: skcipher - fix crash
+ * flushing dcache in error path"). This test verifies the kernel doesn't crash
+ * when trying to encrypt a message with size not aligned to the block cipher's
+ * block size, and where the destination buffer starts exactly at a page
+ * boundary. Based on the reproducer from the commit message. Note that this
+ * issue only reproduces on certain architectures, such as arm and arm64.
+ */
+
+#include <errno.h>
+
+#include "tst_test.h"
+#include "tst_af_alg.h"
+
+static void run(void)
+{
+ char buffer[4096] __attribute__((aligned(4096))) = { 0 };
+ int reqfd;
+
+ reqfd = tst_alg_setup_reqfd("skcipher", "cbc(aes-generic)", NULL, 16);
+
+ SAFE_WRITE(1, reqfd, buffer, 15);
+ /* with the bug, this crashed the kernel on some architectures */
+ TEST(read(reqfd, buffer, 15));
+
+ if (TST_RET == 0)
+ tst_res(TBROK, "read() unexpectedly succeeded");
+ else if (TST_ERR == EINVAL)
+ tst_res(TPASS, "read() expectedly failed with EINVAL");
+ else
+ tst_res(TBROK | TTERRNO, "read() failed with unexpected error");
+
+ close(reqfd);
+}
+
+static struct tst_test test = {
+ .test_all = run,
+};
--
2.21.0.225.g810b269d1ac-goog
From: Eric Biggers <[email protected]>
Add helper functions for creating and using AF_ALG sockets. AF_ALG is
the userspace interface to algorithms in the Linux kernel's crypto API.
See https://www.kernel.org/doc/html/latest/crypto/userspace-if.html for
more information about this interface.
Signed-off-by: Eric Biggers <[email protected]>
---
configure.ac | 1 +
include/lapi/if_alg.h | 38 +++++++++++
include/lapi/socket.h | 8 +++
include/tst_af_alg.h | 136 ++++++++++++++++++++++++++++++++++++++
lib/tst_af_alg.c | 147 ++++++++++++++++++++++++++++++++++++++++++
5 files changed, 330 insertions(+)
create mode 100644 include/lapi/if_alg.h
create mode 100644 include/tst_af_alg.h
create mode 100644 lib/tst_af_alg.c
diff --git a/configure.ac b/configure.ac
index e73f7d92e..e002c248e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -40,6 +40,7 @@ AC_CHECK_HEADERS([ \
linux/cryptouser.h \
linux/genetlink.h \
linux/keyctl.h \
+ linux/if_alg.h \
linux/if_packet.h \
linux/if_ether.h \
linux/mempolicy.h \
diff --git a/include/lapi/if_alg.h b/include/lapi/if_alg.h
new file mode 100644
index 000000000..5a74df99b
--- /dev/null
+++ b/include/lapi/if_alg.h
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#ifndef IF_ALG_H__
+#define IF_ALG_H__
+
+#ifdef HAVE_LINUX_IF_ALG_H
+# include <linux/if_alg.h>
+#else
+# include <stdint.h>
+
+struct sockaddr_alg {
+ uint16_t salg_family;
+ uint8_t salg_type[14];
+ uint32_t salg_feat;
+ uint32_t salg_mask;
+ uint8_t salg_name[64];
+};
+
+struct af_alg_iv {
+ uint32_t ivlen;
+ uint8_t iv[0];
+};
+
+#define ALG_SET_KEY 1
+#define ALG_SET_IV 2
+#define ALG_SET_OP 3
+#define ALG_SET_AEAD_ASSOCLEN 4
+#define ALG_SET_AEAD_AUTHSIZE 5
+
+#define ALG_OP_DECRYPT 0
+#define ALG_OP_ENCRYPT 1
+
+#endif /* !HAVE_LINUX_IF_ALG_H */
+
+#endif /* IF_ALG_H__ */
diff --git a/include/lapi/socket.h b/include/lapi/socket.h
index 4e856dfb3..2605443e8 100644
--- a/include/lapi/socket.h
+++ b/include/lapi/socket.h
@@ -49,6 +49,10 @@
# define SOCK_CLOEXEC 02000000
#endif
+#ifndef AF_ALG
+# define AF_ALG 38
+#endif
+
#ifndef SOL_SCTP
# define SOL_SCTP 132
#endif
@@ -61,4 +65,8 @@
# define SOL_DCCP 269
#endif
+#ifndef SOL_ALG
+# define SOL_ALG 279
+#endif
+
#endif /* __LAPI_SOCKET_H__ */
diff --git a/include/tst_af_alg.h b/include/tst_af_alg.h
new file mode 100644
index 000000000..fc4b1989a
--- /dev/null
+++ b/include/tst_af_alg.h
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2019 Google LLC
+ */
+/**
+ * @file tst_af_alg.h
+ *
+ * Library for accessing kernel crypto algorithms via AF_ALG.
+ *
+ * See https://www.kernel.org/doc/html/latest/crypto/userspace-if.html
+ * for more information about AF_ALG.
+ */
+
+#ifndef TST_AF_ALG_H
+#define TST_AF_ALG_H
+
+#include "lapi/if_alg.h"
+#include <stdbool.h>
+
+/**
+ * Create an AF_ALG algorithm socket.
+ *
+ * This creates an AF_ALG algorithm socket that is initially not bound to any
+ * particular algorithm. On failure, tst_brk() is called with TCONF if the
+ * kernel doesn't support AF_ALG, otherwise TBROK.
+ *
+ * @return a new AF_ALG algorithm socket
+ */
+int tst_alg_create(void);
+
+/**
+ * Bind an AF_ALG algorithm socket to an algorithm.
+ *
+ * @param algfd An AF_ALG algorithm socket
+ * @param addr A structure which specifies the algorithm to use
+ *
+ * On failure, tst_brk() is called with TCONF if the kernel doesn't support the
+ * specified algorithm, otherwise TBROK.
+ */
+void tst_alg_bind_addr(int algfd, const struct sockaddr_alg *addr);
+
+/**
+ * Bind an AF_ALG algorithm socket to an algorithm.
+ *
+ * @param algfd An AF_ALG algorithm socket
+ * @param algtype The type of algorithm, such as "hash" or "skcipher"
+ * @param algname The name of the algorithm, such as "sha256" or "xts(aes)"
+ *
+ * Like tst_alg_bind_addr(), except this just takes in the algorithm type and
+ * name. The 'feat' and 'mask' fields are left 0.
+ *
+ * On failure, tst_brk() is called with TCONF if the kernel doesn't support the
+ * specified algorithm, otherwise TBROK.
+ */
+void tst_alg_bind(int algfd, const char *algtype, const char *algname);
+
+/**
+ * Check for the availability of an algorithm.
+ *
+ * @param algtype The type of algorithm, such as "hash" or "skcipher"
+ * @param algname The name of the algorithm, such as "sha256" or "xts(aes)"
+ *
+ * Return true if the algorithm is available, or false if unavailable.
+ * If another error occurs, tst_brk() is called with TBROK.
+ */
+bool tst_have_alg(const char *algtype, const char *algname);
+
+/**
+ * Require the availability of an algorithm.
+ *
+ * @param algtype The type of algorithm, such as "hash" or "skcipher"
+ * @param algname The name of the algorithm, such as "sha256" or "xts(aes)"
+ *
+ * If the algorithm is unavailable, tst_brk() is called with TCONF.
+ * If another error occurs, tst_brk() is called with TBROK.
+ */
+void tst_require_alg(const char *algtype, const char *algname);
+
+/**
+ * Assign a cryptographic key to an AF_ALG algorithm socket.
+ *
+ * @param algfd An AF_ALG algorithm socket
+ * @param key Pointer to the key. If NULL, a random key is generated.
+ * @param keylen Length of the key in bytes
+ *
+ * On failure, tst_brk() is called with TBROK.
+ */
+void tst_alg_setkey(int algfd, const uint8_t *key, unsigned int keylen);
+
+/**
+ * Create an AF_ALG request socket for the given algorithm socket.
+ *
+ * @param algfd An AF_ALG algorithm socket
+ *
+ * This creates a request socket for the given algorithm socket, which must be
+ * bound to an algorithm. The same algorithm socket can have many request
+ * sockets used concurrently to perform independent cryptographic operations,
+ * e.g. hashing or encryption/decryption. But the key, if any, that has been
+ * assigned to the algorithm is shared by all request sockets.
+ *
+ * On failure, tst_brk() is called with TBROK.
+ *
+ * @return a new AF_ALG request socket
+ */
+int tst_alg_accept(int algfd);
+
+/**
+ * Set up an AF_ALG algorithm socket for the given algorithm w/ given key.
+ *
+ * @param algtype The type of algorithm, such as "hash" or "skcipher"
+ * @param algname The name of the algorithm, such as "sha256" or "xts(aes)"
+ * @param key The key to use (optional)
+ * @param keylen The length of the key in bytes (optional)
+ *
+ * This is a helper function which creates an AF_ALG algorithm socket, binds it
+ * to the specified algorithm, and optionally sets a key. If keylen is 0 then
+ * no key is set; otherwise if key is NULL a key of the given length is randomly
+ * generated and set; otherwise the given key is set.
+ *
+ * @return the AF_ALG algorithm socket that was set up
+ */
+int tst_alg_setup(const char *algtype, const char *algname,
+ const uint8_t *key, unsigned int keylen);
+
+/**
+ * Set up an AF_ALG request socket for the given algorithm w/ given key.
+ *
+ * This is like tst_alg_setup(), except this returns a request fd instead of the
+ * alg fd. The alg fd is closed, so it doesn't need to be kept track of.
+ *
+ * @return the AF_ALG request socket that was set up
+ */
+int tst_alg_setup_reqfd(const char *algtype, const char *algname,
+ const uint8_t *key, unsigned int keylen);
+
+#endif /* TST_AF_ALG_H */
diff --git a/lib/tst_af_alg.c b/lib/tst_af_alg.c
new file mode 100644
index 000000000..5cae85721
--- /dev/null
+++ b/lib/tst_af_alg.c
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+
+#define TST_NO_DEFAULT_MAIN
+#include "tst_test.h"
+#include "tst_af_alg.h"
+
+int tst_alg_create(void)
+{
+ TEST(socket(AF_ALG, SOCK_SEQPACKET, 0));
+ if (TST_RET >= 0)
+ return TST_RET;
+ if (TST_ERR == EPROTONOSUPPORT)
+ tst_brk(TCONF, "kernel doesn't support AF_ALG");
+ tst_brk(TBROK | TTERRNO, "unexpected error creating AF_ALG socket");
+ return -1;
+}
+
+void tst_alg_bind_addr(int algfd, const struct sockaddr_alg *addr)
+{
+ TEST(bind(algfd, (const struct sockaddr *)addr, sizeof(*addr)));
+ if (TST_RET == 0)
+ return;
+ if (TST_ERR == ENOENT) {
+ tst_brk(TCONF, "kernel doesn't support %s algorithm '%s'",
+ addr->salg_type, addr->salg_name);
+ }
+ tst_brk(TBROK | TTERRNO,
+ "unexpected error binding AF_ALG socket to %s algorithm '%s'",
+ addr->salg_type, addr->salg_name);
+}
+
+static void init_sockaddr_alg(struct sockaddr_alg *addr,
+ const char *algtype, const char *algname)
+{
+ memset(addr, 0, sizeof(*addr));
+
+ addr->salg_family = AF_ALG;
+
+ strncpy((char *)addr->salg_type, algtype, sizeof(addr->salg_type));
+ if (addr->salg_type[sizeof(addr->salg_type) - 1] != '\0')
+ tst_brk(TBROK, "algorithm type too long: '%s'", algtype);
+
+ strncpy((char *)addr->salg_name, algname, sizeof(addr->salg_name));
+ if (addr->salg_name[sizeof(addr->salg_name) - 1] != '\0')
+ tst_brk(TBROK, "algorithm name too long: '%s'", algname);
+}
+
+void tst_alg_bind(int algfd, const char *algtype, const char *algname)
+{
+ struct sockaddr_alg addr;
+
+ init_sockaddr_alg(&addr, algtype, algname);
+
+ tst_alg_bind_addr(algfd, &addr);
+}
+
+bool tst_have_alg(const char *algtype, const char *algname)
+{
+ int algfd;
+ struct sockaddr_alg addr;
+ bool have_alg = true;
+
+ algfd = tst_alg_create();
+
+ init_sockaddr_alg(&addr, algtype, algname);
+
+ TEST(bind(algfd, (const struct sockaddr *)&addr, sizeof(addr)));
+ if (TST_RET != 0) {
+ if (TST_ERR != ENOENT) {
+ tst_brk(TBROK | TTERRNO,
+ "unexpected error binding AF_ALG socket to %s algorithm '%s'",
+ algtype, algname);
+ }
+ have_alg = false;
+ }
+
+ close(algfd);
+ return have_alg;
+}
+
+void tst_require_alg(const char *algtype, const char *algname)
+{
+ int algfd = tst_alg_create();
+
+ tst_alg_bind(algfd, algtype, algname);
+
+ close(algfd);
+}
+
+void tst_alg_setkey(int algfd, const uint8_t *key, unsigned int keylen)
+{
+ uint8_t *keybuf = NULL;
+ unsigned int i;
+
+ if (key == NULL) {
+ /* generate a random key */
+ keybuf = SAFE_MALLOC(keylen);
+ for (i = 0; i < keylen; i++)
+ keybuf[i] = rand();
+ key = keybuf;
+ }
+ TEST(setsockopt(algfd, SOL_ALG, ALG_SET_KEY, key, keylen));
+ if (TST_RET != 0) {
+ tst_brk(TBROK | TTERRNO,
+ "unexpected error setting key (len=%u)", keylen);
+ }
+ free(keybuf);
+}
+
+int tst_alg_accept(int algfd)
+{
+ TEST(accept(algfd, NULL, NULL));
+ if (TST_RET < 0) {
+ tst_brk(TBROK | TTERRNO,
+ "unexpected error accept()ing AF_ALG request socket");
+ }
+ return TST_RET;
+}
+
+int tst_alg_setup(const char *algtype, const char *algname,
+ const uint8_t *key, unsigned int keylen)
+{
+ int algfd = tst_alg_create();
+
+ tst_alg_bind(algfd, algtype, algname);
+
+ if (keylen != 0)
+ tst_alg_setkey(algfd, key, keylen);
+
+ return algfd;
+}
+
+int tst_alg_setup_reqfd(const char *algtype, const char *algname,
+ const uint8_t *key, unsigned int keylen)
+{
+ int algfd = tst_alg_setup(algtype, algname, key, keylen);
+ int reqfd = tst_alg_accept(algfd);
+
+ close(algfd);
+ return reqfd;
+}
--
2.21.0.225.g810b269d1ac-goog
Hi Eric,
> This series adds helper functions for testing AF_ALG (the userspace
> interface to algorithms in the Linux kernel's crypto API) to the
> Linux Test Project. It then adds a few sample regression tests.
> I've had these patches sitting around for a while with the goal of also
> writing some "real" tests that test for more than these specific bugs,
> but haven't gotten around to it yet. And I now consider further
> improving the in-kernel crypto self-tests to be a higher priority. But
> I figured I'd send this out as-is in case people are interested in
> having this merged, e.g. maybe other people want to add AF_ALG tests to
> LTP too and the 'tst_af_alg' lib would be a good starting point.
> Changed since v1:
> - Define 'AF_ALG' in include/lapi/socket.h if undefined.
> Also move 'SOL_ALG' definition to there.
The only minor issue is with missing SOL_ALG on older distros.
Going to push it with this fix including lapi/socket.h on lib/tst_af_alg.c and
testcases/kernel/crypto/af_alg01.c.
Kind regards,
Petr
diff --git lib/tst_af_alg.c lib/tst_af_alg.c
index 5cae85721..9ce1ca471 100644
--- lib/tst_af_alg.c
+++ lib/tst_af_alg.c
@@ -9,6 +9,7 @@
#define TST_NO_DEFAULT_MAIN
#include "tst_test.h"
#include "tst_af_alg.h"
+#include "lapi/socket.h"
int tst_alg_create(void)
{
diff --git testcases/kernel/crypto/af_alg01.c testcases/kernel/crypto/af_alg01.c
index 1ce0e2508..bb6e01738 100644
--- testcases/kernel/crypto/af_alg01.c
+++ testcases/kernel/crypto/af_alg01.c
@@ -14,6 +14,7 @@
#include "tst_test.h"
#include "tst_af_alg.h"
+#include "lapi/socket.h"
static void test_with_hash_alg(const char *hash_algname)
{
Hi Eric,
> > Changed since v1:
> > - Define 'AF_ALG' in include/lapi/socket.h if undefined.
> > Also move 'SOL_ALG' definition to there.
> The only minor issue is with missing SOL_ALG on older distros.
> Going to push it with this fix including lapi/socket.h on lib/tst_af_alg.c and
> testcases/kernel/crypto/af_alg01.c.
Merged with this small fix.
Kind regards,
Petr