| /*- |
| * Copyright 2015-2017 Rivoreo |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer |
| * in this position and unchanged. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR |
| * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
| * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
| * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
| * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| * |
| */ |
| |
| #include <sys/cdefs.h> |
| #include <sys/param.h> |
| #include <sys/systm.h> |
| #include <sys/conf.h> |
| #include <sys/uio.h> |
| #include <sys/kernel.h> |
| #include <sys/malloc.h> |
| #include <sys/module.h> |
| #include <sys/filio.h> |
| |
| #define IOCTL_MYFAULT_PANIC _IOW('m', 0x40, const char *) |
| |
| static char *_strchr(const char *p, int ch) { |
| union { |
| const char *cp; |
| char *p; |
| } u; |
| |
| u.cp = p; |
| while(1) { |
| if (*u.p == ch) |
| return(u.p); |
| if (*u.p == '\0') |
| return(NULL); |
| u.p++; |
| } |
| } |
| #define strchr _strchr |
| |
| /* For use with destroy_dev(9). */ |
| static struct cdev *myfault_dev; |
| |
| static d_write_t myfault_write; |
| static d_ioctl_t myfault_ioctl; |
| static d_read_t myfault_read; |
| |
| static struct cdevsw myfault_cdevsw = { |
| .d_version = D_VERSION, |
| .d_read = myfault_read, |
| .d_write = myfault_write, |
| .d_ioctl = myfault_ioctl, |
| .d_name = "myfault", |
| //.d_flags = D_MMAP_ANON, |
| }; |
| |
| static void stack_corrupt() { |
| volatile char buffer[256]; |
| memset((char *)buffer + (sizeof buffer / 2), 1, sizeof buffer * 2); |
| } |
| |
| static void buffer_overflow() { |
| char *buffer = malloc(1024, M_TEMP, M_WAITOK); |
| memset(buffer, 2, 1080); |
| } |
| |
| static void stack_overflow() { |
| stack_overflow(); |
| } |
| |
| static void double_free() { |
| void *p = malloc(1024, M_TEMP, M_WAITOK); |
| free(p, M_TEMP); |
| free(p, M_TEMP); |
| } |
| |
| static int myfault_write(struct cdev *dev __unused, struct uio *uio, int flags __unused) |
| { |
| char buffer[64]; |
| int len = MIN(uio->uio_resid, sizeof buffer); |
| int error = uiomove(buffer, len, uio); |
| if(error) return error; |
| //uio->uio_resid = 0; |
| buffer[len] = 0; |
| char *newline = strchr(buffer, '\n'); |
| if(newline) *newline = 0; |
| if(!*buffer) return 0; |
| if(strcmp(buffer, "stack") == 0) stack_corrupt(); |
| else if(strcmp(buffer, "buffer overflow") == 0) buffer_overflow(); |
| else if(strcmp(buffer, "stack overflow") == 0) stack_overflow(); |
| else if(strcmp(buffer, "double free") == 0) double_free(); |
| else if(strcmp(buffer, "breakpoint") == 0) breakpoint(); |
| else if(strncmp(buffer, "panic ", 6) == 0) panic("%s", buffer + 6); |
| else printf("myfault: command '%s' not recognized\n", buffer); |
| uio->uio_resid = 0; |
| return 0; |
| } |
| |
| static int myfault_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data, int flags __unused, struct thread *td) |
| { |
| int error; |
| error = 0; |
| |
| switch (cmd) { |
| case FIONBIO: |
| break; |
| case FIOASYNC: |
| if (*(int *)data != 0) |
| error = EINVAL; |
| break; |
| case IOCTL_MYFAULT_PANIC: |
| panic("%s", (const char *)data); |
| break; |
| default: |
| return ENOIOCTL; |
| } |
| return (error); |
| } |
| |
| static int myfault_read(struct cdev *dev __unused, struct uio *uio, int flags __unused) |
| { |
| static char buffer[] = "This is myfault kernel module\n"; |
| int error = 0; |
| |
| KASSERT(uio->uio_rw == UIO_READ, |
| ("Can't be in %s for write", __func__)); |
| if(uio->uio_offset >= sizeof buffer - 1) return 0; |
| error = uiomove(buffer + uio->uio_offset, MIN(uio->uio_resid, sizeof buffer - 1), uio); |
| uio->uio_resid = 0; |
| |
| return (error); |
| } |
| |
| static int myfault_modevent(module_t mod __unused, int type, void *data __unused) |
| { |
| switch(type) { |
| case MOD_LOAD: |
| //myfault_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD, &myfault_cdevsw, 0, |
| // NULL, UID_ROOT, GID_WHEEL, 0666, "myfault"); |
| myfault_dev = make_dev(&myfault_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "myfault"); |
| break; |
| |
| case MOD_UNLOAD: |
| destroy_dev(myfault_dev); |
| break; |
| |
| case MOD_SHUTDOWN: |
| break; |
| |
| default: |
| return (EOPNOTSUPP); |
| } |
| |
| return (0); |
| } |
| |
| DEV_MODULE(myfault, myfault_modevent, NULL); |
| MODULE_VERSION(myfault, 1); |