saner calling conventions for csum_and_copy_..._user()

All callers of these primitives will
	* discard anything we might've copied in case of error
	* ignore the csum value in case of error
	* always pass 0xffffffff as the initial sum, so the
resulting csum value (in case of success, that is) will never be 0.

That suggest the following calling conventions:
	* don't pass err_ptr - just return 0 on error.
	* don't bother with zeroing destination, etc. in case of error
	* don't pass the initial sum - just use 0xffffffff.

This commit does the minimal conversion in the instances of csum_and_copy_...();
the changes of actual asm code behind them are done later in the series.
Note that this asm code is often shared with csum_partial_copy_nocheck();
the difference is that csum_partial_copy_nocheck() passes 0 for initial
sum while csum_and_copy_..._user() pass 0xffffffff.  Fortunately, we are
free to pass 0xffffffff in all cases and subsequent patches will use that
freedom without any special comments.

A part that could be split off: parisc and uml/i386 claimed to have
csum_and_copy_to_user() instances of their own, but those were identical
to the generic one, so we simply drop them.  Not sure if it's worth
a separate commit...

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Al Viro 2020-07-11 00:27:49 -04:00
parent 99a2c96d52
commit c693cc4676
19 changed files with 183 additions and 287 deletions

View File

@ -43,7 +43,7 @@ extern __wsum csum_partial(const void *buff, int len, __wsum sum);
*/ */
#define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER #define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER
#define _HAVE_ARCH_CSUM_AND_COPY #define _HAVE_ARCH_CSUM_AND_COPY
__wsum csum_and_copy_from_user(const void __user *src, void *dst, int len, __wsum sum, int *errp); __wsum csum_and_copy_from_user(const void __user *src, void *dst, int len);
__wsum csum_partial_copy_nocheck(const void *src, void *dst, int len); __wsum csum_partial_copy_nocheck(const void *src, void *dst, int len);

View File

@ -325,30 +325,27 @@ csum_partial_cfu_unaligned(const unsigned long __user * src,
} }
__wsum __wsum
csum_and_copy_from_user(const void __user *src, void *dst, int len, csum_and_copy_from_user(const void __user *src, void *dst, int len)
__wsum sum, int *errp)
{ {
unsigned long checksum = (__force u32) sum; unsigned long checksum = ~0U;
unsigned long soff = 7 & (unsigned long) src; unsigned long soff = 7 & (unsigned long) src;
unsigned long doff = 7 & (unsigned long) dst; unsigned long doff = 7 & (unsigned long) dst;
int err = 0;
if (len) { if (len) {
if (!access_ok(src, len)) { if (!access_ok(src, len))
if (errp) *errp = -EFAULT; return 0;
memset(dst, 0, len);
return sum;
}
if (!doff) { if (!doff) {
if (!soff) if (!soff)
checksum = csum_partial_cfu_aligned( checksum = csum_partial_cfu_aligned(
(const unsigned long __user *) src, (const unsigned long __user *) src,
(unsigned long *) dst, (unsigned long *) dst,
len-8, checksum, errp); len-8, checksum, &err);
else else
checksum = csum_partial_cfu_dest_aligned( checksum = csum_partial_cfu_dest_aligned(
(const unsigned long __user *) src, (const unsigned long __user *) src,
(unsigned long *) dst, (unsigned long *) dst,
soff, len-8, checksum, errp); soff, len-8, checksum, &err);
} else { } else {
unsigned long partial_dest; unsigned long partial_dest;
ldq_u(partial_dest, dst); ldq_u(partial_dest, dst);
@ -357,15 +354,15 @@ csum_and_copy_from_user(const void __user *src, void *dst, int len,
(const unsigned long __user *) src, (const unsigned long __user *) src,
(unsigned long *) dst, (unsigned long *) dst,
doff, len-8, checksum, doff, len-8, checksum,
partial_dest, errp); partial_dest, &err);
else else
checksum = csum_partial_cfu_unaligned( checksum = csum_partial_cfu_unaligned(
(const unsigned long __user *) src, (const unsigned long __user *) src,
(unsigned long *) dst, (unsigned long *) dst,
soff, doff, len-8, checksum, soff, doff, len-8, checksum,
partial_dest, errp); partial_dest, &err);
} }
checksum = from64to16 (checksum); checksum = err ? 0 : from64to16 (checksum);
} }
return (__force __wsum)checksum; return (__force __wsum)checksum;
} }
@ -378,7 +375,7 @@ csum_partial_copy_nocheck(const void *src, void *dst, int len)
mm_segment_t oldfs = get_fs(); mm_segment_t oldfs = get_fs();
set_fs(KERNEL_DS); set_fs(KERNEL_DS);
checksum = csum_and_copy_from_user((__force const void __user *)src, checksum = csum_and_copy_from_user((__force const void __user *)src,
dst, len, 0, NULL); dst, len);
set_fs(oldfs); set_fs(oldfs);
return checksum; return checksum;
} }

View File

@ -43,16 +43,15 @@ csum_partial_copy_from_user(const void __user *src, void *dst, int len, __wsum s
#define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER #define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER
#define _HAVE_ARCH_CSUM_AND_COPY #define _HAVE_ARCH_CSUM_AND_COPY
static inline static inline
__wsum csum_and_copy_from_user (const void __user *src, void *dst, __wsum csum_and_copy_from_user(const void __user *src, void *dst, int len)
int len, __wsum sum, int *err_ptr)
{ {
if (access_ok(src, len)) int err = 0;
return csum_partial_copy_from_user(src, dst, len, sum, err_ptr);
if (len) if (!access_ok(src, len))
*err_ptr = -EFAULT; return 0;
return sum; sum = csum_partial_copy_from_user(src, dst, len, ~0U, &err);
return err ? 0 : sum;
} }
/* /*

View File

@ -34,8 +34,7 @@ __wsum csum_partial(const void *buff, int len, __wsum sum);
#define _HAVE_ARCH_CSUM_AND_COPY #define _HAVE_ARCH_CSUM_AND_COPY
extern __wsum csum_and_copy_from_user(const void __user *src, extern __wsum csum_and_copy_from_user(const void __user *src,
void *dst, void *dst,
int len, __wsum sum, int len);
int *csum_err);
extern __wsum csum_partial_copy_nocheck(const void *src, extern __wsum csum_partial_copy_nocheck(const void *src,
void *dst, int len); void *dst, int len);

View File

@ -129,8 +129,7 @@ EXPORT_SYMBOL(csum_partial);
*/ */
__wsum __wsum
csum_and_copy_from_user(const void __user *src, void *dst, csum_and_copy_from_user(const void __user *src, void *dst, int len)
int len, __wsum sum, int *csum_err)
{ {
/* /*
* GCC doesn't like more than 10 operands for the asm * GCC doesn't like more than 10 operands for the asm
@ -138,6 +137,7 @@ csum_and_copy_from_user(const void __user *src, void *dst,
* code. * code.
*/ */
unsigned long tmp1, tmp2; unsigned long tmp1, tmp2;
__wsum sum = ~0U;
__asm__("movel %2,%4\n\t" __asm__("movel %2,%4\n\t"
"btst #1,%4\n\t" /* Check alignment */ "btst #1,%4\n\t" /* Check alignment */
@ -311,9 +311,7 @@ csum_and_copy_from_user(const void __user *src, void *dst,
: "0" (sum), "1" (len), "2" (src), "3" (dst) : "0" (sum), "1" (len), "2" (src), "3" (dst)
); );
*csum_err = tmp2; return tmp2 ? 0 : sum;
return(sum);
} }
EXPORT_SYMBOL(csum_and_copy_from_user); EXPORT_SYMBOL(csum_and_copy_from_user);

View File

@ -60,16 +60,15 @@ __wsum csum_partial_copy_from_user(const void __user *src, void *dst, int len,
#define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER #define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER
static inline static inline
__wsum csum_and_copy_from_user(const void __user *src, void *dst, __wsum csum_and_copy_from_user(const void __user *src, void *dst, int len)
int len, __wsum sum, int *err_ptr)
{ {
if (access_ok(src, len)) __wsum sum = ~0U;
return csum_partial_copy_from_user(src, dst, len, sum, int err = 0;
err_ptr);
if (len)
*err_ptr = -EFAULT;
return sum; if (!access_ok(src, len))
return 0;
sum = csum_partial_copy_from_user(src, dst, len, sum, &err);
return err ? 0 : sum;
} }
/* /*
@ -77,24 +76,23 @@ __wsum csum_and_copy_from_user(const void __user *src, void *dst,
*/ */
#define HAVE_CSUM_COPY_USER #define HAVE_CSUM_COPY_USER
static inline static inline
__wsum csum_and_copy_to_user(const void *src, void __user *dst, int len, __wsum csum_and_copy_to_user(const void *src, void __user *dst, int len)
__wsum sum, int *err_ptr)
{ {
might_fault(); int err = 0;
if (access_ok(dst, len)) { __wsum sum = ~0U;
if (uaccess_kernel())
return __csum_partial_copy_kernel(src,
(__force void *)dst,
len, sum, err_ptr);
else
return __csum_partial_copy_to_user(src,
(__force void *)dst,
len, sum, err_ptr);
}
if (len)
*err_ptr = -EFAULT;
return (__force __wsum)-1; /* invalid checksum */ might_fault();
if (!access_ok(dst, len))
return 0;
if (uaccess_kernel())
sum = __csum_partial_copy_kernel(src,
(__force void *)dst,
len, sum, &err);
else
sum = __csum_partial_copy_to_user(src,
(__force void *)dst,
len, sum, &err);
return err ? 0 : sum;
} }
/* /*

View File

@ -173,25 +173,5 @@ static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
return csum_fold(sum); return csum_fold(sum);
} }
/*
* Copy and checksum to user
*/
#define HAVE_CSUM_COPY_USER
static __inline__ __wsum csum_and_copy_to_user(const void *src,
void __user *dst,
int len, __wsum sum,
int *err_ptr)
{
/* code stolen from include/asm-mips64 */
sum = csum_partial(src, len, sum);
if (copy_to_user(dst, src, len)) {
*err_ptr = -EFAULT;
return (__force __wsum)-1;
}
return sum;
}
#endif #endif

View File

@ -24,10 +24,10 @@ extern __wsum csum_partial_copy_generic(const void *src, void *dst,
#define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER #define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER
extern __wsum csum_and_copy_from_user(const void __user *src, void *dst, extern __wsum csum_and_copy_from_user(const void __user *src, void *dst,
int len, __wsum sum, int *err_ptr); int len);
#define HAVE_CSUM_COPY_USER #define HAVE_CSUM_COPY_USER
extern __wsum csum_and_copy_to_user(const void *src, void __user *dst, extern __wsum csum_and_copy_to_user(const void *src, void __user *dst,
int len, __wsum sum, int *err_ptr); int len);
#define _HAVE_ARCH_CSUM_AND_COPY #define _HAVE_ARCH_CSUM_AND_COPY
#define csum_partial_copy_nocheck(src, dst, len) \ #define csum_partial_copy_nocheck(src, dst, len) \

View File

@ -12,82 +12,56 @@
#include <linux/uaccess.h> #include <linux/uaccess.h>
__wsum csum_and_copy_from_user(const void __user *src, void *dst, __wsum csum_and_copy_from_user(const void __user *src, void *dst,
int len, __wsum sum, int *err_ptr) int len)
{ {
unsigned int csum; unsigned int csum;
int err = 0;
might_sleep(); might_sleep();
if (unlikely(!access_ok(src, len)))
return 0;
allow_read_from_user(src, len); allow_read_from_user(src, len);
*err_ptr = 0;
if (!len) {
csum = 0;
goto out;
}
if (unlikely((len < 0) || !access_ok(src, len))) {
*err_ptr = -EFAULT;
csum = (__force unsigned int)sum;
goto out;
}
csum = csum_partial_copy_generic((void __force *)src, dst, csum = csum_partial_copy_generic((void __force *)src, dst,
len, sum, err_ptr, NULL); len, ~0U, &err, NULL);
if (unlikely(*err_ptr)) { if (unlikely(err)) {
int missing = __copy_from_user(dst, src, len); int missing = __copy_from_user(dst, src, len);
if (missing) { if (missing)
memset(dst + len - missing, 0, missing); csum = 0;
*err_ptr = -EFAULT; else
} else { csum = csum_partial(dst, len, ~0U);
*err_ptr = 0;
}
csum = csum_partial(dst, len, sum);
} }
out:
prevent_read_from_user(src, len); prevent_read_from_user(src, len);
return (__force __wsum)csum; return (__force __wsum)csum;
} }
EXPORT_SYMBOL(csum_and_copy_from_user); EXPORT_SYMBOL(csum_and_copy_from_user);
__wsum csum_and_copy_to_user(const void *src, void __user *dst, int len, __wsum csum_and_copy_to_user(const void *src, void __user *dst, int len)
__wsum sum, int *err_ptr)
{ {
unsigned int csum; unsigned int csum;
int err = 0;
might_sleep(); might_sleep();
if (unlikely(!access_ok(dst, len)))
return 0;
allow_write_to_user(dst, len); allow_write_to_user(dst, len);
*err_ptr = 0;
if (!len) {
csum = 0;
goto out;
}
if (unlikely((len < 0) || !access_ok(dst, len))) {
*err_ptr = -EFAULT;
csum = -1; /* invalid checksum */
goto out;
}
csum = csum_partial_copy_generic(src, (void __force *)dst, csum = csum_partial_copy_generic(src, (void __force *)dst,
len, sum, NULL, err_ptr); len, ~0U, NULL, &err);
if (unlikely(*err_ptr)) { if (unlikely(err)) {
csum = csum_partial(src, len, sum); csum = csum_partial(src, len, ~0U);
if (copy_to_user(dst, src, len)) { if (copy_to_user(dst, src, len))
*err_ptr = -EFAULT; csum = 0;
csum = -1; /* invalid checksum */
}
} }
out:
prevent_write_to_user(dst, len); prevent_write_to_user(dst, len);
return (__force __wsum)csum; return (__force __wsum)csum;
} }

View File

@ -50,15 +50,16 @@ __wsum csum_partial_copy_nocheck(const void *src, void *dst, int len)
#define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER #define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER
static inline static inline
__wsum csum_and_copy_from_user(const void __user *src, void *dst, __wsum csum_and_copy_from_user(const void __user *src, void *dst, int len)
int len, __wsum sum, int *err_ptr)
{ {
if (access_ok(src, len)) int err = 0;
return csum_partial_copy_generic((__force const void *)src, dst, __wsum sum = ~0U;
len, sum, err_ptr, NULL);
if (len) if (!access_ok(src, len))
*err_ptr = -EFAULT; return 0;
return sum; sum = csum_partial_copy_generic((__force const void *)src, dst,
len, sum, &err, NULL);
return err ? 0 : sum;
} }
/* /*
@ -199,16 +200,15 @@ static inline __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
#define HAVE_CSUM_COPY_USER #define HAVE_CSUM_COPY_USER
static inline __wsum csum_and_copy_to_user(const void *src, static inline __wsum csum_and_copy_to_user(const void *src,
void __user *dst, void __user *dst,
int len, __wsum sum, int len)
int *err_ptr)
{ {
if (access_ok(dst, len)) int err = 0;
return csum_partial_copy_generic((__force const void *)src, __wsum sum = ~0U;
dst, len, sum, NULL, err_ptr);
if (len) if (!access_ok(dst, len))
*err_ptr = -EFAULT; return 0;
sum = csum_partial_copy_generic((__force const void *)src,
return (__force __wsum)-1; /* invalid checksum */ dst, len, sum, NULL, &err);
return err ? 0 : sum;
} }
#endif /* __ASM_SH_CHECKSUM_H */ #endif /* __ASM_SH_CHECKSUM_H */

View File

@ -60,19 +60,16 @@ csum_partial_copy_nocheck(const void *src, void *dst, int len)
} }
static inline __wsum static inline __wsum
csum_and_copy_from_user(const void __user *src, void *dst, int len, csum_and_copy_from_user(const void __user *src, void *dst, int len)
__wsum sum, int *err)
{ {
register unsigned long ret asm("o0") = (unsigned long)src; register unsigned long ret asm("o0") = (unsigned long)src;
register char *d asm("o1") = dst; register char *d asm("o1") = dst;
register int l asm("g1") = len; register int l asm("g1") = len;
register __wsum s asm("g7") = sum; register __wsum s asm("g7") = ~0U;
int err = 0;
if (unlikely(!access_ok(src, len))) { if (unlikely(!access_ok(src, len)))
if (len) return 0;
*err = -EFAULT;
return sum;
}
__asm__ __volatile__ ( __asm__ __volatile__ (
".section __ex_table,#alloc\n\t" ".section __ex_table,#alloc\n\t"
@ -83,42 +80,40 @@ csum_and_copy_from_user(const void __user *src, void *dst, int len,
"call __csum_partial_copy_sparc_generic\n\t" "call __csum_partial_copy_sparc_generic\n\t"
" st %8, [%%sp + 64]\n" " st %8, [%%sp + 64]\n"
: "=&r" (ret), "=&r" (d), "=&r" (l), "=&r" (s) : "=&r" (ret), "=&r" (d), "=&r" (l), "=&r" (s)
: "0" (ret), "1" (d), "2" (l), "3" (s), "r" (err) : "0" (ret), "1" (d), "2" (l), "3" (s), "r" (&err)
: "o2", "o3", "o4", "o5", "o7", "g2", "g3", "g4", "g5", : "o2", "o3", "o4", "o5", "o7", "g2", "g3", "g4", "g5",
"cc", "memory"); "cc", "memory");
return (__force __wsum)ret; return err ? 0 : (__force __wsum)ret;
} }
#define HAVE_CSUM_COPY_USER #define HAVE_CSUM_COPY_USER
static inline __wsum static inline __wsum
csum_and_copy_to_user(const void *src, void __user *dst, int len, csum_and_copy_to_user(const void *src, void __user *dst, int len)
__wsum sum, int *err)
{ {
if (!access_ok(dst, len)) { register unsigned long ret asm("o0") = (unsigned long)src;
*err = -EFAULT; register char __user *d asm("o1") = dst;
return sum; register int l asm("g1") = len;
} else { register __wsum s asm("g7") = ~0U;
register unsigned long ret asm("o0") = (unsigned long)src; int err = 0;
register char __user *d asm("o1") = dst;
register int l asm("g1") = len;
register __wsum s asm("g7") = sum;
__asm__ __volatile__ ( if (!access_ok(dst, len))
".section __ex_table,#alloc\n\t" return 0;
".align 4\n\t"
".word 1f,1\n\t" __asm__ __volatile__ (
".previous\n" ".section __ex_table,#alloc\n\t"
"1:\n\t" ".align 4\n\t"
"call __csum_partial_copy_sparc_generic\n\t" ".word 1f,1\n\t"
" st %8, [%%sp + 64]\n" ".previous\n"
: "=&r" (ret), "=&r" (d), "=&r" (l), "=&r" (s) "1:\n\t"
: "0" (ret), "1" (d), "2" (l), "3" (s), "r" (err) "call __csum_partial_copy_sparc_generic\n\t"
: "o2", "o3", "o4", "o5", "o7", " st %8, [%%sp + 64]\n"
"g2", "g3", "g4", "g5", : "=&r" (ret), "=&r" (d), "=&r" (l), "=&r" (s)
"cc", "memory"); : "0" (ret), "1" (d), "2" (l), "3" (s), "r" (&err)
return (__force __wsum)ret; : "o2", "o3", "o4", "o5", "o7",
} "g2", "g3", "g4", "g5",
"cc", "memory");
return err ? 0 : (__force __wsum)ret;
} }
/* ihl is always 5 or greater, almost always is 5, and iph is word aligned /* ihl is always 5 or greater, almost always is 5, and iph is word aligned

View File

@ -51,12 +51,11 @@ long __csum_partial_copy_from_user(const void __user *src,
static inline __wsum static inline __wsum
csum_and_copy_from_user(const void __user *src, csum_and_copy_from_user(const void __user *src,
void *dst, int len, void *dst, int len)
__wsum sum, int *err)
{ {
long ret = __csum_partial_copy_from_user(src, dst, len, sum); long ret = __csum_partial_copy_from_user(src, dst, len, ~0U);
if (ret < 0) if (ret < 0)
*err = -EFAULT; return 0;
return (__force __wsum) ret; return (__force __wsum) ret;
} }
@ -70,12 +69,11 @@ long __csum_partial_copy_to_user(const void *src,
static inline __wsum static inline __wsum
csum_and_copy_to_user(const void *src, csum_and_copy_to_user(const void *src,
void __user *dst, int len, void __user *dst, int len)
__wsum sum, int *err)
{ {
long ret = __csum_partial_copy_to_user(src, dst, len, sum); long ret = __csum_partial_copy_to_user(src, dst, len, ~0U);
if (ret < 0) if (ret < 0)
*err = -EFAULT; return 0;
return (__force __wsum) ret; return (__force __wsum) ret;
} }

View File

@ -44,22 +44,19 @@ static inline __wsum csum_partial_copy_nocheck(const void *src, void *dst, int l
} }
static inline __wsum csum_and_copy_from_user(const void __user *src, static inline __wsum csum_and_copy_from_user(const void __user *src,
void *dst, int len, void *dst, int len)
__wsum sum, int *err_ptr)
{ {
__wsum ret; __wsum ret;
int err = 0;
might_sleep(); might_sleep();
if (!user_access_begin(src, len)) { if (!user_access_begin(src, len))
if (len) return 0;
*err_ptr = -EFAULT;
return sum;
}
ret = csum_partial_copy_generic((__force void *)src, dst, ret = csum_partial_copy_generic((__force void *)src, dst,
len, sum, err_ptr, NULL); len, ~0U, &err, NULL);
user_access_end(); user_access_end();
return ret; return err ? 0 : ret;
} }
/* /*
@ -177,23 +174,19 @@ static inline __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
*/ */
static inline __wsum csum_and_copy_to_user(const void *src, static inline __wsum csum_and_copy_to_user(const void *src,
void __user *dst, void __user *dst,
int len, __wsum sum, int len)
int *err_ptr)
{ {
__wsum ret; __wsum ret;
int err = 0;
might_sleep(); might_sleep();
if (user_access_begin(dst, len)) { if (!user_access_begin(dst, len))
ret = csum_partial_copy_generic(src, (__force void *)dst, return 0;
len, sum, NULL, err_ptr);
user_access_end();
return ret;
}
if (len) ret = csum_partial_copy_generic(src, (__force void *)dst,
*err_ptr = -EFAULT; len, ~0U, NULL, &err);
user_access_end();
return (__force __wsum)-1; /* invalid checksum */ return err ? 0 : ret;
} }
#endif /* _ASM_X86_CHECKSUM_32_H */ #endif /* _ASM_X86_CHECKSUM_32_H */

View File

@ -135,10 +135,8 @@ extern __visible __wsum csum_partial_copy_generic(const void *src, const void *d
int *src_err_ptr, int *dst_err_ptr); int *src_err_ptr, int *dst_err_ptr);
extern __wsum csum_and_copy_from_user(const void __user *src, void *dst, extern __wsum csum_and_copy_from_user(const void __user *src, void *dst, int len);
int len, __wsum isum, int *errp); extern __wsum csum_and_copy_to_user(const void *src, void __user *dst, int len);
extern __wsum csum_and_copy_to_user(const void *src, void __user *dst,
int len, __wsum isum, int *errp);
extern __wsum csum_partial_copy_nocheck(const void *src, void *dst, int len); extern __wsum csum_partial_copy_nocheck(const void *src, void *dst, int len);
/** /**

View File

@ -22,13 +22,15 @@
*/ */
__wsum __wsum
csum_and_copy_from_user(const void __user *src, void *dst, csum_and_copy_from_user(const void __user *src, void *dst,
int len, __wsum isum, int *errp) int len)
{ {
int err = 0;
__wsum isum = ~0U;
might_sleep(); might_sleep();
*errp = 0;
if (!user_access_begin(src, len)) if (!user_access_begin(src, len))
goto out_err; return 0;
/* /*
* Why 6, not 7? To handle odd addresses aligned we * Why 6, not 7? To handle odd addresses aligned we
@ -53,20 +55,15 @@ csum_and_copy_from_user(const void __user *src, void *dst,
} }
} }
isum = csum_partial_copy_generic((__force const void *)src, isum = csum_partial_copy_generic((__force const void *)src,
dst, len, isum, errp, NULL); dst, len, isum, &err, NULL);
user_access_end(); user_access_end();
if (unlikely(*errp)) if (unlikely(err))
goto out_err; isum = 0;
return isum; return isum;
out: out:
user_access_end(); user_access_end();
out_err: return 0;
*errp = -EFAULT;
memset(dst, 0, len);
return isum;
} }
EXPORT_SYMBOL(csum_and_copy_from_user); EXPORT_SYMBOL(csum_and_copy_from_user);
@ -83,16 +80,15 @@ EXPORT_SYMBOL(csum_and_copy_from_user);
*/ */
__wsum __wsum
csum_and_copy_to_user(const void *src, void __user *dst, csum_and_copy_to_user(const void *src, void __user *dst,
int len, __wsum isum, int *errp) int len)
{ {
__wsum ret; __wsum ret, isum = ~0U;
int err = 0;
might_sleep(); might_sleep();
if (!user_access_begin(dst, len)) { if (!user_access_begin(dst, len))
*errp = -EFAULT;
return 0; return 0;
}
if (unlikely((unsigned long)dst & 6)) { if (unlikely((unsigned long)dst & 6)) {
while (((unsigned long)dst & 6) && len >= 2) { while (((unsigned long)dst & 6) && len >= 2) {
@ -107,15 +103,13 @@ csum_and_copy_to_user(const void *src, void __user *dst,
} }
} }
*errp = 0;
ret = csum_partial_copy_generic(src, (void __force *)dst, ret = csum_partial_copy_generic(src, (void __force *)dst,
len, isum, NULL, errp); len, isum, NULL, &err);
user_access_end(); user_access_end();
return ret; return err ? 0 : ret;
out: out:
user_access_end(); user_access_end();
*errp = -EFAULT; return 0;
return isum;
} }
EXPORT_SYMBOL(csum_and_copy_to_user); EXPORT_SYMBOL(csum_and_copy_to_user);

View File

@ -35,27 +35,4 @@ static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
return csum_fold(sum); return csum_fold(sum);
} }
/*
* Copy and checksum to user
*/
#define HAVE_CSUM_COPY_USER
static __inline__ __wsum csum_and_copy_to_user(const void *src,
void __user *dst,
int len, __wsum sum, int *err_ptr)
{
if (access_ok(dst, len)) {
if (copy_to_user(dst, src, len)) {
*err_ptr = -EFAULT;
return (__force __wsum)-1;
}
return csum_partial(src, len, sum);
}
if (len)
*err_ptr = -EFAULT;
return (__force __wsum)-1; /* invalid checksum */
}
#endif #endif

View File

@ -55,14 +55,16 @@ __wsum csum_partial_copy_nocheck(const void *src, void *dst, int len)
#define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER #define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER
static inline static inline
__wsum csum_and_copy_from_user(const void __user *src, void *dst, __wsum csum_and_copy_from_user(const void __user *src, void *dst,
int len, __wsum sum, int *err_ptr) int len)
{ {
if (access_ok(src, len)) int err = 0;
return csum_partial_copy_generic((__force const void *)src, dst,
len, sum, err_ptr, NULL); if (!access_ok(src, len))
if (len) return 0;
*err_ptr = -EFAULT;
return sum; sum = csum_partial_copy_generic((__force const void *)src, dst,
len, ~0U, &err, NULL);
return err ? 0 : sum;
} }
/* /*
@ -243,15 +245,15 @@ static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
*/ */
#define HAVE_CSUM_COPY_USER #define HAVE_CSUM_COPY_USER
static __inline__ __wsum csum_and_copy_to_user(const void *src, static __inline__ __wsum csum_and_copy_to_user(const void *src,
void __user *dst, int len, void __user *dst, int len)
__wsum sum, int *err_ptr)
{ {
if (access_ok(dst, len)) int err = 0;
return csum_partial_copy_generic(src,dst,len,sum,NULL,err_ptr); __wsum sum = ~0U;
if (len) if (!access_ok(dst, len))
*err_ptr = -EFAULT; return 0;
return (__force __wsum)-1; /* invalid checksum */ sum = csum_partial_copy_generic(src,dst,len,sum,NULL,&err);
return err ? 0 : sum;
} }
#endif #endif

View File

@ -24,26 +24,23 @@
#ifndef _HAVE_ARCH_COPY_AND_CSUM_FROM_USER #ifndef _HAVE_ARCH_COPY_AND_CSUM_FROM_USER
static inline static inline
__wsum csum_and_copy_from_user (const void __user *src, void *dst, __wsum csum_and_copy_from_user (const void __user *src, void *dst,
int len, __wsum sum, int *err_ptr) int len)
{ {
if (copy_from_user(dst, src, len)) if (copy_from_user(dst, src, len))
*err_ptr = -EFAULT; return 0;
return csum_partial(dst, len, sum); return csum_partial(dst, len, ~0U);
} }
#endif #endif
#ifndef HAVE_CSUM_COPY_USER #ifndef HAVE_CSUM_COPY_USER
static __inline__ __wsum csum_and_copy_to_user static __inline__ __wsum csum_and_copy_to_user
(const void *src, void __user *dst, int len, __wsum sum, int *err_ptr) (const void *src, void __user *dst, int len)
{ {
sum = csum_partial(src, len, sum); __wsum sum = csum_partial(src, len, ~0U);
if (copy_to_user(dst, src, len) == 0) if (copy_to_user(dst, src, len) == 0)
return sum; return sum;
if (len) return 0;
*err_ptr = -EFAULT;
return (__force __wsum)-1; /* invalid checksum */
} }
#endif #endif

View File

@ -1449,15 +1449,14 @@ size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum,
return 0; return 0;
} }
iterate_and_advance(i, bytes, v, ({ iterate_and_advance(i, bytes, v, ({
int err = 0;
next = csum_and_copy_from_user(v.iov_base, next = csum_and_copy_from_user(v.iov_base,
(to += v.iov_len) - v.iov_len, (to += v.iov_len) - v.iov_len,
v.iov_len, ~0U, &err); v.iov_len);
if (!err) { if (next) {
sum = csum_block_add(sum, next, off); sum = csum_block_add(sum, next, off);
off += v.iov_len; off += v.iov_len;
} }
err ? v.iov_len : 0; next ? 0 : v.iov_len;
}), ({ }), ({
char *p = kmap_atomic(v.bv_page); char *p = kmap_atomic(v.bv_page);
sum = csum_and_memcpy((to += v.bv_len) - v.bv_len, sum = csum_and_memcpy((to += v.bv_len) - v.bv_len,
@ -1491,11 +1490,10 @@ bool csum_and_copy_from_iter_full(void *addr, size_t bytes, __wsum *csum,
if (unlikely(i->count < bytes)) if (unlikely(i->count < bytes))
return false; return false;
iterate_all_kinds(i, bytes, v, ({ iterate_all_kinds(i, bytes, v, ({
int err = 0;
next = csum_and_copy_from_user(v.iov_base, next = csum_and_copy_from_user(v.iov_base,
(to += v.iov_len) - v.iov_len, (to += v.iov_len) - v.iov_len,
v.iov_len, ~0U, &err); v.iov_len);
if (err) if (!next)
return false; return false;
sum = csum_block_add(sum, next, off); sum = csum_block_add(sum, next, off);
off += v.iov_len; off += v.iov_len;
@ -1537,15 +1535,14 @@ size_t csum_and_copy_to_iter(const void *addr, size_t bytes, void *csump,
return 0; return 0;
} }
iterate_and_advance(i, bytes, v, ({ iterate_and_advance(i, bytes, v, ({
int err = 0;
next = csum_and_copy_to_user((from += v.iov_len) - v.iov_len, next = csum_and_copy_to_user((from += v.iov_len) - v.iov_len,
v.iov_base, v.iov_base,
v.iov_len, ~0U, &err); v.iov_len);
if (!err) { if (next) {
sum = csum_block_add(sum, next, off); sum = csum_block_add(sum, next, off);
off += v.iov_len; off += v.iov_len;
} }
err ? v.iov_len : 0; next ? 0 : v.iov_len;
}), ({ }), ({
char *p = kmap_atomic(v.bv_page); char *p = kmap_atomic(v.bv_page);
sum = csum_and_memcpy(p + v.bv_offset, sum = csum_and_memcpy(p + v.bv_offset,