Am I doing something obviously wrong?
Yes.
First one - raw_lv_request() should be called before using the live raw stream, and raw_lv_release after you are done with it. Keep in mind there may or may not be other tasks using this raw stream - such as the raw-based image overlays, if any of them is enabled. The LiveView raw stream is a shared resource, managed with reference counting (using these two functions).
Second one - by default, there is only one Bayer buffer, written over and over, from a DMA channel. If you turn off the raw stream, and no other tasks are using it, you can get away with that - which appears to be what you are trying to do. You can, however, redirect the image buffer for the next frame, into your own buffer(s).
The silent picture module allocates memory for each frame, so you can use that as reference.
Third, reversing the bytes (for DNG) is done in-place, destroying the original image. The corruption you are seeing might be that - easy to check. If you want to reuse the old image after reversing the bytes, you may need to memcpy first into your buffer, and reverse only that. If you also need to modify the raw_info structure (which is global), you will need a local copy of that structure, too.
Fourth, you may want to use the lossless compression (which is much faster, doesn't destroy the input buffers, and the result is directly usable in a DNG). You will need to work on top of some crop_rec_4k* branch for that.
And while you are at it, you may also want to check the full sensor readout presets from Danne's builds.