block layer zero-copy: missing access_ok() check
A message that is not in the archive (sent off-list or not yet received): 20130315133748.GA31887@Krystal
A message that is not in the archive (sent off-list or not yet received): [email protected]
A message that is not in the archive (sent off-list or not yet received): 20130315155808.GB1659@Krystal
A message that is not in the archive (sent off-list or not yet received): CA+55aFxW0vkpgJCpJVJVqDmDG61P_AOoVMFVhfqVxM45Mj-LNA@mail.gmail.com
A message that is not in the archive (sent off-list or not yet received): 20130315171000.GA2342@Krystal
Adding linux-arch. Guys, can you check your architectures?
Also, make sure to check huge-pages if they are separate. Basically, if you have code like this:
if (!pte_present(pte) ||
pte_special(pte) || (write && !pte_write(pte))) {
pte_unmap(ptep);
return 0;
}it's probably buggy. It's not sufficient to just check write permissions, you do need to check user permissions too.
Powerpc,x86 and sh seem to get it right by virtue of checking rthe user bit. s390 checks against TASK_SIZE.
MIPS does seem buggy. Sparc I don't know the meaning of the bits for. And powerpc does have several variants, so while the main one looks fine, I didn't look at the other ones.
Linus
Quoted 46 lines · Mathieu Desnoyers
Quoted 6 lines · * Linus Torvalds ([email protected]) wrote:
It's a bit subtle, but at least the x86 get-user-pages does actually check
access_ok()implicitly. It's just that it does so using the bits in the page table, and does the page table lookup as a "user access". So it checks the page tables themselves, not the user limit.Quoted 7 lines
Which is fine, because that's what the *hardware* does. So if the page tables make something readable to users, then they are readable by definition.
So
get_user_pages_fast()doesn't needaccess_ok()before it, and the naming isn't actually confusing. And I'm sure we knew this at some point.Ah, I see! so my guess is that it is expected that "gup_*" functions implicitly check that they are getting user pages. If we look at this through fresh eyes, across all architectures:
* x86: looks OK: gup* checks with
_PAGE_USERflag. The slow path that goes through__get_user_pages()seem to rely onfollow_page_mask()and thenpgd_bad()as well aspud_bad()to check the_PAGE_USERflag.* mips:
access_okmissing inget_user_pages_fast,
-> I don't see any explicit mention of "USER" pages flags within the
gup functions.* powerpc:
access_okis there, everything is fine,* s390:
access_okmissing in both__get_user_pages_fastandget_user_pages_fast.
-> I don't see clear indication of USER pages being flagged.* sh:
access_okmissing inget_user_pages_fast, -> OK, gup_* functions are checking a_PAGE_USERflag.* sparc:
access_okmissing inget_user_pages_fast, -> no indication of any_PAGE_USERflag.* generic: mm/util.c:get_user_pages_fast() ends up calling mm/memory.c:get_user_pages() and then
__get_user_pages(), which are also used as slow-path for all architectures above:-> from my understanding, through
follow_page_mask()pgd_bad()and
pud_bad()are checking_PAGE_USERflags (when they exist). Unfortunately, the following grep is slightly worrying:
Quoted 14 lines · * Linus Torvalds ([email protected]) wrote:
Adding linux-arch. Guys, can you check your architectures?
Also, make sure to check huge-pages if they are separate. Basically, if you have code like this:
if (!pte_present(pte) || pte_special(pte) || (write && !pte_write(pte))) { pte_unmap(ptep); return 0; }it's probably buggy. It's not sufficient to just check write permissions, you do need to check user permissions too.
Quoted 6 lines
Powerpc,x86 and sh seem to get it right by virtue of checking rthe user bit. s390 checks against
TASK_SIZE.MIPS does seem buggy. Sparc I don't know the meaning of the bits for. And powerpc does have several variants, so while the main one looks fine, I didn't look at the other ones.
In addition to get_user_pages_fast() issues, I see that there are many direct callers of get_user_pages() that seem to assume that access checks are performed within this function. AFAIU, on architectures that have a _PAGE_USER flag, this check is performed internally by pgd_bad() and pud_bad(), but what happens to all the others ?
One possible way to fix this without adding unwelcomed performance impact might be to add an access_ok check in __get_user_pages() that is entirely skipped by architectures that define a non-nopped-out pgd_bad()/pud_bad().
Thoughts ?
Thanks,
Mathieu
Quoted 51 lines
Linus
Quoted 46 lines · Mathieu Desnoyers
Quoted 6 lines · * Linus Torvalds ([email protected]) wrote:
It's a bit subtle, but at least the x86 get-user-pages does actually check
access_ok()implicitly. It's just that it does so using the bits in the page table, and does the page table lookup as a "user access". So it checks the page tables themselves, not the user limit.Quoted 7 lines
Which is fine, because that's what the *hardware* does. So if the page tables make something readable to users, then they are readable by definition.
So
get_user_pages_fast()doesn't needaccess_ok()before it, and the naming isn't actually confusing. And I'm sure we knew this at some point.Ah, I see! so my guess is that it is expected that "gup_*" functions implicitly check that they are getting user pages. If we look at this through fresh eyes, across all architectures:
* x86: looks OK: gup* checks with
_PAGE_USERflag. The slow path that goes through__get_user_pages()seem to rely onfollow_page_mask()and thenpgd_bad()as well aspud_bad()to check the_PAGE_USERflag.* mips:
access_okmissing inget_user_pages_fast,
-> I don't see any explicit mention of "USER" pages flags within the
gup functions.* powerpc:
access_okis there, everything is fine,* s390:
access_okmissing in both__get_user_pages_fastandget_user_pages_fast.
-> I don't see clear indication of USER pages being flagged.* sh:
access_okmissing inget_user_pages_fast, -> OK, gup_* functions are checking a_PAGE_USERflag.* sparc:
access_okmissing inget_user_pages_fast, -> no indication of any_PAGE_USERflag.* generic: mm/util.c:get_user_pages_fast() ends up calling mm/memory.c:get_user_pages() and then
__get_user_pages(), which are also used as slow-path for all architectures above:-> from my understanding, through
follow_page_mask()pgd_bad()and
pud_bad()are checking_PAGE_USERflags (when they exist). Unfortunately, the following grep is slightly worrying:
Signature · 3 lines
Mathieu Desnoyers EfficiOS Inc. http://www.efficios.com
Quoted 4 lines · Mathieu Desnoyers
In addition to
get_user_pages_fast()issues, I see that there are many direct callers ofget_user_pages()that seem to assume that access checks are performed within this function.
get_user_pages() does check permissions. It looks up the vma and checks them there, which is much more than access_ok() ever does.
Quoted 3 lines
AFAIU, on architectures that
have a_PAGE_USERflag, this check is performed internally bypgd_bad()andpud_bad(), but what happens to all the others ?
Irrelevant. See above.
Linus
Quoted 3 lines · Linus Torvalds
get_user_pages()does check permissions. It looks up the vma and checks them there, which is much more thanaccess_ok()ever does.
To clarify: the fact that a vma exists at all already means "it's a user mapping" (with the special gate area being a secondary user mapping). So you don't need any kind of explicit user check.
Linus
Quoted 9 lines · * Linus Torvalds ([email protected]) wrote:
Quoted 3 lines · Linus Torvalds
get_user_pages()does check permissions. It looks up the vma and checks them there, which is much more thanaccess_ok()ever does.To clarify: the fact that a vma exists at all already means "it's a user mapping" (with the special gate area being a secondary user mapping). So you don't need any kind of explicit user check.
Ah! That's the bit I was missing.
Thanks,
Mathieu
Signature · 3 lines
Mathieu Desnoyers EfficiOS Inc. http://www.efficios.com
Quoted 14 lines · Linus Torvalds
Adding linux-arch. Guys, can you check your architectures?
Also, make sure to check huge-pages if they are separate. Basically, if you have code like this:
if (!pte_present(pte) || pte_special(pte) || (write && !pte_write(pte))) { pte_unmap(ptep); return 0; }it's probably buggy. It's not sufficient to just check write permissions, you do need to check user permissions too.
Quoted 6 lines
Powerpc,x86 and sh seem to get it right by virtue of checking rthe user bit. s390 checks against
TASK_SIZE.MIPS does seem buggy. Sparc I don't know the meaning of the bits for. And powerpc does have several variants, so while the main one looks fine, I didn't look at the other ones.
Took the train half way through... I assume we are talking gup_fast here ? So we have an access_ok() accross the range, which should make us safe. Additionally on ppc64 we have a different pgd for user and kernel pages anyway.
We do check for huge pages at every level as far as I can tell (and those are user only) and finally we check for _PAGE_USER.
The only "subtlety" I can think of is that PROT_NONE has no _PAGE_USER for us and thus will fail a gup but that's expected right ?
Cheers,
Ben.
From: Linus Torvalds <[email protected]>
Date: Fri, 15 Mar 2013 10:21:41 -0700
Quoted 1 line
Adding linux-arch. Guys, can you check your architectures?
...
Quoted 2 lines
Quoted 2 lines
* sparc:
access_okmissing inget_user_pages_fast, -> no indication of any_PAGE_USERflag.
Well, access_ok() returns 1 unconditionally on sparc64. I can add a call there if you want. :-)
And that's because the user virtual address space is %100 segregated from the privileged one. There are no "user address ranges" vs. kernel ones.
For example, we can and do give 64-bit processes the full 64-bit virtual address space for user mappings.
The page tables, outside of swapper_pg_dir, only map user pages.