Re: veritysetup forward error correction failure

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

 



On 17/07/2019 8:49 pm, Milan Broz wrote:
> If you can still reproduce it, please send version of the utility and
> kernel (and --debug output as suggested in another mail) and if you have some
> data/hash/fec images that can be used to reproduce it, let me know where I can find it.

Attached is a bash script gen_image.sh which should reproduce the issue.
find_and_corrupt.c should be in the working directory when gen_image.sh is
run. find_and_corrupt.c corrupts the disk image by simply searching for a
known string and introducing an error (see the diff outputted by gen_image.sh).

See in particular the error and dmesg sample when reading the corrupted file
(gen_image.sh:77) and the success when running veritysetup verify
(gen_image.sh:86).

I have created an issue at https://gitlab.com/cryptsetup/cryptsetup/issues/462

Thanks,
Tom
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

// n <-> o is 0x6e <-> 0x6f so it is a single bit change
#define SEARCH_TEXT  "Can you spot this error?"
#define REPLACE_TEXT "Cao you spot this error?"
#define READ_SIZE    4096

// command line args
enum {
	PROG_NAME,
	PATH,
	MAX_ARGS
};

// so that we don't spend all our time in syscall overhead
struct read_buf {
	char *buffer;
	ssize_t len;
	ssize_t read_ptr;
	int fd;
};

static struct read_buf *read_buf_init(ssize_t size, int fd) {
	if (fd < 0) {
		return NULL;
	}

	struct read_buf *buf = malloc(sizeof(*buf));
	if (buf == NULL) {
		return NULL;
	}

	buf->buffer = malloc(size);
	if (buf->buffer == NULL) {
		free(buf);
		return NULL;
	}

	buf->len = size;
	buf->read_ptr = -1;
	buf->fd = fd;
	return buf;
}

static void read_buf_free(struct read_buf *buf) {
	free(buf->buffer);
	free(buf);
	// doesn't close fd
}

static inline int read_buf_getc(struct read_buf *buf, char *out) {
	// if we need to do another read
	if (buf->read_ptr == -1 || buf->read_ptr == buf->len) {
		// TODO partial read
		ssize_t count = read(buf->fd, buf->buffer, buf->len);
		if (count != buf->len) {
			fprintf(stderr, "Read %lli, wanted %lli: %s\n",
				(long long) count, (long long) buf->len,
				strerror(errno));
			return EXIT_FAILURE;
		}
		buf->read_ptr = 0;
	}

	*out = buf->buffer[buf->read_ptr++];
	return EXIT_SUCCESS;
}

// seek through fd until we find text.
// Position the file pointer at the start of the text
static int find_text(const int fd, const char *text)
{
	int ret = EXIT_FAILURE;
	const size_t len = strlen(text);
	size_t n_matching = 0;

	off_t offset = lseek(fd, 0, SEEK_CUR);;
	if (offset == -1) {
		fprintf(stderr, "Failed to get current offset: %s\n",
			strerror(errno));
		return EXIT_FAILURE;
	}

	struct read_buf *buf = read_buf_init(READ_SIZE, fd);
	if (buf == NULL) {
		fprintf(stderr, "Couldn't allocate read_buf\n");
		return EXIT_FAILURE;
	}

	printf("Searching for \"%s\"\n", text);

	while (n_matching < len) {
		char readc;

		if (read_buf_getc(buf, &readc) != EXIT_SUCCESS) {
			fprintf(stderr, "read_buf_getc failed\n");
			goto free_buffer;
		}
		++offset;

		if (readc == text[n_matching]) {
			++n_matching;
			if (n_matching == len) {
				break;
			}
		} else {
			// not a match
			if (n_matching) {
				n_matching = 0;
			}
		}
	}

	// go back to the beginning of the text
	off_t err = lseek(fd, offset - len, SEEK_SET);
	if (err == -1) {
		fprintf(stderr, "Lseek error: %s\n", strerror(errno));
		goto free_buffer;
	}

	printf("Found at %lli!\n", (long long) offset);
	ret = EXIT_SUCCESS;

free_buffer:
	read_buf_free(buf);
	return ret;
}

static int find_and_replace(const int fd, const char *search_text,
		     const char *replace_text)
{
	if (find_text(fd, search_text) != EXIT_SUCCESS) {
		return EXIT_FAILURE;
	}

	const ssize_t len = strlen(replace_text);

	printf("Overwriting with \"%s\"\n", replace_text);
	ssize_t count = write(fd, replace_text, len);
	// TODO partial write
	if (count != len) {
		fprintf(stderr, "write error: %s\n", strerror(errno));
		return EXIT_FAILURE;
	}

	return EXIT_SUCCESS;
}

static void print_help(const char *name)
{
	fprintf(stderr, "Usage: %s FILE\n", name);
}

int main(int argc, char **argv)
{
	int ret = EXIT_FAILURE;

	if (argc != MAX_ARGS) {
		print_help(argv[PROG_NAME]);
		return EXIT_FAILURE;
	}

	if (strcmp("--help", argv[1]) == 0 || strcmp("-h", argv[1]) == 0) {
		print_help(argv[PROG_NAME]);
		return EXIT_SUCCESS;
	}
	const char *path = argv[PATH];

	int fd = open(path, O_RDWR);
	if (fd == -1) {
		int err = errno;
		fprintf(stderr, "Can't open %s: %i: %s\n", path, err, strerror(err));
		return EXIT_FAILURE;
	}

	ret = find_and_replace(fd, SEARCH_TEXT, REPLACE_TEXT);

	close(fd);

	return ret;
}

Attachment: gen_image.sh
Description: application/shellscript

_______________________________________________
dm-crypt mailing list
dm-crypt@xxxxxxxx
https://www.saout.de/mailman/listinfo/dm-crypt

[Index of Archives]     [Device Mapper Devel]     [Fedora Desktop]     [ATA RAID]     [Fedora Marketing]     [Fedora Packaging]     [Fedora SELinux]     [Yosemite News]     [KDE Users]     [Fedora Tools]     [Fedora Docs]

  Powered by Linux