I am learning about buffer overflow attacks and one thing that i am not able to understand is that in most operating systems an stack is may not necessarily be a contiguous block of memory in the physical memory. if that's true then how can an overflow overwrite the other data in stack ?
The stack may not be physically contiguous but it is logically contiguous. If your function return pointer is logically 20 bytes or 2000 bytes above the current stack pointer then you only need to offset a write by the proper amount to smash it. The stack must always be logically contiguous to function correctly.
A much bigger problem for modern exploiters is that stack pages should be marked as non-executable. The only pages marked as executable should be the code (program) pages, and those should be marked as non-writeable. This doesn't defeat all stack overflow attacks, but it defeats the "classic" ones.
Logical to physical address mapping is done by the segmentation and paging units of the CPU. A process (which means both your program and any malicious code that gets executed in it's address space) doesn't know about this mapping; they see a continuous address space, even if that address space might not be mapped to continuous regions of physical memory by the paging unit.
Your example doesn't really work out, because page size, at least on the x86, is at least 4k. So we can't have a page boundary between 0x100 and 0x104. These addresses would map to the same physical memory, because they'd lie in the same page.
However, that doesn't matter, because even if your malicious code wrote data over a page boundary, that wouldn't magically turn off the paging unit; instead, the paging unit would translate the virtual address to the physical address of the other page.
It's really rather simple. Assuming we're dealing with 4k pages, pages start at physical addresses with the last 12 bits zeroed.
The last 12 bits of any virtual address are an offset into a page. The other bits of an address are used to identify the page in a multilayer page table, which in turn stores the physical address of the page.
A running program (and that includes any malicious code running in the same address space) can't write directly to physical adresses; any address supplied by machine instructions is considered to be a virtual address and always ends up getting translated by the segmentation and the paging unit of the cpu, so the "gap" between 0x1000 and 0x2000 that you perceive doesn't exist for the program.