aboutsummaryrefslogtreecommitdiff
path: root/lib/strncpy_from_user.c
diff options
context:
space:
mode:
authorSanrio Alvares <salvares@codeaurora.org>2016-02-08 18:42:08 -0800
committerMister Oyster <oysterized@gmail.com>2017-04-11 10:59:17 +0200
commit45246aeeab710cb51832d0549fc8ff8ebf048f34 (patch)
tree9dfedbf33ec6908fe7934ba75261c4c7b99eb302 /lib/strncpy_from_user.c
parent82832b1ca6bf78e365b67cf260f2a41c78ad2a93 (diff)
lib: align source before using optimized implementation
If the source is at the boundary of the VMA, loading one word at a time can cause an alignment fault when the adjacent VMA is IO mapped. Do byte-by-byte copy until source aligns to 8 bytes and then continue with optimized version. CRs-Fixed: 973724 Change-Id: I05e085597c58169fc6e275508a907029b9c7ec64 Signed-off-by: Sanrio Alvares <salvares@codeaurora.org> Signed-off-by: Pranav Vashi <neobuddy89@gmail.com>
Diffstat (limited to 'lib/strncpy_from_user.c')
-rw-r--r--lib/strncpy_from_user.c17
1 files changed, 17 insertions, 0 deletions
diff --git a/lib/strncpy_from_user.c b/lib/strncpy_from_user.c
index bb2b201d6..2cd748031 100644
--- a/lib/strncpy_from_user.c
+++ b/lib/strncpy_from_user.c
@@ -13,6 +13,8 @@
(((long) dst | (long) src) & (sizeof(long) - 1))
#endif
+#define CHECK_ALIGN(v, a) ((((unsigned long)(v)) & ((a) - 1)) == 0)
+
/*
* Do a strncpy, return length of string without final '\0'.
* 'count' is the user-supplied count (return 'count' if we
@@ -34,6 +36,21 @@ static inline long do_strncpy_from_user(char *dst, const char __user *src, long
if (IS_UNALIGNED(src, dst))
goto byte_at_a_time;
+ /* Copy a byte at a time until we align to 8 bytes */
+ while (max && (!CHECK_ALIGN(src + res, 8))) {
+ char c;
+ int ret;
+
+ ret = __get_user(c, src + res);
+ if (ret)
+ return -ret;
+ dst[res] = c;
+ if (!c)
+ return res;
+ res++;
+ max--;
+ }
+
while (max >= sizeof(unsigned long)) {
unsigned long c, data;