diff options
author | Stanislaw W. Gruszka <stf_xl@wp.pl> | 2005-06-28 23:44:51 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-29 00:20:30 -0400 |
commit | b92eac01c3c6ad5dab5c74d3bc32ac8e9bf4dae7 (patch) | |
tree | 23d8b84caeee73709f6a6837f773ed4b4be84444 /drivers/base/firmware_class.c | |
parent | bcc8ca09920755520ba8a1e2d9f72fe8ff892643 (diff) |
[PATCH] request_firmware(): avoid race conditions
Avoid race occurs when some process have open file descriptor for class
device attributes and already firmware allocated memory are freed. Don't
allow negative loading timeout.
Signed-off-by: Stanislaw W. Gruszka <stf_xl@wp.pl>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/base/firmware_class.c')
-rw-r--r-- | drivers/base/firmware_class.c | 13 |
1 files changed, 10 insertions, 3 deletions
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 97fe13f7f07c..652281402c92 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c | |||
@@ -74,6 +74,8 @@ static ssize_t | |||
74 | firmware_timeout_store(struct class *class, const char *buf, size_t count) | 74 | firmware_timeout_store(struct class *class, const char *buf, size_t count) |
75 | { | 75 | { |
76 | loading_timeout = simple_strtol(buf, NULL, 10); | 76 | loading_timeout = simple_strtol(buf, NULL, 10); |
77 | if (loading_timeout < 0) | ||
78 | loading_timeout = 0; | ||
77 | return count; | 79 | return count; |
78 | } | 80 | } |
79 | 81 | ||
@@ -138,6 +140,10 @@ firmware_loading_store(struct class_device *class_dev, | |||
138 | switch (loading) { | 140 | switch (loading) { |
139 | case 1: | 141 | case 1: |
140 | down(&fw_lock); | 142 | down(&fw_lock); |
143 | if (!fw_priv->fw) { | ||
144 | up(&fw_lock); | ||
145 | break; | ||
146 | } | ||
141 | vfree(fw_priv->fw->data); | 147 | vfree(fw_priv->fw->data); |
142 | fw_priv->fw->data = NULL; | 148 | fw_priv->fw->data = NULL; |
143 | fw_priv->fw->size = 0; | 149 | fw_priv->fw->size = 0; |
@@ -178,7 +184,7 @@ firmware_data_read(struct kobject *kobj, | |||
178 | 184 | ||
179 | down(&fw_lock); | 185 | down(&fw_lock); |
180 | fw = fw_priv->fw; | 186 | fw = fw_priv->fw; |
181 | if (test_bit(FW_STATUS_DONE, &fw_priv->status)) { | 187 | if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) { |
182 | ret_count = -ENODEV; | 188 | ret_count = -ENODEV; |
183 | goto out; | 189 | goto out; |
184 | } | 190 | } |
@@ -238,9 +244,10 @@ firmware_data_write(struct kobject *kobj, | |||
238 | 244 | ||
239 | if (!capable(CAP_SYS_RAWIO)) | 245 | if (!capable(CAP_SYS_RAWIO)) |
240 | return -EPERM; | 246 | return -EPERM; |
247 | |||
241 | down(&fw_lock); | 248 | down(&fw_lock); |
242 | fw = fw_priv->fw; | 249 | fw = fw_priv->fw; |
243 | if (test_bit(FW_STATUS_DONE, &fw_priv->status)) { | 250 | if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) { |
244 | retval = -ENODEV; | 251 | retval = -ENODEV; |
245 | goto out; | 252 | goto out; |
246 | } | 253 | } |
@@ -418,7 +425,7 @@ request_firmware(const struct firmware **firmware_p, const char *name, | |||
418 | 425 | ||
419 | fw_priv = class_get_devdata(class_dev); | 426 | fw_priv = class_get_devdata(class_dev); |
420 | 427 | ||
421 | if (loading_timeout) { | 428 | if (loading_timeout > 0) { |
422 | fw_priv->timeout.expires = jiffies + loading_timeout * HZ; | 429 | fw_priv->timeout.expires = jiffies + loading_timeout * HZ; |
423 | add_timer(&fw_priv->timeout); | 430 | add_timer(&fw_priv->timeout); |
424 | } | 431 | } |