How to access kernel memory from user space

Alexej Sokolov bsd.quest at googlemail.com
Fri Jan 16 05:21:25 PST 2009


On Thu, Jan 15, 2009 at 01:22:18PM -0600, Gerry Weaver wrote:
> _____  
> 
> From: Alexej Sokolov [mailto:bsd.quest at googlemail.com]
> To: Gerry Weaver [mailto:gerryw at compvia.com]
> Cc: freebsd-hackers at freebsd.org
> Sent: Thu, 15 Jan 2009 12:31:00 -0600
> Subject: Re: How to access kernel memory from user space
> 
> 
> 
> 
> 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. 
> Hi,
> 
> This looks like a very nice solution. I would like to see the user space code very much.
> I really appreciate your help!
> 
> Thanks Again,
> Gerry
User space program: 

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/module.h>
 
int
main(int argc, char *argv[])
{
        int sysc_num, error; 
        struct module_stat mstat;
 
        /* This Variable will save the addres of remapped buffer */
        unsigned int  some_var;
 
        /* Pointer to pointer to remapped buffer */
        unsigned int  *p = &some_var;
 
        printf("USER: Pointer   = %p \n", p);
 
        /* Search module with system call */
        mstat.version = sizeof(mstat);
        if ( !(modstat(modfind("fiveg_sysc"), &mstat)) ){
                /* Our module */
                sysc_num = mstat.data.intval;
                printf("USER: Module found! Syscall number = %d \n",
sysc_num);
 
                /* make system call */
                error = syscall(sysc_num, p);
 
                /* Read the string from remapped buffer */
                printf("USER: String = %s\n", (char *)*p);
 
 
        } else {
                printf("USER: Module seems to be not loaded! \n");
        }
 
        return(0);
}

-- 
Alexej Sokolov <bsd.quest at googlemail.com>


More information about the freebsd-hackers mailing list