A buffer is simply a collection of data registers that your program can access. In case of CAN, there is usually one or several "control field registers" where you can find the CAN identifier, message data length, RTR and such things. Followed by 8 bytes of the actual data.
A FIFO (first in first out) is simply a number of buffers, that form a queue. The first item to arrive in the queue is the first to leave. This is handled by hardware, so that you don't have to trigger an interrupt to service each and every CAN message. Most commonly there will be a Rx FIFO for received messages - this makes most sense since these would be causing interrupts, but some CAN controllers also support some manner of Tx FIFO.
In the case of Tx FIFO, it is usually just a mechanism to allow you have several out-going messages (usually 3), but have the CAN controller pick the one with lowest CAN identifier at the next point of message arbitration on the bus. There are also plenty of dumb CAN controllers which requires you to set a manual "Tx prio" instead of simply using the CAN identifier. Avoid these.
It is possible that some microcontrollers support DMA for CAN buffers, so that you can have them stored directly in some convenient chunk of RAM, instead of having to repeatedly poll/interrupt trigger on the CAN peripheral's registers.
Mailboxes is a different alternative. Each mailbox is a buffer (rx and/or tx), but it can be configured to only work with one specific CAN identifier. Meaning that it also have a receive flag and maybe also interrupt possibilities. These are perfect for systems where your MCU is only interested in a limited amounts of identifiers.
One more advanced, but fairly common setup, is to combine a Rx FIFO with mailboxes, so that high priority messages will end up in their dedicated mailbox, while everything else ends up in the FIFO. This could be a good solution for more advanced CAN applications like for example CANopen, where you have countless possible identifiers on the same bus.