Pull IOMMU fixes from Joerg Roedel: "Two similar fixes for the Intel and AMD IOMMU drivers to add proper access checks before calling handle_mm_fault" * tag 'iommu-fixes-v4.4-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu: iommu/vt-d: Do access checks before calling handle_mm_fault() iommu/amd: Do proper access checking before calling handle_mm_fault()
Unified · Split
| @@ -494,6 +494,22 @@ static void handle_fault_error(struct fault *fault) · 493 unmodified lines | ||
| 494 | 494 | } |
| 495 | 495 | } |
| 496 | 496 | |
| 497 | +static bool access_error(struct vm_area_struct *vma, struct fault *fault) | |
| 498 | +{ | |
| 499 | + unsigned long requested = 0; | |
| 500 | + | |
| 501 | + if (fault->flags & PPR_FAULT_EXEC) | |
| 502 | + requested |= VM_EXEC; | |
| 503 | + | |
| 504 | + if (fault->flags & PPR_FAULT_READ) | |
| 505 | + requested |= VM_READ; | |
| 506 | + | |
| 507 | + if (fault->flags & PPR_FAULT_WRITE) | |
| 508 | + requested |= VM_WRITE; | |
| 509 | + | |
| 510 | + return (requested & ~vma->vm_flags) != 0; | |
| 511 | +} | |
| 512 | + | |
| 497 | 513 | static void do_fault(struct work_struct *work) |
| 498 | 514 | { |
| 499 | 515 | struct fault *fault = container_of(work, struct fault, work); |
| @@ -516,8 +532,8 @@ static void do_fault(struct work_struct *work) · 16 unmodified lines | ||
| 516 | 532 | goto out; |
| 517 | 533 | } |
| 518 | 534 | |
| 519 | − if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))) { | |
| 520 | − /* handle_mm_fault would BUG_ON() */ | |
| 535 | + /* Check if we have the right permissions on the vma */ | |
| 536 | + if (access_error(vma, fault)) { | |
| 521 | 537 | up_read(&mm->mmap_sem); |
| 522 | 538 | handle_fault_error(fault); |
| 523 | 539 | goto out; |
| @@ -484,6 +484,23 @@ struct page_req_dsc { · 483 unmodified lines | ||
| 484 | 484 | }; |
| 485 | 485 | |
| 486 | 486 | #define PRQ_RING_MASK ((0x1000 << PRQ_ORDER) - 0x10) |
| 487 | + | |
| 488 | +static bool access_error(struct vm_area_struct *vma, struct page_req_dsc *req) | |
| 489 | +{ | |
| 490 | + unsigned long requested = 0; | |
| 491 | + | |
| 492 | + if (req->exe_req) | |
| 493 | + requested |= VM_EXEC; | |
| 494 | + | |
| 495 | + if (req->rd_req) | |
| 496 | + requested |= VM_READ; | |
| 497 | + | |
| 498 | + if (req->wr_req) | |
| 499 | + requested |= VM_WRITE; | |
| 500 | + | |
| 501 | + return (requested & ~vma->vm_flags) != 0; | |
| 502 | +} | |
| 503 | + | |
| 487 | 504 | static irqreturn_t prq_event_thread(int irq, void *d) |
| 488 | 505 | { |
| 489 | 506 | struct intel_iommu *iommu = d; |
| @@ -539,6 +556,9 @@ static irqreturn_t prq_event_thread(int irq, void *d) · 49 unmodified lines | ||
| 539 | 556 | if (!vma || address < vma->vm_start) |
| 540 | 557 | goto invalid; |
| 541 | 558 | |
| 559 | + if (access_error(vma, req)) | |
| 560 | + goto invalid; | |
| 561 | + | |
| 542 | 562 | ret = handle_mm_fault(svm->mm, vma, address, |
| 543 | 563 | req->wr_req ? FAULT_FLAG_WRITE : 0); |
| 544 | 564 | if (ret & VM_FAULT_ERROR) |