It's not the kernel that's preventing bad memory accesses, it's the CPU. The role of the kernel is only to configure the CPU correctly.
More precisely, the hardware component that prevents bad memory accesses is the MMU. When a program accesses a memory address, the address is decoded by the CPU based on the content of the MMU. The MMU establishes a translation from virtual addresses to physical addresses: when the CPU does a load or a store at a certain virtual address, it calculates the corresponding physical address based on the MMU content. The kernel sets the MMU configuration in such a way that each program can only access memory that it's entitled to. Other programs' memory and hardware registers are not mapped at all in a program's memory: these physical addresses have no corresponding virtual address in the MMU configuration for that program.
On a context switch between different processes, the kernel modifies the MMU configuration so that it contains the desired translation for the new process.
Some virtual addresses are not mapped at all, i.e. the MMU translates them to a special “no such address” value. When the processor dereferences an unmapped address, this causes a trap: the processor branches to a predefined location in kernel code. Some traps are legitimate; for example the virtual address could correspond to a page that's in swap space, in which case the kernel code will load the page content from swap then switch back to the original program in such a way that the memory access instruction is executed again. Other traps are not legitimate, in which case the process receives a signal which by default kills the program immediately (and if not branches to the signal handler in the program: in any case the memory access instruction is not completed).