Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=4fc75ff4816c3483b4b772b2f6cb3d8fd88ca547
Commit:     4fc75ff4816c3483b4b772b2f6cb3d8fd88ca547
Parent:     af7c693f146069a1f44739acef9abf1bc27f7247
Author:     Nick Piggin <[EMAIL PROTECTED]>
AuthorDate: Tue May 8 00:25:16 2007 -0700
Committer:  Linus Torvalds <[EMAIL PROTECTED]>
CommitDate: Tue May 8 11:15:00 2007 -0700

    exec: fix remove_arg_zero
    
    Petr Tesarik discovered a problem in remove_arg_zero(). He writes:
    
     When a script is loaded, load_script() replaces argv[0] with the
     name of the interpreter and the filename passed to the exec syscall.
     However, there is no guarantee that the length of the interpreter
     name plus the length of the filename is greater than the length of
     the original argv[0]. If the difference happens to cross a page boundary,
     setup_arg_pages() will call put_dirty_page() [aka install_arg_page()]
     with an address outside the VMA.
    
     Therefore, remove_arg_zero() must free all pages which would be unused
     after the argument is removed.
    
    So, rewrite the remove_arg_zero function without gotos, with a few comments,
    and with the commonly used explicit index/offset. This fixes the problem
    and makes it easier to understand as well.
    
    [EMAIL PROTECTED]: add comment]
    Signed-off-by: Nick Piggin <[EMAIL PROTECTED]>
    Cc: Petr Tesarik <[EMAIL PROTECTED]>
    Signed-off-by: Peter Zijlstra <[EMAIL PROTECTED]>
    Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
    Signed-off-by: Linus Torvalds <[EMAIL PROTECTED]>
---
 fs/exec.c |   50 ++++++++++++++++++++++++++++++++++----------------
 1 files changed, 34 insertions(+), 16 deletions(-)

diff --git a/fs/exec.c b/fs/exec.c
index 3155e91..f1691cd 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -982,33 +982,51 @@ void compute_creds(struct linux_binprm *bprm)
        task_unlock(current);
        security_bprm_post_apply_creds(bprm);
 }
-
 EXPORT_SYMBOL(compute_creds);
 
+/*
+ * Arguments are '\0' separated strings found at the location bprm->p
+ * points to; chop off the first by relocating brpm->p to right after
+ * the first '\0' encountered.
+ */
 void remove_arg_zero(struct linux_binprm *bprm)
 {
        if (bprm->argc) {
-               unsigned long offset;
-               char * kaddr;
-               struct page *page;
+               char ch;
 
-               offset = bprm->p % PAGE_SIZE;
-               goto inside;
+               do {
+                       unsigned long offset;
+                       unsigned long index;
+                       char *kaddr;
+                       struct page *page;
 
-               while (bprm->p++, *(kaddr+offset++)) {
-                       if (offset != PAGE_SIZE)
-                               continue;
-                       offset = 0;
-                       kunmap_atomic(kaddr, KM_USER0);
-inside:
-                       page = bprm->page[bprm->p/PAGE_SIZE];
+                       offset = bprm->p & ~PAGE_MASK;
+                       index = bprm->p >> PAGE_SHIFT;
+
+                       page = bprm->page[index];
                        kaddr = kmap_atomic(page, KM_USER0);
-               }
-               kunmap_atomic(kaddr, KM_USER0);
+
+                       /* run through page until we reach end or find NUL */
+                       do {
+                               ch = *(kaddr + offset);
+
+                               /* discard that character... */
+                               bprm->p++;
+                               offset++;
+                       } while (offset < PAGE_SIZE && ch != '\0');
+
+                       kunmap_atomic(kaddr, KM_USER0);
+
+                       /* free the old page */
+                       if (offset == PAGE_SIZE) {
+                               __free_page(page);
+                               bprm->page[index] = NULL;
+                       }
+               } while (ch != '\0');
+
                bprm->argc--;
        }
 }
-
 EXPORT_SYMBOL(remove_arg_zero);
 
 /*
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to