How to access kernel memory from user space

Alexej Sokolov bsd.quest at googlemail.com
Thu Jan 15 10:31:01 PST 2009


2008/12/23 Gerry Weaver <gerryw at compvia.com>

> Hello All,
>
> I am working on a driver that collects various network statistics via pfil.
> I have a simple array of structures that I use to store the statistics. I
> also have a user space process that needs to collect these statistics every
> second or so. A copy operation from kernel to user space would be too
> expensive. Is there a mechanism that would allow me to gain direct access to
> my kernel array from user space? The user process would only need read
> access. It seems like maybe this could be done with mmap, but since this is
> not a character driver, there is no device file etc.. I'm a newbie, so I
> apologize if this is something that should be obvious.
>
>
> Thanks in advance,
> Gerry
> _______________________________________________
> freebsd-hackers at freebsd.org mailing list
> http://lists.freebsd.org/mailman/listinfo/freebsd-hackers
> To unsubscribe, send any mail to "freebsd-hackers-unsubscribe at freebsd.org"
>
Hi,
some times ago I solve this task. That's my solution in a system call
(whithout cdev).
Thanx in advance for founded mistakes and possible bugs (-:


#include <sys/param.h>
#include <sys/proc.h>
#include <sys/conf.h>
#include <sys/module.h>
#include <sys/sysent.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/sysproto.h>
#include <sys/resourcevar.h>

#include <vm/vm.h>
#include <vm/pmap.h>
#include <vm/vm_map.h>
#include <vm/vm_param.h>
#include <vm/vm_kern.h>
#include <vm/vm_object.h>


/* Arguments for syscall */
struct args {

        /* Pointer to allocated Buffer */
        unsigned int  *p;
};

/* String to be located in maped buffer */
const char *str = "BSD IS SEXY";

/* Syscall func */
static int
syscf(struct thread *td, void *sa)
{
        int error;
        struct args *uap;
        vm_offset_t addr;          /* Kernel space address */
        vm_offset_t user_addr;  /* User space address  */

        struct proc *procp = (struct proc *)td->td_proc;

        struct vmspace *vms = procp->p_vmspace;

        uap = (struct args *)sa;

        PROC_LOCK(procp);
        user_addr = round_page((vm_offset_t)vms->vm_daddr +
                        lim_max(procp, RLIMIT_DATA));
        PROC_UNLOCK(procp);

        MALLOC(addr, vm_offset_t, PAGE_SIZE, M_DEVBUF, M_WAITOK | M_ZERO);

        vm_map_entry_t  myentry;
        vm_object_t     myobject;
        vm_pindex_t     mypindex;
        vm_prot_t       myprot;
        boolean_t       mywired;
        vm_ooffset_t    objoffset;

        vm_map_lookup(&kmem_map, addr, VM_PROT_ALL,
                        &myentry, &myobject, &mypindex, &myprot, &mywired);
/* OUT */
        vm_map_lookup_done(kmem_map, myentry);

        printf("---> Syscall: hint for allocating space = 0x%X\n", addr);

        if (myobject == kmem_object){
                printf("---> Syscall: Yes, it is kmem_obj! \n");
        }

        /* Offset in vm_object */
        objoffset = addr - myentry->start + myentry->offset;

        printf("------> Syscall: Object offset = 0x%X \n", (unsigned
int)objoffset);

        /*
         * Try to map kernel buffer to user space
         */
        vm_object_reference(myobject); /* NEEDED Increment vm_obj references
*/
        error = vm_map_find(&vms->vm_map, myobject, objoffset, (vm_offset_t
*)&user_addr,
                        PAGE_SIZE, TRUE, VM_PROT_RW, VM_PROT_RW,
                        MAP_ENTRY_NOFAULT);

        if (error == KERN_SUCCESS) {
        /* copy string using kernel address */
                size_t len;
                copystr(str, (void *)addr, 12, &len);

                /*
                 * Tell to user process it's  user space address
                 */
                *uap->p = user_addr;

                /*
                 * Try to read the string using user space address
                 */
                printf("String: %s\n", (char *)*uap->p);

                printf("---> Syscall: user_addr for allocating space =
0x%X\n", user_addr);
        }

        return (0);
}

/* Sysent entity for syscall */
static struct sysent sc_sysent = {
        1,                                              /* Number of
arguments */
        syscf                                   /* Syscall function    */
};

/* Offset in sysent[] */
static int offset = NO_SYSCALL;

/* Loader */
static int
load (struct module *m, int cmd, void *something)
{
        int error = 0;
        switch(cmd){
                case MOD_LOAD:
                        printf("Module with sysc loaded. Offset = %d \n",
offset);
                        break;

                case MOD_UNLOAD:
                        printf("Module with sysc unloaded. Offset = %d \n",
offset);
                        break;

                default:
                        error = EOPNOTSUPP;
                        break;
        }
        return (error);
}

/* Syscall macro*/
SYSCALL_MODULE(fiveg_sysc, &offset, &sc_sysent, load, NULL);

If needed, I can post user space program.


More information about the freebsd-hackers mailing list