aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc
diff options
context:
space:
mode:
authorBertrand Achard <ba@cykian.net>2013-04-29 19:19:26 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-04-29 21:28:28 -0400
commitbc48b9023b0ee7ec4ad0d6b3332804d3b3e77fa8 (patch)
tree8e5a0f78bff1aa581681a0f338602b932c612b8f /drivers/rtc
parent68567112ee3fa3c4eec0c525c39929564809dbb4 (diff)
drivers/rtc/rtc-ds1307.c: long block operations bugfix
The rtc-ds1307 driver does not properly handle block operations bigger than 32 bytes in either of the two modes supported (SMbus native, or emulated if not supported by the SMbus platform driver). It also does not properly handle userland-supplied input (block operation length) through sysfs and may suffer a type of buffer overrun. The driver has been modified with proper input validation, buffer sizes, and now splits block transfers bigger than 32 bytes into separate transfers. Explanation : Buffer size allocated is I2C_SMBUS_BLOCK_MAX which equals to 32 as per the SMbus spec. Reads and write may be up to 56 bytes (to the NVRAM). This patch allocated a 255 byte buffer, the maximum allowable (address is an u8). It's not only a buffer problem, SMbus only supports up to 32 bytes transfer at once, so it's needed to split bigger transfers. Patch successfully tested on 3.2.27; cleanly applies on 3.7-rc4. [akpm@linux-foundation.org: rework code to avoid 80-column overflows] Signed-off-by: Bertrand Achard <ba@cykian.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/rtc')
-rw-r--r--drivers/rtc/rtc-ds1307.c60
1 files changed, 56 insertions, 4 deletions
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index 970a236b147a..a65621c42170 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -4,6 +4,7 @@
4 * Copyright (C) 2005 James Chapman (ds1337 core) 4 * Copyright (C) 2005 James Chapman (ds1337 core)
5 * Copyright (C) 2006 David Brownell 5 * Copyright (C) 2006 David Brownell
6 * Copyright (C) 2009 Matthias Fuchs (rx8025 support) 6 * Copyright (C) 2009 Matthias Fuchs (rx8025 support)
7 * Copyright (C) 2012 Bertrand Achard (nvram access fixes)
7 * 8 *
8 * This program is free software; you can redistribute it and/or modify 9 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as 10 * it under the terms of the GNU General Public License version 2 as
@@ -196,7 +197,7 @@ static s32 ds1307_read_block_data_once(const struct i2c_client *client,
196static s32 ds1307_read_block_data(const struct i2c_client *client, u8 command, 197static s32 ds1307_read_block_data(const struct i2c_client *client, u8 command,
197 u8 length, u8 *values) 198 u8 length, u8 *values)
198{ 199{
199 u8 oldvalues[I2C_SMBUS_BLOCK_MAX]; 200 u8 oldvalues[255];
200 s32 ret; 201 s32 ret;
201 int tries = 0; 202 int tries = 0;
202 203
@@ -222,7 +223,7 @@ static s32 ds1307_read_block_data(const struct i2c_client *client, u8 command,
222static s32 ds1307_write_block_data(const struct i2c_client *client, u8 command, 223static s32 ds1307_write_block_data(const struct i2c_client *client, u8 command,
223 u8 length, const u8 *values) 224 u8 length, const u8 *values)
224{ 225{
225 u8 currvalues[I2C_SMBUS_BLOCK_MAX]; 226 u8 currvalues[255];
226 int tries = 0; 227 int tries = 0;
227 228
228 dev_dbg(&client->dev, "ds1307_write_block_data (length=%d)\n", length); 229 dev_dbg(&client->dev, "ds1307_write_block_data (length=%d)\n", length);
@@ -250,6 +251,57 @@ static s32 ds1307_write_block_data(const struct i2c_client *client, u8 command,
250 251
251/*----------------------------------------------------------------------*/ 252/*----------------------------------------------------------------------*/
252 253
254/* These RTC devices are not designed to be connected to a SMbus adapter.
255 SMbus limits block operations length to 32 bytes, whereas it's not
256 limited on I2C buses. As a result, accesses may exceed 32 bytes;
257 in that case, split them into smaller blocks */
258
259static s32 ds1307_native_smbus_write_block_data(const struct i2c_client *client,
260 u8 command, u8 length, const u8 *values)
261{
262 u8 suboffset = 0;
263
264 if (length <= I2C_SMBUS_BLOCK_MAX)
265 return i2c_smbus_write_i2c_block_data(client,
266 command, length, values);
267
268 while (suboffset < length) {
269 s32 retval = i2c_smbus_write_i2c_block_data(client,
270 command + suboffset,
271 min(I2C_SMBUS_BLOCK_MAX, length - suboffset),
272 values + suboffset);
273 if (retval < 0)
274 return retval;
275
276 suboffset += I2C_SMBUS_BLOCK_MAX;
277 }
278 return length;
279}
280
281static s32 ds1307_native_smbus_read_block_data(const struct i2c_client *client,
282 u8 command, u8 length, u8 *values)
283{
284 u8 suboffset = 0;
285
286 if (length <= I2C_SMBUS_BLOCK_MAX)
287 return i2c_smbus_read_i2c_block_data(client,
288 command, length, values);
289
290 while (suboffset < length) {
291 s32 retval = i2c_smbus_read_i2c_block_data(client,
292 command + suboffset,
293 min(I2C_SMBUS_BLOCK_MAX, length - suboffset),
294 values + suboffset);
295 if (retval < 0)
296 return retval;
297
298 suboffset += I2C_SMBUS_BLOCK_MAX;
299 }
300 return length;
301}
302
303/*----------------------------------------------------------------------*/
304
253/* 305/*
254 * The IRQ logic includes a "real" handler running in IRQ context just 306 * The IRQ logic includes a "real" handler running in IRQ context just
255 * long enough to schedule this workqueue entry. We need a task context 307 * long enough to schedule this workqueue entry. We need a task context
@@ -646,8 +698,8 @@ static int ds1307_probe(struct i2c_client *client,
646 698
647 buf = ds1307->regs; 699 buf = ds1307->regs;
648 if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) { 700 if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) {
649 ds1307->read_block_data = i2c_smbus_read_i2c_block_data; 701 ds1307->read_block_data = ds1307_native_smbus_read_block_data;
650 ds1307->write_block_data = i2c_smbus_write_i2c_block_data; 702 ds1307->write_block_data = ds1307_native_smbus_write_block_data;
651 } else { 703 } else {
652 ds1307->read_block_data = ds1307_read_block_data; 704 ds1307->read_block_data = ds1307_read_block_data;
653 ds1307->write_block_data = ds1307_write_block_data; 705 ds1307->write_block_data = ds1307_write_block_data;