Re: [PATCH v2 1/2] bpf: extend stackmap to save binary_build_id+offset instead of address
> On Mar 6, 2018, at 10:25 AM, Peter Zijlstrawrote: > > On Tue, Mar 06, 2018 at 10:09:13AM -0800, Song Liu wrote: >> +/* Parse build ID of ELF file mapped to vma */ >> +static int stack_map_get_build_id(struct vm_area_struct *vma, >> + unsigned char *build_id) >> +{ >> +Elf32_Ehdr *ehdr; >> +struct page *page; >> +int ret; >> + >> +/* >> + * vm_start is user memory, so we need to be careful with it. >> + * We don't want too many copy_from_user to reduce overhead. >> + * Most ELF file is at least one page long, and the build_id >> + * is stored in the first page. Therefore, we limit the search of >> + * build_id to the first page only. This can be made safe with >> + * get_user_pages_fast(). If the file is smaller than PAGE_SIZE, >> + * or the build_id is not in the first page, the look up fails. >> + */ >> +if (vma->vm_end - vma->vm_start < PAGE_SIZE || >> +vma->vm_start & (PAGE_SIZE - 1))/* page aligned */ >> +return -EINVAL; >> + >> +if (get_user_pages_fast(vma->vm_start, 1, 0, ) != 1) >> +return -EFAULT; >> + >> +ret = -EINVAL; >> +ehdr = (Elf32_Ehdr *)vma->vm_start; >> + > > You're still directly accessing a user pointer afaict. This will > insta-fault on SMAP enabled hardware due to the lack of STAC (or PAN on > ARM). > > You _really_ cannot just access user pointers without the proper APIs. > > Did you maybe mean to use: > > ehdr = (Elf32_Ehdr *)page_address(page); > > ? Yeah, I missed this part. Let me fix it. Thanks again! Song >> +/* compare magic x7f "ELF" */ >> +if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) >> +goto out; >> + >> +/* only support executable file and shared object file */ >> +if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) >> +goto out; >> + >> +if (ehdr->e_ident[EI_CLASS] == 1) >> +ret = stack_map_get_build_id_32(vma, build_id); >> +else if (ehdr->e_ident[EI_CLASS] == 2) >> +ret = stack_map_get_build_id_64(vma, build_id); >> +out: >> +put_page(page); >> +return ret; >> +}
Re: [PATCH v2 1/2] bpf: extend stackmap to save binary_build_id+offset instead of address
On Tue, Mar 06, 2018 at 10:09:13AM -0800, Song Liu wrote: > +/* Parse build ID of ELF file mapped to vma */ > +static int stack_map_get_build_id(struct vm_area_struct *vma, > + unsigned char *build_id) > +{ > + Elf32_Ehdr *ehdr; > + struct page *page; > + int ret; > + > + /* > + * vm_start is user memory, so we need to be careful with it. > + * We don't want too many copy_from_user to reduce overhead. > + * Most ELF file is at least one page long, and the build_id > + * is stored in the first page. Therefore, we limit the search of > + * build_id to the first page only. This can be made safe with > + * get_user_pages_fast(). If the file is smaller than PAGE_SIZE, > + * or the build_id is not in the first page, the look up fails. > + */ > + if (vma->vm_end - vma->vm_start < PAGE_SIZE || > + vma->vm_start & (PAGE_SIZE - 1))/* page aligned */ > + return -EINVAL; > + > + if (get_user_pages_fast(vma->vm_start, 1, 0, ) != 1) > + return -EFAULT; > + > + ret = -EINVAL; > + ehdr = (Elf32_Ehdr *)vma->vm_start; > + You're still directly accessing a user pointer afaict. This will insta-fault on SMAP enabled hardware due to the lack of STAC (or PAN on ARM). You _really_ cannot just access user pointers without the proper APIs. Did you maybe mean to use: ehdr = (Elf32_Ehdr *)page_address(page); ? > + /* compare magic x7f "ELF" */ > + if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) > + goto out; > + > + /* only support executable file and shared object file */ > + if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) > + goto out; > + > + if (ehdr->e_ident[EI_CLASS] == 1) > + ret = stack_map_get_build_id_32(vma, build_id); > + else if (ehdr->e_ident[EI_CLASS] == 2) > + ret = stack_map_get_build_id_64(vma, build_id); > +out: > + put_page(page); > + return ret; > +}