Commit ac20427e authored by Neil Horman's avatar Neil Horman Committed by Linus Torvalds

[PATCH] add check to /proc/devices read routines

Patch to add check to get_chrdev_list and get_blkdev_list to prevent reads
of /proc/devices from spilling over the provided page if more than 4096
bytes of string data are generated from all the registered character and
block devices in a system
Signed-off-by: default avatarNeil Horman <nhorman@redhat.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: <viro@parcelfarce.linux.theplanet.co.uk>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 3bc1ee3e
...@@ -40,7 +40,7 @@ static inline int major_to_index(int major) ...@@ -40,7 +40,7 @@ static inline int major_to_index(int major)
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
/* get block device names in somewhat random order */ /* get block device names in somewhat random order */
int get_blkdev_list(char *p) int get_blkdev_list(char *p, int used)
{ {
struct blk_major_name *n; struct blk_major_name *n;
int i, len; int i, len;
...@@ -49,10 +49,18 @@ int get_blkdev_list(char *p) ...@@ -49,10 +49,18 @@ int get_blkdev_list(char *p)
down(&block_subsys_sem); down(&block_subsys_sem);
for (i = 0; i < ARRAY_SIZE(major_names); i++) { for (i = 0; i < ARRAY_SIZE(major_names); i++) {
for (n = major_names[i]; n; n = n->next) for (n = major_names[i]; n; n = n->next) {
/*
* If the curent string plus the 5 extra characters
* in the line would run us off the page, then we're done
*/
if ((len + used + strlen(n->name) + 5) >= PAGE_SIZE)
goto page_full;
len += sprintf(p+len, "%3d %s\n", len += sprintf(p+len, "%3d %s\n",
n->major, n->name); n->major, n->name);
} }
}
page_full:
up(&block_subsys_sem); up(&block_subsys_sem);
return len; return len;
......
...@@ -56,10 +56,21 @@ int get_chrdev_list(char *page) ...@@ -56,10 +56,21 @@ int get_chrdev_list(char *page)
down(&chrdevs_lock); down(&chrdevs_lock);
for (i = 0; i < ARRAY_SIZE(chrdevs) ; i++) { for (i = 0; i < ARRAY_SIZE(chrdevs) ; i++) {
for (cd = chrdevs[i]; cd; cd = cd->next) for (cd = chrdevs[i]; cd; cd = cd->next) {
/*
* if the current name, plus the 5 extra characters
* in the device line for this entry
* would run us off the page, we're done
*/
if ((len+strlen(cd->name) + 5) >= PAGE_SIZE)
goto page_full;
len += sprintf(page+len, "%3d %s\n", len += sprintf(page+len, "%3d %s\n",
cd->major, cd->name); cd->major, cd->name);
} }
}
page_full:
up(&chrdevs_lock); up(&chrdevs_lock);
return len; return len;
......
...@@ -451,7 +451,7 @@ static int devices_read_proc(char *page, char **start, off_t off, ...@@ -451,7 +451,7 @@ static int devices_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data) int count, int *eof, void *data)
{ {
int len = get_chrdev_list(page); int len = get_chrdev_list(page);
len += get_blkdev_list(page+len); len += get_blkdev_list(page+len, len);
return proc_calc_metrics(page, start, off, count, eof, len); return proc_calc_metrics(page, start, off, count, eof, len);
} }
......
...@@ -224,7 +224,7 @@ static inline void free_disk_stats(struct gendisk *disk) ...@@ -224,7 +224,7 @@ static inline void free_disk_stats(struct gendisk *disk)
extern void disk_round_stats(struct gendisk *disk); extern void disk_round_stats(struct gendisk *disk);
/* drivers/block/genhd.c */ /* drivers/block/genhd.c */
extern int get_blkdev_list(char *); extern int get_blkdev_list(char *, int);
extern void add_disk(struct gendisk *disk); extern void add_disk(struct gendisk *disk);
extern void del_gendisk(struct gendisk *gp); extern void del_gendisk(struct gendisk *gp);
extern void unlink_gendisk(struct gendisk *gp); extern void unlink_gendisk(struct gendisk *gp);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment