Commit d2f21286 authored by Andrew Morton's avatar Andrew Morton Committed by Patrick Mochel

[PATCH] pass the stack protection flags into put_dirty_page()

put_dirty_page() currently assumes PAGE_COPY for the stack page's ptes.  But
for x86_64 (at least) this is not the case.

The patch adds the extra arg to put_dirty_page(), updates all callers and fixes
x86_64.
parent a397214b
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/config.h> #include <linux/config.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/mm.h>
#include <asm/param.h> #include <asm/param.h>
#include <asm/signal.h> #include <asm/signal.h>
...@@ -40,7 +41,6 @@ ...@@ -40,7 +41,6 @@
#define CLOCKS_PER_SEC IA32_CLOCKS_PER_SEC #define CLOCKS_PER_SEC IA32_CLOCKS_PER_SEC
extern void ia64_elf32_init (struct pt_regs *regs); extern void ia64_elf32_init (struct pt_regs *regs);
extern void put_dirty_page (struct task_struct * tsk, struct page *page, unsigned long address);
static void elf32_set_personality (void); static void elf32_set_personality (void);
...@@ -200,7 +200,7 @@ ia32_setup_arg_pages (struct linux_binprm *bprm) ...@@ -200,7 +200,7 @@ ia32_setup_arg_pages (struct linux_binprm *bprm)
struct page *page = bprm->page[i]; struct page *page = bprm->page[i];
if (page) { if (page) {
bprm->page[i] = NULL; bprm->page[i] = NULL;
put_dirty_page(current, page, stack_base); put_dirty_page(current, page, stack_base, PAGE_COPY);
} }
stack_base += PAGE_SIZE; stack_base += PAGE_SIZE;
} }
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/mm.h>
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/binfmts.h> #include <linux/binfmts.h>
...@@ -32,8 +33,6 @@ ...@@ -32,8 +33,6 @@
#endif #endif
extern void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long address);
#undef STACK_TOP #undef STACK_TOP
#define STACK_TOP TASK31_SIZE #define STACK_TOP TASK31_SIZE
...@@ -81,7 +80,7 @@ int setup_arg_pages32(struct linux_binprm *bprm) ...@@ -81,7 +80,7 @@ int setup_arg_pages32(struct linux_binprm *bprm)
struct page *page = bprm->page[i]; struct page *page = bprm->page[i];
if (page) { if (page) {
bprm->page[i] = NULL; bprm->page[i] = NULL;
put_dirty_page(current,page,stack_base); put_dirty_page(current,page,stack_base,PAGE_COPY);
} }
stack_base += PAGE_SIZE; stack_base += PAGE_SIZE;
} }
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/binfmts.h> #include <linux/binfmts.h>
#include <linux/mm.h>
#include <asm/segment.h> #include <asm/segment.h>
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <asm/processor.h> #include <asm/processor.h>
...@@ -272,9 +273,6 @@ static void elf32_init(struct pt_regs *regs) ...@@ -272,9 +273,6 @@ static void elf32_init(struct pt_regs *regs)
set_thread_flag(TIF_IA32); set_thread_flag(TIF_IA32);
} }
extern void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long address);
int setup_arg_pages(struct linux_binprm *bprm) int setup_arg_pages(struct linux_binprm *bprm)
{ {
unsigned long stack_base; unsigned long stack_base;
...@@ -319,7 +317,7 @@ int setup_arg_pages(struct linux_binprm *bprm) ...@@ -319,7 +317,7 @@ int setup_arg_pages(struct linux_binprm *bprm)
struct page *page = bprm->page[i]; struct page *page = bprm->page[i];
if (page) { if (page) {
bprm->page[i] = NULL; bprm->page[i] = NULL;
put_dirty_page(current,page,stack_base); put_dirty_page(current,page,stack_base,PAGE_COPY_EXEC);
} }
stack_base += PAGE_SIZE; stack_base += PAGE_SIZE;
} }
......
...@@ -287,7 +287,8 @@ int copy_strings_kernel(int argc,char ** argv, struct linux_binprm *bprm) ...@@ -287,7 +287,8 @@ int copy_strings_kernel(int argc,char ** argv, struct linux_binprm *bprm)
* *
* tsk->mmap_sem is held for writing. * tsk->mmap_sem is held for writing.
*/ */
void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long address) void put_dirty_page(struct task_struct *tsk, struct page *page,
unsigned long address, pgprot_t prot)
{ {
pgd_t * pgd; pgd_t * pgd;
pmd_t * pmd; pmd_t * pmd;
...@@ -295,7 +296,8 @@ void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long a ...@@ -295,7 +296,8 @@ void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long a
struct pte_chain *pte_chain; struct pte_chain *pte_chain;
if (page_count(page) != 1) if (page_count(page) != 1)
printk(KERN_ERR "mem_map disagrees with %p at %08lx\n", page, address); printk(KERN_ERR "mem_map disagrees with %p at %08lx\n",
page, address);
pgd = pgd_offset(tsk->mm, address); pgd = pgd_offset(tsk->mm, address);
pte_chain = pte_chain_alloc(GFP_KERNEL); pte_chain = pte_chain_alloc(GFP_KERNEL);
...@@ -314,7 +316,7 @@ void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long a ...@@ -314,7 +316,7 @@ void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long a
} }
lru_cache_add_active(page); lru_cache_add_active(page);
flush_dcache_page(page); flush_dcache_page(page);
set_pte(pte, pte_mkdirty(pte_mkwrite(mk_pte(page, PAGE_COPY)))); set_pte(pte, pte_mkdirty(pte_mkwrite(mk_pte(page, prot))));
pte_chain = page_add_rmap(page, pte, pte_chain); pte_chain = page_add_rmap(page, pte, pte_chain);
pte_unmap(pte); pte_unmap(pte);
tsk->mm->rss++; tsk->mm->rss++;
...@@ -421,7 +423,8 @@ int setup_arg_pages(struct linux_binprm *bprm) ...@@ -421,7 +423,8 @@ int setup_arg_pages(struct linux_binprm *bprm)
struct page *page = bprm->page[i]; struct page *page = bprm->page[i];
if (page) { if (page) {
bprm->page[i] = NULL; bprm->page[i] = NULL;
put_dirty_page(current,page,stack_base); put_dirty_page(current, page, stack_base,
mpnt->vm_page_prot);
} }
stack_base += PAGE_SIZE; stack_base += PAGE_SIZE;
} }
...@@ -434,8 +437,6 @@ int setup_arg_pages(struct linux_binprm *bprm) ...@@ -434,8 +437,6 @@ int setup_arg_pages(struct linux_binprm *bprm)
#else #else
#define put_dirty_page(tsk, page, address)
#define setup_arg_pages(bprm) (0)
static inline void free_arg_pages(struct linux_binprm *bprm) static inline void free_arg_pages(struct linux_binprm *bprm)
{ {
int i; int i;
......
...@@ -426,7 +426,8 @@ extern int handle_mm_fault(struct mm_struct *mm,struct vm_area_struct *vma, unsi ...@@ -426,7 +426,8 @@ extern int handle_mm_fault(struct mm_struct *mm,struct vm_area_struct *vma, unsi
extern int make_pages_present(unsigned long addr, unsigned long end); extern int make_pages_present(unsigned long addr, unsigned long end);
extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write); extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write);
extern long sys_remap_file_pages(unsigned long start, unsigned long size, unsigned long prot, unsigned long pgoff, unsigned long nonblock); extern long sys_remap_file_pages(unsigned long start, unsigned long size, unsigned long prot, unsigned long pgoff, unsigned long nonblock);
void put_dirty_page(struct task_struct *tsk, struct page *page,
unsigned long address, pgprot_t prot);
int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start,
int len, int write, int force, struct page **pages, struct vm_area_struct **vmas); int len, int write, int force, struct page **pages, struct vm_area_struct **vmas);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment