Fix misuse of the kernel map in miscellaneous image activators.
Vnode-backed mappings cannot be put into the kernel map, since it is a system map. Use exec_map for transient mappings, and remove the mappings with kmem_free_wakeup() to notify the waiters on available map space. Do not map the whole executable into KVA at all to copy it out into usermode. Directly use vn_rdwr() for the case of not page aligned binary. There is one place left where the potentially unbounded amount of data is mapped into exec_map, namely, in the COFF image activator enumeration of the needed shared libraries. Reviewed by: alc MFC after: 2 weeks
This commit is contained in:
@@ -229,9 +229,9 @@ linux_uselib(struct thread *td, struct linux_uselib_args *args)
|
|||||||
struct vattr attr;
|
struct vattr attr;
|
||||||
vm_offset_t vmaddr;
|
vm_offset_t vmaddr;
|
||||||
unsigned long file_offset;
|
unsigned long file_offset;
|
||||||
vm_offset_t buffer;
|
|
||||||
unsigned long bss_size;
|
unsigned long bss_size;
|
||||||
char *library;
|
char *library;
|
||||||
|
ssize_t aresid;
|
||||||
int error;
|
int error;
|
||||||
int locked, vfslocked;
|
int locked, vfslocked;
|
||||||
|
|
||||||
@@ -308,8 +308,8 @@ linux_uselib(struct thread *td, struct linux_uselib_args *args)
|
|||||||
if (error)
|
if (error)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
/* Pull in executable header into kernel_map */
|
/* Pull in executable header into exec_map */
|
||||||
error = vm_mmap(kernel_map, (vm_offset_t *)&a_out, PAGE_SIZE,
|
error = vm_mmap(exec_map, (vm_offset_t *)&a_out, PAGE_SIZE,
|
||||||
VM_PROT_READ, VM_PROT_READ, 0, OBJT_VNODE, vp, 0);
|
VM_PROT_READ, VM_PROT_READ, 0, OBJT_VNODE, vp, 0);
|
||||||
if (error)
|
if (error)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@@ -402,24 +402,15 @@ linux_uselib(struct thread *td, struct linux_uselib_args *args)
|
|||||||
if (error)
|
if (error)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
/* map file into kernel_map */
|
error = vn_rdwr(UIO_READ, vp, (void *)vmaddr, file_offset,
|
||||||
error = vm_mmap(kernel_map, &buffer,
|
a_out->a_text + a_out->a_data, UIO_USERSPACE, 0,
|
||||||
round_page(a_out->a_text + a_out->a_data + file_offset),
|
td->td_ucred, NOCRED, &aresid, td);
|
||||||
VM_PROT_READ, VM_PROT_READ, 0, OBJT_VNODE, vp,
|
if (error != 0)
|
||||||
trunc_page(file_offset));
|
|
||||||
if (error)
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
if (aresid != 0) {
|
||||||
/* copy from kernel VM space to user space */
|
error = ENOEXEC;
|
||||||
error = copyout(PTRIN(buffer + file_offset),
|
|
||||||
(void *)vmaddr, a_out->a_text + a_out->a_data);
|
|
||||||
|
|
||||||
/* release temporary kernel space */
|
|
||||||
vm_map_remove(kernel_map, buffer, buffer +
|
|
||||||
round_page(a_out->a_text + a_out->a_data + file_offset));
|
|
||||||
|
|
||||||
if (error)
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
printf("uselib: Page aligned binary %lu\n", file_offset);
|
printf("uselib: Page aligned binary %lu\n", file_offset);
|
||||||
@@ -463,10 +454,9 @@ linux_uselib(struct thread *td, struct linux_uselib_args *args)
|
|||||||
VFS_UNLOCK_GIANT(vfslocked);
|
VFS_UNLOCK_GIANT(vfslocked);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Release the kernel mapping. */
|
/* Release the temporary mapping. */
|
||||||
if (a_out)
|
if (a_out)
|
||||||
vm_map_remove(kernel_map, (vm_offset_t)a_out,
|
kmem_free_wakeup(exec_map, (vm_offset_t)a_out, PAGE_SIZE);
|
||||||
(vm_offset_t)a_out + PAGE_SIZE);
|
|
||||||
|
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,8 +66,8 @@ exec_svr4_imgact(imgp)
|
|||||||
struct vmspace *vmspace;
|
struct vmspace *vmspace;
|
||||||
vm_offset_t vmaddr;
|
vm_offset_t vmaddr;
|
||||||
unsigned long virtual_offset, file_offset;
|
unsigned long virtual_offset, file_offset;
|
||||||
vm_offset_t buffer;
|
|
||||||
unsigned long bss_size;
|
unsigned long bss_size;
|
||||||
|
ssize_t aresid;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
if (((a_out->a_magic >> 16) & 0xff) != 0x64)
|
if (((a_out->a_magic >> 16) & 0xff) != 0x64)
|
||||||
@@ -145,21 +145,15 @@ exec_svr4_imgact(imgp)
|
|||||||
if (error)
|
if (error)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
error = vm_mmap(kernel_map, &buffer,
|
error = vn_rdwr(UIO_READ, imgp->vp, (void *)vmaddr, file_offset,
|
||||||
round_page(a_out->a_text + a_out->a_data + file_offset),
|
a_out->a_text + a_out->a_data, UIO_USERSPACE, 0,
|
||||||
VM_PROT_READ, VM_PROT_READ, 0,
|
curthread->td_ucred, NOCRED, &aresid, curthread);
|
||||||
OBJT_VNODE, imgp->vp, trunc_page(file_offset));
|
if (error != 0)
|
||||||
if (error)
|
goto fail;
|
||||||
goto fail;
|
if (aresid != 0) {
|
||||||
|
error = ENOEXEC;
|
||||||
error = copyout((caddr_t)(buffer + file_offset), (caddr_t)vmaddr,
|
goto fail;
|
||||||
a_out->a_text + a_out->a_data);
|
}
|
||||||
|
|
||||||
vm_map_remove(kernel_map, buffer,
|
|
||||||
buffer + round_page(a_out->a_text + a_out->a_data + file_offset));
|
|
||||||
|
|
||||||
if (error)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* remove write enable on the 'text' part
|
* remove write enable on the 'text' part
|
||||||
|
|||||||
@@ -146,10 +146,7 @@ load_coff_section(struct vmspace *vmspace, struct vnode *vp, vm_offset_t offset,
|
|||||||
|
|
||||||
error = copyout(data_buf, (caddr_t) map_addr, copy_len);
|
error = copyout(data_buf, (caddr_t) map_addr, copy_len);
|
||||||
|
|
||||||
if (vm_map_remove(exec_map,
|
kmem_free_wakeup(exec_map, (vm_offset_t)data_buf, PAGE_SIZE);
|
||||||
(vm_offset_t) data_buf,
|
|
||||||
(vm_offset_t) data_buf + PAGE_SIZE))
|
|
||||||
panic("load_coff_section vm_map_remove failed");
|
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
@@ -280,11 +277,7 @@ coff_load_file(struct thread *td, char *name)
|
|||||||
error = 0;
|
error = 0;
|
||||||
|
|
||||||
dealloc_and_fail:
|
dealloc_and_fail:
|
||||||
if (vm_map_remove(exec_map,
|
kmem_free_wakeup(exec_map, (vm_offset_t)ptr, PAGE_SIZE);
|
||||||
(vm_offset_t) ptr,
|
|
||||||
(vm_offset_t) ptr + PAGE_SIZE))
|
|
||||||
panic("%s vm_map_remove failed", __func__);
|
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
VOP_UNLOCK(vp, 0);
|
VOP_UNLOCK(vp, 0);
|
||||||
unlocked_fail:
|
unlocked_fail:
|
||||||
@@ -421,10 +414,7 @@ exec_coff_imgact(imgp)
|
|||||||
}
|
}
|
||||||
free(libbuf, M_TEMP);
|
free(libbuf, M_TEMP);
|
||||||
}
|
}
|
||||||
if (vm_map_remove(exec_map,
|
kmem_free_wakeup(exec_map, (vm_offset_t)buf, len);
|
||||||
(vm_offset_t) buf,
|
|
||||||
(vm_offset_t) buf + len))
|
|
||||||
panic("exec_coff_imgact vm_map_remove failed");
|
|
||||||
if (error)
|
if (error)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,8 +64,8 @@ exec_linux_imgact(struct image_params *imgp)
|
|||||||
struct vmspace *vmspace;
|
struct vmspace *vmspace;
|
||||||
vm_offset_t vmaddr;
|
vm_offset_t vmaddr;
|
||||||
unsigned long virtual_offset, file_offset;
|
unsigned long virtual_offset, file_offset;
|
||||||
vm_offset_t buffer;
|
|
||||||
unsigned long bss_size;
|
unsigned long bss_size;
|
||||||
|
ssize_t aresid;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
if (((a_out->a_magic >> 16) & 0xff) != 0x64)
|
if (((a_out->a_magic >> 16) & 0xff) != 0x64)
|
||||||
@@ -144,21 +144,15 @@ exec_linux_imgact(struct image_params *imgp)
|
|||||||
if (error)
|
if (error)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
error = vm_mmap(kernel_map, &buffer,
|
error = vn_rdwr(UIO_READ, imgp->vp, (void *)vmaddr, file_offset,
|
||||||
round_page(a_out->a_text + a_out->a_data + file_offset),
|
a_out->a_text + a_out->a_data, UIO_USERSPACE, 0,
|
||||||
VM_PROT_READ, VM_PROT_READ, 0, OBJT_VNODE,
|
curthread->td_ucred, NOCRED, &aresid, curthread);
|
||||||
imgp->vp, trunc_page(file_offset));
|
if (error != 0)
|
||||||
if (error)
|
goto fail;
|
||||||
goto fail;
|
if (aresid != 0) {
|
||||||
|
error = ENOEXEC;
|
||||||
error = copyout((void *)(uintptr_t)(buffer + file_offset),
|
goto fail;
|
||||||
(void *)vmaddr, a_out->a_text + a_out->a_data);
|
}
|
||||||
|
|
||||||
vm_map_remove(kernel_map, buffer,
|
|
||||||
buffer + round_page(a_out->a_text + a_out->a_data + file_offset));
|
|
||||||
|
|
||||||
if (error)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* remove write enable on the 'text' part
|
* remove write enable on the 'text' part
|
||||||
|
|||||||
+9
-21
@@ -70,7 +70,7 @@ static int
|
|||||||
exec_gzip_imgact(imgp)
|
exec_gzip_imgact(imgp)
|
||||||
struct image_params *imgp;
|
struct image_params *imgp;
|
||||||
{
|
{
|
||||||
int error, error2 = 0;
|
int error;
|
||||||
const u_char *p = (const u_char *) imgp->image_header;
|
const u_char *p = (const u_char *) imgp->image_header;
|
||||||
struct imgact_gzip igz;
|
struct imgact_gzip igz;
|
||||||
struct inflate infl;
|
struct inflate infl;
|
||||||
@@ -136,22 +136,17 @@ exec_gzip_imgact(imgp)
|
|||||||
VM_PROT_READ|VM_PROT_EXECUTE,0);
|
VM_PROT_READ|VM_PROT_EXECUTE,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (igz.inbuf) {
|
if (igz.inbuf)
|
||||||
error2 =
|
kmem_free_wakeup(exec_map, (vm_offset_t)igz.inbuf, PAGE_SIZE);
|
||||||
vm_map_remove(kernel_map, (vm_offset_t) igz.inbuf,
|
if (igz.error || error) {
|
||||||
(vm_offset_t) igz.inbuf + PAGE_SIZE);
|
|
||||||
}
|
|
||||||
if (igz.error || error || error2) {
|
|
||||||
printf("Output=%lu ", igz.output);
|
printf("Output=%lu ", igz.output);
|
||||||
printf("Inflate_error=%d igz.error=%d error2=%d where=%d\n",
|
printf("Inflate_error=%d igz.error=%d where=%d\n",
|
||||||
error, igz.error, error2, igz.where);
|
error, igz.error, igz.where);
|
||||||
}
|
}
|
||||||
if (igz.error)
|
if (igz.error)
|
||||||
return igz.error;
|
return igz.error;
|
||||||
if (error)
|
if (error)
|
||||||
return ENOEXEC;
|
return ENOEXEC;
|
||||||
if (error2)
|
|
||||||
return error2;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,18 +309,11 @@ NextByte(void *vp)
|
|||||||
if (igz->inbuf && igz->idx < (igz->offset + PAGE_SIZE)) {
|
if (igz->inbuf && igz->idx < (igz->offset + PAGE_SIZE)) {
|
||||||
return igz->inbuf[(igz->idx++) - igz->offset];
|
return igz->inbuf[(igz->idx++) - igz->offset];
|
||||||
}
|
}
|
||||||
if (igz->inbuf) {
|
if (igz->inbuf)
|
||||||
error = vm_map_remove(kernel_map, (vm_offset_t) igz->inbuf,
|
kmem_free_wakeup(exec_map, (vm_offset_t)igz->inbuf, PAGE_SIZE);
|
||||||
(vm_offset_t) igz->inbuf + PAGE_SIZE);
|
|
||||||
if (error) {
|
|
||||||
igz->where = __LINE__;
|
|
||||||
igz->error = error;
|
|
||||||
return GZ_EOF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
igz->offset = igz->idx & ~PAGE_MASK;
|
igz->offset = igz->idx & ~PAGE_MASK;
|
||||||
|
|
||||||
error = vm_mmap(kernel_map, /* map */
|
error = vm_mmap(exec_map, /* map */
|
||||||
(vm_offset_t *) & igz->inbuf, /* address */
|
(vm_offset_t *) & igz->inbuf, /* address */
|
||||||
PAGE_SIZE, /* size */
|
PAGE_SIZE, /* size */
|
||||||
VM_PROT_READ, /* protection */
|
VM_PROT_READ, /* protection */
|
||||||
|
|||||||
Reference in New Issue
Block a user