public inbox for dm-crypt@saout.de
 help / color / mirror / Atom feed
From: Tom Eccles <tom.eccles@codethink.co.uk>
To: dm-crypt@saout.de
Cc: richardmaw@codethink.co.uk
Subject: Re: [dm-crypt] veritysetup forward error correction failure
Date: Thu, 18 Jul 2019 12:41:21 +0100	[thread overview]
Message-ID: <e28edf2d-36d3-7f0e-91c1-ded42fe2d688@codethink.co.uk> (raw)
In-Reply-To: <0ce29b38-3f32-d2bc-651e-071075941d43@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 842 bytes --]

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

[-- Attachment #2: find_and_corrupt.c --]
[-- Type: text/x-csrc, Size: 3883 bytes --]

#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 #3: gen_image.sh --]
[-- Type: application/x-shellscript, Size: 2154 bytes --]

  parent reply	other threads:[~2019-07-18 11:41 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-07-17 17:06 [dm-crypt] veritysetup forward error correction failure Tom Eccles
2019-07-17 18:00 ` Michael Kjörling
2019-07-17 19:49 ` Milan Broz
2019-07-18  9:10   ` Tom Eccles
2019-07-18  9:50     ` Milan Broz
2019-07-18 10:16       ` Tom Eccles
2019-07-18 11:41   ` Tom Eccles [this message]
2019-07-18 13:09     ` Milan Broz
2019-07-18 13:49       ` Tom Eccles
2019-07-18 13:59         ` Milan Broz
2019-07-18 14:01           ` Tom Eccles
2019-07-18 13:59       ` Tom Eccles
2019-07-19  7:38         ` Milan Broz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=e28edf2d-36d3-7f0e-91c1-ded42fe2d688@codethink.co.uk \
    --to=tom.eccles@codethink.co.uk \
    --cc=dm-crypt@saout.de \
    --cc=richardmaw@codethink.co.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox