On Mon, Apr 12, 2021 at 01:05:09PM -0700, Kees Cook wrote: > On Mon, Apr 12, 2021 at 10:00:16AM +0200, Peter Zijlstra wrote: > > +struct vpr_data { > > + int (*fn)(pte_t pte, unsigned long addr, void *data); > > + void *data; > > +}; > > Eeerg. This is likely to become an attack target itself. Stored function > pointer with stored (3rd) argument. > > This doesn't seem needed: only DRM uses it, and that's for error > reporting. I'd rather plumb back errors in a way to not have to add > another place in the kernel where we do func+arg stored calling. Is this any better? It does have the stored pointer, but not a stored argument, assuming you don't count returns as arguments I suppose. The alternative is refactoring apply_to_page_range() :-/ --- struct vpr_data { bool (*fn)(pte_t pte, unsigned long addr); unsigned long addr; }; static int vpr_fn(pte_t *pte, unsigned long addr, void *data) { struct vpr_data *vpr = data; if (!vpr->fn(*pte, addr)) { vpr->addr = addr; return -EINVAL; } return 0; } /** * verify_page_range() - Scan (and fill) a range of virtual memory and validate PTEs * @mm: mm identifying the virtual memory map * @addr: starting virtual address of the range * @size: size of the range * @fn: function that verifies the PTEs * * Scan a region of virtual memory, filling in page tables as necessary and * calling a provided function on each leaf, providing a copy of the * page-table-entry. * * Similar apply_to_page_range(), but does not provide direct access to the * page-tables. * * NOTE! this function does not work correctly vs large pages. * * Return: the address that failed verification or 0 on success. */ unsigned long verify_page_range(struct mm_struct *mm, unsigned long addr, unsigned long size, bool (*fn)(pte_t pte, unsigned long addr)) { struct vpr_data vpr = { .fn = fn, .addr = 0, }; apply_to_page_range(mm, addr, size, vpr_fn, &vpr); return vpr.addr; } EXPORT_SYMBOL_GPL(verify_page_range);