Subject: Re: building a userland interface to a kernel structure
To: Michael L. Hitch <mhitch@lightning.oscs.montana.edu>
From: Dustin Sallings <dustin@spy.net>
List: current-users
Date: 01/12/1999 11:16:13
On Tue, 12 Jan 1999, Michael L. Hitch wrote:

	This is good for reading, but how might I, say, add an entry to a
linked list in a kernel structure from userland?  And where should I put
this list?

	Basically, I'm breaking root down a little bit, and I want to
define ACLs for something that's been root/not root to have a more
granular security control.  Down with root!

# On Tue, 12 Jan 1999, David Maxwell wrote:
# 
# > On Tue, Jan 12, 1999 at 12:08:25AM -0800, dustin sallings wrote:
# > > 
# > > 	For a kernel modification I'm doing, I need to be able to build
# > > and maintain a simple array of (arrays|hashes|linked lists) from a
# > > userland process.
# > > 
# > > 	I don't have the slightest idea where to put this in the kernel,
# > > what to name it, or how to interface it.  Can someone give me an idea?
# > 
# > I'll tag onto this message and ask... I'd like to write a userland program
# > which can read the kernel disklist linked list. I've looked into the 
# > kernel memory syscalls in a fair amount of detail, and looked at some
# > examples in the tree, but I can't find anything in the tree that
# > reads _structures_ from the kernel, just simple variables. I haven't
# > been able to make my code work.
# 
#   Here's a simple example.  I don't remember where I got this - it doesn't
# look like I wrote it, although I may have modified it somewhat.  [The
# program is almost 3 years old.]  I have written a number of little
# kernel-groveling programs like this to make it easier to see what's going
# on in a live kernel.
# 
# #include <stdio.h>
# #include <stdlib.h>
# #include <string.h>
# #include <unistd.h>
# 
# #include <sys/dkstat.h>
# #include <sys/time.h>
# #include <sys/disk.h>
# 
# #include <err.h>
# #include <fcntl.h>
# #include <kvm.h>
# #include <limits.h>
# #include <nlist.h>
# 
# static struct nlist namelist[] = {
# #define	X_TK_NIN	0
# 	{ "_tk_nin" },		/* tty characters in */
# #define	X_TK_NOUT	1
# 	{ "_tk_nout" },		/* tty characters out */
# #define	X_CP_TIME	2
# 	{ "_cp_time" },		/* system timer ticks */
# #define	X_HZ		3
# 	{ "_hz" },		/* ticks per second */
# #define	X_STATHZ	4
# 	{ "_stathz" },
# #define X_DISK_COUNT	5
# 	{ "_disk_count" },	/* number of disks */
# #define X_DISKLIST	6
# 	{ "_disklist" },	/* TAILQ of disks */
# 	{ NULL },
# };
# 
# /* Kernel pointers: nlistf and memf defined in calling program. */
# static kvm_t	*kd = NULL;
# char	*nlistf;
# char	*memf;
# 
# /* Pointer to list of disks. */
# static struct disk	*dk_drivehead = NULL;
# 
# /* Backward compatibility references. */
# int	  	dk_ndrive = 0;
# 
# #define	KVM_ERROR(_string) {						\
# 	warnx((_string));						\
# 	errx(1, kvm_geterr(kd));					\
# }
# 
# /*
#  * Dereference the namelist pointer `v' and fill in the local copy 
#  * 'p' which is of size 's'.
#  */
# #define deref_nl(v, p, s) deref_kptr((void *)namelist[(v)].n_value, (p), (s));
# 
# static void deref_kptr __P((void *, void *, size_t));
# 
# main(int argc, char *argv[])
# {
# 	int i;
# 	struct disklist_head disk_head;
# 	struct disk	cur_disk, *p;
#         char		errbuf[_POSIX2_LINE_MAX];
# 
#         if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf)) == NULL)
# 		errx(1, "kvm_openfiles: %s", errbuf);
# 
# 	/* Obtain the namelist symbols from the kernel. */
# 	if (kvm_nlist(kd, namelist))
# 		KVM_ERROR("kvm_nlist failed to read symbols.");
# 
# 	/* Get the number of attached drives. */
# 	deref_nl(X_DISK_COUNT, &dk_ndrive, sizeof(dk_ndrive));
# 
# 	if (dk_ndrive < 0)
# 		errx(1, "invalid _disk_count %d.", dk_ndrive);
# 	else if (dk_ndrive == 0) {
# 		warnx("No drives attached.");
# 	}
# 	else {
# 		/* Get a pointer to the first disk. */
# 		deref_nl(X_DISKLIST, &disk_head, sizeof(disk_head));
# 		dk_drivehead = disk_head.tqh_first;
# 	}
# 
# 	printf("%d drives, header %x\n", dk_ndrive, dk_drivehead);
# 
# 	p = dk_drivehead;
# 	printf("Address  Name     Transfers   Seeks     Bytes\n");
# 	for (i = 0; i < dk_ndrive; ++i) {
# 		deref_kptr(p, &cur_disk, sizeof(cur_disk));
# 		deref_kptr(cur_disk.dk_name, errbuf, 10);
# 		printf("%08x %-10s%8lld%8lld%10lld\n", p, errbuf,
# 		    cur_disk.dk_xfer, cur_disk.dk_seek, cur_disk.dk_bytes);
# 		p = cur_disk.dk_link.tqe_next;
# 	}
# }
# 
# /*
#  * Dereference the kernel pointer `kptr' and fill in the local copy 
#  * pointed to by `ptr'.  The storage space must be pre-allocated,
#  * and the size of the copy passed in `len'.
#  */
# static void
# deref_kptr(kptr, ptr, len)
# 	void *kptr, *ptr;
# 	size_t len;
# {
# 	char buf[128];
# 
# 	if (kvm_read(kd, (u_long)kptr, (char *)ptr, len) != len) {
# 		bzero(buf, sizeof(buf));
# 		snprintf(buf, (sizeof(buf) - 1),
# 		     "can't dereference kptr 0x%lx", (u_long)kptr);
# 		KVM_ERROR(buf);
# 	}
# }
# 
# ---
# Michael L. Hitch			mhitch@montana.edu
# Computer Consultant
# Information Technology Center
# Montana State University	Bozeman, MT	USA
# 
# 

--
SA, beyond.com           My girlfriend asked me which one I like better.
pub  1024/3CAE01D5 1994/11/03 Dustin Sallings <dustin@spy.net>
|    Key fingerprint =  87 02 57 08 02 D0 DA D6  C8 0F 3E 65 51 98 D8 BE 
L_______________________ I hope the answer won't upset her. ____________