diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/filemap.c | 8 | ||||
-rw-r--r-- | mm/filemap.h | 26 |
2 files changed, 20 insertions, 14 deletions
diff --git a/mm/filemap.c b/mm/filemap.c index 807a463fd5ed..1ed4be2a7654 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -1892,7 +1892,7 @@ int remove_suid(struct dentry *dentry) | |||
1892 | EXPORT_SYMBOL(remove_suid); | 1892 | EXPORT_SYMBOL(remove_suid); |
1893 | 1893 | ||
1894 | size_t | 1894 | size_t |
1895 | __filemap_copy_from_user_iovec(char *vaddr, | 1895 | __filemap_copy_from_user_iovec_inatomic(char *vaddr, |
1896 | const struct iovec *iov, size_t base, size_t bytes) | 1896 | const struct iovec *iov, size_t base, size_t bytes) |
1897 | { | 1897 | { |
1898 | size_t copied = 0, left = 0; | 1898 | size_t copied = 0, left = 0; |
@@ -1908,12 +1908,8 @@ __filemap_copy_from_user_iovec(char *vaddr, | |||
1908 | vaddr += copy; | 1908 | vaddr += copy; |
1909 | iov++; | 1909 | iov++; |
1910 | 1910 | ||
1911 | if (unlikely(left)) { | 1911 | if (unlikely(left)) |
1912 | /* zero the rest of the target like __copy_from_user */ | ||
1913 | if (bytes) | ||
1914 | memset(vaddr, 0, bytes); | ||
1915 | break; | 1912 | break; |
1916 | } | ||
1917 | } | 1913 | } |
1918 | return copied - left; | 1914 | return copied - left; |
1919 | } | 1915 | } |
diff --git a/mm/filemap.h b/mm/filemap.h index 5683cde22055..536979fb4ba7 100644 --- a/mm/filemap.h +++ b/mm/filemap.h | |||
@@ -16,15 +16,23 @@ | |||
16 | #include <linux/uaccess.h> | 16 | #include <linux/uaccess.h> |
17 | 17 | ||
18 | size_t | 18 | size_t |
19 | __filemap_copy_from_user_iovec(char *vaddr, | 19 | __filemap_copy_from_user_iovec_inatomic(char *vaddr, |
20 | const struct iovec *iov, | 20 | const struct iovec *iov, |
21 | size_t base, | 21 | size_t base, |
22 | size_t bytes); | 22 | size_t bytes); |
23 | 23 | ||
24 | /* | 24 | /* |
25 | * Copy as much as we can into the page and return the number of bytes which | 25 | * Copy as much as we can into the page and return the number of bytes which |
26 | * were sucessfully copied. If a fault is encountered then clear the page | 26 | * were sucessfully copied. If a fault is encountered then clear the page |
27 | * out to (offset+bytes) and return the number of bytes which were copied. | 27 | * out to (offset+bytes) and return the number of bytes which were copied. |
28 | * | ||
29 | * NOTE: For this to work reliably we really want copy_from_user_inatomic_nocache | ||
30 | * to *NOT* zero any tail of the buffer that it failed to copy. If it does, | ||
31 | * and if the following non-atomic copy succeeds, then there is a small window | ||
32 | * where the target page contains neither the data before the write, nor the | ||
33 | * data after the write (it contains zero). A read at this time will see | ||
34 | * data that is inconsistent with any ordering of the read and the write. | ||
35 | * (This has been detected in practice). | ||
28 | */ | 36 | */ |
29 | static inline size_t | 37 | static inline size_t |
30 | filemap_copy_from_user(struct page *page, unsigned long offset, | 38 | filemap_copy_from_user(struct page *page, unsigned long offset, |
@@ -60,13 +68,15 @@ filemap_copy_from_user_iovec(struct page *page, unsigned long offset, | |||
60 | size_t copied; | 68 | size_t copied; |
61 | 69 | ||
62 | kaddr = kmap_atomic(page, KM_USER0); | 70 | kaddr = kmap_atomic(page, KM_USER0); |
63 | copied = __filemap_copy_from_user_iovec(kaddr + offset, iov, | 71 | copied = __filemap_copy_from_user_iovec_inatomic(kaddr + offset, iov, |
64 | base, bytes); | 72 | base, bytes); |
65 | kunmap_atomic(kaddr, KM_USER0); | 73 | kunmap_atomic(kaddr, KM_USER0); |
66 | if (copied != bytes) { | 74 | if (copied != bytes) { |
67 | kaddr = kmap(page); | 75 | kaddr = kmap(page); |
68 | copied = __filemap_copy_from_user_iovec(kaddr + offset, iov, | 76 | copied = __filemap_copy_from_user_iovec_inatomic(kaddr + offset, iov, |
69 | base, bytes); | 77 | base, bytes); |
78 | if (bytes - copied) | ||
79 | memset(kaddr + offset + copied, 0, bytes - copied); | ||
70 | kunmap(page); | 80 | kunmap(page); |
71 | } | 81 | } |
72 | return copied; | 82 | return copied; |