| From a1e3b0b210950c4573229ccd5754172d4a269549 Mon Sep 17 00:00:00 2001 |
| From: Jens Thoms Toerring <jt@toerring.de> |
| Date: Sun, 31 May 2020 11:53:00 +0200 |
| Subject: [PATCH] regmap: fix alignment issue |
| |
| commit 53d860952c8215cf9ae1ea33409c8cb71ad6ad3d upstream. |
| |
| The assembly and disassembly of data to be sent to or received from |
| a device invoke functions regmap_format_XX() and regmap_parse_XX() |
| that extract or insert data items from or into a buffer, using |
| assignments. In some cases the functions are called with a buffer |
| pointer with an odd address. On architectures with strict alignment |
| requirements this can result in a kernel crash. The assignments |
| have been replaced by functions that take alignment into account. |
| |
| Signed-off-by: Jens Thoms Toerring <jt@toerring.de> |
| Link: https://lore.kernel.org/r/20200531095300.GA27570@toerring.de |
| Signed-off-by: Mark Brown <broonie@kernel.org> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c |
| index 508bbd6ea439..320d23de02c2 100644 |
| --- a/drivers/base/regmap/regmap.c |
| +++ b/drivers/base/regmap/regmap.c |
| @@ -17,6 +17,7 @@ |
| #include <linux/delay.h> |
| #include <linux/log2.h> |
| #include <linux/hwspinlock.h> |
| +#include <asm/unaligned.h> |
| |
| #define CREATE_TRACE_POINTS |
| #include "trace.h" |
| @@ -249,22 +250,20 @@ static void regmap_format_8(void *buf, unsigned int val, unsigned int shift) |
| |
| static void regmap_format_16_be(void *buf, unsigned int val, unsigned int shift) |
| { |
| - __be16 *b = buf; |
| - |
| - b[0] = cpu_to_be16(val << shift); |
| + put_unaligned_be16(val << shift, buf); |
| } |
| |
| static void regmap_format_16_le(void *buf, unsigned int val, unsigned int shift) |
| { |
| - __le16 *b = buf; |
| - |
| - b[0] = cpu_to_le16(val << shift); |
| + put_unaligned_le16(val << shift, buf); |
| } |
| |
| static void regmap_format_16_native(void *buf, unsigned int val, |
| unsigned int shift) |
| { |
| - *(u16 *)buf = val << shift; |
| + u16 v = val << shift; |
| + |
| + memcpy(buf, &v, sizeof(v)); |
| } |
| |
| static void regmap_format_24(void *buf, unsigned int val, unsigned int shift) |
| @@ -280,43 +279,39 @@ static void regmap_format_24(void *buf, unsigned int val, unsigned int shift) |
| |
| static void regmap_format_32_be(void *buf, unsigned int val, unsigned int shift) |
| { |
| - __be32 *b = buf; |
| - |
| - b[0] = cpu_to_be32(val << shift); |
| + put_unaligned_be32(val << shift, buf); |
| } |
| |
| static void regmap_format_32_le(void *buf, unsigned int val, unsigned int shift) |
| { |
| - __le32 *b = buf; |
| - |
| - b[0] = cpu_to_le32(val << shift); |
| + put_unaligned_le32(val << shift, buf); |
| } |
| |
| static void regmap_format_32_native(void *buf, unsigned int val, |
| unsigned int shift) |
| { |
| - *(u32 *)buf = val << shift; |
| + u32 v = val << shift; |
| + |
| + memcpy(buf, &v, sizeof(v)); |
| } |
| |
| #ifdef CONFIG_64BIT |
| static void regmap_format_64_be(void *buf, unsigned int val, unsigned int shift) |
| { |
| - __be64 *b = buf; |
| - |
| - b[0] = cpu_to_be64((u64)val << shift); |
| + put_unaligned_be64((u64) val << shift, buf); |
| } |
| |
| static void regmap_format_64_le(void *buf, unsigned int val, unsigned int shift) |
| { |
| - __le64 *b = buf; |
| - |
| - b[0] = cpu_to_le64((u64)val << shift); |
| + put_unaligned_le64((u64) val << shift, buf); |
| } |
| |
| static void regmap_format_64_native(void *buf, unsigned int val, |
| unsigned int shift) |
| { |
| - *(u64 *)buf = (u64)val << shift; |
| + u64 v = (u64) val << shift; |
| + |
| + memcpy(buf, &v, sizeof(v)); |
| } |
| #endif |
| |
| @@ -333,35 +328,34 @@ static unsigned int regmap_parse_8(const void *buf) |
| |
| static unsigned int regmap_parse_16_be(const void *buf) |
| { |
| - const __be16 *b = buf; |
| - |
| - return be16_to_cpu(b[0]); |
| + return get_unaligned_be16(buf); |
| } |
| |
| static unsigned int regmap_parse_16_le(const void *buf) |
| { |
| - const __le16 *b = buf; |
| - |
| - return le16_to_cpu(b[0]); |
| + return get_unaligned_le16(buf); |
| } |
| |
| static void regmap_parse_16_be_inplace(void *buf) |
| { |
| - __be16 *b = buf; |
| + u16 v = get_unaligned_be16(buf); |
| |
| - b[0] = be16_to_cpu(b[0]); |
| + memcpy(buf, &v, sizeof(v)); |
| } |
| |
| static void regmap_parse_16_le_inplace(void *buf) |
| { |
| - __le16 *b = buf; |
| + u16 v = get_unaligned_le16(buf); |
| |
| - b[0] = le16_to_cpu(b[0]); |
| + memcpy(buf, &v, sizeof(v)); |
| } |
| |
| static unsigned int regmap_parse_16_native(const void *buf) |
| { |
| - return *(u16 *)buf; |
| + u16 v; |
| + |
| + memcpy(&v, buf, sizeof(v)); |
| + return v; |
| } |
| |
| static unsigned int regmap_parse_24(const void *buf) |
| @@ -376,69 +370,67 @@ static unsigned int regmap_parse_24(const void *buf) |
| |
| static unsigned int regmap_parse_32_be(const void *buf) |
| { |
| - const __be32 *b = buf; |
| - |
| - return be32_to_cpu(b[0]); |
| + return get_unaligned_be32(buf); |
| } |
| |
| static unsigned int regmap_parse_32_le(const void *buf) |
| { |
| - const __le32 *b = buf; |
| - |
| - return le32_to_cpu(b[0]); |
| + return get_unaligned_le32(buf); |
| } |
| |
| static void regmap_parse_32_be_inplace(void *buf) |
| { |
| - __be32 *b = buf; |
| + u32 v = get_unaligned_be32(buf); |
| |
| - b[0] = be32_to_cpu(b[0]); |
| + memcpy(buf, &v, sizeof(v)); |
| } |
| |
| static void regmap_parse_32_le_inplace(void *buf) |
| { |
| - __le32 *b = buf; |
| + u32 v = get_unaligned_le32(buf); |
| |
| - b[0] = le32_to_cpu(b[0]); |
| + memcpy(buf, &v, sizeof(v)); |
| } |
| |
| static unsigned int regmap_parse_32_native(const void *buf) |
| { |
| - return *(u32 *)buf; |
| + u32 v; |
| + |
| + memcpy(&v, buf, sizeof(v)); |
| + return v; |
| } |
| |
| #ifdef CONFIG_64BIT |
| static unsigned int regmap_parse_64_be(const void *buf) |
| { |
| - const __be64 *b = buf; |
| - |
| - return be64_to_cpu(b[0]); |
| + return get_unaligned_be64(buf); |
| } |
| |
| static unsigned int regmap_parse_64_le(const void *buf) |
| { |
| - const __le64 *b = buf; |
| - |
| - return le64_to_cpu(b[0]); |
| + return get_unaligned_le64(buf); |
| } |
| |
| static void regmap_parse_64_be_inplace(void *buf) |
| { |
| - __be64 *b = buf; |
| + u64 v = get_unaligned_be64(buf); |
| |
| - b[0] = be64_to_cpu(b[0]); |
| + memcpy(buf, &v, sizeof(v)); |
| } |
| |
| static void regmap_parse_64_le_inplace(void *buf) |
| { |
| - __le64 *b = buf; |
| + u64 v = get_unaligned_le64(buf); |
| |
| - b[0] = le64_to_cpu(b[0]); |
| + memcpy(buf, &v, sizeof(v)); |
| } |
| |
| static unsigned int regmap_parse_64_native(const void *buf) |
| { |
| - return *(u64 *)buf; |
| + u64 v; |
| + |
| + memcpy(&v, buf, sizeof(v)); |
| + return v; |
| } |
| #endif |
| |
| -- |
| 2.27.0 |
| |