From: Hugh Dickins <hugh@veritas.com>
To: Andrew Morton <akpm@osdl.org>
Cc: linux-kernel@vger.kernel.org
Subject: [PATCH 13/15] mm: get_user_pages check count
Date: Thu, 10 Nov 2005 02:03:10 +0000 (GMT) [thread overview]
Message-ID: <Pine.LNX.4.61.0511100201430.5814@goblin.wat.veritas.com> (raw)
In-Reply-To: <Pine.LNX.4.61.0511100139550.5814@goblin.wat.veritas.com>
Most calls to get_user_pages soon release the pages and then return to
user space, but some are long term - notably Infiniband's ib_umem_get.
That's blessed with good locked_vm checking, but if the system were
misconfigured, then it might be possible to build up a huge page_count.
Guard against overflow by page_count_too_high checks in get_user_pages:
refuse with -ENOMEM once page count reaches its final PID_MAX_LIMIT
(which is why we allowed for 2*PID_MAX_LIMIT in the 23 bits of count).
Sorry, can't touch get_user_pages without giving it more cleanup.
Signed-off-by: Hugh Dickins <hugh@veritas.com>
---
include/linux/mm.h | 16 ++++++++++++++++
mm/memory.c | 40 +++++++++++++++++++++++-----------------
2 files changed, 39 insertions(+), 17 deletions(-)
--- mm12/include/linux/mm.h 2005-11-09 14:40:00.000000000 +0000
+++ mm13/include/linux/mm.h 2005-11-09 14:40:17.000000000 +0000
@@ -312,6 +312,7 @@ struct page {
*/
#define PCOUNT_SHIFT 23
#define PCOUNT_MASK ((1UL << PCOUNT_SHIFT) - 1)
+#define PCOUNT_HIGH (PCOUNT_MASK - PID_MAX_LIMIT)
/*
* Drop a ref, return true if the logical refcount fell to zero
@@ -377,8 +378,17 @@ static inline int page_mapped(struct pag
return (unsigned long)atomic64_read(&page->_pcount) > PCOUNT_MASK;
}
+static inline int page_count_too_high(struct page *page)
+{
+ /* get_user_pages check when nearing overflow */
+ return ((unsigned long)atomic64_read(&page->_pcount) & PCOUNT_MASK)
+ >= PCOUNT_HIGH;
+}
+
#else /* !ATOMIC64_INIT */
+#define PCOUNT_HIGH (INT_MAX - PID_MAX_LIMIT)
+
/*
* Drop a ref, return true if the logical refcount fell to zero
* (the page has no users)
@@ -437,6 +447,12 @@ static inline int page_mapped(struct pag
return atomic_read(&page->_mapcount) >= 0;
}
+static inline int page_count_too_high(struct page *page)
+{
+ /* get_user_pages check when nearing overflow */
+ return atomic_read(&page->_count) >= PCOUNT_HIGH;
+}
+
#endif /* !ATOMIC64_INIT */
void FASTCALL(__page_cache_release(struct page *));
--- mm12/mm/memory.c 2005-11-09 14:40:00.000000000 +0000
+++ mm13/mm/memory.c 2005-11-09 14:40:17.000000000 +0000
@@ -928,39 +928,43 @@ int get_user_pages(struct task_struct *t
do {
struct vm_area_struct *vma;
unsigned int foll_flags;
+ struct page *page;
vma = find_extend_vma(mm, start);
if (!vma && in_gate_area(tsk, start)) {
- unsigned long pg = start & PAGE_MASK;
- struct vm_area_struct *gate_vma = get_gate_vma(tsk);
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
pte_t *pte;
+ pte_t ptent;
+
if (write) /* user gate pages are read-only */
return i ? : -EFAULT;
- if (pg > TASK_SIZE)
- pgd = pgd_offset_k(pg);
+ start &= PAGE_MASK; /* what needs that? */
+ if (start >= TASK_SIZE)
+ pgd = pgd_offset_k(start);
else
- pgd = pgd_offset_gate(mm, pg);
+ pgd = pgd_offset_gate(mm, start);
BUG_ON(pgd_none(*pgd));
- pud = pud_offset(pgd, pg);
+ pud = pud_offset(pgd, start);
BUG_ON(pud_none(*pud));
- pmd = pmd_offset(pud, pg);
+ pmd = pmd_offset(pud, start);
if (pmd_none(*pmd))
return i ? : -EFAULT;
- pte = pte_offset_map(pmd, pg);
- if (pte_none(*pte)) {
- pte_unmap(pte);
+ pte = pte_offset_map(pmd, start);
+ ptent = *pte;
+ pte_unmap(pte);
+ if (pte_none(ptent))
return i ? : -EFAULT;
- }
if (pages) {
- pages[i] = pte_page(*pte);
- get_page(pages[i]);
+ page = pte_page(ptent);
+ if (page_count_too_high(page))
+ return i ? : -ENOMEM;
+ get_page(page);
+ pages[i] = page;
}
- pte_unmap(pte);
if (vmas)
- vmas[i] = gate_vma;
+ vmas[i] = get_gate_vma(tsk);
i++;
start += PAGE_SIZE;
len--;
@@ -985,8 +989,6 @@ int get_user_pages(struct task_struct *t
foll_flags |= FOLL_ANON;
do {
- struct page *page;
-
if (write)
foll_flags |= FOLL_WRITE;
@@ -1020,6 +1022,10 @@ int get_user_pages(struct task_struct *t
}
}
if (pages) {
+ if (page_count_too_high(page)) {
+ put_page(page);
+ return i ? : -ENOMEM;
+ }
pages[i] = page;
flush_dcache_page(page);
}
next prev parent reply other threads:[~2005-11-10 2:04 UTC|newest]
Thread overview: 52+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-11-10 1:42 [PATCH 00/15] mm: struct page lock and counts Hugh Dickins
2005-11-10 1:43 ` [PATCH 01/15] mm: poison struct page for ptlock Hugh Dickins
2005-11-10 2:10 ` Andrew Morton
2005-11-10 2:22 ` Hugh Dickins
2005-11-10 2:56 ` Andrew Morton
2005-11-10 2:58 ` Andrew Morton
2005-11-10 11:28 ` Ingo Molnar
2005-11-10 12:06 ` Ingo Molnar
2005-11-10 12:26 ` Andrew Morton
2005-11-10 21:37 ` Christoph Lameter
2005-11-10 21:52 ` Christoph Hellwig
2005-11-11 10:46 ` Ingo Molnar
2005-11-12 23:48 ` Adrian Bunk
2005-11-10 12:35 ` Hugh Dickins
2005-11-10 12:51 ` Andrew Morton
2005-11-10 13:29 ` Hugh Dickins
2005-11-10 15:00 ` Ingo Molnar
2005-11-10 15:38 ` Hugh Dickins
2005-11-10 19:49 ` Andrew Morton
2005-11-10 19:56 ` Linus Torvalds
2005-11-11 0:10 ` Russell King
2005-11-12 6:27 ` Benjamin Herrenschmidt
2005-11-11 15:02 ` Hugh Dickins
2005-11-15 18:49 ` Andrew Morton
2005-11-15 19:51 ` Hugh Dickins
2005-11-15 20:05 ` Andrew Morton
2005-11-10 1:44 ` [PATCH 02/15] mm: revert page_private Hugh Dickins
2005-11-10 1:46 ` [PATCH 03/15] mm reiser4: " Hugh Dickins
2005-11-10 1:47 ` [PATCH 04/15] mm: update split ptlock Kconfig Hugh Dickins
2005-11-10 1:48 ` [PATCH 05/15] mm: unbloat get_futex_key Hugh Dickins
2005-11-10 1:50 ` [PATCH 06/15] mm: remove ppc highpte Hugh Dickins
2005-11-10 1:52 ` Benjamin Herrenschmidt
2005-11-10 1:55 ` Paul Mackerras
2005-11-10 2:46 ` Hugh Dickins
2005-11-10 1:51 ` [PATCH 07/15] mm: powerpc ptlock comments Hugh Dickins
2005-11-10 1:53 ` [PATCH 08/15] mm: powerpc init_mm without ptlock Hugh Dickins
2005-11-10 1:56 ` [PATCH 09/15] mm: fill arch atomic64 gaps Hugh Dickins
2005-11-10 13:38 ` Andi Kleen
2005-11-10 15:19 ` Hugh Dickins
2005-11-10 1:57 ` [PATCH 10/15] mm: atomic64 page counts Hugh Dickins
2005-11-10 2:16 ` Andrew Morton
2005-11-10 2:33 ` Hugh Dickins
2005-11-10 3:01 ` Andrew Morton
2005-11-10 21:43 ` Christoph Lameter
2005-11-10 21:53 ` Andrew Morton
2005-11-11 15:25 ` Hugh Dickins
2005-11-11 18:03 ` Christoph Lameter
2005-11-10 2:00 ` [PATCH 11/15] mm: long " Hugh Dickins
2005-11-10 2:01 ` [PATCH 12/15] mm reiser4: " Hugh Dickins
2005-11-10 2:03 ` Hugh Dickins [this message]
2005-11-10 2:08 ` [PATCH 14/15] mm: inc_page_table_pages check max Hugh Dickins
2005-11-10 2:09 ` [PATCH 15/15] mm: remove install_page limit Hugh Dickins
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=Pine.LNX.4.61.0511100201430.5814@goblin.wat.veritas.com \
--to=hugh@veritas.com \
--cc=akpm@osdl.org \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).