(I modified subject line in order to split this thread into "mprotect 
restriction"
 part and "simple GUI for learning mode" part. This is the "mprotect 
restriction" part.)

Radoslaw Szkodzinski wrote:
> On Sun, Sep 26, 2010 at 7:46 AM, Tetsuo Handa
> <[email protected]> wrote:
> >
> > Radoslaw Szkodzinski wrote:
> > > The hook would check the mask of the argument of mprotect, rejecting
> > > PROT_EXEC | PROT_WRITE, check whether a formerly PROT_WRITE page is
> > > being now mprotect()ed to PROT_EXEC
> > > or vice versa.
> >
> > It will be possible to reject A-2 and B-2 below
> >
> > (Step A-1) Create a vma as PROT_WRITE .
> > (Step A-2) Change that vma to PROT_EXECUTE .
> >
> > (Step B-1) Create a vma as PROT_EXECUTE .
> > (Step B-2) Change that vma to PROT_WRITE .
> >
> > by doing
> >
> 
> Do not touch vm_flags directly. grSecurity does that, because it's not
> an LSM hook...

I don't modify vm_flags. I modify only vm_flags_ever_specified.
What does "touch vm_flags" mean?
Do you mean not only "modifying vm_flags" but also "reading vm_flags"?

> As I said before, mainline developers might not like touching them from a 
> hook.
> 
> Fixed:
>   if ((reqprot & (VM_MAYWRITE | VM_MAYEXEC)) ^ (prot & (VM_MAYWRITE |
> VM_MAYEXEC))) &&
> >  ? ? ?!ccs_capable(CCS_USE_WRITABLE_EXECUTABLE_VMA))
> > ? ?return -EPERM;
> 
> (or possibly with the check of vma->vm_flags_ever_specified like that below 
> ;) )
> 
I think vma->vm_flags_ever_specified is needed in order to handle C-3 .

> This means that pages already marked write and executable would stay
> that way and not throw -EPERM
> when being marked VM_MAYREAD.
> 
Why not to throw -EPERM?

> >
> > inside security_file_mprotect(vma, reqprot, prot).
> >
> > But it is impossible to reject C-3 below
> >
> > (Step C-1) Create a vma as PROT_WRITE .
> > (Step C-2) Change that vma to PROT_READ .
> > (Step C-3) Change that vma to PROT_READ|PROT_EXECUTE .
> >
> 
> Correct, this needs storage of the flags ever set on said mapping.
> grSecurity seems to have a hole here.
> 
> > unless "struct vm_area_struct" has a variable which remembers the bitwise 
> > OR of
> > PROT_* flags ever specified since the moment a vma was created. I need to 
> > add
> 
> Yes, exactly, that would close the hole if there were such a
> bitfield... That would go into vm_area_struct.
> 
I see.

> > Also, I think
> >
> > (Step D-1) Create a vma as PROT_WRITE|PROT_EXECUTE .
> >
> > is possible by using mmap().
> 
> Yes, but only of an anonymous mapping, file mapping can be stopped
> with deny_open.
> This should be caught too, possibly by adding a new LSM hook...
> 
> > If D-1 is possible, checking it at security_file_mprotect() is not 
> > sufficient.
> > What do you think?
> 
> It isn't, but combined with a proposed security_mmap() hook it would be.
> 

As of 2.6.36-rc5, there are 6 callers of security_file_mmap(). However, only
do_mmap_pgoff() (which is called by mmap() syscall in mm/mmap.c) and
validate_mmap_request() (which is called by do_mmap_pgoff() which is called
by mmap() syscall in mm/nommu.c) receive reqprot and prot arguments.

965 unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
966                         unsigned long len, unsigned long prot,
967                         unsigned long flags, unsigned long pgoff)
(...snipped...)
1095         error = security_file_mmap(file, reqprot, prot, flags, addr, 0);
1096         if (error)
1097                 return error;
1098 
1099         return mmap_region(file, addr, len, flags, vm_flags, pgoff);

815 static int validate_mmap_request(struct file *file,
816                                  unsigned long addr,
817                                  unsigned long len,
818                                  unsigned long prot,
819                                  unsigned long flags,
820                                  unsigned long pgoff,
821                                  unsigned long *_capabilities)
(...snipped...)
982         ret = security_file_mmap(file, reqprot, prot, flags, addr, 0);

Therefore, I think that checking VM_MAYWRITE | VM_MAYEXEC inside
existing security_file_mmap() can cover D-1. Doing

  vma->vm_flags_ever_specified |= vma->vm_flags;
  if (((vma->vm_flags_ever_specified | (prot << 4)) &
      (VM_MAYWRITE | VM_MAYEXEC)) == (VM_MAYWRITE | VM_MAYEXEC) &&
      !ccs_capable(CCS_USE_WRITABLE_EXECUTABLE_VMA))
    return -EPERM;

inside security_file_mmap() is not needed because the vma is not yet created.


After all, what I need to do are add

  unsigned long vm_flags_ever_specified;

to "struct vm_area_struct" and do

  if ((prot << 4) & (VM_MAYWRITE | VM_MAYEXEC)) == (VM_MAYWRITE | VM_MAYEXEC) &&
      !ccs_capable(CCS_USE_WRITABLE_EXECUTABLE_VMA))
    return -EPERM;

inside security_file_mmap(file, reqprot, prot, flags, addr, addr_only) and do

  vma->vm_flags_ever_specified |= vma->vm_flags;
  if (((vma->vm_flags_ever_specified | (prot << 4)) &
      (VM_MAYWRITE | VM_MAYEXEC)) == (VM_MAYWRITE | VM_MAYEXEC) &&
      !ccs_capable(CCS_USE_WRITABLE_EXECUTABLE_VMA))
    return -EPERM;

inside security_file_mprotect(vma, reqprot, prot). What do you think?



> No, PAX_MPROTECT alone isn't arch-dependent, rest of the PaX is.
> CONFIG_PAX_MPROTECT touches two files, fs/binfmt_elf.c
> (to check its enable/disable flag) and mm/mprotect.c.

config PAX_MPROTECT depends on (PAX_PAGEEXEC || PAX_SEGMEXEC) and
config PAX_PAGEEXEC depends on !COMPAT_VDSO && PAX_NOEXEC && (!X86_32 || M586 
|| M586TSC || M586MMX || M686 || MPENTIUMII || MPENTIUMIII || MPENTIUMM || 
MCORE2 || MPENTIUM4 || MPSC || MATOM || MK7 || MK8 || MWINCHIPC6 || MWINCHIP2 
|| MWINCHIP3D || MVIAC3_2 || MVIAC7) and
config PAX_SEGMEXEC depends on !COMPAT_VDSO && PAX_NOEXEC && X86_32 .

It seems to me that I can't clone code from PAX_MPROTECT without limiting archs.


> > TOMOYO simply validates arguments passed to syscalls. TOMOYO does not track
> > owner of objects. TOMOYO tracks only subjects using domainnames
> > (e.g. <kernel> /usr/sbin/httpd ). I think CONFIG_MM_OWNER=n is not a 
> > problem.
> 
> But the security_file_mprotect hook doesn't have a "domain" argument
> or anything linking the mapping directly to the task, neither does
> vm_addr_struct.
> How can you get domain info without the domain name? :)
> 
I couldn't understand it.
What TOMOYO will control is whether current thread is allowed to specify

  PROT_WRITE|PROTO_EXEC when creating a VMA using mmap() syscall

  PROT_WRITE when modifying an existing VMA which ever had PROT_EXEC in the past
  using mprotect() syscall

  PROT_EXEC when modifying an existing VMA which ever had PROT_WRITE in the past
  using mprotect() syscall

or not. TOMOYO doesn't care who owns a VMA (as with who created a file,
whereas inode-based security cares it by allocating memory and using xattr on
filesystems).
TOMOYO's domainname is derived from "struct task_struct"->ccs_domain_info .


Regards.

_______________________________________________
tomoyo-users-en mailing list
[email protected]
http://lists.sourceforge.jp/mailman/listinfo/tomoyo-users-en

Reply via email to