aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mtd/mtdchar.c48
1 files changed, 42 insertions, 6 deletions
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index f2f482bec573..a6e74514e662 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -1123,6 +1123,33 @@ static unsigned long mtdchar_get_unmapped_area(struct file *file,
1123} 1123}
1124#endif 1124#endif
1125 1125
1126static inline unsigned long get_vm_size(struct vm_area_struct *vma)
1127{
1128 return vma->vm_end - vma->vm_start;
1129}
1130
1131static inline resource_size_t get_vm_offset(struct vm_area_struct *vma)
1132{
1133 return (resource_size_t) vma->vm_pgoff << PAGE_SHIFT;
1134}
1135
1136/*
1137 * Set a new vm offset.
1138 *
1139 * Verify that the incoming offset really works as a page offset,
1140 * and that the offset and size fit in a resource_size_t.
1141 */
1142static inline int set_vm_offset(struct vm_area_struct *vma, resource_size_t off)
1143{
1144 pgoff_t pgoff = off >> PAGE_SHIFT;
1145 if (off != (resource_size_t) pgoff << PAGE_SHIFT)
1146 return -EINVAL;
1147 if (off + get_vm_size(vma) - 1 < off)
1148 return -EINVAL;
1149 vma->vm_pgoff = pgoff;
1150 return 0;
1151}
1152
1126/* 1153/*
1127 * set up a mapping for shared memory segments 1154 * set up a mapping for shared memory segments
1128 */ 1155 */
@@ -1132,20 +1159,29 @@ static int mtdchar_mmap(struct file *file, struct vm_area_struct *vma)
1132 struct mtd_file_info *mfi = file->private_data; 1159 struct mtd_file_info *mfi = file->private_data;
1133 struct mtd_info *mtd = mfi->mtd; 1160 struct mtd_info *mtd = mfi->mtd;
1134 struct map_info *map = mtd->priv; 1161 struct map_info *map = mtd->priv;
1135 unsigned long start; 1162 resource_size_t start, off;
1136 unsigned long off; 1163 unsigned long len, vma_len;
1137 u32 len;
1138 1164
1139 if (mtd->type == MTD_RAM || mtd->type == MTD_ROM) { 1165 if (mtd->type == MTD_RAM || mtd->type == MTD_ROM) {
1140 off = vma->vm_pgoff << PAGE_SHIFT; 1166 off = get_vm_offset(vma);
1141 start = map->phys; 1167 start = map->phys;
1142 len = PAGE_ALIGN((start & ~PAGE_MASK) + map->size); 1168 len = PAGE_ALIGN((start & ~PAGE_MASK) + map->size);
1143 start &= PAGE_MASK; 1169 start &= PAGE_MASK;
1144 if ((vma->vm_end - vma->vm_start + off) > len) 1170 vma_len = get_vm_size(vma);
1171
1172 /* Overflow in off+len? */
1173 if (vma_len + off < off)
1174 return -EINVAL;
1175 /* Does it fit in the mapping? */
1176 if (vma_len + off > len)
1145 return -EINVAL; 1177 return -EINVAL;
1146 1178
1147 off += start; 1179 off += start;
1148 vma->vm_pgoff = off >> PAGE_SHIFT; 1180 /* Did that overflow? */
1181 if (off < start)
1182 return -EINVAL;
1183 if (set_vm_offset(vma, off) < 0)
1184 return -EINVAL;
1149 vma->vm_flags |= VM_IO | VM_RESERVED; 1185 vma->vm_flags |= VM_IO | VM_RESERVED;
1150 1186
1151#ifdef pgprot_noncached 1187#ifdef pgprot_noncached