Skip to content

Commit 67daea4

Browse files
nicolincgregkh
authored andcommitted
iommufd: Avoid partial fault group delivery in iommufd_fault_fops_read()
commit 091ab6d upstream. The cookie returned by xa_alloc() in iommufd_fault_fops_read() is per fault group, but the inner copy_to_user() runs per fault inside the group. If a copy fails mid-group, xa_erase clears the cookie and the group is restored to the deliver list, yet done is not rolled back. The function returns the partial byte count, with the successfully copied faults sitting at offsets below done carrying the now-erased cookie. The next read() then re-fetches the group, allocates a fresh cookie, and re-delivers every fault including the ones already copied; userspace sees duplicates carrying the new cookie, and a stale cookie that can never be responded to. Use a local group_done variable that tracks the per-group progress inside the inner loop, and only commit done = group_done after the inner loop has finished successfully. On a copy_to_user failure the outer break skips the commit, so done remains at its prior start-of-group baseline; the partial bytes already written past done are undefined to userspace per the read(2) contract, and the next read re-delivers the whole group atomically. Fixes: 07838f7 ("iommufd: Add iommufd fault object") Link: https://patch.msgid.link/r/360cab4d4aeccb0bae275a970e2b3c340a71e0e0.1780343944.git.nicolinc@nvidia.com Cc: stable@vger.kernel.org Assisted-by: Claude:claude-opus-4-7 Signed-off-by: Nicolin Chen <nicolinc@nvidia.com> Reviewed-by: Pranjal Shrivastava <praan@google.com> Reviewed-by: Kevin Tian <kevin.tian@intel.com> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 5539da1 commit 67daea4

1 file changed

Lines changed: 5 additions & 2 deletions

File tree

drivers/iommu/iommufd/eventq.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ static ssize_t iommufd_fault_fops_read(struct file *filep, char __user *buf,
139139

140140
mutex_lock(&fault->mutex);
141141
while ((group = iommufd_fault_deliver_fetch(fault))) {
142+
size_t group_done = done;
143+
142144
if (done >= count ||
143145
group->fault_count * fault_size > count - done) {
144146
iommufd_fault_deliver_restore(fault, group);
@@ -160,16 +162,17 @@ static ssize_t iommufd_fault_fops_read(struct file *filep, char __user *buf,
160162
iommufd_compose_fault_message(&iopf->fault,
161163
&data, idev,
162164
group->cookie);
163-
if (copy_to_user(buf + done, &data, fault_size)) {
165+
if (copy_to_user(buf + group_done, &data, fault_size)) {
164166
xa_erase(&fault->response, group->cookie);
165167
iommufd_fault_deliver_restore(fault, group);
166168
rc = -EFAULT;
167169
break;
168170
}
169-
done += fault_size;
171+
group_done += fault_size;
170172
}
171173
if (rc)
172174
break;
175+
done = group_done;
173176
}
174177
mutex_unlock(&fault->mutex);
175178

0 commit comments

Comments
 (0)