I would obligate the user to allocate a shared-memory segment and then provide you with a handle to it. With each request you then verify that the segment exists, that it really does belong to this user, and that it is of sufficient size, and that the coordinates are plausible. Then, the kernel-mode routine can gain access to the memory
(caution: it's virtual!) and use it.
Needless to say, the interface to your kernel module will reside in a library that the user will employ to actually get at whatever functionality you provide. So, all the shared-memory strangeness can be wrapped-up in that "cleverly designed, easy-to-use" library. Although this does not relieve your kernel-routine of the obligation to validate its parameters on the assumption that some "
133t h4x0R" has hijacked it, it does allow you to design some fairly crufty kernel-interfaces and get away with it.