don't let /dev/mem read beyond top of physical memory

This commit is contained in:
Ben Gras 2007-02-16 15:57:05 +00:00
parent 49d2195722
commit 654f6faf05

View file

@ -17,6 +17,7 @@
#include "../drivers.h" #include "../drivers.h"
#include "../libdriver/driver.h" #include "../libdriver/driver.h"
#include <sys/ioc_memory.h> #include <sys/ioc_memory.h>
#include <env.h>
#include <minix/ds.h> #include <minix/ds.h>
#include "../../kernel/const.h" #include "../../kernel/const.h"
#include "../../kernel/config.h" #include "../../kernel/config.h"
@ -140,6 +141,11 @@ int safe; /* safe copies */
static int n = 0; static int n = 0;
if(!safe) {
printf("m_transfer: unsafe?\n");
return EPERM;
}
if (ex64hi(pos64) != 0) if (ex64hi(pos64) != 0)
return OK; /* Beyond EOF */ return OK; /* Beyond EOF */
position= cv64ul(pos64); position= cv64ul(pos64);
@ -170,21 +176,11 @@ int safe; /* safe copies */
seg = m_seg[m_device]; seg = m_seg[m_device];
if (opcode == DEV_GATHER_S) { /* copy actual data */ if (opcode == DEV_GATHER_S) { /* copy actual data */
if(safe) {
r=sys_safecopyto(proc_nr, user_vir, vir_offset, r=sys_safecopyto(proc_nr, user_vir, vir_offset,
position, count, seg); position, count, seg);
} else {
r=sys_vircopy(SELF,seg,position,
proc_nr,D,user_vir+vir_offset, count);
}
} else { } else {
if(safe) {
r=sys_safecopyfrom(proc_nr, user_vir, vir_offset, r=sys_safecopyfrom(proc_nr, user_vir, vir_offset,
position, count, seg); position, count, seg);
} else {
r=sys_vircopy(proc_nr,D,user_vir+vir_offset,
SELF,seg,position, count);
}
} }
if(r != OK) { if(r != OK) {
panic("MEM","I/O copy failed",r); panic("MEM","I/O copy failed",r);
@ -193,10 +189,18 @@ int safe; /* safe copies */
/* Physical copying. Only used to access entire memory. */ /* Physical copying. Only used to access entire memory. */
case MEM_DEV: case MEM_DEV:
if (position >= dv_size) return(OK); /* check for EOF */ if (position >= dv_size) {
if (position + count > dv_size) count = dv_size - position; printf("memory: read 0x%lx beyond physical memory of 0x%lx\n",
position, dv_size);
return(OK); /* check for EOF */
}
if (position + count > dv_size) {
printf("memory: truncating count from %d to ", count);
count = dv_size - position;
printf("%d (size %d)\n", count, dv_size);
}
mem_phys = cv64ul(dv->dv_base) + position; mem_phys = cv64ul(dv->dv_base) + position;
if((r=sys_umap(proc_nr, safe ? GRANT_SEG : D, user_vir, if((r=sys_umap(proc_nr, GRANT_SEG, user_vir,
count + vir_offset, &user_phys)) != OK) { count + vir_offset, &user_phys)) != OK) {
panic("MEM","sys_umap failed in m_transfer",r); panic("MEM","sys_umap failed in m_transfer",r);
} }
@ -217,14 +221,8 @@ int safe; /* safe copies */
left = count; left = count;
while (left > 0) { while (left > 0) {
chunk = (left > ZERO_BUF_SIZE) ? ZERO_BUF_SIZE : left; chunk = (left > ZERO_BUF_SIZE) ? ZERO_BUF_SIZE : left;
if(safe) {
s=sys_safecopyto(proc_nr, user_vir, s=sys_safecopyto(proc_nr, user_vir,
vir_offset+suboffset, (vir_bytes) dev_zero, chunk, D); vir_offset+suboffset, (vir_bytes) dev_zero, chunk, D);
} else {
s=sys_vircopy(SELF, D, (vir_bytes) dev_zero,
proc_nr, D, user_vir + vir_offset+suboffset,
chunk);
}
if(s != OK) if(s != OK)
report("MEM","sys_vircopy failed", s); report("MEM","sys_vircopy failed", s);
left -= chunk; left -= chunk;
@ -238,21 +236,11 @@ int safe; /* safe copies */
if (position + count > dv_size) count = dv_size - position; if (position + count > dv_size) count = dv_size - position;
if (opcode == DEV_GATHER_S) { /* copy actual data */ if (opcode == DEV_GATHER_S) { /* copy actual data */
if(safe) {
s=sys_safecopyto(proc_nr, user_vir, vir_offset, s=sys_safecopyto(proc_nr, user_vir, vir_offset,
(vir_bytes)&imgrd[position], count, D); (vir_bytes)&imgrd[position], count, D);
} else {
s=sys_vircopy(SELF, D, (vir_bytes)&imgrd[position],
proc_nr, D, user_vir+vir_offset, count);
}
} else { } else {
if(safe) {
s=sys_safecopyfrom(proc_nr, user_vir, vir_offset, s=sys_safecopyfrom(proc_nr, user_vir, vir_offset,
(vir_bytes)&imgrd[position], count, D); (vir_bytes)&imgrd[position], count, D);
} else {
s=sys_vircopy(proc_nr, D, user_vir+vir_offset,
SELF, D, (vir_bytes)&imgrd[position], count);
}
} }
break; break;
@ -304,11 +292,28 @@ PRIVATE void m_init()
u32_t ramdev_base; u32_t ramdev_base;
message m; message m;
int i, s; int i, s;
phys_bytes mem_top = 0;
/* Physical memory, to check validity of /dev/mem access. */
#define MAX_MEM_RANGES 10
struct memory mem_chunks[MAX_MEM_RANGES];
if (OK != (s=sys_getkinfo(&kinfo))) { if (OK != (s=sys_getkinfo(&kinfo))) {
panic("MEM","Couldn't get kernel information.",s); panic("MEM","Couldn't get kernel information.",s);
} }
/* Obtain physical memory chunks for /dev/mem memory. */
if(env_memory_parse(mem_chunks, MAX_MEM_RANGES) != OK)
printf("memory driver: no memory layout, /dev/mem won't work\n");
else {
for(i = 0; i < MAX_MEM_RANGES; i++) {
phys_bytes top;
top = mem_chunks[i].base + mem_chunks[i].size;
if(top > mem_top)
mem_top = top;
}
}
/* Install remote segment for /dev/kmem memory. */ /* Install remote segment for /dev/kmem memory. */
m_geom[KMEM_DEV].dv_base = cvul64(kinfo.kmem_base); m_geom[KMEM_DEV].dv_base = cvul64(kinfo.kmem_base);
m_geom[KMEM_DEV].dv_size = cvul64(kinfo.kmem_size); m_geom[KMEM_DEV].dv_size = cvul64(kinfo.kmem_size);
@ -350,13 +355,8 @@ PRIVATE void m_init()
dev_zero[i] = '\0'; dev_zero[i] = '\0';
} }
/* Set up memory ranges for /dev/mem. */ /* Set up memory range for /dev/mem. */
#if (CHIP == INTEL) m_geom[MEM_DEV].dv_size = cvul64(mem_top);
if (OK != (s=sys_getmachine(&machine))) {
panic("MEM","Couldn't get machine information.",s);
}
m_geom[MEM_DEV].dv_size = cvul64(0xFFFFFFFF); /* 4G-1 for 386 systems */
#endif /* !(CHIP == INTEL) */
} }
/*===========================================================================* /*===========================================================================*
@ -372,6 +372,11 @@ int safe;
*/ */
struct device *dv; struct device *dv;
if(!safe) {
printf("m_transfer: unsafe?\n");
return EPERM;
}
switch (m_ptr->REQUEST) { switch (m_ptr->REQUEST) {
case MIOCRAMSIZE: { case MIOCRAMSIZE: {
/* Someone wants to create a new RAM disk with the given size. */ /* Someone wants to create a new RAM disk with the given size. */
@ -391,14 +396,8 @@ int safe;
ramdev_size= m_ptr->POSITION; ramdev_size= m_ptr->POSITION;
#else #else
/* Get request structure */ /* Get request structure */
if(safe) {
s= sys_safecopyfrom(m_ptr->IO_ENDPT, (vir_bytes)m_ptr->IO_GRANT, s= sys_safecopyfrom(m_ptr->IO_ENDPT, (vir_bytes)m_ptr->IO_GRANT,
0, (vir_bytes)&ramdev_size, sizeof(ramdev_size), D); 0, (vir_bytes)&ramdev_size, sizeof(ramdev_size), D);
} else {
s= sys_vircopy(m_ptr->IO_ENDPT, D, (vir_bytes)m_ptr->ADDRESS,
SELF, D, (vir_bytes)&ramdev_size, sizeof(ramdev_size));
}
if (s != OK) if (s != OK)
return s; return s;
#endif #endif
@ -448,13 +447,8 @@ int safe;
do_map= (m_ptr->REQUEST == MIOCMAP); /* else unmap */ do_map= (m_ptr->REQUEST == MIOCMAP); /* else unmap */
/* Get request structure */ /* Get request structure */
if(safe) {
r= sys_safecopyfrom(m_ptr->IO_ENDPT, (vir_bytes)m_ptr->IO_GRANT, r= sys_safecopyfrom(m_ptr->IO_ENDPT, (vir_bytes)m_ptr->IO_GRANT,
0, (vir_bytes)&mapreq, sizeof(mapreq), D); 0, (vir_bytes)&mapreq, sizeof(mapreq), D);
} else {
r= sys_vircopy(m_ptr->IO_ENDPT, D, (vir_bytes)m_ptr->ADDRESS,
SELF, D, (vir_bytes)&mapreq, sizeof(mapreq));
}
if (r != OK) if (r != OK)
return r; return r;
@ -480,4 +474,3 @@ struct partition *entry;
entry->heads = 64; entry->heads = 64;
entry->sectors = 32; entry->sectors = 32;
} }