(1) The linear memory is one large array of bytes, and WebAssembly offers load and store instructions to manipulate bytes in this array. There aren't any instructions in WebAssembly that work on native pointers. The Wasm code can only load/store in the linear memory (in the future, any one of the linear memories once multiple memories support is added).
(2) WebAssembly is essentially a sandbox. The WebAssembly code isn't native CPU code on any platform, we have a specification for how the WebAssembly instructions behave in order to interpret or compile them. You can do only the things the specification says you can.
There isn't any instruction pointer you can move (there aren't any registers at all in WebAssembly). You can never have a pointer to the stack (put another way, the stack holds WebAssembly values, not bytes, and does not have any address for you to take). You can't trigger system calls or interrupts (there aren't any such instructions in WebAssembly). You can't mutate or even read your own code, and you can't JIT and produce new code. The Wasm code's access to the outside world is limited to exactly the interface the host embedder gives it.
WebAssembly does not protect against problems inside the sandbox. If you have C++ code that executed undefined behaviour, it can do any possible thing it likes inside that sandbox, and poking the interface to the host in any possible way, but the full C++ UB experience does not transfer to the embedder. In that way, it can be thought of like a mini-process in your process, or as a container for a library.
(3) There aren't any instructions in WebAssembly that would let you read/write the function return stack, and therefore it is impossible to modify.