aboutsummaryrefslogtreecommitdiffstats
path: root/fs/debugfs
diff options
context:
space:
mode:
authorDavid Rientjes <rientjes@google.com>2012-09-21 05:16:29 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-09-21 13:28:17 -0400
commit36048853c5257a7b6df346b83758ffa776a59e9f (patch)
treec8167eb505d2f8af213faa15acf27c6554783294 /fs/debugfs
parentc46de2263f42fb4bbde411b9126f471e9343cb22 (diff)
debugfs: fix race in u32_array_read and allocate array at open
u32_array_open() is racy when multiple threads read from a file with a seek position of zero, i.e. when two or more simultaneous reads are occurring after the non-seekable files are created. It is possible that file->private_data is double-freed because the threads races between kfree(file->private-data); and file->private_data = NULL; The fix is to only do format_array_alloc() when the file is opened and free it when it is closed. Note that because the file has always been non-seekable, you can't open it and read it multiple times anyway, so the data has always been generated just once. The difference is that now it is generated at open time rather than at the time of the first read, and that avoids the race. Reported-by: Dave Jones <davej@redhat.com> Acked-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Tested-by: Raghavendra <raghavendra.kt@linux.vnet.ibm.com> Signed-off-by: David Rientjes <rientjes@google.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/debugfs')
-rw-r--r--fs/debugfs/file.c33
1 files changed, 11 insertions, 22 deletions
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c
index 2340f6978d6e..a09d3c0aad68 100644
--- a/fs/debugfs/file.c
+++ b/fs/debugfs/file.c
@@ -526,12 +526,6 @@ struct array_data {
526 u32 elements; 526 u32 elements;
527}; 527};
528 528
529static int u32_array_open(struct inode *inode, struct file *file)
530{
531 file->private_data = NULL;
532 return nonseekable_open(inode, file);
533}
534
535static size_t format_array(char *buf, size_t bufsize, const char *fmt, 529static size_t format_array(char *buf, size_t bufsize, const char *fmt,
536 u32 *array, u32 array_size) 530 u32 *array, u32 array_size)
537{ 531{
@@ -573,26 +567,21 @@ static char *format_array_alloc(const char *fmt, u32 *array,
573 return ret; 567 return ret;
574} 568}
575 569
576static ssize_t u32_array_read(struct file *file, char __user *buf, size_t len, 570static int u32_array_open(struct inode *inode, struct file *file)
577 loff_t *ppos)
578{ 571{
579 struct inode *inode = file->f_path.dentry->d_inode;
580 struct array_data *data = inode->i_private; 572 struct array_data *data = inode->i_private;
581 size_t size;
582 573
583 if (*ppos == 0) { 574 file->private_data = format_array_alloc("%u", data->array,
584 if (file->private_data) { 575 data->elements);
585 kfree(file->private_data); 576 if (!file->private_data)
586 file->private_data = NULL; 577 return -ENOMEM;
587 } 578 return nonseekable_open(inode, file);
588 579}
589 file->private_data = format_array_alloc("%u", data->array,
590 data->elements);
591 }
592 580
593 size = 0; 581static ssize_t u32_array_read(struct file *file, char __user *buf, size_t len,
594 if (file->private_data) 582 loff_t *ppos)
595 size = strlen(file->private_data); 583{
584 size_t size = strlen(file->private_data);
596 585
597 return simple_read_from_buffer(buf, len, ppos, 586 return simple_read_from_buffer(buf, len, ppos,
598 file->private_data, size); 587 file->private_data, size);