Re: Regression bisected to "crypto: af_alg: Convert af_alg_sendpage() to use MSG_SPLICE_PAGES"

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Here's a smaller test program.  If it works correctly, it will print:

000: 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
020: 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
...

With the merging problem, it will print:

000: 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
020: 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
040: 6162636465666768696a6b6c6d6e6f707172737475767778797a313233343536
060: 4142434445464748494a4b4c4d4e4f505152535455565758595a313233343536
...

You can see the data from the send() ("abcd...") got appended to the page
passed by vmsplice() ("5a" x 64).

Arguably, if vmsplice() is given SPLICE_F_GIFT, AF_ALG would be within its
rights to remove the page from the caller's address space (as fuse will do
with SPLICE_F_MOVE), attach it to its scatterlist and append data to it.  In
such a case, however, the calling process should no longer be able to access
the page - and in the case of libkcapi, the heap would be corrupted.

David
---
// SPDX-License-Identifier: GPL-2.0-or-later
/* AF_ALG vmsplice test
 *
 * Copyright (C) 2023 Red Hat, Inc. All Rights Reserved.
 * Written by David Howells (dhowells@xxxxxxxxxx)
 */

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <limits.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/mman.h>
#include <linux/if_alg.h>

#define OSERROR(X, Y) \
	do { if ((long)(X) == -1) { perror(Y); exit(1); } } while (0)
#define min(x, y) ((x) < (y) ? (x) : (y))

static unsigned char buffer[4096 * 32] __attribute__((aligned(4096)));
static unsigned char iv[16];
static unsigned char key[16];

static const struct sockaddr_alg sa = {
	.salg_family	= AF_ALG,
	.salg_type	= "skcipher",
	.salg_name	= "cbc(aes)",
};

static void algif_add_set_op(struct msghdr *msg, unsigned int op)
{
	struct cmsghdr *__cmsg;

	__cmsg = msg->msg_control + msg->msg_controllen;
	__cmsg->cmsg_len	= CMSG_LEN(sizeof(unsigned int));
	__cmsg->cmsg_level	= SOL_ALG;
	__cmsg->cmsg_type	= ALG_SET_OP;
	*(unsigned int *)CMSG_DATA(__cmsg) = op;
	msg->msg_controllen += CMSG_ALIGN(__cmsg->cmsg_len);
}

static void algif_add_set_iv(struct msghdr *msg, const void *iv, size_t ivlen)
{
	struct af_alg_iv *ivbuf;
	struct cmsghdr *__cmsg;

	__cmsg = msg->msg_control + msg->msg_controllen;
	__cmsg->cmsg_len	= CMSG_LEN(sizeof(*ivbuf) + ivlen);
	__cmsg->cmsg_level	= SOL_ALG;
	__cmsg->cmsg_type	= ALG_SET_IV;
	ivbuf = (struct af_alg_iv *)CMSG_DATA(__cmsg);
	ivbuf->ivlen = ivlen;
	memcpy(ivbuf->iv, iv, ivlen);
	msg->msg_controllen += CMSG_ALIGN(__cmsg->cmsg_len);
}

void check(const unsigned char *p)
{
	unsigned int i, j;
	int blank = 0;

	for (i = 0; i < 4096; i += 32) {
		for (j = 0; j < 32; j++)
			if (p[i + j])
				break;
		if (j == 32) {
			if (!blank) {
				printf("...\n");
				blank = 1;
			}
			continue;
		}

		printf("%03x: ", i);
		for (j = 0; j < 32; j++)
			printf("%02x", p[i + j]);
		printf("\n");
		blank = 0;
	}
}

int main(int argc, char *argv[])
{
	struct iovec iov;
	struct msghdr msg;
	unsigned char ctrl[4096];
	ssize_t ret;
	size_t total = 0, i, out = 160;
	unsigned char *buf;
	int alg, sock, pfd[2];

	alg = socket(AF_ALG, SOCK_SEQPACKET, 0);
	OSERROR(alg, "AF_ALG");
	OSERROR(bind(alg, (struct sockaddr *)&sa, sizeof(sa)), "bind");
	OSERROR(setsockopt(alg, SOL_ALG, ALG_SET_KEY, key, sizeof(key)),
		"ALG_SET_KEY");
	sock = accept(alg, NULL, 0);
	OSERROR(sock, "accept");

	memset(&msg, 0, sizeof(msg));
	msg.msg_control = ctrl;
	algif_add_set_op(&msg, ALG_OP_ENCRYPT);
	algif_add_set_iv(&msg, iv, sizeof(iv));

	OSERROR(sendmsg(sock, &msg, MSG_MORE), "sock/sendmsg");

	OSERROR(pipe(pfd), "pipe");

	buf = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0);
	OSERROR(buf, "mmap");

	memset(buf, 0x5a, 64);
	iov.iov_base = buf;
	iov.iov_len = 64;
	OSERROR(vmsplice(pfd[1], &iov, 1, SPLICE_F_MORE), "vmsplice");
	OSERROR(splice(pfd[0], NULL, sock, NULL, 64, SPLICE_F_MORE), "splice");

	OSERROR(send(sock, "abcdefghijklmnopqrstuvwxyz123456ABCDEFGHIJKLMNOPQRSTUVWXYZ123456",
		     64, 0), "sock/send");

	while (total > 0) {
		ret = read(sock, buffer, min(sizeof(buffer), total));
		OSERROR(ret, "sock/read");
		if (ret == 0)
			break;
		total -= ret;

		if (out > 0) {
			ret = min(out, ret);
			out -= ret;
			for (i = 0; i < ret; i++)
				printf("%02x", (unsigned char)buffer[i]);
		}
		printf("...\n");
	}

	check(buf);

	OSERROR(close(sock), "sock/close");
	OSERROR(close(alg), "alg/close");
	OSERROR(close(pfd[0]), "close/p0");
	OSERROR(close(pfd[1]), "close/p1");
	return 0;
}





[Index of Archives]     [Kernel]     [Gnu Classpath]     [Gnu Crypto]     [DM Crypt]     [Netfilter]     [Bugtraq]
  Powered by Linux