do_mmap () 함수

7654 단어 mmap

do_mmap () 함수


do_mmap는 주로 가상 메모리와 물리 메모리를 직접 비추는 데 쓰인다
그 핵심은 error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
그 핵심 함수는 바로 이do_mmap_pgoff 함수

do_mmap_pgoff

unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
                            unsigned long len, unsigned long prot,
                            unsigned long flags, unsigned long pgoff);  
  • 먼저 len에 대해 페이지 정렬을 하고 정렬 후의 크기가 정확한지 확인하며, 오류가 있으면addr로 직접 되돌려줍니다
  • 호출 do_mmap_pgoff(file, addr, len, prot, flag, offset >> PAGE_SHIFT);
  • unsigned long do_mmap_pgoff(struct file *file,
                                unsigned long addr,
                                unsigned long len,
                                unsigned long prot,
                                unsigned long flags,
                                unsigned long pgoff);
  • 일련의 보안 검사를 실시하고 메모리 검사, len의 페이지 정렬 길이 검사..
       if (flags & MAP_FIXED || addr) {
           printk(KERN_DEBUG "%d: Can't do fixed-address/overlay mmap of RAM
    ", current->pid); return -EINVAL; } if (PAGE_ALIGN(len) == 0) return addr; if (len > TASK_SIZE) return -EINVAL; if (flags & MAP_FIXED || addr) { printk(KERN_DEBUG "%d: Can't do fixed-address/overlay mmap of RAM
    ", current->pid); return -EINVAL; } if (PAGE_ALIGN(len) == 0) return addr; if (len > TASK_SIZE) return -EINVAL;
  • 페이지 오프셋을 확인합니다
       if ((pgoff + (len >> PAGE_SHIFT)) < pgoff)
           return -EINVAL;  
  • 파일 정보 검증
       /* validate file mapping requests */
       membacked = 0;
       if (file) {
           /* files must support mmap */
           // mmap;
           if (!file->f_op || !file->f_op->mmap)
               return -ENODEV;
    
           if ((prot & PROT_EXEC) &&
               (file->f_vfsmnt->mnt_flags & MNT_NOEXEC))
               return -EPERM;
    
           // ??
           // memory backed , , ?
           if (S_ISCHR(file->f_dentry->d_inode->i_mode)) {
               membacked = 1;
           }
           else {
               struct address_space *mapping = file->f_mapping;
               if (!mapping)
                   mapping = file->f_dentry->d_inode->i_mapping;
               if (mapping && mapping->backing_dev_info)
                   membacked = mapping->backing_dev_info->memory_backed;
           }
    
           // , 
           if (flags & MAP_SHARED) {
               /* do checks for writing, appending and locking */
               if ((prot & PROT_WRITE) && !(file->f_mode & FMODE_WRITE))
                   return -EACCES;
    
               if (IS_APPEND(file->f_dentry->d_inode) &&
                   (file->f_mode & FMODE_WRITE))
                   return -EACCES;
    
               if (locks_verify_locked(file->f_dentry->d_inode))
                   return -EAGAIN;
    
               if (!membacked) {
                   printk("MAP_SHARED not completely supported on !MMU
    "); return -EINVAL; } if (!file->f_op->get_unmapped_area) return -ENODEV; } // else { /* we read private files into memory we allocate */ if (!file->f_op->read) return -ENODEV; } }
  • EXEC를 설정하지 않은 경우 PROT의 플래그를 확인합니다
       /* handle PROT_EXEC implication by PROT_READ */
       if ((prot & PROT_READ) && (current->personality & READ_IMPLIES_EXEC))
           if (!(file && (file->f_vfsmnt->mnt_flags & MNT_NOEXEC)))
               prot |= PROT_EXEC;
  • 계속 검사..
       /* do simple checking here so the lower-level routines won't have
        * to. we assume access permissions have been handled by the open
        * of the memory object, so we don't do any here.     */
           vm_flags = calc_vm_flags(prot,flags) /* | mm->def_flags */
           | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
    
           if (!membacked) {
               /* share any file segment that's mapped read-only */
               if (((flags & MAP_PRIVATE) && !(prot & PROT_WRITE) && file) ||
                   ((flags & MAP_SHARED) && !(prot & PROT_WRITE) && file))
                   vm_flags |= VM_MAYSHARE;
       
               /* refuse to let anyone share files with this process if it's being traced -
                * otherwise breakpoints set in it may interfere with another untraced process
                    */
                   if (current->ptrace & PT_PTRACED)
                       vm_flags &= ~(VM_SHARED | VM_MAYSHARE);
                   }
                   else {
                       /* permit sharing of character devices and ramfs files at any time for
                        * anything other than a privately writable mapping */
                           if (!(flags & MAP_PRIVATE) || !(prot & PROT_WRITE)) {
                               vm_flags |= VM_MAYSHARE;
                               if (flags & MAP_SHARED)
                                   vm_flags |= VM_SHARED;
                           }
  • 파일 매핑
       /* allow the security API to have its say  API */
       ret =  _file_mmap(file, prot, flags);
       if (ret)
           return ret;
  • 직접 비출 수 없지만 공유할 수 있습니다
       /* we're going to need to  record the mapping if it works */
       vml = kmalloc(sizeof(struct vm_list_struct), GFP_KERNEL);
       if (!vml)
           goto error_getting_vml;
       memset(vml, 0, sizeof(*vml));
    
       down_write(&nommu_vma_sem);
    
       /* if we want to share, we need to search for VMAs created by another
        * mmap() call that overlap with our proposed mapping
        * - we can only share with an exact match on most regular files
        * - shared mappings on character devices and memory backed files are
        *   permitted to overlap inexactly as far as we are concerned for in
        *   these cases, sharing is handled in the driver or filesystem rather
        *   than here
         */
           if (vm_flags & VM_MAYSHARE) {
               unsigned long pglen = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
               unsigned long vmpglen;
       
               for (rb = rb_first(&nommu_vma_tree); rb; rb = rb_next(rb)) {
                   vma = rb_entry(rb, struct vm_area_struct, vm_rb);
       
                   if (!(vma->vm_flags & VM_MAYSHARE))
                       continue;
       
                   /* search for overlapping mappings on the same file */
                   if (vma->vm_file->f_dentry->d_inode != file->f_dentry->d_inode)
                       continue;
       
                   if (vma->vm_pgoff >= pgoff + pglen)
                       continue;
       
                   vmpglen = (vma->vm_end - vma->vm_start + PAGE_SIZE - 1) >> PAGE_SHIFT;
                   if (pgoff >= vma->vm_pgoff + vmpglen)
                       continue;
       
                   /* handle inexact matches between mappings */
                   if (vmpglen != pglen || vma->vm_pgoff != pgoff) {
                       if (!membacked)
                           goto sharing_violation;
                       continue;
                   }
       
                   /* we've found a VMA we can share */
                   atomic_inc(&vma->vm_usage);
       
                   vml->vma = vma;
                   result = (void *) vma->vm_start;
                   goto shared;
               }
           }
    

  • 어쨌든 기존의 권한 아래 파일을 비추도록 최선을 다하겠다고 말했다.

    좋은 웹페이지 즐겨찾기