1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * 4 * Copyright (C) IBM Corporation, 2010 5 * 6 * Author: Anton Blanchard <anton@au.ibm.com> 7 */ 8 #include <linux/export.h> 9 #include <linux/compiler.h> 10 #include <linux/types.h> 11 #include <asm/checksum.h> 12 #include <linux/uaccess.h> 13 14 __wsum csum_and_copy_from_user(const void __user *src, void *dst, 15 int len, __wsum sum, int *err_ptr) 16 { 17 unsigned int csum; 18 19 might_sleep(); 20 allow_read_from_user(src, len); 21 22 *err_ptr = 0; 23 24 if (!len) { 25 csum = 0; 26 goto out; 27 } 28 29 if (unlikely((len < 0) || !access_ok(src, len))) { 30 *err_ptr = -EFAULT; 31 csum = (__force unsigned int)sum; 32 goto out; 33 } 34 35 csum = csum_partial_copy_generic((void __force *)src, dst, 36 len, sum, err_ptr, NULL); 37 38 if (unlikely(*err_ptr)) { 39 int missing = __copy_from_user(dst, src, len); 40 41 if (missing) { 42 memset(dst + len - missing, 0, missing); 43 *err_ptr = -EFAULT; 44 } else { 45 *err_ptr = 0; 46 } 47 48 csum = csum_partial(dst, len, sum); 49 } 50 51 out: 52 prevent_read_from_user(src, len); 53 return (__force __wsum)csum; 54 } 55 EXPORT_SYMBOL(csum_and_copy_from_user); 56 57 __wsum csum_and_copy_to_user(const void *src, void __user *dst, int len, 58 __wsum sum, int *err_ptr) 59 { 60 unsigned int csum; 61 62 might_sleep(); 63 allow_write_to_user(dst, len); 64 65 *err_ptr = 0; 66 67 if (!len) { 68 csum = 0; 69 goto out; 70 } 71 72 if (unlikely((len < 0) || !access_ok(dst, len))) { 73 *err_ptr = -EFAULT; 74 csum = -1; /* invalid checksum */ 75 goto out; 76 } 77 78 csum = csum_partial_copy_generic(src, (void __force *)dst, 79 len, sum, NULL, err_ptr); 80 81 if (unlikely(*err_ptr)) { 82 csum = csum_partial(src, len, sum); 83 84 if (copy_to_user(dst, src, len)) { 85 *err_ptr = -EFAULT; 86 csum = -1; /* invalid checksum */ 87 } 88 } 89 90 out: 91 prevent_write_to_user(dst, len); 92 return (__force __wsum)csum; 93 } 94 EXPORT_SYMBOL(csum_and_copy_to_user); 95