malloc pages map to user space
Eric Saint-Etienne
eric.saintetienne at gmail.com
Thu Mar 22 20:11:10 UTC 2012
Here is some code which fails with malloc < 1 page
and sometimes succeeds with large mallocs (> 16 pages)
What's wrong?
#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>
// Copyright: skeleton took from an older post on the freebsd list
#include <vm/vm.h>
#include <vm/pmap.h>
#include <vm/vm_map.h>
#include <vm/vm_extern.h>
#include <vm/vm_param.h>
#include <vm/vm_kern.h>
#include <vm/vm_object.h>
#include <vm/vm_page.h>
MALLOC_DEFINE(M_FIVEG_SYSC, "fiveg_sysc", "fiveg_sysc test");
struct args {
unsigned char **p;
};
/* String to be located in maped buffer */
#define SIZE PAGE_SIZE // 1 page always fail
static void initialize_array(char *p) {
int i;
for (i = 0; i < 26; i++)
p[i] = i+'a';
p[26] = '!';
p[27] = '\0';
}
static vm_offset_t addr; // allocated/freed at module load/unload
/* Syscall func */
static int syscf(struct thread *td, void *sa) {
vm_offset_t user_addr; /* User space address */
struct args *uap = (struct args*) sa;
struct proc *procp = (struct proc *)td->td_proc;
struct vmspace *vms = procp->p_vmspace;
vm_map_t map;
int result;
vm_object_t object;
vm_ooffset_t objoffset;
vm_map_entry_t entry;
vm_pindex_t pindex;
vm_prot_t prot;
boolean_t wired;
map = kernel_map; // it always return data within kmeme anyway
uprintf("KERNEL string is '%s' (%p)\n", (char*) addr, (void*) addr);
result = vm_map_lookup(&map, addr, VM_PROT_ALL, &entry, &object,
&pindex, &prot, &wired);
if (result != KERN_SUCCESS) {
uprintf("KERNEL vm_map_lookup failed (%d)\n", result);
return ENOMEM;
}
vm_map_lookup_done(map, entry);
if (object == kernel_object) uprintf("object is kernel_object\n");
else if (object == kmem_object) uprintf("object is kmem_object\n");
else uprintf("object=%p (not kmem, not kernel)\n", object);
uprintf("entry=%p\n", entry);
/* Offset in vm_object */
objoffset = addr - entry->start + entry->offset;
user_addr = 0;
result = vm_map_find(&vms->vm_map, object, objoffset, (vm_offset_t
*) &user_addr, SIZE, VMFS_ANY_SPACE, VM_PROT_RW, VM_PROT_RW, 0);
if (result != KERN_SUCCESS)
uprintf("vm_map_find failed: %d\n", result);
else {
*uap->p = (char*) user_addr;
uprintf("KERNEL ---> Syscall: user_addr for allocating space =
0x%lx\n", user_addr);
}
return result;
}
/* Sysent entity for syscall */
static struct sysent sc_sysent = {
1, /* Number of arguments */
syscf /* Syscall function */
};
//static struct sysent *old_sysent;
/* 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:
//MALLOC(addr, vm_offset_t, SIZE, M_FIVEG_SYSC, M_WAITOK | M_ZERO);
addr = (vm_offset_t) malloc(SIZE, M_FIVEG_SYSC, M_WAITOK);
initialize_array((char*) addr);
uprintf("KERNEL Module with sysc loaded. Offset = %d \n", offset);
break;
case MOD_UNLOAD:
free((void*) addr, M_FIVEG_SYSC);
uprintf("KERNEL 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);
/* eof */
------------------------------------------------
-- USERLAND 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 char *some_var = NULL;
/* Pointer to pointer to remapped buffer */
unsigned char **p = &some_var;
/* Search module with system call */
mstat.version = sizeof(mstat);
if (!(modstat(modfind("sys/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);
if (error != 0) {
printf("USER: an error occured: %d\n", error);
return -1;
}
/* Read the string from remapped buffer */
printf("USER: p = %p\n", p);
printf("USER: *p = %p\n", *p);
printf("USER: String = %s\n", *p);
} else
printf("USER: Module seems to be not loaded! \n");
return 0;
}
/* eof */
More information about the freebsd-hackers
mailing list