diff options
author | Michal Nazarewicz <mina86@mina86.com> | 2013-11-12 18:11:42 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-12 22:09:35 -0500 |
commit | bb67093796a41e0f2601f5c0022fd8873ed59fee (patch) | |
tree | f52f201e90f5b6678a83bf19a399bec238f906de /drivers/w1/w1.c | |
parent | 75f9e937d24fdf661ebd5c9bed05caa4aad90539 (diff) |
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.c')
-rw-r--r-- | drivers/w1/w1.c | 10 |
1 files changed, 5 insertions, 5 deletions
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index fa932c2f7d97..66efa96c4603 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c | |||
@@ -709,7 +709,7 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn) | |||
709 | 709 | ||
710 | sl->owner = THIS_MODULE; | 710 | sl->owner = THIS_MODULE; |
711 | sl->master = dev; | 711 | sl->master = dev; |
712 | set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); | 712 | set_bit(W1_SLAVE_ACTIVE, &sl->flags); |
713 | 713 | ||
714 | memset(&msg, 0, sizeof(msg)); | 714 | memset(&msg, 0, sizeof(msg)); |
715 | memcpy(&sl->reg_num, rn, sizeof(sl->reg_num)); | 715 | memcpy(&sl->reg_num, rn, sizeof(sl->reg_num)); |
@@ -866,7 +866,7 @@ void w1_slave_found(struct w1_master *dev, u64 rn) | |||
866 | 866 | ||
867 | sl = w1_slave_search_device(dev, tmp); | 867 | sl = w1_slave_search_device(dev, tmp); |
868 | if (sl) { | 868 | if (sl) { |
869 | set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); | 869 | set_bit(W1_SLAVE_ACTIVE, &sl->flags); |
870 | } else { | 870 | } else { |
871 | if (rn && tmp->crc == w1_calc_crc8((u8 *)&rn_le, 7)) | 871 | if (rn && tmp->crc == w1_calc_crc8((u8 *)&rn_le, 7)) |
872 | w1_attach_slave_device(dev, tmp); | 872 | w1_attach_slave_device(dev, tmp); |
@@ -984,14 +984,14 @@ void w1_search_process_cb(struct w1_master *dev, u8 search_type, | |||
984 | struct w1_slave *sl, *sln; | 984 | struct w1_slave *sl, *sln; |
985 | 985 | ||
986 | list_for_each_entry(sl, &dev->slist, w1_slave_entry) | 986 | list_for_each_entry(sl, &dev->slist, w1_slave_entry) |
987 | clear_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); | 987 | clear_bit(W1_SLAVE_ACTIVE, &sl->flags); |
988 | 988 | ||
989 | w1_search_devices(dev, search_type, cb); | 989 | w1_search_devices(dev, search_type, cb); |
990 | 990 | ||
991 | list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { | 991 | list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { |
992 | if (!test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl) | 992 | if (!test_bit(W1_SLAVE_ACTIVE, &sl->flags) && !--sl->ttl) |
993 | w1_slave_detach(sl); | 993 | w1_slave_detach(sl); |
994 | else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags)) | 994 | else if (test_bit(W1_SLAVE_ACTIVE, &sl->flags)) |
995 | sl->ttl = dev->slave_ttl; | 995 | sl->ttl = dev->slave_ttl; |
996 | } | 996 | } |
997 | 997 | ||