It seems like my initial understanding was correct - chassis -> map transforms were already published by Slam Toolbox, I just had to select map as a Fixed Frame in Rviz.
The second problem was not using the sim time in Slam Toolbox, so the map was published with the system's timestamp, so the transform only worked in one direction (I could select odom_demo as a fixed frame in RViz, but not the map).
Switching to sim time and checking Use Timestamp in RViz for the Map solved the problem.