load_elf_binary阅读(1)
来源:互联网 发布:淘宝运营论坛 编辑:程序博客网 时间:2024/06/07 06:14
static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
{
struct file *interpreter = NULL; /* to shut gcc up */
unsigned long load_addr = 0, load_bias = 0;
int load_addr_set = 0;
char * elf_interpreter = NULL;
unsigned long error;
struct elf_phdr *elf_ppnt, *elf_phdata;
unsigned long elf_bss, elf_brk;
int retval, i;
unsigned int size;
unsigned long elf_entry;
unsigned long interp_load_addr = 0;
unsigned long start_code, end_code, start_data, end_data;
unsigned long reloc_func_desc = 0;
int executable_stack = EXSTACK_DEFAULT;
unsigned long def_flags = 0;
struct {
struct elfhdr elf_ex;
struct elfhdr interp_elf_ex;
} *loc;
定义了loc结构体,其中elfhdr就是 elf32_hdr
loc = kmalloc(sizeof(*loc), GFP_KERNEL);
if (!loc) {
retval = -ENOMEM; 错误代码:ENOMEM:核心内存不足
goto out_ret;
}
void *kmalloc(size_t size, int flags);
size要分配内存的大小. 以字节为单位.
flags要分配内存的类型。
kmalloc函数返回的是虚拟地址(线性地址). kmalloc特殊之处在于它分配的内存是物理上连续的
GFP_KERNEL是内核内存分配时最常用的,无内存可用时可引起休眠。
看上去就是给loc分配了一个虚拟地址
/* Get the exec-header */
loc->elf_ex = *((struct elfhdr *)bprm->buf);
retval = -ENOEXEC; 不是出错才赋值吗
/* First of all, some simple consistency checks */
if (memcmp(loc->elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
goto out;
if (loc->elf_ex.e_type != ET_EXEC && loc->elf_ex.e_type != ET_DYN)
goto out;
if (!elf_check_arch(&loc->elf_ex))
goto out;
if (!bprm->file->f_op||!bprm->file->f_op->mmap)
goto out;
e_type = ET_EXEC为2(可执行文件) = ET_DYN为3(动态链接库文件)
EF_CRIS_VARIANT_ANY_V0_V10为 0x00000000 判断3,2,1是否为0
EF_CRIS_VARIANT_COMMON_V10_V320x00000004 0100 判断2位是否为1,第3,1位是否为0
也就是第3位第1位是否为0
/* Now read in all of the header information */
if (loc->elf_ex.e_phentsize != sizeof(struct elf_phdr)) 确认e_phentsize 大小
goto out;
if (loc->elf_ex.e_phnum < 1 ||
loc->elf_ex.e_phnum > 65536U / sizeof(struct elf_phdr))
goto out;
size = loc->elf_ex.e_phnum * sizeof(struct elf_phdr);
retval = -ENOMEM;
elf_phdata = kmalloc(size, GFP_KERNEL); 又分配空间了,分配地址成功返回分配的地址值(虚拟地址?)
if (!elf_phdata)
goto out;
retval = kernel_read(bprm->file, loc->elf_ex.e_phoff,
(char *)elf_phdata, size);
if (retval != size) {
if (retval >= 0)
retval = -EIO;
goto out_free_ph;
}
为什么找不到kernel_read的资料。。。
这个struct elf_phdr和之前的elf32_hdr 不是同一个,差点弄错了,这样就可以理解了。
elf_bss = 0;
elf_brk = 0;
start_code = ~0UL;
end_code = 0;
start_data = 0;
end_data = 0;
变量的初始化 0UL是无符号长整型 0, ~ 表示按位取反,即:0xffff
原来这是一个0啊,我以为是O
for (i = 0; i < loc->elf_ex.e_phnum; i++) { 按程序个数一个一个找吗
if (elf_ppnt->p_type == PT_INTERP) { 之前elf_ppnt = elf_phdata; -->elf_phdata=kmalloc(size, GFP_KERNEL); 这个elf_ppnt就是另一份映射吧
/* This is the program interpreter used for
* shared libraries - for now assume that this
* is an a.out format binary
*/PT_INTERP是3,于是判断是否为动态链接库
retval = -ENOEXEC;
if (elf_ppnt->p_filesz > PATH_MAX ||
elf_ppnt->p_filesz < 2) PATH_MAX 4096
goto out_free_ph;
retval = -ENOMEM;
elf_interpreter = kmalloc(elf_ppnt->p_filesz,
GFP_KERNEL); 之前elf_phdata = kmalloc(size, GFP_KERNEL); 这里分配内存大小应该也一样吧
if (!elf_interpreter)
goto out_free_ph;
retval = kernel_read(bprm->file, elf_ppnt->p_offset,
elf_interpreter,
elf_ppnt->p_filesz); 这里又在读取了,比较一下之前的①都是bprm->file,②elf_ppnt->p_offset和loc->elf_ex.e_phoff
elf_ppnt= elf_phdata;elf_phdata又是loc->elf_ex分配的这两个也是一样的吧?③elf_interpreter存放地址④elf_ppnt->p_filesz和size也一样吧。
if (retval != elf_ppnt->p_filesz) { 大小不对就错了
if (retval >= 0)
retval = -EIO;
goto out_free_interp;
}
/* make sure path is NULL terminated */
retval = -ENOEXEC;
if (elf_interpreter[elf_ppnt->p_filesz - 1] != '\0') 防止指针泄露?
goto out_free_interp;
interpreter = open_exec(elf_interpreter);
retval = PTR_ERR(interpreter);
if (IS_ERR(interpreter))
goto out_free_interp;
又来了open_exec
* If the binary is not readable then enforce
* mm->dumpable = 0 regardless of the interpreter's
* permissions.
*/
if (file_permission(interpreter, MAY_READ) < 0)
bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP;
retval = kernel_read(interpreter, 0, bprm->buf,
BINPRM_BUF_SIZE);
if (retval != BINPRM_BUF_SIZE) {
if (retval >= 0)
retval = -EIO;
goto out_free_dentry;
}
file_permission -->inode_permission(file->f_path.dentry->d_inode, mask);
通过kernel_read()读入其开头128个字节,这就是映像的头部。
/* Get the exec headers */
loc->interp_elf_ex = *((struct elfhdr *)bprm->buf);
break;
}
elf_ppnt++;
}
又获取了头部,这么翻来覆去的搞,指是把东西读出来么,循环到这里结束了。
读出来判断是否有动态链接库?
elf_ppnt = elf_phdata; 为什么又赋一遍,上面的循环elf_ppnt已经到底了,又让它回来了
for (i = 0; i < loc->elf_ex.e_phnum; i++, elf_ppnt++)
if (elf_ppnt->p_type == PT_GNU_STACK) {
if (elf_ppnt->p_flags & PF_X)
executable_stack = EXSTACK_ENABLE_X;
else
executable_stack = EXSTACK_DISABLE_X;
break;
}
上面这个这个真心看不懂
/* Some simple consistency checks for the interpreter */
if (elf_interpreter) {
retval = -ELIBBAD;
/* Not an ELF interpreter */
if (memcmp(loc->interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
goto out_free_dentry;
/* Verify the interpreter has a valid arch */
if (!elf_check_arch(&loc->interp_elf_ex))
goto out_free_dentry;
}
又检查是否是可执行文件,elf_interpreter怎么是动态链接器呢
/* Flush all traces of the currently running executable */
retval = flush_old_exec(bprm);
if (retval)
goto out_free_dentry;
flush_old_exec()把当前进程用户空间的页面都释放了
/* OK, This is the point of no return */
current->flags &= ~PF_FORKNOEXEC;
current->mm->def_flags = def_flags;
没办法看懂
/* Do this immediately, since STACK_TOP as used in setup_arg_pages
may depend on the personality. */
SET_PERSONALITY(loc->elf_ex); 设置进程的个性标志
if (elf_read_implies_exec(loc->elf_ex, executable_stack))
current->personality |= READ_IMPLIES_EXEC;
if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
current->flags |= PF_RANDOMIZE;
setup_new_exec(bprm);
/* Do this so that we can load the interpreter, if need be. We will
change some of these later */
current->mm->free_area_cache = current->mm->mmap_base;
current->mm->cached_hole_size = 0;
retval = setup_arg_pages(bprm, randomize_stack_top(STACK_TOP),
executable_stack);
if (retval < 0) {
send_sig(SIGKILL, current, 0); 发送终止信号
goto out_free_dentry;
}
current->mm->start_stack = bprm->p; 设置堆栈的起始地址
/* Now we do a little grungy work by mmapping the ELF image into
the correct location in memory. */
for(i = 0, elf_ppnt = elf_phdata;
i < loc->elf_ex.e_phnum; i++, elf_ppnt++) {
int elf_prot = 0, elf_flags;
unsigned long k, vaddr;
if (elf_ppnt->p_type != PT_LOAD) 判断是否是可装入段
continue;
if (unlikely (elf_brk > elf_bss)) { 判断初始化是否正确
unsigned long nbyte;
/* There was a PT_LOAD segment with p_memsz > p_filesz
before this one. Map anonymous pages, if needed,
and clear the area. */
retval = set_brk (elf_bss + load_bias,
elf_brk + load_bias); 确保段的栈地址比堆大
if (retval) {
send_sig(SIGKILL, current, 0);
goto out_free_dentry;
}
nbyte = ELF_PAGEOFFSET(elf_bss); 还在确认栈地址?
if (nbyte) {
nbyte = ELF_MIN_ALIGN - nbyte;
if (nbyte > elf_brk - elf_bss)
nbyte = elf_brk - elf_bss;
if (clear_user((void __user *)elf_bss +
load_bias, nbyte)) {
/*
* This bss-zeroing can fail if the ELF
* file specifies odd protections. So
* we don't check the return value
*/
}
}
}
if (elf_ppnt->p_flags & PF_R) 判断权限位可读?
elf_prot |= PROT_READ;
if (elf_ppnt->p_flags & PF_W) 判断权限位可写?
elf_prot |= PROT_WRITE;
if (elf_ppnt->p_flags & PF_X) 判断权限位可执行?
elf_prot |= PROT_EXEC;
elf_flags = MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE; mmap的flag?
vaddr = elf_ppnt->p_vaddr; 映像装入地址
if (loc->elf_ex.e_type == ET_EXEC || load_addr_set) { 如果地址是固定的
elf_flags |= MAP_FIXED;
} else if (loc->elf_ex.e_type == ET_DYN) { 如果为共享库,要加偏移量,e_type 为3就是共享库
/* Try and get dynamic programs out of the way of the
* default mmap base, as well as whatever program they
* might try to exec. This is because the brk will
* follow the loader, and is not movable. */
#ifdef CONFIG_X86
load_bias = 0;
#else
load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr);
#endif
}
error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt,
elf_prot, elf_flags, 0); 映射了一个固定的地址?
if (BAD_ADDR(error)) {
send_sig(SIGKILL, current, 0); 出错就停止
retval = IS_ERR((void *)error) ?
PTR_ERR((void*)error) : -EINVAL;
goto out_free_dentry;
}
if (!load_addr_set) { load_addr_set不是本来就是0吗
load_addr_set = 1;
load_addr = (elf_ppnt->p_vaddr - elf_ppnt->p_offset); 段虚拟地址减去段偏移地址就是段基地址
if (loc->elf_ex.e_type == ET_DYN) { 如果是共享库
load_bias += error -
ELF_PAGESTART(load_bias + vaddr); 这是内存转换吧,虚拟地址转到内存地址
load_addr += load_bias; 加上物理基地址,就是段的物理地址了
reloc_func_desc = load_bias;
}
}
k = elf_ppnt->p_vaddr;
if (k < start_code)
start_code = k; 代码段?
if (start_data < k)
start_data = k; 数据段?
/*
* Check to see if the section's size will overflow the
* allowed task size. Note that p_filesz must always be
* <= p_memsz so it is only necessary to check p_memsz.
*/
if (BAD_ADDR(k) || elf_ppnt->p_filesz > elf_ppnt->p_memsz ||
elf_ppnt->p_memsz > TASK_SIZE || 判断使用的空间是否小于分配空间
TASK_SIZE - elf_ppnt->p_memsz < k) {
/* set_brk can never work. Avoid overflows. */
send_sig(SIGKILL, current, 0);
retval = -EINVAL;
goto out_free_dentry;
}
k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; 段虚拟地址加上段大小就到了段尾
if (k > elf_bss)
elf_bss = k; 后面接elf_bss?
if ((elf_ppnt->p_flags & PF_X) && end_code < k) ELF 段标志可执行 并且。。。
end_code = k;
if (end_data < k)
end_data = k;
k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
if (k > elf_brk)
elf_brk = k;
}
loc->elf_ex.e_entry += load_bias;
elf_bss += load_bias;
elf_brk += load_bias;
start_code += load_bias;
end_code += load_bi
{
struct file *interpreter = NULL; /* to shut gcc up */
unsigned long load_addr = 0, load_bias = 0;
int load_addr_set = 0;
char * elf_interpreter = NULL;
unsigned long error;
struct elf_phdr *elf_ppnt, *elf_phdata;
unsigned long elf_bss, elf_brk;
int retval, i;
unsigned int size;
unsigned long elf_entry;
unsigned long interp_load_addr = 0;
unsigned long start_code, end_code, start_data, end_data;
unsigned long reloc_func_desc = 0;
int executable_stack = EXSTACK_DEFAULT;
unsigned long def_flags = 0;
struct {
struct elfhdr elf_ex;
struct elfhdr interp_elf_ex;
} *loc;
定义了loc结构体,其中elfhdr就是 elf32_hdr
typedef struct elf32_hdr{unsigned chare_ident[EI_NIDENT];Elf32_Halfe_type; ELF文件类型,1表示此文件是重定位文件,2表示可执行文件,3表示动态连接库Elf32_Halfe_machine; CPU类型,它指出了此文件使用何种指令集。如果是Intel 0x386 CPU此值为3Elf32_Worde_version; ELF文件版本,为1。Elf32_Addre_entry; /* Entry point */映像的程序入口Elf32_Offe_phoff; 这个是Program Header offset 程序头位移量Elf32_Offe_shoff; 这个是Section Header offset 节头偏移量Elf32_Worde_flags; 处理器特定标志Elf32_Halfe_ehsize; ELF头部长度Elf32_Halfe_phentsize; 数组元素(表项)的大小Elf32_Halfe_phnum; Program Header numberElf32_Halfe_shentsize; 数组元素(表项)的大小Elf32_Halfe_shnum; Section Header numberElf32_Halfe_shstrndx; 节头部字符表索引} Elf32_Ehdr;//此结构体一共52个字节
loc = kmalloc(sizeof(*loc), GFP_KERNEL);
if (!loc) {
retval = -ENOMEM; 错误代码:ENOMEM:核心内存不足
goto out_ret;
}
void *kmalloc(size_t size, int flags);
size要分配内存的大小. 以字节为单位.
flags要分配内存的类型。
kmalloc函数返回的是虚拟地址(线性地址). kmalloc特殊之处在于它分配的内存是物理上连续的
GFP_KERNEL是内核内存分配时最常用的,无内存可用时可引起休眠。
看上去就是给loc分配了一个虚拟地址
/* Get the exec-header */
loc->elf_ex = *((struct elfhdr *)bprm->buf);
retval = -ENOEXEC; 不是出错才赋值吗
/*
* This structure is used to hold the arguments that are used when loading binaries.
*/这种结构是用来装是用来装载二进制时的参数。
该函数用到了一个类型为linux_binprm的结构体来保存要要执行的文件相关的信息
struct linux_binprm{
char buf[BINPRM_BUF_SIZE]; 保存可执行文件的头128字节
#ifdef CONFIG_MMU
struct vm_area_struct *vma;
#else
# define MAX_ARG_PAGES32
struct page *page[MAX_ARG_PAGES];
#endif
struct mm_struct *mm;
unsigned long p; /* current top of mem */当前内存页最高地址
unsigned int
cred_prepared:1,
cap_effective:1;
#ifdef __alpha__
unsigned int taso:1;
#endif
unsigned int recursion_depth;
struct file * file; 要执行的文件
struct cred *cred;/* new credentials */
int unsafe;/* how unsafe this exec is (mask of LSM_UNSAFE_*) */
unsigned int per_clear;/* bits to clear in current->personality */
int argc, envc; 命令行参数和环境变量数目
char * filename;/* Name of binary as seen by procps */要执行的文件的名称
char * interp; 要执行的文件的真实名称,通常和filename相同
unsigned interp_flags;
unsigned interp_data;
unsigned long loader, exec;
};
保存可执行文件的头128字节到loc->elf_ex
/* First of all, some simple consistency checks */
if (memcmp(loc->elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
goto out;
int memcmp(const void *buf1, const void *buf2, unsigned int count);
loc->elf_ex.e_ident 确认是否为"\177ELF"的ELF格式文件 SELFMAG是4
这里\177为8进制,十六进制为0x7f,后面的为'E','L','F'
if (loc->elf_ex.e_type != ET_EXEC && loc->elf_ex.e_type != ET_DYN)
goto out;
if (!elf_check_arch(&loc->elf_ex))
goto out;
if (!bprm->file->f_op||!bprm->file->f_op->mmap)
goto out;
e_type = ET_EXEC为2(可执行文件) = ET_DYN为3(动态链接库文件)
#define elf_check_arch(x)\EF_CRIS_VARIANT_MASK 为0x0000000e 1110
((x)->e_machine == EM_CRIS\ 确认处理器
&& ((((x)->e_flags & EF_CRIS_VARIANT_MASK) == EF_CRIS_VARIANT_ANY_V0_V10\
|| (((x)->e_flags & EF_CRIS_VARIANT_MASK) == EF_CRIS_VARIANT_COMMON_V10_V32))))
EF_CRIS_VARIANT_ANY_V0_V10为 0x00000000 判断3,2,1是否为0
EF_CRIS_VARIANT_COMMON_V10_V320x00000004 0100 判断2位是否为1,第3,1位是否为0
也就是第3位第1位是否为0
/* Now read in all of the header information */
if (loc->elf_ex.e_phentsize != sizeof(struct elf_phdr)) 确认e_phentsize 大小
goto out;
if (loc->elf_ex.e_phnum < 1 ||
loc->elf_ex.e_phnum > 65536U / sizeof(struct elf_phdr))
goto out;
size = loc->elf_ex.e_phnum * sizeof(struct elf_phdr);
retval = -ENOMEM;
elf_phdata = kmalloc(size, GFP_KERNEL); 又分配空间了,分配地址成功返回分配的地址值(虚拟地址?)
if (!elf_phdata)
goto out;
retval = kernel_read(bprm->file, loc->elf_ex.e_phoff,
(char *)elf_phdata, size);
if (retval != size) {
if (retval >= 0)
retval = -EIO;
goto out_free_ph;
}
为什么找不到kernel_read的资料。。。
int kernel_read(struct file *file, loff_t offset,
char *addr, unsigned long count)
{
mm_segment_t old_fs;
loff_t pos = offset;
int result;
old_fs = get_fs();
set_fs(get_ds());
/* The cast to a user pointer is valid due to the set_fs() */
result = vfs_read(file, (void __user *)addr, count, &pos);
set_fs(old_fs);
return result;
}
kernel_read就是把那个loc映像文件的程序表头读入了。然后就是get_fs了
#define get_fs()(current_thread_info()->addr_limit) 看名字就是获取当前的地址访问限制值。
然后是set_fs
set_fs(get_ds()); #define get_ds()(KERNEL_DS) #define KERNEL_DS((mm_segment_t){0})看不懂
后面vfs_read() 应该是内核读取到用户空间吧,放到addr的字符串指针? 返回的读取长度?
这个struct elf_phdr和之前的elf32_hdr 不是同一个,差点弄错了,这样就可以理解了。
typedef struct elf32_phdr {elf_ppnt = elf_phdata;
Elf32_Word p_type; 部的类型
Elf32_Off p_offset; 该段在文件中的偏移。这个偏移是相对于整个文件的。
Elf32_Addr p_vaddr; 该段加载后在进程空间中占用的内存起始地址。
Elf32_Addr p_paddr; 该段的物理地地址。这个字段被忽略,因为在多数现代操作系统下物理地址是进程无法触及的。
Elf32_Word p_filesz; 该段在文件中占用的字节大小,有些段可能在文件中不存在但却占内存空间,此时这个字段为0。
Elf32_Word p_memsz;该段在内存中占用的字节大小,有些段可能仅存在于文件中而不被加载到内存,此时这个字段为0。
Elf32_Word p_flags;段的属性。它用每一个二进制位表示一种属,相应位为1表示含有相应的属性,为0表示不含那种属性。其中最低位是可执行位,次低位是可写位,第三低位是可读位。
Elf32_Word p_align; 对齐。
} Elf32_Phdr;
elf_bss = 0;
elf_brk = 0;
start_code = ~0UL;
end_code = 0;
start_data = 0;
end_data = 0;
变量的初始化 0UL是无符号长整型 0, ~ 表示按位取反,即:0xffff
原来这是一个0啊,我以为是O
for (i = 0; i < loc->elf_ex.e_phnum; i++) { 按程序个数一个一个找吗
if (elf_ppnt->p_type == PT_INTERP) { 之前elf_ppnt = elf_phdata; -->elf_phdata=kmalloc(size, GFP_KERNEL); 这个elf_ppnt就是另一份映射吧
/* This is the program interpreter used for
* shared libraries - for now assume that this
* is an a.out format binary
*/PT_INTERP是3,于是判断是否为动态链接库
retval = -ENOEXEC;
if (elf_ppnt->p_filesz > PATH_MAX ||
elf_ppnt->p_filesz < 2) PATH_MAX 4096
goto out_free_ph;
retval = -ENOMEM;
elf_interpreter = kmalloc(elf_ppnt->p_filesz,
GFP_KERNEL); 之前elf_phdata = kmalloc(size, GFP_KERNEL); 这里分配内存大小应该也一样吧
if (!elf_interpreter)
goto out_free_ph;
retval = kernel_read(bprm->file, elf_ppnt->p_offset,
elf_interpreter,
elf_ppnt->p_filesz); 这里又在读取了,比较一下之前的①都是bprm->file,②elf_ppnt->p_offset和loc->elf_ex.e_phoff
elf_ppnt= elf_phdata;elf_phdata又是loc->elf_ex分配的这两个也是一样的吧?③elf_interpreter存放地址④elf_ppnt->p_filesz和size也一样吧。
if (retval != elf_ppnt->p_filesz) { 大小不对就错了
if (retval >= 0)
retval = -EIO;
goto out_free_interp;
}
/* make sure path is NULL terminated */
retval = -ENOEXEC;
if (elf_interpreter[elf_ppnt->p_filesz - 1] != '\0') 防止指针泄露?
goto out_free_interp;
interpreter = open_exec(elf_interpreter);
retval = PTR_ERR(interpreter);
if (IS_ERR(interpreter))
goto out_free_interp;
又来了open_exec
struct file *open_exec(const char *name)好像不搞懂dentry不行啊
{
struct file *file;
int err;
这个就是最主要的函数吧
file = do_filp_open(AT_FDCWD, name, AT_FDCWD -100 当前路径吧?相对路径名
O_LARGEFILE | O_RDONLY | FMODE_EXEC, 0, O_LARGEFILE 大文件?O_RDONLY 可读写FMODE_EXEC文件被打开
MAY_EXEC | MAY_OPEN); MAY_EXEC允许本地用户绕过限制执行文件 MAY_OPEN.......
if (IS_ERR(file))
goto out;
err = -EACCES; #defineEACCES13 Permission denied!!!
if (!S_ISREG(file->f_path.dentry->d_inode->i_mode))
goto exit;
if (file->f_path.mnt->mnt_flags & MNT_NOEXEC)
goto exit;
fsnotify_open(file->f_path.dentry);
err = deny_write_access(file);
if (err)
goto exit;
out:
return file;
exit:
fput(file);
return ERR_PTR(err);
}
struct file *do_filp_open(int dfd, const char *pathname,
int open_flag, int mode, int acc_mode)
这个函数再说吧http://blog.csdn.net/f413933206/article/details/5701913
do_filp_open先是把函数中的open_flag确认各种flag保证文件的权限,防止被破坏。然后link_path_walk()将用户传进来的字符串表示的文件路径转换成一个dentry结构,并建立好相应的inode和file结构。path_init为查找作准备工作,path_walk真正上路查找,这两个函数联合起来根据一段路径名找到对应的dentry
struct dentry {
atomic_t d_count; 目录项对象使用计数器
unsigned int d_flags;/* protected by d_lock */ 目录项标志
spinlock_t d_lock;/* per dentry lock */
int d_mounted;
struct inode *d_inode;/* Where the name belongs to - NULL is 与文件名关联的索引节点
* negative */
/*
* The next three fields are touched by __d_lookup. Place them here
* so they all fit in a cache line.
*/
struct hlist_node d_hash;/* lookup hash list */ 散列表表项的指针
struct dentry *d_parent;/* parent directory */ 父目录的目录项对象
struct qstr d_name;
struct list_head d_lru;/* LRU list */ 未使用链表的指针
/*
* d_child and d_rcu can share memory
*/
union {
struct list_head d_child;/* child of parent list */ 父目录中目录项对象的链表的指针
struct rcu_head d_rcu;
} d_u;
struct list_head d_subdirs;/* our children */ 对目录而言,表示子目录目录项对象的链表
struct list_head d_alias;/* inode alias list */ 相关索引节点(别名)的链表
unsigned long d_time;/* used by d_revalidate */
const struct dentry_operations *d_op; 目录项方法
struct super_block *d_sb;/* The root of the dentry tree */ 文件的超级块对象
void *d_fsdata;/* fs-specific data */ 与文件系统相关的数据
unsigned char d_iname[DNAME_INLINE_LEN_MIN];/* small names */ 存放短文件名
};d_count有三种状态,回收内存的时候会考虑它
/*struct inode {
struct hlist_nodei_hash; 哈希表
struct list_headi_list;/* backing dev IO list */索引节点链表
struct list_headi_sb_list;
struct list_headi_dentry;,怎么两边都有目录项链表
unsigned longi_ino; 节点号
atomic_ti_count; 引用记数
unsigned inti_nlink;
uid_ti_uid; 使用者id
gid_ti_gid; 使用者id组
dev_ti_rdev; 实设备标识符
unsigned inti_blkbits; 以位为单位的块大小
u64i_version; 版本号
loff_ti_size; 以字节为单位的文件大小
#ifdef __NEED_I_SIZE_ORDERED
seqcount_ti_size_seqcount;
#endif
struct timespeci_atime; 最后访问时间
struct timespeci_mtime; 最后修改(modify)时间
struct timespeci_ctime; 最后改变(change)时间
blkcnt_ti_blocks; 文件的块数
unsigned short i_bytes; 使用的字节数
umode_ti_mode;
spinlock_ti_lock;/* i_blocks, i_bytes, maybe i_size */自旋锁
struct mutexi_mutex;
struct rw_semaphorei_alloc_sem; 索引节点信号量
const struct inode_operations*i_op; 索引节点操作表
const struct file_operations*i_fop;/* former ->i_op->default_file_ops */默认的索引节点操作
struct super_block*i_sb; 相关的超级块
struct file_lock*i_flock; 文件锁链表
struct address_space*i_mapping; 相关的地址映射
struct address_spacei_data; 设备地址映射
#ifdef CONFIG_QUOTA
struct dquot*i_dquot[MAXQUOTAS]; 节点的磁盘限额
#endif
struct list_headi_devices; 块设备链表
union {
struct pipe_inode_info*i_pipe; 这个是网络设备?管道信息
struct block_device*i_bdev; 块设备驱动
struct cdev*i_cdev; 当inode指向一个字符设备文件时
};
__u32i_generation;
#ifdef CONFIG_FSNOTIFY
__u32i_fsnotify_mask; /* all events this inode cares about */
struct hlist_headi_fsnotify_mark_entries; /* fsnotify mark entries */
#endif
#ifdef CONFIG_INOTIFY
struct list_headinotify_watches; /* watches on this inode */
struct mutexinotify_mutex;/* protects the watches list */
#endif
unsigned longi_state;
unsigned longdirtied_when;/* jiffies of first dirtying */
unsigned inti_flags;
atomic_ti_writecount;
#ifdef CONFIG_SECURITY
void*i_security;
#endif
#ifdef CONFIG_FS_POSIX_ACL
struct posix_acl*i_acl;
struct posix_acl*i_default_acl;
#endif
void*i_private; /* fs or device private pointer */
};
* If the binary is not readable then enforce
* mm->dumpable = 0 regardless of the interpreter's
* permissions.
*/
if (file_permission(interpreter, MAY_READ) < 0)
bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP;
retval = kernel_read(interpreter, 0, bprm->buf,
BINPRM_BUF_SIZE);
if (retval != BINPRM_BUF_SIZE) {
if (retval >= 0)
retval = -EIO;
goto out_free_dentry;
}
file_permission -->inode_permission(file->f_path.dentry->d_inode, mask);
int inode_permission(struct inode *inode, int mask)然后又是kernel_read到底是读到哪里啊,读文件还是读内存啊。读到bprm->buf里吧。
{
int retval;
if (mask & MAY_WRITE) {
umode_t mode = inode->i_mode;
/*
* Nobody gets write access to a read-only fs.
*/
if (IS_RDONLY(inode) &&
(S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
return -EROFS;
/*
* Nobody gets write access to an immutable file.
*/
if (IS_IMMUTABLE(inode))
return -EACCES;
}
if (inode->i_op->permission)
retval = inode->i_op->permission(inode, mask);
else
retval = generic_permission(inode, mask, inode->i_op->check_acl);
if (retval)
return retval;
retval = devcgroup_inode_permission(inode, mask);
if (retval)
return retval;
return security_inode_permission(inode,
mask & (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND));
}好像在确认文件的读写执行的权限,具体的也不是很看得懂了
通过kernel_read()读入其开头128个字节,这就是映像的头部。
/* Get the exec headers */
loc->interp_elf_ex = *((struct elfhdr *)bprm->buf);
break;
}
elf_ppnt++;
}
又获取了头部,这么翻来覆去的搞,指是把东西读出来么,循环到这里结束了。
读出来判断是否有动态链接库?
elf_ppnt = elf_phdata; 为什么又赋一遍,上面的循环elf_ppnt已经到底了,又让它回来了
for (i = 0; i < loc->elf_ex.e_phnum; i++, elf_ppnt++)
if (elf_ppnt->p_type == PT_GNU_STACK) {
if (elf_ppnt->p_flags & PF_X)
executable_stack = EXSTACK_ENABLE_X;
else
executable_stack = EXSTACK_DISABLE_X;
break;
}
上面这个这个真心看不懂
/* Some simple consistency checks for the interpreter */
if (elf_interpreter) {
retval = -ELIBBAD;
/* Not an ELF interpreter */
if (memcmp(loc->interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
goto out_free_dentry;
/* Verify the interpreter has a valid arch */
if (!elf_check_arch(&loc->interp_elf_ex))
goto out_free_dentry;
}
又检查是否是可执行文件,elf_interpreter怎么是动态链接器呢
/* Flush all traces of the currently running executable */
retval = flush_old_exec(bprm);
if (retval)
goto out_free_dentry;
flush_old_exec()把当前进程用户空间的页面都释放了
/* OK, This is the point of no return */
current->flags &= ~PF_FORKNOEXEC;
current->mm->def_flags = def_flags;
没办法看懂
/* Do this immediately, since STACK_TOP as used in setup_arg_pages
may depend on the personality. */
SET_PERSONALITY(loc->elf_ex); 设置进程的个性标志
if (elf_read_implies_exec(loc->elf_ex, executable_stack))
current->personality |= READ_IMPLIES_EXEC;
current->flags |= PF_RANDOMIZE;
setup_new_exec(bprm);
这个函数完全不能理解
void setup_new_exec(struct linux_binprm * bprm)
{
int i, ch;
char * name;
char tcomm[sizeof(current->comm)];
arch_pick_mmap_layout(current->mm); 好像在判断栈的格式
/* This is the point of no return */
current->sas_ss_sp = current->sas_ss_size = 0;
if (current_euid() == current_uid() && current_egid() == current_gid())
set_dumpable(current->mm, 1);
else
set_dumpable(current->mm, suid_dumpable);
name = bprm->filename;
/* Copies the binary name from after last slash */
for (i=0; (ch = *(name++)) != '\0';) {
if (ch == '/')
i = 0; /* overwrite what we wrote */
else
if (i < (sizeof(tcomm) - 1))
tcomm[i++] = ch;
}
tcomm[i] = '\0';
set_task_comm(current, tcomm);
/* Set the new mm task size. We have to do that late because it may
* depend on TIF_32BIT which is only updated in flush_thread() on
* some architectures like powerpc
*/
current->mm->task_size = TASK_SIZE;
/* install the new credentials */
if (bprm->cred->uid != current_euid() ||
bprm->cred->gid != current_egid()) {
current->pdeath_signal = 0;
} else if (file_permission(bprm->file, MAY_READ) ||
bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP) {
set_dumpable(current->mm, suid_dumpable);
}
/*
* Flush performance counters when crossing a
* security domain:
*/
if (!get_dumpable(current->mm))
perf_event_exit_task(current);
/* An exec changes our domain. We are no longer part of the thread
group */
current->self_exec_id++;
flush_signal_handlers(current, 0);
flush_old_files(current->files);
}
/* Do this so that we can load the interpreter, if need be. We will
change some of these later */
current->mm->free_area_cache = current->mm->mmap_base;
current->mm->cached_hole_size = 0;
retval = setup_arg_pages(bprm, randomize_stack_top(STACK_TOP),
executable_stack);
if (retval < 0) {
send_sig(SIGKILL, current, 0); 发送终止信号
goto out_free_dentry;
}
current->mm->start_stack = bprm->p; 设置堆栈的起始地址
/* Now we do a little grungy work by mmapping the ELF image into
the correct location in memory. */
for(i = 0, elf_ppnt = elf_phdata;
i < loc->elf_ex.e_phnum; i++, elf_ppnt++) {
int elf_prot = 0, elf_flags;
unsigned long k, vaddr;
if (elf_ppnt->p_type != PT_LOAD) 判断是否是可装入段
continue;
if (unlikely (elf_brk > elf_bss)) { 判断初始化是否正确
unsigned long nbyte;
/* There was a PT_LOAD segment with p_memsz > p_filesz
before this one. Map anonymous pages, if needed,
and clear the area. */
retval = set_brk (elf_bss + load_bias,
elf_brk + load_bias); 确保段的栈地址比堆大
if (retval) {
send_sig(SIGKILL, current, 0);
goto out_free_dentry;
}
nbyte = ELF_PAGEOFFSET(elf_bss); 还在确认栈地址?
if (nbyte) {
nbyte = ELF_MIN_ALIGN - nbyte;
if (nbyte > elf_brk - elf_bss)
nbyte = elf_brk - elf_bss;
if (clear_user((void __user *)elf_bss +
load_bias, nbyte)) {
/*
* This bss-zeroing can fail if the ELF
* file specifies odd protections. So
* we don't check the return value
*/
}
}
}
if (elf_ppnt->p_flags & PF_R) 判断权限位可读?
elf_prot |= PROT_READ;
if (elf_ppnt->p_flags & PF_W) 判断权限位可写?
elf_prot |= PROT_WRITE;
if (elf_ppnt->p_flags & PF_X) 判断权限位可执行?
elf_prot |= PROT_EXEC;
elf_flags = MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE; mmap的flag?
vaddr = elf_ppnt->p_vaddr; 映像装入地址
if (loc->elf_ex.e_type == ET_EXEC || load_addr_set) { 如果地址是固定的
elf_flags |= MAP_FIXED;
} else if (loc->elf_ex.e_type == ET_DYN) { 如果为共享库,要加偏移量,e_type 为3就是共享库
/* Try and get dynamic programs out of the way of the
* default mmap base, as well as whatever program they
* might try to exec. This is because the brk will
* follow the loader, and is not movable. */
#ifdef CONFIG_X86
load_bias = 0;
#else
load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr);
#endif
}
error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt,
elf_prot, elf_flags, 0); 映射了一个固定的地址?
if (BAD_ADDR(error)) {
send_sig(SIGKILL, current, 0); 出错就停止
retval = IS_ERR((void *)error) ?
PTR_ERR((void*)error) : -EINVAL;
goto out_free_dentry;
}
if (!load_addr_set) { load_addr_set不是本来就是0吗
load_addr_set = 1;
load_addr = (elf_ppnt->p_vaddr - elf_ppnt->p_offset); 段虚拟地址减去段偏移地址就是段基地址
if (loc->elf_ex.e_type == ET_DYN) { 如果是共享库
load_bias += error -
ELF_PAGESTART(load_bias + vaddr); 这是内存转换吧,虚拟地址转到内存地址
load_addr += load_bias; 加上物理基地址,就是段的物理地址了
reloc_func_desc = load_bias;
}
}
k = elf_ppnt->p_vaddr;
if (k < start_code)
start_code = k; 代码段?
if (start_data < k)
start_data = k; 数据段?
/*
* Check to see if the section's size will overflow the
* allowed task size. Note that p_filesz must always be
* <= p_memsz so it is only necessary to check p_memsz.
*/
if (BAD_ADDR(k) || elf_ppnt->p_filesz > elf_ppnt->p_memsz ||
elf_ppnt->p_memsz > TASK_SIZE || 判断使用的空间是否小于分配空间
TASK_SIZE - elf_ppnt->p_memsz < k) {
/* set_brk can never work. Avoid overflows. */
send_sig(SIGKILL, current, 0);
retval = -EINVAL;
goto out_free_dentry;
}
k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; 段虚拟地址加上段大小就到了段尾
if (k > elf_bss)
elf_bss = k; 后面接elf_bss?
if ((elf_ppnt->p_flags & PF_X) && end_code < k) ELF 段标志可执行 并且。。。
end_code = k;
if (end_data < k)
end_data = k;
k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
if (k > elf_brk)
elf_brk = k;
}
loc->elf_ex.e_entry += load_bias;
elf_bss += load_bias;
elf_brk += load_bias;
start_code += load_bias;
end_code += load_bi
0
上一篇:tq2440编译ARM版本的Qt4出错问题解决
下一篇:load_elf_binary阅读(2)
相关热门文章
- linux 常见服务端口
- xmanager 2.0 for linux配置
- 【ROOTFS搭建】busybox的httpd...
- openwrt中luci学习笔记
- 什么是shell
- linux dhcp peizhi roc
- 关于Unix文件的软链接
- 求教这个命令什么意思,我是新...
- sed -e "/grep/d" 是什么意思...
- 谁能够帮我解决LINUX 2.6 10...
给主人留下些什么吧!~~
评论热议
0 0
- load_elf_binary阅读(1)
- load_elf_binary阅读(2)
- load_elf_binary中使用的内存映射机制
- 阅读1
- ELF文件的加载过程(load_elf_binary函数详解)--Linux进程的管理与调度(十三)
- 【代码阅读摘记】阅读AForge.NET (1)
- 阅读lcc (1)
- OS161 源代码阅读-1
- 阅读>心得(1)
- CET---阅读技巧1
- 代码阅读日志1
- PcShare2005代码阅读(1)
- 英语阅读常考词1
- tcpl 阅读笔记 1
- OpenCV源码阅读(1)
- C++汇编语言阅读1
- android 代码阅读--1
- opencv源码阅读(1)
- 小甲鱼PE详解之输入表(导入表)详解2(PE详解08)
- Java运算符
- Android ActionBar隐藏修改图标和标题
- qwt 6.1.0集成进Qt creator 2.8.1步骤
- tq2440编译ARM版本的Qt4出错问题解决
- load_elf_binary阅读(1)
- 设计模式之装饰者模式
- load_elf_binary阅读(2)
- 日本“冷知识”你都知道吗?
- main.c阅读
- preloader_exec整理
- JAVA基础【3.10】《Java核心技术1》Java的基本程序设计结构-数组
- wld_start
- umask函数linux
原创粉丝点击
热门IT博客
热门问题
老师的惩罚
人脸识别
我在镇武司摸鱼那些年
重生之率土为王
我在大康的咸鱼生活
盘龙之生命进化
天生仙种
凡人之先天五行
春回大明朝
姑娘不必设防,我是瞎子
瘦肚子的方法
瘦腰方法
如何才能瘦腰
产后如何瘦腰
转呼啦圈可以瘦腰吗
怎么减去腰部赘肉
如何减小肚子
收腹减肥法
瘦腰神器
产后收腹
怎么瘦腰瘦腿
怎样可以快速瘦小腿
瘦腰瘦肚子运动
腰部减肥产品
产后怎么收腹
如何快速瘦小腿肌肉
呼拉圈瘦腰
瘦腰精油
怎样可以瘦腿瘦腰
如何瘦腰丰胸
康宝莱瘦腰片
办公室瘦腰腹
瘦腰瘦肚子动作
瘦腰瘦肚子瑜伽
提臀瘦腰裤
瘦腰减肥圈
如何有效瘦腰腹
瘦腰减肥汤
咋样瘦腰
怎么瘦腰跟肚子
瘦大腿瘦腰的方法
瑜伽 瘦腰腹
怎样瘦腰和臀部
收臧
www997788
997788
收藏网址
7788收藏网
中国收藏热线网
997788中国收藏热线
中国收藏品交易网