https://software.intel.com/content/www/us/en/develop/article...
Essentially an attacker who has the ability to exploit the first stage of a vulnerability will be able to stitch together "gadgets" from the program to build up a second stage of the exploit.
Control flow integrity, to my understanding, applies a validation or restriction of the program's call graph. This limits the attackers ability to just stitch up their own arbitrary call graph. There are 'forward edge' protections (calling a function) and 'reverse edge' protections (ret). But of course there are more ways to control the flow of a program, as this document discusses - like longjmp.
I won't try to get more detailed as I'm not an expert. Hopefully this will help you find more information.