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