Index: qemu/exec.c =================================================================== --- qemu.orig/exec.c 2007-03-22 17:18:32.000000000 -0400 +++ qemu/exec.c 2007-03-22 17:42:30.000000000 -0400 @@ -1785,6 +1785,29 @@ spin_unlock(&tb_lock); } +int page_check_range(target_ulong start, target_ulong len, int flags) +{ + PageDesc *p; + target_ulong end; + target_ulong addr; + + end = TARGET_PAGE_ALIGN(start+len); /* must do before we loose bits in the next step */ + start = start & TARGET_PAGE_MASK; + + if( end < start ) return EFAULT; /* we've wrapped around */ + for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) { + p = page_find(addr >> TARGET_PAGE_BITS); + if( !p ) return EFAULT; + if( !(p->flags & PAGE_VALID) ) return EFAULT; + + if (!(p->flags & PAGE_READ) && + (flags & PAGE_READ) ) return EFAULT; + if (!(p->flags & PAGE_WRITE) && + (flags & PAGE_WRITE) ) return EFAULT; + } + return 0; +} + /* called from signal handler: invalidate the code and unprotect the page. Return TRUE if the fault was succesfully handled. */ int page_unprotect(target_ulong address, unsigned long pc, void *puc) Index: qemu/cpu-all.h =================================================================== --- qemu.orig/cpu-all.h 2007-03-22 17:18:32.000000000 -0400 +++ qemu/cpu-all.h 2007-03-22 17:19:10.000000000 -0400 @@ -689,6 +689,7 @@ int page_get_flags(target_ulong address); void page_set_flags(target_ulong start, target_ulong end, int flags); void page_unprotect_range(target_ulong data, target_ulong data_size); +int page_check_range(target_ulong start, target_ulong len, int flags); #define SINGLE_CPU_DEFINES #ifdef SINGLE_CPU_DEFINES Index: qemu/linux-user/syscall.c =================================================================== --- qemu.orig/linux-user/syscall.c 2007-03-22 17:19:00.000000000 -0400 +++ qemu/linux-user/syscall.c 2007-03-22 17:26:17.000000000 -0400 @@ -1287,12 +1287,15 @@ target_ulong __unused5; }; -static inline void target_to_host_msqid_ds(struct msqid_ds *host_md, - target_ulong target_addr) +/* static inline */ long target_to_host_msqid_ds(struct msqid_ds *host_md, + target_ulong target_addr, + int pg_access) { + long ret = 0; struct target_msqid_ds *target_md; lock_user_struct(target_md, target_addr, 1); + if( ret=page_check_range(target_md,sizeof(*target_md),pg_access) ) return -ret; target_to_host_ipc_perm(&(host_md->msg_perm),target_addr); host_md->msg_stime = tswapl(target_md->msg_stime); host_md->msg_rtime = tswapl(target_md->msg_rtime); @@ -1303,9 +1306,10 @@ host_md->msg_lspid = tswapl(target_md->msg_lspid); host_md->msg_lrpid = tswapl(target_md->msg_lrpid); unlock_user_struct(target_md, target_addr, 0); + return ret; } -static inline void host_to_target_msqid_ds(target_ulong target_addr, +/* static inline */ void host_to_target_msqid_ds(target_ulong target_addr, struct msqid_ds *host_md) { struct target_msqid_ds *target_md; @@ -1323,17 +1327,22 @@ unlock_user_struct(target_md, target_addr, 1); } -static inline long do_msgctl(long first, long second, long ptr) +/* static inline */ long do_msgctl(long first, long second, long ptr) { struct msqid_ds dsarg; int cmd = second&0xff; long ret = 0; switch( cmd ) { case IPC_STAT: + if( ret=target_to_host_msqid_ds(&dsarg,ptr,PAGE_WRITE) ) return -ret; + ret = get_errno(msgctl(first, cmd, &dsarg)); + host_to_target_msqid_ds(ptr,&dsarg); + break; case IPC_SET: - target_to_host_msqid_ds(&dsarg,ptr); + if( ret=target_to_host_msqid_ds(&dsarg,ptr,PAGE_READ) ) return -ret; ret = get_errno(msgctl(first, cmd, &dsarg)); host_to_target_msqid_ds(ptr,&dsarg); + break; default: ret = get_errno(msgctl(first, cmd, &dsarg)); } @@ -1345,13 +1354,14 @@ char mtext[1]; }; -static inline long do_msgsnd(long msqid, long msgp, long msgsz, long msgflg) +/* static inline */ long do_msgsnd(long msqid, long msgp, long msgsz, long msgflg) { struct target_msgbuf *target_mb; struct msgbuf *host_mb; long ret = 0; lock_user_struct(target_mb,msgp,0); + if( ret=page_check_range(target_mb,sizeof(long)+msgsz,PAGE_READ) ) return -ret; host_mb = malloc(msgsz+sizeof(long)); host_mb->mtype = tswapl(target_mb->mtype); memcpy(host_mb->mtext,target_mb->mtext,msgsz); @@ -1362,13 +1372,14 @@ return ret; } -static inline long do_msgrcv(long msqid, long msgp, long msgsz, long msgtype, long msgflg) +/* static inline */ long do_msgrcv(long msqid, long msgp, long msgsz, long msgtype, long msgflg) { struct target_msgbuf *target_mb; struct msgbuf *host_mb; long ret = 0; lock_user_struct(target_mb,msgp,0); + if( ret=page_check_range(target_mb,sizeof(long)+msgsz,PAGE_WRITE) ) return -ret; host_mb = malloc(msgsz+sizeof(long)); ret = get_errno(msgrcv(msqid, host_mb, msgsz, 1, msgflg)); if( ret > 0 ) @@ -1381,7 +1392,7 @@ } /* ??? This only works with linear mappings. */ -static long do_ipc(long call, long first, long second, long third, +/* static */ long do_ipc(long call, long first, long second, long third, long ptr, long fifth) { int version;