diff options
author | Michal Nazarewicz <mina86@mina86.com> | 2013-11-13 00:11:42 +0100 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-13 04:09:35 +0100 |
commit | bb67093796a41e0f2601f5c0022fd8873ed59fee (patch) | |
tree | f52f201e90f5b6678a83bf19a399bec238f906de /drivers/w1/w1.h | |
parent | drivers/w1/masters/ds1wm.cuse dev_get_platdata() (diff) | |
download | linux-bb67093796a41e0f2601f5c0022fd8873ed59fee.tar.xz linux-bb67093796a41e0f2601f5c0022fd8873ed59fee.zip |
drivers: w1: make w1_slave::flags long to avoid memory corruption
On architectures where long is more then 32 bits, modifying a 32-bit field
with set_bit (and other atomic bit operations) may cause bytes following
the field to by modified.
Because the endianness of the bits within a field is the native endianness
of the CPU[1], on big-endian machines, bit number zero is in the last byte
of the field.
Therefore, `set_bit(0, ptr)' on a 64-bit big-endian machine is roughly
equivalent to `((char *)ptr)[7] |= 1', and since w1 driver uses a 32-bit
field for holding the flags, this causes bytes beyond the field to be
modified.
[1] From Documentation/atomic_ops.txt:
Native atomic bit operations are defined to operate on objects
aligned to the size of an "unsigned long" C data type, and are
least of that size. The endianness of the bits within each
"unsigned long" are the native endianness of the cpu.
Signed-off-by: Michal Nazarewicz <mina86@mina86.com>
Cc: Evgeniy Polyakov <zbr@ioremap.net>
Cc: Greg KH <greg@kroah.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/w1/w1.h')
-rw-r--r-- | drivers/w1/w1.h | 2 |
1 files changed, 1 insertions, 1 deletions
diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h index 45908e56c2f8..ca8081a101d6 100644 --- a/drivers/w1/w1.h +++ b/drivers/w1/w1.h @@ -67,8 +67,8 @@ struct w1_slave struct w1_reg_num reg_num; atomic_t refcnt; u8 rom[9]; - u32 flags; int ttl; + unsigned long flags; struct w1_master *master; struct w1_family *family; |