Line 113... |
Line 113... |
p=putstring(p, array[--count]);
|
p=putstring(p, array[--count]);
|
}
|
}
|
return p;
|
return p;
|
}
|
}
|
|
|
|
static unsigned long stringarraylen(int count, char ** array)
|
|
{
|
|
int l = 4;
|
|
while(count) {
|
|
l += strlen(array[--count]);
|
|
l++;
|
|
l+=4;
|
|
}
|
|
return l;
|
|
}
|
|
|
int do_relocate(int dst_indx,
|
int do_relocate(int dst_indx,
|
int rel_nb,
|
int rel_nb,
|
struct elf32_rel *rel_ptr,
|
struct elf32_rel *rel_ptr,
|
struct elf32_sym *sym_ptr,
|
struct elf32_sym *sym_ptr,
|
struct sec_add *sec)
|
struct sec_add *sec)
|
Line 210... |
Line 221... |
|
|
static inline int do_load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
|
static inline int do_load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
|
{
|
{
|
struct elfhdr elf_ex;
|
struct elfhdr elf_ex;
|
struct file *file;
|
struct file *file;
|
unsigned char ibcs2_interpreter;
|
|
int i,j;
|
int i,j;
|
int old_fs;
|
int old_fs;
|
struct elf32_shdr *elf_spnt, *elf_shdata;
|
struct elf32_shdr *elf_spnt, *elf_shdata;
|
int elf_exec_fileno;
|
int elf_exec_fileno;
|
unsigned long elf_entry = 0;
|
unsigned long elf_entry = 0;
|
int status;
|
unsigned long code_start, code_end, code_len = 0;
|
unsigned long start_code, end_code, start_data, end_data, start_brk, brk;
|
unsigned long data_start, data_end, data_len = 0;
|
unsigned long elf_stack;
|
unsigned long bss_start, bss_end, bss_len = 0;
|
|
unsigned long stack_len = 0;
|
int rel_indx, symtab_indx = 0, strtab_indx = 0;
|
int rel_indx, symtab_indx = 0, strtab_indx = 0;
|
struct elf32_rel *rel_ptr;
|
struct elf32_rel *rel_ptr;
|
struct elf32_sym *sym_ptr = (struct elf32_sym *)0;
|
struct elf32_sym *sym_ptr = (struct elf32_sym *)0;
|
char *str_ptr = (char *)0;
|
char *str_ptr = (char *)0;
|
int retval;
|
int retval;
|
|
|
or32_consth_add = 0;
|
or32_consth_add = 0;
|
or32_consth_rel = 0;
|
or32_consth_rel = 0;
|
ibcs2_interpreter = 0;
|
|
status = 0;
|
current->personality = PER_LINUX;
|
|
|
|
elf_exec_fileno = open_inode(bprm->inode, O_RDONLY);
|
|
|
|
if (elf_exec_fileno < 0)
|
|
return elf_exec_fileno;
|
|
|
|
file = current->files->fd[elf_exec_fileno];
|
|
|
|
|
elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
|
elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
|
|
|
if (elf_ex.e_ident[0] != 0x7f ||
|
/* First of all, some simple consistency checks */
|
|
if (elf_ex.e_type != ET_REL ||
|
|
0 /*!elf_check_arch(elf_ex.e_machine)*/ ||
|
|
!bprm->inode->i_op ||
|
|
!bprm->inode->i_op->default_file_ops ||
|
|
!bprm->inode->i_op->default_file_ops->mmap ||
|
|
elf_ex.e_ident[0] != 0x7f ||
|
strncmp(&elf_ex.e_ident[1], "ELF", 3) != 0) {
|
strncmp(&elf_ex.e_ident[1], "ELF", 3) != 0) {
|
return -ENOEXEC;
|
return -ENOEXEC;
|
}
|
}
|
|
|
/* First of all, some simple consistency checks */
|
if (flush_old_exec(bprm)) {
|
if (elf_ex.e_type != ET_REL ||
|
return -ENOMEM;
|
(!elf_check_arch(elf_ex.e_machine)) ||
|
|
(!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops ||
|
|
!bprm->inode->i_op->default_file_ops->mmap)) {
|
|
return -ENOEXEC;
|
|
}
|
}
|
|
|
if(elf_ex.e_shnum > ELF_SECTION_NB)
|
if(elf_ex.e_shnum > ELF_SECTION_NB)
|
return -ETOOMANYSECT;
|
return -ETOOMANYSECT;
|
|
|
for(i = 0; i < ELF_SECTION_NB; i++)
|
for(i = 0; i < ELF_SECTION_NB; i++)
|
sec[i].len = 0;
|
sec[i].len = 0;
|
|
|
/* Now read in all of the header information */
|
/* Now read in all of the header information */
|
|
|
elf_shdata = (struct elf32_shdr *) kmalloc(elf_ex.e_shnum *
|
elf_shdata = (struct elf32_shdr *) kmalloc(elf_ex.e_shnum *
|
elf_ex.e_shentsize, GFP_KERNEL);
|
elf_ex.e_shentsize, GFP_KERNEL);
|
if (elf_shdata == NULL) {
|
|
|
if (elf_shdata == NULL)
|
return -ENOMEM;
|
return -ENOMEM;
|
}
|
|
retval = read_exec(bprm->inode, elf_ex.e_shoff, (char *) elf_shdata,
|
retval = read_exec(bprm->inode, elf_ex.e_shoff, (char *) elf_shdata,
|
elf_ex.e_shentsize * elf_ex.e_shnum, 1);
|
elf_ex.e_shentsize * elf_ex.e_shnum, 1);
|
|
|
if (retval < 0) {
|
if (retval < 0) {
|
kfree(elf_shdata);
|
kfree(elf_shdata);
|
return retval;
|
return retval;
|
}
|
}
|
|
|
elf_exec_fileno = open_inode(bprm->inode, O_RDONLY);
|
|
|
|
if (elf_exec_fileno < 0) {
|
|
kfree(elf_shdata);
|
|
return elf_exec_fileno;
|
|
}
|
|
file = current->files->fd[elf_exec_fileno];
|
|
|
|
elf_stack = ~0UL;
|
|
start_code = ~0UL;
|
|
end_code = 0;
|
|
start_data = ~0UL;
|
|
end_data = 0;
|
|
start_brk = ~0UL;
|
|
brk = 0;
|
|
|
|
if (flush_old_exec(bprm)) {
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/* OK, This is the point of no return */
|
/* OK, This is the point of no return */
|
|
|
current->mm->end_data = 0;
|
current->mm->end_data = 0;
|
current->mm->end_code = 0;
|
current->mm->end_code = 0;
|
|
|
Line 296... |
Line 299... |
address. */
|
address. */
|
|
|
old_fs = get_fs();
|
old_fs = get_fs();
|
set_fs(get_ds());
|
set_fs(get_ds());
|
|
|
|
/* Calculate the total size of memory needed */
|
for(i = 0, elf_spnt = elf_shdata; i < elf_ex.e_shnum; i++, elf_spnt++) {
|
for(i = 0, elf_spnt = elf_shdata; i < elf_ex.e_shnum; i++, elf_spnt++) {
|
if((elf_spnt->sh_flags & SHF_ALLOC)) {
|
if(elf_spnt->sh_type == SHT_PROGBITS) {
|
int elf_prot = PROT_READ;
|
|
unsigned long retval;
|
|
if (elf_spnt->sh_flags & SHF_WRITE)
|
|
elf_prot |= PROT_WRITE;
|
|
if (elf_spnt->sh_flags & SHF_EXECINSTR)
|
if (elf_spnt->sh_flags & SHF_EXECINSTR)
|
elf_prot |= PROT_EXEC;
|
code_len += (elf_spnt->sh_size + 3) & ~(3);
|
|
else if(elf_spnt->sh_flags & SHF_ALLOC)
|
if(elf_spnt->sh_size == 0)
|
data_len += (elf_spnt->sh_size + 3) & ~(3);
|
continue;
|
}
|
|
else if(elf_spnt->sh_type == SHT_NOBITS) {
|
|
if(elf_spnt->sh_flags & SHF_ALLOC)
|
|
bss_len += (elf_spnt->sh_size + 3) & ~(3);
|
|
}
|
|
}
|
|
|
|
/* Allocate space */
|
retval = (unsigned long)do_mmap(NULL,
|
retval = (unsigned long)do_mmap(NULL,
|
0,
|
0,
|
elf_spnt->sh_size,
|
code_len + code_len + bss_len + stack_len,
|
elf_prot,
|
PROT_EXEC | PROT_WRITE | PROT_READ,
|
0,
|
0,
|
0);
|
0);
|
|
|
if(retval > (unsigned long)-4096) {
|
if(retval > (unsigned long)-4096) {
|
for(j = 0; j < elf_ex.e_shnum; j++)
|
|
if(sec[j].len)
|
|
do_munmap(sec[j].pm_add, sec[j].len);
|
|
kfree(elf_shdata);
|
kfree(elf_shdata);
|
return retval;
|
return retval;
|
}
|
}
|
|
|
sec[i].pm_add = retval;
|
code_start = retval;
|
sec[i].vm_add = elf_spnt->sh_addr;
|
code_end = code_start;
|
sec[i].len = elf_spnt->sh_size;
|
data_start = code_start + code_len;
|
|
data_end = data_start;
|
|
bss_start = data_start + data_len;
|
|
bss_end = bss_start;
|
|
stack_len = STACK_SIZE;
|
|
|
|
/* Make room on stack for arguments & environment */
|
|
stack_len += strlen(bprm->filename) + 1;
|
|
stack_len += stringarraylen(bprm->envc, bprm->envp);
|
|
stack_len += stringarraylen(bprm->argc, bprm->argv);
|
|
|
|
current->mm->executable = 0;
|
|
|
|
/* Now copy sections in memory */
|
|
|
|
for(i = 0, elf_spnt = elf_shdata; i < elf_ex.e_shnum; i++, elf_spnt++) {
|
|
|
|
if(elf_spnt->sh_type == SHT_PROGBITS && elf_spnt->sh_flags & SHF_EXECINSTR) {
|
|
|
if(elf_spnt->sh_type == SHT_PROGBITS) {
|
|
retval = read_exec(bprm->inode, elf_spnt->sh_offset,
|
retval = read_exec(bprm->inode, elf_spnt->sh_offset,
|
(char *)retval, elf_spnt->sh_size, 1);
|
(char *)code_end, elf_spnt->sh_size, 1);
|
|
|
if (retval < 0) {
|
if (retval < 0) {
|
for(j = 0; j < elf_ex.e_shnum; j++)
|
do_munmap(code_start, code_len + code_len + bss_len + stack_len);
|
if(sec[j].len)
|
|
do_munmap(sec[j].pm_add, sec[j].len);
|
|
kfree(elf_shdata);
|
kfree(elf_shdata);
|
return retval;
|
return retval;
|
}
|
}
|
}
|
|
|
|
if(elf_spnt->sh_type == SHT_PROGBITS) {
|
sec[i].pm_add = code_end;
|
if(elf_spnt->sh_flags & SHF_EXECINSTR) {
|
sec[i].vm_add = elf_spnt->sh_addr;
|
if(sec[i].pm_add < start_code)
|
|
start_code = sec[i].pm_add;
|
code_end = code_end + ((elf_spnt->sh_size + 3) & ~(3));
|
if((sec[i].pm_add + elf_spnt->sh_size) > end_code)
|
|
end_code = sec[i].pm_add + elf_spnt->sh_size;
|
|
}
|
|
else {
|
|
if(sec[i].pm_add < start_data)
|
|
start_data = sec[i].pm_add;
|
|
if((sec[i].pm_add + elf_spnt->sh_size) > end_data)
|
|
end_data = sec[i].pm_add + elf_spnt->sh_size;
|
|
}
|
}
|
|
else if (elf_spnt->sh_type == SHT_PROGBITS && elf_spnt->sh_flags & SHF_ALLOC) {
|
|
|
|
retval = read_exec(bprm->inode, elf_spnt->sh_offset,
|
|
(char *)data_end, elf_spnt->sh_size, 1);
|
|
|
|
if (retval < 0) {
|
|
do_munmap(code_start, code_len + code_len + bss_len + stack_len);
|
|
kfree(elf_shdata);
|
|
return retval;
|
}
|
}
|
else if(elf_spnt->sh_type == SHT_NOBITS) {
|
|
if(sec[i].pm_add < start_brk)
|
sec[i].pm_add = data_end;
|
start_brk = sec[i].pm_add;
|
sec[i].vm_add = elf_spnt->sh_addr;
|
if((sec[i].pm_add + elf_spnt->sh_size) > brk)
|
|
brk = sec[i].pm_add + elf_spnt->sh_size;
|
data_end = data_end + ((elf_spnt->sh_size + 3) & ~(3));
|
}
|
}
|
|
else if (elf_spnt->sh_type == SHT_NOBITS && elf_spnt->sh_flags & SHF_ALLOC) {
|
|
|
|
sec[i].pm_add = bss_end;
|
|
sec[i].vm_add = elf_spnt->sh_addr;
|
|
|
|
bss_end = bss_end + ((elf_spnt->sh_size + 3) & ~(3));
|
}
|
}
|
}
|
}
|
|
|
|
/* Set bss and stack to zero */
|
|
memset((void*)(bss_start), 0, bss_len + stack_len);
|
|
|
for(i = 0, elf_spnt = elf_shdata; i < elf_ex.e_shnum; elf_spnt++, i++) {
|
for(i = 0, elf_spnt = elf_shdata; i < elf_ex.e_shnum; elf_spnt++, i++) {
|
if(elf_spnt->sh_type == SHT_SYMTAB && (elf_spnt->sh_size != 0)) {
|
if(elf_spnt->sh_type == SHT_SYMTAB && (elf_spnt->sh_size != 0)) {
|
struct elf32_shdr *link_shdr;
|
struct elf32_shdr *link_shdr;
|
int sym_nb;
|
int sym_nb;
|
unsigned long retval;
|
unsigned long retval;
|
Line 379... |
Line 406... |
0);
|
0);
|
if(retval > (unsigned long)-4096) {
|
if(retval > (unsigned long)-4096) {
|
for(j = 0; j < elf_ex.e_shnum; j++)
|
for(j = 0; j < elf_ex.e_shnum; j++)
|
if(sec[j].len)
|
if(sec[j].len)
|
do_munmap(sec[j].pm_add, sec[j].len);
|
do_munmap(sec[j].pm_add, sec[j].len);
|
|
do_munmap(code_start, code_len + code_len + bss_len + stack_len);
|
kfree(elf_shdata);
|
kfree(elf_shdata);
|
return retval;
|
return retval;
|
}
|
}
|
|
|
symtab_indx = i;
|
symtab_indx = i;
|
Line 394... |
Line 422... |
(char *)retval, elf_spnt->sh_size, 1);
|
(char *)retval, elf_spnt->sh_size, 1);
|
if (retval < 0) {
|
if (retval < 0) {
|
for(j = 0; j < elf_ex.e_shnum; j++)
|
for(j = 0; j < elf_ex.e_shnum; j++)
|
if(sec[j].len)
|
if(sec[j].len)
|
do_munmap(sec[j].pm_add, sec[j].len);
|
do_munmap(sec[j].pm_add, sec[j].len);
|
|
do_munmap(code_start, code_len + code_len + bss_len + stack_len);
|
kfree(elf_shdata);
|
kfree(elf_shdata);
|
return retval;
|
return retval;
|
}
|
}
|
|
|
strtab_indx = elf_spnt->sh_link;
|
strtab_indx = elf_spnt->sh_link;
|
Line 412... |
Line 441... |
0);
|
0);
|
if(retval > (unsigned long)-4096) {
|
if(retval > (unsigned long)-4096) {
|
for(j = 0; j < elf_ex.e_shnum; j++)
|
for(j = 0; j < elf_ex.e_shnum; j++)
|
if(sec[j].len)
|
if(sec[j].len)
|
do_munmap(sec[j].pm_add, sec[j].len);
|
do_munmap(sec[j].pm_add, sec[j].len);
|
|
do_munmap(code_start, code_len + code_len + bss_len + stack_len);
|
kfree(elf_shdata);
|
kfree(elf_shdata);
|
return retval;
|
return retval;
|
}
|
}
|
|
|
sec[strtab_indx].pm_add = retval;
|
sec[strtab_indx].pm_add = retval;
|
Line 426... |
Line 456... |
(char *)retval, link_shdr->sh_size, 1);
|
(char *)retval, link_shdr->sh_size, 1);
|
if (retval < 0) {
|
if (retval < 0) {
|
for(j = 0; j < elf_ex.e_shnum; j++)
|
for(j = 0; j < elf_ex.e_shnum; j++)
|
if(sec[j].len)
|
if(sec[j].len)
|
do_munmap(sec[j].pm_add, sec[j].len);
|
do_munmap(sec[j].pm_add, sec[j].len);
|
|
do_munmap(code_start, code_len + code_len + bss_len + stack_len);
|
kfree(elf_shdata);
|
kfree(elf_shdata);
|
return retval;
|
return retval;
|
}
|
}
|
|
|
sym_nb = sec[symtab_indx].len / sizeof(struct elf32_sym);
|
sym_nb = sec[symtab_indx].len / sizeof(struct elf32_sym);
|
Line 454... |
Line 485... |
0);
|
0);
|
if(retval > (unsigned long)-4096) {
|
if(retval > (unsigned long)-4096) {
|
for(j = 0; j < elf_ex.e_shnum; j++)
|
for(j = 0; j < elf_ex.e_shnum; j++)
|
if(sec[j].len)
|
if(sec[j].len)
|
do_munmap(sec[j].pm_add, sec[j].len);
|
do_munmap(sec[j].pm_add, sec[j].len);
|
|
do_munmap(code_start, code_len + code_len + bss_len + stack_len);
|
kfree(elf_shdata);
|
kfree(elf_shdata);
|
return retval;
|
return retval;
|
}
|
}
|
|
|
sec[i].pm_add = retval;
|
sec[i].pm_add = retval;
|
Line 468... |
Line 500... |
(char *)retval, elf_spnt->sh_size, 1);
|
(char *)retval, elf_spnt->sh_size, 1);
|
if (retval < 0) {
|
if (retval < 0) {
|
for(j = 0; j < elf_ex.e_shnum; j++)
|
for(j = 0; j < elf_ex.e_shnum; j++)
|
if(sec[j].len)
|
if(sec[j].len)
|
do_munmap(sec[j].pm_add, sec[j].len);
|
do_munmap(sec[j].pm_add, sec[j].len);
|
|
do_munmap(code_start, code_len + code_len + bss_len + stack_len);
|
kfree(elf_shdata);
|
kfree(elf_shdata);
|
return retval;
|
return retval;
|
}
|
}
|
|
|
rel_indx = i;
|
rel_indx = i;
|
symtab_indx = elf_spnt->sh_link;
|
|
link_shdr = elf_shdata + symtab_indx;
|
link_shdr = elf_shdata + symtab_indx;
|
|
|
/* Now do relocations for the n-th section. n is read from
|
/* Now do relocations for the n-th section. n is read from
|
real setiona hader info field. */
|
real setiona hader info field. */
|
|
|
Line 486... |
Line 518... |
|
|
if (retval < 0) {
|
if (retval < 0) {
|
for(j = 0; j < elf_ex.e_shnum; j++)
|
for(j = 0; j < elf_ex.e_shnum; j++)
|
if(sec[j].len)
|
if(sec[j].len)
|
do_munmap(sec[j].pm_add, sec[j].len);
|
do_munmap(sec[j].pm_add, sec[j].len);
|
|
do_munmap(code_start, code_len + code_len + bss_len + stack_len);
|
kfree(elf_shdata);
|
kfree(elf_shdata);
|
return retval;
|
return retval;
|
}
|
}
|
|
|
/* Now unmap rel section */
|
/* Now unmap rel section */
|
Line 505... |
Line 538... |
sec[strtab_indx].len = 0;
|
sec[strtab_indx].len = 0;
|
|
|
set_fs(old_fs);
|
set_fs(old_fs);
|
kfree(elf_shdata);
|
kfree(elf_shdata);
|
|
|
sys_close(elf_exec_fileno);
|
|
|
|
current->personality = PER_LINUX;
|
|
|
|
if (current->exec_domain && current->exec_domain->use_count)
|
if (current->exec_domain && current->exec_domain->use_count)
|
(*current->exec_domain->use_count)--;
|
(*current->exec_domain->use_count)--;
|
if (current->binfmt && current->binfmt->use_count)
|
if (current->binfmt && current->binfmt->use_count)
|
(*current->binfmt->use_count)--;
|
(*current->binfmt->use_count)--;
|
current->exec_domain = lookup_exec_domain(current->personality);
|
current->exec_domain = lookup_exec_domain(current->personality);
|
Line 520... |
Line 549... |
if (current->exec_domain && current->exec_domain->use_count)
|
if (current->exec_domain && current->exec_domain->use_count)
|
(*current->exec_domain->use_count)++;
|
(*current->exec_domain->use_count)++;
|
if (current->binfmt && current->binfmt->use_count)
|
if (current->binfmt && current->binfmt->use_count)
|
(*current->binfmt->use_count)++;
|
(*current->binfmt->use_count)++;
|
|
|
bprm->p = do_mmap(0, 0, STACK_SIZE, PROT_READ|PROT_WRITE, 0, 0) + STACK_SIZE;
|
bprm->p = bss_end + stack_len - 4;
|
|
|
bprm->p = putstringarray(bprm->p, 1, &bprm->filename);
|
bprm->p = putstringarray(bprm->p, 1, &bprm->filename);
|
|
|
bprm->p = putstringarray(bprm->p, bprm->envc, bprm->envp);
|
bprm->p = putstringarray(bprm->p, bprm->envc, bprm->envp);
|
|
|
Line 533... |
Line 562... |
current->suid = current->euid = current->fsuid = bprm->e_uid;
|
current->suid = current->euid = current->fsuid = bprm->e_uid;
|
current->sgid = current->egid = current->fsgid = bprm->e_gid;
|
current->sgid = current->egid = current->fsgid = bprm->e_gid;
|
current->flags &= ~PF_FORKNOEXEC;
|
current->flags &= ~PF_FORKNOEXEC;
|
bprm->p = (unsigned long)create_elf_tables((char *) bprm->p, bprm->argc, bprm->envc, regs);
|
bprm->p = (unsigned long)create_elf_tables((char *) bprm->p, bprm->argc, bprm->envc, regs);
|
|
|
current->mm->start_brk = start_brk;
|
current->mm->brk = bss_end;
|
current->mm->brk = brk;
|
current->mm->start_code = code_start;
|
current->mm->start_code = start_code;
|
current->mm->end_code = code_end;
|
current->mm->end_code = end_code;
|
current->mm->start_data = data_start;
|
current->mm->start_data = start_data;
|
current->mm->end_data = data_end;
|
current->mm->end_data = end_data;
|
|
current->mm->start_stack = bprm->p;
|
current->mm->start_stack = bprm->p;
|
|
|
if(start_brk != ~0UL) {
|
_print("%s - %s:%d\n",__FILE__,__FUNCTION__,__LINE__);
|
int nbyte = brk - start_brk;
|
_print(" start_code = %x\n", current->mm->start_code);
|
char *fpnt = (char *)brk;
|
_print(" end_code = %x\n", current->mm->end_code);
|
|
_print(" start_data = %x\n", current->mm->start_data);
|
do {
|
_print(" end_data = %x\n", current->mm->end_data);
|
put_user(0, fpnt++);
|
_print(" start_brk = %x\n", current->mm->start_brk);
|
} while (--nbyte);
|
_print(" brk = %x\n", current->mm->brk);
|
}
|
_print(" start_stack = %x\n", current->mm->start_stack);
|
|
_print(" arg_start = %x\n", current->mm->arg_start);
|
|
_print(" env_start = %x\n", current->mm->env_start);
|
|
_print(" env_end = %x\n", current->mm->env_end);
|
|
_print(" elf_entry = %x\n", elf_entry);
|
|
|
start_thread(regs, elf_entry, bprm->p);
|
start_thread(regs, elf_entry, bprm->p);
|
|
|
if (current->flags & PF_PTRACED)
|
if (current->flags & PF_PTRACED)
|
send_sig(SIGTRAP, current, 0);
|
send_sig(SIGTRAP, current, 0);
|