Skip to content

Commit 1c82abc

Browse files
Jack Morgensteingregkh
authored andcommitted
IB/mlx4: Mark user MR as writable if actual virtual memory is writable
commit d8f9cc3 upstream. To allow rereg_user_mr to modify the MR from read-only to writable without using get_user_pages again, we needed to define the initial MR as writable. However, this was originally done unconditionally, without taking into account the writability of the underlying virtual memory. As a result, any attempt to register a read-only MR over read-only virtual memory failed. To fix this, do not add the writable flag bit when the user virtual memory is not writable (e.g. const memory). However, when the underlying memory is NOT writable (and we therefore do not define the initial MR as writable), the IB core adds a "force writable" flag to its user-pages request. If this succeeds, the reg_user_mr caller gets a writable copy of the original pages. If the user-space caller then does a rereg_user_mr operation to enable writability, this will succeed. This should not be allowed, since the original virtual memory was not writable. Cc: <[email protected]> Fixes: 9376932 ("IB/mlx4_ib: Add support for user MR re-registration") Signed-off-by: Jason Gunthorpe <[email protected]> Signed-off-by: Jack Morgenstein <[email protected]> Signed-off-by: Leon Romanovsky <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 49e1083 commit 1c82abc

File tree

1 file changed

+42
-8
lines changed
  • drivers/infiniband/hw/mlx4

1 file changed

+42
-8
lines changed

drivers/infiniband/hw/mlx4/mr.c

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,40 @@ int mlx4_ib_umem_write_mtt(struct mlx4_ib_dev *dev, struct mlx4_mtt *mtt,
131131
return err;
132132
}
133133

134+
static struct ib_umem *mlx4_get_umem_mr(struct ib_ucontext *context, u64 start,
135+
u64 length, u64 virt_addr,
136+
int access_flags)
137+
{
138+
/*
139+
* Force registering the memory as writable if the underlying pages
140+
* are writable. This is so rereg can change the access permissions
141+
* from readable to writable without having to run through ib_umem_get
142+
* again
143+
*/
144+
if (!ib_access_writable(access_flags)) {
145+
struct vm_area_struct *vma;
146+
147+
down_read(&current->mm->mmap_sem);
148+
/*
149+
* FIXME: Ideally this would iterate over all the vmas that
150+
* cover the memory, but for now it requires a single vma to
151+
* entirely cover the MR to support RO mappings.
152+
*/
153+
vma = find_vma(current->mm, start);
154+
if (vma && vma->vm_end >= start + length &&
155+
vma->vm_start <= start) {
156+
if (vma->vm_flags & VM_WRITE)
157+
access_flags |= IB_ACCESS_LOCAL_WRITE;
158+
} else {
159+
access_flags |= IB_ACCESS_LOCAL_WRITE;
160+
}
161+
162+
up_read(&current->mm->mmap_sem);
163+
}
164+
165+
return ib_umem_get(context, start, length, access_flags, 0);
166+
}
167+
134168
struct ib_mr *mlx4_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
135169
u64 virt_addr, int access_flags,
136170
struct ib_udata *udata)
@@ -145,10 +179,8 @@ struct ib_mr *mlx4_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
145179
if (!mr)
146180
return ERR_PTR(-ENOMEM);
147181

148-
/* Force registering the memory as writable. */
149-
/* Used for memory re-registeration. HCA protects the access */
150-
mr->umem = ib_umem_get(pd->uobject->context, start, length,
151-
access_flags | IB_ACCESS_LOCAL_WRITE, 0);
182+
mr->umem = mlx4_get_umem_mr(pd->uobject->context, start, length,
183+
virt_addr, access_flags);
152184
if (IS_ERR(mr->umem)) {
153185
err = PTR_ERR(mr->umem);
154186
goto err_free;
@@ -215,6 +247,9 @@ int mlx4_ib_rereg_user_mr(struct ib_mr *mr, int flags,
215247
}
216248

217249
if (flags & IB_MR_REREG_ACCESS) {
250+
if (ib_access_writable(mr_access_flags) && !mmr->umem->writable)
251+
return -EPERM;
252+
218253
err = mlx4_mr_hw_change_access(dev->dev, *pmpt_entry,
219254
convert_access(mr_access_flags));
220255

@@ -228,10 +263,9 @@ int mlx4_ib_rereg_user_mr(struct ib_mr *mr, int flags,
228263

229264
mlx4_mr_rereg_mem_cleanup(dev->dev, &mmr->mmr);
230265
ib_umem_release(mmr->umem);
231-
mmr->umem = ib_umem_get(mr->uobject->context, start, length,
232-
mr_access_flags |
233-
IB_ACCESS_LOCAL_WRITE,
234-
0);
266+
mmr->umem =
267+
mlx4_get_umem_mr(mr->uobject->context, start, length,
268+
virt_addr, mr_access_flags);
235269
if (IS_ERR(mmr->umem)) {
236270
err = PTR_ERR(mmr->umem);
237271
/* Prevent mlx4_ib_dereg_mr from free'ing invalid pointer */

0 commit comments

Comments
 (0)