Home | History | Annotate | Line # | Download | only in panic_string
panic_string.c revision 1.1.4.1
      1      1.1   kamil /*	$NetBSD: panic_string.c,v 1.1.4.1 2020/04/08 14:08:55 martin Exp $	*/
      2      1.1   kamil 
      3      1.1   kamil /*-
      4      1.1   kamil  * Copyright (c) 2018 The NetBSD Foundation, Inc.
      5      1.1   kamil  * All rights reserved.
      6      1.1   kamil  *
      7      1.1   kamil  * Redistribution and use in source and binary forms, with or without
      8      1.1   kamil  * modification, are permitted provided that the following conditions
      9      1.1   kamil  * are met:
     10      1.1   kamil  * 1. Redistributions of source code must retain the above copyright
     11      1.1   kamil  *    notice, this list of conditions and the following disclaimer.
     12      1.1   kamil  * 2. Redistributions in binary form must reproduce the above copyright
     13      1.1   kamil  *    notice, this list of conditions and the following disclaimer in the
     14      1.1   kamil  *    documentation and/or other materials provided with the distribution.
     15      1.1   kamil  *
     16      1.1   kamil  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17      1.1   kamil  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18      1.1   kamil  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19      1.1   kamil  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20      1.1   kamil  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21      1.1   kamil  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22      1.1   kamil  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23      1.1   kamil  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24      1.1   kamil  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25      1.1   kamil  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26      1.1   kamil  * POSSIBILITY OF SUCH DAMAGE.
     27      1.1   kamil  */
     28      1.1   kamil 
     29      1.1   kamil 
     30      1.1   kamil #include <sys/cdefs.h>
     31      1.1   kamil __KERNEL_RCSID(0, "$NetBSD: panic_string.c,v 1.1.4.1 2020/04/08 14:08:55 martin Exp $");
     32      1.1   kamil 
     33      1.1   kamil #include <sys/param.h>
     34      1.1   kamil #include <sys/types.h>
     35      1.1   kamil #include <sys/conf.h>
     36      1.1   kamil #include <sys/device.h>
     37      1.1   kamil #include <sys/filedesc.h>
     38      1.1   kamil #include <sys/kernel.h>
     39      1.1   kamil #include <sys/kmem.h>
     40      1.1   kamil #include <sys/lwp.h>
     41      1.1   kamil #include <sys/module.h>
     42      1.1   kamil #include <sys/vfs_syscalls.h>
     43      1.1   kamil 
     44      1.1   kamil /*
     45      1.1   kamil  * Create a device /dev/panic from which you can read sequential
     46      1.1   kamil  * user input.
     47      1.1   kamil  *
     48      1.1   kamil  * To use this device you need to do:
     49  1.1.4.1  martin  *      mknod /dev/panic c 351 0
     50      1.1   kamil  *
     51      1.1   kamil  * To write to the device you might need:
     52      1.1   kamil  *      chmod 666 /dev/panic
     53      1.1   kamil  *
     54      1.1   kamil  * Commentary:
     55      1.1   kamil  * This module manages the device /dev/panic,
     56      1.1   kamil  * tranfers a string from userspace to kernel space
     57      1.1   kamil  * and calls kernel panic with the passed string.
     58      1.1   kamil  *
     59      1.1   kamil  *  echo 'string' > /dev/panic
     60      1.1   kamil  * will do the trick after loading the module.
     61      1.1   kamil  */
     62      1.1   kamil 
     63      1.1   kamil dev_type_open(panic_string_open);
     64      1.1   kamil dev_type_close(panic_string_close);
     65      1.1   kamil dev_type_write(panic_string_write);
     66      1.1   kamil 
     67      1.1   kamil static struct cdevsw panic_string_cdevsw = {
     68      1.1   kamil 	.d_open = panic_string_open,
     69      1.1   kamil 	.d_close = panic_string_close,
     70      1.1   kamil 	.d_read = noread,
     71      1.1   kamil 	.d_write = panic_string_write,
     72      1.1   kamil 	.d_ioctl = noioctl,
     73      1.1   kamil 	.d_stop = nostop,
     74      1.1   kamil 	.d_tty = notty,
     75      1.1   kamil 	.d_poll = nopoll,
     76      1.1   kamil 	.d_mmap = nommap,
     77      1.1   kamil 	.d_kqfilter = nokqfilter,
     78      1.1   kamil 	.d_discard = nodiscard,
     79      1.1   kamil 	.d_flag = D_OTHER
     80      1.1   kamil };
     81      1.1   kamil 
     82      1.1   kamil static struct panic_string_softc {
     83      1.1   kamil 	int refcnt;
     84      1.1   kamil } sc;
     85      1.1   kamil 
     86      1.1   kamil /*
     87      1.1   kamil  * A function similar to strnlen + isprint
     88      1.1   kamil  *
     89      1.1   kamil  * Detect length of the printable and non-whitespace string in the buffer.
     90      1.1   kamil  * A string is accepted if it contains any non-space character.
     91      1.1   kamil  */
     92      1.1   kamil 
     93      1.1   kamil static size_t
     94      1.1   kamil printable_length(const char *str, size_t len)
     95      1.1   kamil {
     96      1.1   kamil 	size_t n;
     97      1.1   kamil 	bool accepted;
     98      1.1   kamil 
     99      1.1   kamil 	n = 0;
    100      1.1   kamil 	accepted = false;
    101      1.1   kamil 
    102      1.1   kamil 	while (len > n) {
    103      1.1   kamil 		if (str[n] >= 0x20 && str[n] <= 0x7e) {
    104      1.1   kamil 			if (str[n] != 0x20 /* space */)
    105      1.1   kamil 				accepted = true;
    106      1.1   kamil 			n++;
    107      1.1   kamil 		} else
    108      1.1   kamil 			break;
    109      1.1   kamil 	}
    110      1.1   kamil 
    111      1.1   kamil 	if (accepted)
    112      1.1   kamil 		return n;
    113      1.1   kamil 	else
    114      1.1   kamil 		return 0;
    115      1.1   kamil }
    116      1.1   kamil 
    117      1.1   kamil int
    118      1.1   kamil panic_string_open(dev_t self __unused, int flag __unused, int mod __unused, struct lwp *l)
    119      1.1   kamil {
    120      1.1   kamil 
    121      1.1   kamil 	/* Make sure the device is opened once at a time */
    122      1.1   kamil 	if (sc.refcnt > 0)
    123      1.1   kamil 		return EBUSY;
    124      1.1   kamil 
    125      1.1   kamil 	++sc.refcnt;
    126      1.1   kamil 
    127      1.1   kamil 	return 0;
    128      1.1   kamil }
    129      1.1   kamil 
    130      1.1   kamil int
    131      1.1   kamil panic_string_close(dev_t self __unused, int flag __unused, int mod __unused, struct lwp *l __unused)
    132      1.1   kamil {
    133      1.1   kamil 
    134      1.1   kamil 	--sc.refcnt;
    135      1.1   kamil 	return 0;
    136      1.1   kamil }
    137      1.1   kamil 
    138      1.1   kamil int
    139      1.1   kamil panic_string_write(dev_t self, struct uio *uio, int flags)
    140      1.1   kamil {
    141      1.1   kamil 	size_t len, printlen;
    142      1.1   kamil 	char *buffer;
    143      1.1   kamil 
    144      1.1   kamil 	/* Buffer length */
    145      1.1   kamil 	len = uio->uio_iov->iov_len;
    146      1.1   kamil 
    147      1.1   kamil 	/* Allocate a local buffer to store the string */
    148      1.1   kamil 	buffer = (char *)kmem_alloc(len, KM_SLEEP);
    149      1.1   kamil 
    150      1.1   kamil 	/* Move the string from user to kernel space and store it locally */
    151      1.1   kamil 	uiomove(buffer, len, uio);
    152      1.1   kamil 
    153      1.1   kamil 	printlen = printable_length(buffer, len);
    154      1.1   kamil 
    155      1.1   kamil 	if (printlen > 0) {
    156      1.1   kamil 		/* Flushing disk changes */
    157      1.1   kamil 		do_sys_sync(curlwp);
    158      1.1   kamil 
    159      1.1   kamil 		panic("panic string: %.*s\n", (int)printlen, buffer);
    160      1.1   kamil //		printf("panic string: %.*s\n", (int)printlen, buffer);
    161      1.1   kamil 
    162      1.1   kamil 		/* NOTREACHED */
    163      1.1   kamil 	}
    164      1.1   kamil 
    165      1.1   kamil 	kmem_free(buffer, len);
    166      1.1   kamil 	return 0;
    167      1.1   kamil }
    168      1.1   kamil 
    169      1.1   kamil MODULE(MODULE_CLASS_MISC, panic_string, NULL);
    170      1.1   kamil 
    171      1.1   kamil static int
    172      1.1   kamil panic_string_modcmd(modcmd_t cmd, void *arg __unused)
    173      1.1   kamil {
    174      1.1   kamil 	/* The major should be verified and changed if needed to avoid
    175      1.1   kamil 	 * conflicts with other devices. */
    176  1.1.4.1  martin 	int cmajor = 351, bmajor = -1;
    177      1.1   kamil 
    178      1.1   kamil 	switch (cmd) {
    179      1.1   kamil 	case MODULE_CMD_INIT:
    180      1.1   kamil 		printf("Panic String module loaded.\n");
    181      1.1   kamil 		if (devsw_attach("panic", NULL, &bmajor, &panic_string_cdevsw,
    182      1.1   kamil 						 &cmajor))
    183      1.1   kamil 			return ENXIO;
    184      1.1   kamil 		return 0;
    185      1.1   kamil 
    186      1.1   kamil 	case MODULE_CMD_FINI:
    187      1.1   kamil 		printf("Panic String module unloaded.\n");
    188      1.1   kamil 		if (sc.refcnt > 0)
    189      1.1   kamil 			return EBUSY;
    190      1.1   kamil 
    191      1.1   kamil 		devsw_detach(NULL, &panic_string_cdevsw);
    192      1.1   kamil 		return 0;
    193      1.1   kamil 	default:
    194      1.1   kamil 		return ENOTTY;
    195      1.1   kamil 	}
    196      1.1   kamil }
    197