[LTP] [PATCH 2/2] Add CVE-2017-18075, pcrypt mishandles freeing instances
Richard Palethorpe
rpalethorpe@suse.de
Thu Mar 15 09:50:25 CET 2018
Hello Eric,
Eric Biggers writes:
> Hi Richard,
>
> On Wed, Mar 14, 2018 at 03:54:27PM +0100, Richard Palethorpe wrote:
>> Signed-off-by: Richard Palethorpe <rpalethorpe@suse.com>
>> ---
>>
>> I can not find the original reproducer posted upstream. I assume it was
>> created by syzkaller.
>>
>> This patch will not display error messages correctly without the previous
>> TRERRNO patch I posted.
>>
>> runtest/cve | 1 +
>> testcases/cve/.gitignore | 1 +
>> testcases/cve/cve-2017-18075.c | 201 +++++++++++++++++++++++++++++++++++++++++
>
> Thanks for writing an LTP test for this!
>
> Just my 2 cents, but I think it is insane to be naming tests after CVE numbers
> instead of putting them in an appropriate place, like a crypto/ directory for
> this one. People aren't going to remember what "CVE-2017-18075" is. I'm even
> the person who fixed this bug and requested this CVE, and I still didn't
> recognize the CVE number; this patch only drew my attention because the subject
> line mentioned pcrypt. (And now I see that I missed the recent test for the
> modify_ldt() use-after-free bug because the patch subject line and description
> only mentioned "CVE-2017-17053".)
>
> Note that you can still put the test in the "cve" runtest file even if the test
> is not in the cve/ directory.
I'm happy to put it in kernel/crypto. I just wasn't sure where to put it
so submitted it under the CVE directory. I guess I should have CC'ed you.
>
> (More comments below)
>
>> diff --git a/testcases/cve/cve-2017-18075.c b/testcases/cve/cve-2017-18075.c
> [...]
>> +
>> +#define ATTEMPTS 10000
>> +
>> +enum {
>> + CRYPTO_MSG_BASE = 0x10,
>> + CRYPTO_MSG_NEWALG = 0x10,
>> + CRYPTO_MSG_DELALG,
>> + CRYPTO_MSG_UPDATEALG,
>> + CRYPTO_MSG_GETALG,
>> + CRYPTO_MSG_DELRNG,
>> + __CRYPTO_MSG_MAX
>> +};
>> +
>> +#define CRYPTO_MAX_ALG_NAME 64
>> +#define CRYPTO_MAX_NAME CRYPTO_MAX_ALG_NAME
>> +
>> +#define CRYPTO_ALG_TYPE_MASK 0x0000000f
>> +#define CRYPTO_ALG_TYPE_AEAD 0x00000003
>> +
>> +#ifndef NETLINK_CRYPTO
>> +#define NETLINK_CRYPTO 21
>> +#endif
>> +
>> +struct crypto_user_alg {
>> + char cru_name[CRYPTO_MAX_ALG_NAME];
>> + char cru_driver_name[CRYPTO_MAX_ALG_NAME];
>> + char cru_module_name[CRYPTO_MAX_ALG_NAME];
>> + uint32_t cru_type;
>> + uint32_t cru_mask;
>> + uint32_t cru_refcnt;
>> + uint32_t cru_flags;
>> +};
>> +
>> +static void send_nl_msg(int fd, struct nlmsghdr *nh, void *payload)
>> +{
>> + static unsigned int sequence_number;
>> + struct sockaddr_nl sa = { .nl_family = AF_NETLINK };
>> + struct iovec iov[2] = {
>> + {nh, sizeof(*nh)},
>> + {payload, nh->nlmsg_len - sizeof(*nh)}
>> + };
>> + struct msghdr msg = {
>> + .msg_name = &sa,
>> + .msg_namelen = sizeof(sa),
>> + .msg_iov = iov,
>> + .msg_iovlen = 2
>> + };
>> +
>> + nh->nlmsg_pid = 0;
>> + nh->nlmsg_seq = ++sequence_number;
>> + /* Request an ack from kernel by setting NLM_F_ACK */
>> + nh->nlmsg_flags |= NLM_F_ACK;
>> +
>> + SAFE_SENDMSG(nh->nlmsg_len, fd, &msg, 0);
>> +}
>> +
>> +static int read_reply(int fd)
>> +{
>> + int len;
>> + char buf[4096];
>> + struct iovec iov = { buf, sizeof(buf) };
>> + struct sockaddr_nl sa;
>> + struct msghdr msg = {
>> + .msg_name = &sa,
>> + .msg_namelen = sizeof(sa),
>> + .msg_iov = &iov,
>> + .msg_iovlen = 1
>> + };
>> + struct nlmsghdr *nh;
>> +
>> + len = SAFE_RECVMSG(0, fd, &msg, 0);
>> +
>> + for (nh = (struct nlmsghdr *) buf;
>> + NLMSG_OK(nh, len);
>> + nh = NLMSG_NEXT(nh, len)) {
>> + /* The end of multipart message. */
>> + if (nh->nlmsg_type == NLMSG_DONE)
>> + return 0;
>> +
>> + if (nh->nlmsg_type == NLMSG_ERROR)
>> + return ((struct nlmsgerr *)NLMSG_DATA(nh))->error;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int add_alg(int fd, struct crypto_user_alg *a)
>> +{
>> + int r;
>> + struct nlmsghdr nh = {
>> + .nlmsg_len = sizeof(struct nlmsghdr) + sizeof(*a),
>> + .nlmsg_type = CRYPTO_MSG_NEWALG,
>> + .nlmsg_flags = NLM_F_REQUEST,
>> + };
>> +
>> + send_nl_msg(fd, &nh, a);
>> +
>> + r = read_reply(fd);
>> + if (r == -EEXIST)
>> + return 0;
>> + return r;
>> +}
>> +
>> +static int del_alg(int fd, struct crypto_user_alg *a)
>> +{
>> + int i;
>> + struct timespec delay = { .tv_nsec = 1000000 };
>> + struct nlmsghdr nh = {
>> + .nlmsg_len = sizeof(struct nlmsghdr) + sizeof(*a),
>> + .nlmsg_type = CRYPTO_MSG_DELALG,
>> + .nlmsg_flags = NLM_F_REQUEST,
>> + };
>> +
>> + for (i = 0; i < 1000; i++) {
>> + send_nl_msg(fd, &nh, a);
>> +
>> + TEST(read_reply(fd));
>> + if (TEST_RETURN != -EBUSY)
>> + break;
>> +
>> + if (nanosleep(&delay, NULL) && errno != EINTR)
>> + tst_brk(TBROK | TERRNO, "nanosleep");
>> + }
>> +
>> + return TEST_RETURN;
>> +}
>
> I suggest putting this NETLINK_CRYPTO stuff in a common location that can be
> used by other tests too. This will not be the last crypto API bug. The
> definitions for AF_ALG probably should be there too; though AF_ALG isn't used by
> this test, many crypto bugs I've fixed or seen fixed recently are accessible
> through it. (E.g. see commit ecaaab564978, "crypto: salsa20 - fix
> blkcipher_walk API usage" or commit e57121d08c38, "crypto: chacha20poly1305 -
> validate the digest size". Sorry, I was a bit lazy by just putting reproducers
> in the commit messages and not writing "real" tests.) It would be great to have
> helper functions in LTP for testing the crypto API, so that they don't have to
> be repeated in every test.
I suppose we would benefit from some generic netlink helper functions
also. In my netlink.h there are about 21 different protocols defined, so
we could create include/tst_netlink.h and then add
include/tst_netlink_crypto.h and tst_netlink_route.h etc.
Currently we only have a few tests using netlink and they are mostly
doing their own thing.
>
>> +
>> +void setup(void)
>> +{
>> + tst_taint_init(TST_TAINT_W | TST_TAINT_D);
>> +}
>> +
>> +void run(void)
>> +{
>> + int fd, i;
>> + struct crypto_user_alg a = {
>> + .cru_driver_name = "pcrypt(authenc(hmac(sha256-generic),cbc(aes-generic)))",
>> + .cru_type = CRYPTO_ALG_TYPE_AEAD,
>> + .cru_mask = CRYPTO_ALG_TYPE_MASK,
>> + };
>> +
>> + fd = SAFE_SOCKET(AF_NETLINK, SOCK_DGRAM, NETLINK_CRYPTO);
>
> Does this test get correctly skipped if the needed crypto modules are not
> enabled? There are several cases:
>
> - NETLINK_CRYPTO unsupported (CONFIG_CRYPTO_USER not set)
> - pcrypt unsupported (CONFIG_CRYPTO_PCRYPT not set)
> - underlying algorithms unsupported (CONFIG_CRYPTO_AUTHENC, CONFIG_CRYPTO_HMAC,
> CONFIG_CRYPTO_SHA256, CONFIG_CRYPTO_CBC, or CONFIG_CRYPTO_AES not set)
>
>> +static struct tst_test test = {
>> + .setup = setup,
>> + .test_all = run,
>> + .needs_root = 1,
>> + .min_kver = "4.2.0",
>> +};
>
> Why is a minimum kernel version needed?
>
> - Eric
So this is wrong then, I need to check the errno of socket() when it
fails and can remove the min_kver which I think was the kernel version
where the feature was introduced.
--
Thank you,
Richard.
More information about the ltp
mailing list