IB/ipath: Don't corrupt pending mmap list when unmapped objects are freed
Fix the pending mmap code so it doesn't corrupt the list of pending mmaps and crash the machine when pending mmaps are destroyed without first being mapped. Also, remove an unused variable, and use standard kernel lists instead of our own homebrewed linked list implementation to keep the pending mmap list. Signed-off-by: Robert Walsh <robert.walsh@qlogic.com> Signed-off-by: Ralph Campbell <ralph.campbell@qlogic.com> Signed-off-by: Roland Dreier <rolandd@cisco.com>
Este cometimento está contido em:

cometido por
Roland Dreier

ascendente
9ba6d5529d
cometimento
6b66b2da1e
@@ -46,6 +46,11 @@ void ipath_release_mmap_info(struct kref *ref)
|
||||
{
|
||||
struct ipath_mmap_info *ip =
|
||||
container_of(ref, struct ipath_mmap_info, ref);
|
||||
struct ipath_ibdev *dev = to_idev(ip->context->device);
|
||||
|
||||
spin_lock_irq(&dev->pending_lock);
|
||||
list_del(&ip->pending_mmaps);
|
||||
spin_unlock_irq(&dev->pending_lock);
|
||||
|
||||
vfree(ip->obj);
|
||||
kfree(ip);
|
||||
@@ -60,14 +65,12 @@ static void ipath_vma_open(struct vm_area_struct *vma)
|
||||
struct ipath_mmap_info *ip = vma->vm_private_data;
|
||||
|
||||
kref_get(&ip->ref);
|
||||
ip->mmap_cnt++;
|
||||
}
|
||||
|
||||
static void ipath_vma_close(struct vm_area_struct *vma)
|
||||
{
|
||||
struct ipath_mmap_info *ip = vma->vm_private_data;
|
||||
|
||||
ip->mmap_cnt--;
|
||||
kref_put(&ip->ref, ipath_release_mmap_info);
|
||||
}
|
||||
|
||||
@@ -87,7 +90,7 @@ int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
|
||||
struct ipath_ibdev *dev = to_idev(context->device);
|
||||
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
|
||||
unsigned long size = vma->vm_end - vma->vm_start;
|
||||
struct ipath_mmap_info *ip, **pp;
|
||||
struct ipath_mmap_info *ip, *pp;
|
||||
int ret = -EINVAL;
|
||||
|
||||
/*
|
||||
@@ -96,15 +99,16 @@ int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
|
||||
* CQ, QP, or SRQ is soon followed by a call to mmap().
|
||||
*/
|
||||
spin_lock_irq(&dev->pending_lock);
|
||||
for (pp = &dev->pending_mmaps; (ip = *pp); pp = &ip->next) {
|
||||
list_for_each_entry_safe(ip, pp, &dev->pending_mmaps,
|
||||
pending_mmaps) {
|
||||
/* Only the creator is allowed to mmap the object */
|
||||
if (context != ip->context || (void *) offset != ip->obj)
|
||||
if (context != ip->context || (__u64) offset != ip->offset)
|
||||
continue;
|
||||
/* Don't allow a mmap larger than the object. */
|
||||
if (size > ip->size)
|
||||
break;
|
||||
|
||||
*pp = ip->next;
|
||||
list_del_init(&ip->pending_mmaps);
|
||||
spin_unlock_irq(&dev->pending_lock);
|
||||
|
||||
ret = remap_vmalloc_range(vma, ip->obj, 0);
|
||||
@@ -119,3 +123,51 @@ int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate information for ipath_mmap
|
||||
*/
|
||||
struct ipath_mmap_info *ipath_create_mmap_info(struct ipath_ibdev *dev,
|
||||
u32 size,
|
||||
struct ib_ucontext *context,
|
||||
void *obj) {
|
||||
struct ipath_mmap_info *ip;
|
||||
|
||||
ip = kmalloc(sizeof *ip, GFP_KERNEL);
|
||||
if (!ip)
|
||||
goto bail;
|
||||
|
||||
size = PAGE_ALIGN(size);
|
||||
|
||||
spin_lock_irq(&dev->mmap_offset_lock);
|
||||
if (dev->mmap_offset == 0)
|
||||
dev->mmap_offset = PAGE_SIZE;
|
||||
ip->offset = dev->mmap_offset;
|
||||
dev->mmap_offset += size;
|
||||
spin_unlock_irq(&dev->mmap_offset_lock);
|
||||
|
||||
INIT_LIST_HEAD(&ip->pending_mmaps);
|
||||
ip->size = size;
|
||||
ip->context = context;
|
||||
ip->obj = obj;
|
||||
kref_init(&ip->ref);
|
||||
|
||||
bail:
|
||||
return ip;
|
||||
}
|
||||
|
||||
void ipath_update_mmap_info(struct ipath_ibdev *dev,
|
||||
struct ipath_mmap_info *ip,
|
||||
u32 size, void *obj) {
|
||||
size = PAGE_ALIGN(size);
|
||||
|
||||
spin_lock_irq(&dev->mmap_offset_lock);
|
||||
if (dev->mmap_offset == 0)
|
||||
dev->mmap_offset = PAGE_SIZE;
|
||||
ip->offset = dev->mmap_offset;
|
||||
dev->mmap_offset += size;
|
||||
spin_unlock_irq(&dev->mmap_offset_lock);
|
||||
|
||||
ip->size = size;
|
||||
ip->obj = obj;
|
||||
}
|
||||
|
Criar uma nova questão referindo esta
Bloquear um utilizador