Lines 137-142
SYSCTL_INT(_kern_elf32, OID_AUTO, read_exec, CTLFLAG_RW, &i386_read_exec, 0,
Link Here
|
137 |
#endif |
137 |
#endif |
138 |
#endif |
138 |
#endif |
139 |
|
139 |
|
|
|
140 |
static int __elfN(aslr_enabled) = 1; |
141 |
SYSCTL_INT(__CONCAT(_kern_elf, __ELF_WORD_SIZE), OID_AUTO, |
142 |
aslr_enabled, CTLFLAG_RWTUN, &__elfN(aslr_enabled), 0, |
143 |
__XSTRING(__CONCAT(ELF, __ELF_WORD_SIZE)) ": enable aslr"); |
144 |
|
145 |
static int __elfN(pie_aslr_enabled) = 1; |
146 |
SYSCTL_INT(__CONCAT(_kern_elf, __ELF_WORD_SIZE), OID_AUTO, |
147 |
pie_aslr_enabled, CTLFLAG_RWTUN, &__elfN(pie_aslr_enabled), 0, |
148 |
__XSTRING(__CONCAT(ELF, __ELF_WORD_SIZE)) ": enable aslr for PIE binaries"); |
149 |
|
150 |
static int __elfN(aslr_care_sbrk) = 0; |
151 |
SYSCTL_INT(__CONCAT(_kern_elf, __ELF_WORD_SIZE), OID_AUTO, |
152 |
aslr_care_sbrk, CTLFLAG_RW, &__elfN(aslr_care_sbrk), 0, |
153 |
__XSTRING(__CONCAT(ELF, __ELF_WORD_SIZE)) ": assume sbrk is used"); |
154 |
|
140 |
static Elf_Brandinfo *elf_brand_list[MAX_BRANDS]; |
155 |
static Elf_Brandinfo *elf_brand_list[MAX_BRANDS]; |
141 |
|
156 |
|
142 |
#define trunc_page_ps(va, ps) ((va) & ~(ps - 1)) |
157 |
#define trunc_page_ps(va, ps) ((va) & ~(ps - 1)) |
Lines 424-436
__elfN(map_partial)(vm_map_t map, vm_object_t object, vm_ooffset_t offset,
Link Here
|
424 |
} |
439 |
} |
425 |
|
440 |
|
426 |
static int |
441 |
static int |
427 |
__elfN(map_insert)(vm_map_t map, vm_object_t object, vm_ooffset_t offset, |
442 |
__elfN(map_insert)(struct image_params *imgp, vm_map_t map, vm_object_t object, |
428 |
vm_offset_t start, vm_offset_t end, vm_prot_t prot, int cow) |
443 |
vm_ooffset_t offset, vm_offset_t start, vm_offset_t end, vm_prot_t prot, |
|
|
444 |
int cow) |
429 |
{ |
445 |
{ |
430 |
struct sf_buf *sf; |
446 |
struct sf_buf *sf; |
431 |
vm_offset_t off; |
447 |
vm_offset_t off; |
432 |
vm_size_t sz; |
448 |
vm_size_t sz; |
433 |
int error, rv; |
449 |
int error, locked, rv; |
434 |
|
450 |
|
435 |
if (start != trunc_page(start)) { |
451 |
if (start != trunc_page(start)) { |
436 |
rv = __elfN(map_partial)(map, object, offset, start, |
452 |
rv = __elfN(map_partial)(map, object, offset, start, |
Lines 453-462
__elfN(map_insert)(vm_map_t map, vm_object_t object, vm_ooffset_t offset,
Link Here
|
453 |
* The mapping is not page aligned. This means we have |
469 |
* The mapping is not page aligned. This means we have |
454 |
* to copy the data. Sigh. |
470 |
* to copy the data. Sigh. |
455 |
*/ |
471 |
*/ |
456 |
rv = vm_map_find(map, NULL, 0, &start, end - start, 0, |
472 |
vm_map_lock(map); |
457 |
VMFS_NO_SPACE, prot | VM_PROT_WRITE, VM_PROT_ALL, |
473 |
rv = vm_map_insert(map, NULL, 0, start, end, |
458 |
0); |
474 |
prot | VM_PROT_WRITE, VM_PROT_ALL, 0); |
459 |
if (rv) |
475 |
vm_map_unlock(map); |
|
|
476 |
if (rv != KERN_SUCCESS) |
460 |
return (rv); |
477 |
return (rv); |
461 |
if (object == NULL) |
478 |
if (object == NULL) |
462 |
return (KERN_SUCCESS); |
479 |
return (KERN_SUCCESS); |
Lines 471-479
__elfN(map_insert)(vm_map_t map, vm_object_t object, vm_ooffset_t offset,
Link Here
|
471 |
error = copyout((caddr_t)sf_buf_kva(sf) + off, |
488 |
error = copyout((caddr_t)sf_buf_kva(sf) + off, |
472 |
(caddr_t)start, sz); |
489 |
(caddr_t)start, sz); |
473 |
vm_imgact_unmap_page(sf); |
490 |
vm_imgact_unmap_page(sf); |
474 |
if (error) { |
491 |
if (error != 0) |
475 |
return (KERN_FAILURE); |
492 |
return (KERN_FAILURE); |
476 |
} |
|
|
477 |
offset += sz; |
493 |
offset += sz; |
478 |
} |
494 |
} |
479 |
rv = KERN_SUCCESS; |
495 |
rv = KERN_SUCCESS; |
Lines 483-490
__elfN(map_insert)(vm_map_t map, vm_object_t object, vm_ooffset_t offset,
Link Here
|
483 |
rv = vm_map_insert(map, object, offset, start, end, |
499 |
rv = vm_map_insert(map, object, offset, start, end, |
484 |
prot, VM_PROT_ALL, cow); |
500 |
prot, VM_PROT_ALL, cow); |
485 |
vm_map_unlock(map); |
501 |
vm_map_unlock(map); |
486 |
if (rv != KERN_SUCCESS) |
502 |
if (rv != KERN_SUCCESS) { |
|
|
503 |
locked = VOP_ISLOCKED(imgp->vp); |
504 |
VOP_UNLOCK(imgp->vp, 0); |
487 |
vm_object_deallocate(object); |
505 |
vm_object_deallocate(object); |
|
|
506 |
vn_lock(imgp->vp, locked | LK_RETRY); |
507 |
} |
488 |
} |
508 |
} |
489 |
return (rv); |
509 |
return (rv); |
490 |
} else { |
510 |
} else { |
Lines 541-547
__elfN(load_section)(struct image_params *imgp, vm_offset_t offset,
Link Here
|
541 |
cow = MAP_COPY_ON_WRITE | MAP_PREFAULT | |
561 |
cow = MAP_COPY_ON_WRITE | MAP_PREFAULT | |
542 |
(prot & VM_PROT_WRITE ? 0 : MAP_DISABLE_COREDUMP); |
562 |
(prot & VM_PROT_WRITE ? 0 : MAP_DISABLE_COREDUMP); |
543 |
|
563 |
|
544 |
rv = __elfN(map_insert)(map, |
564 |
rv = __elfN(map_insert)(imgp, map, |
545 |
object, |
565 |
object, |
546 |
file_addr, /* file offset */ |
566 |
file_addr, /* file offset */ |
547 |
map_addr, /* virtual start */ |
567 |
map_addr, /* virtual start */ |
Lines 571-578
__elfN(load_section)(struct image_params *imgp, vm_offset_t offset,
Link Here
|
571 |
|
591 |
|
572 |
/* This had damn well better be true! */ |
592 |
/* This had damn well better be true! */ |
573 |
if (map_len != 0) { |
593 |
if (map_len != 0) { |
574 |
rv = __elfN(map_insert)(map, NULL, 0, map_addr, map_addr + |
594 |
rv = __elfN(map_insert)(imgp, map, NULL, 0, map_addr, |
575 |
map_len, VM_PROT_ALL, 0); |
595 |
map_addr + map_len, VM_PROT_ALL, 0); |
576 |
if (rv != KERN_SUCCESS) { |
596 |
if (rv != KERN_SUCCESS) { |
577 |
return (EINVAL); |
597 |
return (EINVAL); |
578 |
} |
598 |
} |
Lines 747-752
fail:
Link Here
|
747 |
return (error); |
767 |
return (error); |
748 |
} |
768 |
} |
749 |
|
769 |
|
|
|
770 |
static u_long |
771 |
__CONCAT(rnd_, __elfN(base))(u_long base, u_long minv, u_long maxv, |
772 |
u_int align) |
773 |
{ |
774 |
u_long rbase, res; |
775 |
|
776 |
arc4rand(&rbase, sizeof(rbase), 0); |
777 |
res = base + rbase % (maxv - minv); |
778 |
res &= ~((u_long)align - 1); |
779 |
KASSERT(res >= base, |
780 |
("res %#lx < base %#lx, minv %#lx maxv %#lx rbase %#lx", |
781 |
res, base, minv, maxv, rbase)); |
782 |
KASSERT(res < maxv, |
783 |
("res %#lx > maxv %#lx, minv %#lx base %#lx rbase %#lx", |
784 |
res, maxv, minv, base, rbase)); |
785 |
return (res); |
786 |
} |
787 |
|
750 |
static int |
788 |
static int |
751 |
__CONCAT(exec_, __elfN(imgact))(struct image_params *imgp) |
789 |
__CONCAT(exec_, __elfN(imgact))(struct image_params *imgp) |
752 |
{ |
790 |
{ |
Lines 755-760
__CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
Link Here
|
755 |
const Elf_Phdr *phdr; |
793 |
const Elf_Phdr *phdr; |
756 |
Elf_Auxargs *elf_auxargs; |
794 |
Elf_Auxargs *elf_auxargs; |
757 |
struct vmspace *vmspace; |
795 |
struct vmspace *vmspace; |
|
|
796 |
vm_map_t map; |
758 |
const char *err_str, *newinterp; |
797 |
const char *err_str, *newinterp; |
759 |
char *interp, *interp_buf, *path; |
798 |
char *interp, *interp_buf, *path; |
760 |
Elf_Brandinfo *brand_info; |
799 |
Elf_Brandinfo *brand_info; |
Lines 762-767
__CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
Link Here
|
762 |
vm_prot_t prot; |
801 |
vm_prot_t prot; |
763 |
u_long text_size, data_size, total_size, text_addr, data_addr; |
802 |
u_long text_size, data_size, total_size, text_addr, data_addr; |
764 |
u_long seg_size, seg_addr, addr, baddr, et_dyn_addr, entry, proghdr; |
803 |
u_long seg_size, seg_addr, addr, baddr, et_dyn_addr, entry, proghdr; |
|
|
804 |
u_long maxalign, mapsz, maxv; |
765 |
int32_t osrel; |
805 |
int32_t osrel; |
766 |
int error, i, n, interp_name_len, have_interp; |
806 |
int error, i, n, interp_name_len, have_interp; |
767 |
|
807 |
|
Lines 803-814
__CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
Link Here
|
803 |
err_str = newinterp = NULL; |
843 |
err_str = newinterp = NULL; |
804 |
interp = interp_buf = NULL; |
844 |
interp = interp_buf = NULL; |
805 |
td = curthread; |
845 |
td = curthread; |
|
|
846 |
maxalign = PAGE_SIZE; |
847 |
mapsz = 0; |
806 |
|
848 |
|
807 |
for (i = 0; i < hdr->e_phnum; i++) { |
849 |
for (i = 0; i < hdr->e_phnum; i++) { |
808 |
switch (phdr[i].p_type) { |
850 |
switch (phdr[i].p_type) { |
809 |
case PT_LOAD: |
851 |
case PT_LOAD: |
810 |
if (n == 0) |
852 |
if (n == 0) |
811 |
baddr = phdr[i].p_vaddr; |
853 |
baddr = phdr[i].p_vaddr; |
|
|
854 |
if (phdr[i].p_align > maxalign) |
855 |
maxalign = phdr[i].p_align; |
856 |
mapsz += phdr[i].p_memsz; |
812 |
n++; |
857 |
n++; |
813 |
break; |
858 |
break; |
814 |
case PT_INTERP: |
859 |
case PT_INTERP: |
Lines 862-867
__CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
Link Here
|
862 |
error = ENOEXEC; |
907 |
error = ENOEXEC; |
863 |
goto ret; |
908 |
goto ret; |
864 |
} |
909 |
} |
|
|
910 |
sv = brand_info->sysvec; |
911 |
et_dyn_addr = 0; |
865 |
if (hdr->e_type == ET_DYN) { |
912 |
if (hdr->e_type == ET_DYN) { |
866 |
if ((brand_info->flags & BI_CAN_EXEC_DYN) == 0) { |
913 |
if ((brand_info->flags & BI_CAN_EXEC_DYN) == 0) { |
867 |
uprintf("Cannot execute shared object\n"); |
914 |
uprintf("Cannot execute shared object\n"); |
Lines 872-884
__CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
Link Here
|
872 |
* Honour the base load address from the dso if it is |
919 |
* Honour the base load address from the dso if it is |
873 |
* non-zero for some reason. |
920 |
* non-zero for some reason. |
874 |
*/ |
921 |
*/ |
875 |
if (baddr == 0) |
922 |
if (baddr == 0) { |
876 |
et_dyn_addr = ET_DYN_LOAD_ADDR; |
923 |
if ((sv->sv_flags & SV_ASLR) == 0) |
877 |
else |
924 |
et_dyn_addr = ET_DYN_LOAD_ADDR; |
878 |
et_dyn_addr = 0; |
925 |
else if ((__elfN(pie_aslr_enabled) && |
879 |
} else |
926 |
(imgp->proc->p_flag2 & P2_ASLR_DISABLE) == 0) || |
880 |
et_dyn_addr = 0; |
927 |
(imgp->proc->p_flag2 & P2_ASLR_ENABLE) != 0) |
881 |
sv = brand_info->sysvec; |
928 |
et_dyn_addr = 1; |
|
|
929 |
else |
930 |
et_dyn_addr = ET_DYN_LOAD_ADDR; |
931 |
} |
932 |
} |
882 |
if (interp != NULL && brand_info->interp_newpath != NULL) |
933 |
if (interp != NULL && brand_info->interp_newpath != NULL) |
883 |
newinterp = brand_info->interp_newpath; |
934 |
newinterp = brand_info->interp_newpath; |
884 |
|
935 |
|
Lines 897-902
__CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
Link Here
|
897 |
|
948 |
|
898 |
error = exec_new_vmspace(imgp, sv); |
949 |
error = exec_new_vmspace(imgp, sv); |
899 |
imgp->proc->p_sysent = sv; |
950 |
imgp->proc->p_sysent = sv; |
|
|
951 |
vmspace = imgp->proc->p_vmspace; |
952 |
map = &vmspace->vm_map; |
953 |
|
954 |
if ((sv->sv_flags & SV_ASLR) == 0 || |
955 |
(imgp->proc->p_flag2 & P2_ASLR_DISABLE) != 0) { |
956 |
KASSERT(et_dyn_addr != 1, ("et_dyn_addr == 1 and !ASLR")); |
957 |
} else if ((imgp->proc->p_flag2 & P2_ASLR_ENABLE) != 0 || |
958 |
(__elfN(aslr_enabled) && hdr->e_type != ET_DYN) || |
959 |
et_dyn_addr == 1) { |
960 |
vm_map_lock(map); |
961 |
map->flags |= MAP_ASLR; |
962 |
/* |
963 |
* If user does not care about sbrk, utilize the bss |
964 |
* grow region for mappings as well. We can select |
965 |
* the base for the image anywere and still not suffer |
966 |
* from the fragmentation. |
967 |
*/ |
968 |
if (!__elfN(aslr_care_sbrk) || |
969 |
(imgp->proc->p_flag2 & P2_ASLR_IGNSTART) != 0) |
970 |
map->flags |= MAP_ASLR_IGNSTART; |
971 |
vm_map_unlock(map); |
972 |
} |
973 |
maxv = vm_map_max(map) - lim_max(td, RLIMIT_STACK); |
974 |
if (et_dyn_addr == 1) { |
975 |
KASSERT((map->flags & MAP_ASLR) != 0, |
976 |
("et_dyn_addr but !MAP_ASLR")); |
977 |
et_dyn_addr = __CONCAT(rnd_, __elfN(base))(vm_map_min(map), |
978 |
vm_map_min(map) + mapsz + lim_max(td, RLIMIT_DATA), |
979 |
/* reserve half of the address space to interpreter */ |
980 |
maxv / 2, 1UL << flsl(maxalign)); |
981 |
} |
900 |
|
982 |
|
901 |
vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); |
983 |
vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); |
902 |
if (error != 0) |
984 |
if (error != 0) |
Lines 989-995
__CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
Link Here
|
989 |
goto ret; |
1071 |
goto ret; |
990 |
} |
1072 |
} |
991 |
|
1073 |
|
992 |
vmspace = imgp->proc->p_vmspace; |
|
|
993 |
vmspace->vm_tsize = text_size >> PAGE_SHIFT; |
1074 |
vmspace->vm_tsize = text_size >> PAGE_SHIFT; |
994 |
vmspace->vm_taddr = (caddr_t)(uintptr_t)text_addr; |
1075 |
vmspace->vm_taddr = (caddr_t)(uintptr_t)text_addr; |
995 |
vmspace->vm_dsize = data_size >> PAGE_SHIFT; |
1076 |
vmspace->vm_dsize = data_size >> PAGE_SHIFT; |
Lines 1010-1015
__CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
Link Here
|
1010 |
if (interp != NULL) { |
1091 |
if (interp != NULL) { |
1011 |
have_interp = FALSE; |
1092 |
have_interp = FALSE; |
1012 |
VOP_UNLOCK(imgp->vp, 0); |
1093 |
VOP_UNLOCK(imgp->vp, 0); |
|
|
1094 |
if ((map->flags & MAP_ASLR) != 0) { |
1095 |
addr = __CONCAT(rnd_, __elfN(base))(addr, addr, |
1096 |
/* Assume that interpeter fits into 1/4 of AS */ |
1097 |
(maxv + addr) / 2, PAGE_SIZE); |
1098 |
} |
1013 |
if (brand_info->emul_path != NULL && |
1099 |
if (brand_info->emul_path != NULL && |
1014 |
brand_info->emul_path[0] != '\0') { |
1100 |
brand_info->emul_path[0] != '\0') { |
1015 |
path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); |
1101 |
path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); |