From 75f9922f6d3c1e5bbbe7b90ca170392cc0f5efbc Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Sun, 21 Oct 2018 16:23:23 +0300 Subject: Refactor io utils, add *-address-rw tools Namespace io_ stuff into mem_io_ to be less likely to collision with anything else. Add io-stream utility for working with streams instead of direct buffers. Add address-rw tools for simple memory read/write, where regions aren't needed. --- src/mem/io-ptrace.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/mem/io-stream.c | 53 ++++++++++++++++++++++++++++++++ src/mem/io-stream.h | 27 +++++++++++++++++ src/mem/io-uio.c | 41 +++++++++++++++++++++++++ src/mem/io.h | 30 ++++++++++++++++++ 5 files changed, 238 insertions(+) create mode 100644 src/mem/io-ptrace.c create mode 100644 src/mem/io-stream.c create mode 100644 src/mem/io-stream.h create mode 100644 src/mem/io-uio.c create mode 100644 src/mem/io.h (limited to 'src/mem') diff --git a/src/mem/io-ptrace.c b/src/mem/io-ptrace.c new file mode 100644 index 0000000..cf9a861 --- /dev/null +++ b/src/mem/io-ptrace.c @@ -0,0 +1,87 @@ +#include "io.h" +#include +#include +#include +#include + +static size_t +mem_io_ptrace_do(const struct mem_io *io, void *ptr, const size_t offset, const size_t size, size_t (*iofun)(void*, size_t, size_t, FILE*)) +{ + if (fseek(io->backing, offset, SEEK_SET) != 0) { + warn("fseek(/proc/%u/mem, %zu)", io->pid, offset); + return 0; + } + + return iofun(ptr, 1, size, io->backing); +} + +static size_t +mem_io_ptrace_write(const struct mem_io *io, const void *ptr, const size_t offset, const size_t size) +{ + clearerr(io->backing); + const size_t ret = mem_io_ptrace_do(io, (void*)ptr, offset, size, (size_t(*)())fwrite); + + if (ferror(io->backing)) + warn("fwrite(/proc/%u/mem)", io->pid); + + return ret; +} + +static size_t +mem_io_ptrace_read(const struct mem_io *io, void *ptr, const size_t offset, const size_t size) +{ + clearerr(io->backing); + const size_t ret = mem_io_ptrace_do(io, ptr, offset, size, fread); + + if (ferror(io->backing)) + warn("fread(/proc/%u/mem)", io->pid); + + return ret; +} + +static void +mem_io_ptrace_cleanup(struct mem_io *io) +{ + if (io->backing) + fclose(io->backing); + + if (io->pid) + ptrace(PTRACE_DETACH, io->pid, 1, 0); +} + +bool +mem_io_ptrace_init(struct mem_io *io, const pid_t pid) +{ + *io = (struct mem_io){ + .pid = pid, + .read = mem_io_ptrace_read, + .write = mem_io_ptrace_write, + .cleanup = mem_io_ptrace_cleanup + }; + + if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) == -1L) { + warn("ptrace(PTRACE_ATTACH, %u, NULL, NULL)", pid); + goto fail; + } + + { + int status; + if (waitpid(pid, &status, 0) == -1 || !WIFSTOPPED(status)) { + warn("waitpid(%u) == %d", pid, status); + goto fail; + } + } + + char path[128]; + snprintf(path, sizeof(path), "/proc/%u/mem", pid); + if (!(io->backing = fopen(path, "w+b"))) { + warn("fopen(%s)", path); + goto fail; + } + + return true; + +fail: + io->cleanup(io); + return false; +} diff --git a/src/mem/io-stream.c b/src/mem/io-stream.c new file mode 100644 index 0000000..f7c7834 --- /dev/null +++ b/src/mem/io-stream.c @@ -0,0 +1,53 @@ +#include +#include "io-stream.h" +#include "io.h" + +static size_t +file_istream_read(const struct mem_io_istream *stream, void *ptr, const size_t size) +{ + return fread(ptr, 1, size, stream->backing); +} + +struct mem_io_istream +mem_io_istream_from_file(FILE *file) +{ + return (struct mem_io_istream){ + .read = file_istream_read, + .backing = file + }; +} + +size_t +mem_io_write_from_stream(const struct mem_io *io, const struct mem_io_istream *stream, const size_t offset, const size_t size) +{ + size_t trw = 0; + unsigned char buf[4096]; + for (size_t rd, trd = 0; (rd = stream->read(stream, buf, (trd + sizeof(buf) > size ? size - trd : sizeof(buf)))) && trd < size; trd += rd) + trw += io->write(io, buf, offset + trd, rd); + return trw; +} + +static size_t +file_ostream_write(const struct mem_io_ostream *stream, const void *ptr, const size_t size) +{ + return fwrite(ptr, 1, size, stream->backing); +} + +struct mem_io_ostream +mem_io_ostream_from_file(FILE *file) +{ + return (struct mem_io_ostream){ + .write = file_ostream_write, + .backing = file + }; +} + +size_t +mem_io_read_to_stream(const struct mem_io *io, const struct mem_io_ostream *stream, const size_t offset, const size_t size) +{ + size_t trw = 0; + unsigned char buf[4096]; + for (size_t rd, trd = 0; (rd = io->read(io, buf, offset + trd, (trd + sizeof(buf) > size ? size - trd : sizeof(buf)))) && trd < size; trd += rd) + trw += stream->write(stream, buf, rd); + return trw; +} diff --git a/src/mem/io-stream.h b/src/mem/io-stream.h new file mode 100644 index 0000000..ba3b620 --- /dev/null +++ b/src/mem/io-stream.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +struct mem_io; + +struct mem_io_istream { + size_t (*read)(const struct mem_io_istream *stream, void *ptr, const size_t size); + void *backing; +}; + +struct mem_io_istream +mem_io_istream_from_file(FILE *file); + +size_t +mem_io_write_from_stream(const struct mem_io *io, const struct mem_io_istream *stream, const size_t offset, const size_t size); + +struct mem_io_ostream { + size_t (*write)(const struct mem_io_ostream *stream, const void *ptr, const size_t size); + void *backing; +}; + +struct mem_io_ostream +mem_io_ostream_from_file(FILE *file); + +size_t +mem_io_read_to_stream(const struct mem_io *io, const struct mem_io_ostream *stream, const size_t offset, const size_t size); diff --git a/src/mem/io-uio.c b/src/mem/io-uio.c new file mode 100644 index 0000000..c649a45 --- /dev/null +++ b/src/mem/io-uio.c @@ -0,0 +1,41 @@ +#include "io.h" +#include +#include +#include + +static size_t +mem_io_uio_do(const struct mem_io *io, const void *ptr, const size_t offset, const size_t size, ssize_t (*iofun)(pid_t, const struct iovec*, unsigned long, const struct iovec*, unsigned long, unsigned long)) +{ + const struct iovec lio = { .iov_base = (void*)ptr, .iov_len = size }; + const struct iovec rio = { .iov_base = (void*)(intptr_t)offset, .iov_len = size }; + return iofun(io->pid, &lio, 1, &rio, 1, 0); +} + +static size_t +mem_io_uio_write(const struct mem_io *io, const void *ptr, const size_t offset, const size_t size) +{ + const size_t ret = mem_io_uio_do(io, ptr, offset, size, process_vm_writev); + + if (ret == (size_t)-1) + warn("process_vm_writev(%u)", io->pid); + + return (ret == (size_t)-1 ? 0 : ret); +} + +static size_t +mem_io_uio_read(const struct mem_io *io, void *ptr, const size_t offset, const size_t size) +{ + const size_t ret = mem_io_uio_do(io, ptr, offset, size, process_vm_readv); + + if (ret == (size_t)-1) + warn("process_vm_readv(%u)", io->pid); + + return (ret == (size_t)-1 ? 0 : ret); +} + +bool +mem_io_uio_init(struct mem_io *io, const pid_t pid) +{ + *io = (struct mem_io){ .pid = pid, .read = mem_io_uio_read, .write = mem_io_uio_write }; + return true; +} diff --git a/src/mem/io.h b/src/mem/io.h new file mode 100644 index 0000000..665b0cd --- /dev/null +++ b/src/mem/io.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include +#include // pid_t + +struct mem_io { + size_t (*read)(const struct mem_io *io, void *ptr, const size_t offset, const size_t size); + size_t (*write)(const struct mem_io *io, const void *ptr, const size_t offset, const size_t size); + void (*cleanup)(struct mem_io *io); + void *backing; + pid_t pid; +}; + +static inline void +mem_io_release(struct mem_io *io) +{ + if (io->cleanup) + io->cleanup(io); + *io = (struct mem_io){0}; +} + +void +mem_io_release(struct mem_io *io); + +bool +mem_io_uio_init(struct mem_io *io, const pid_t pid); + +bool +mem_io_ptrace_init(struct mem_io *io, const pid_t pid); -- cgit v1.2.3