What does bash do in the background once it runs a program?

Does the terminal have its input routed through the bash process into the program currently being run, or is the terminal "disconnected" from the bash process and connected to the new program, preventing bash from intercepting or interfering?

Neither. Assuming a simple foreground command with no pipes or redirects... Input from the user and output back to the user are not routed through bash. But bash is not prevented from interfering, bash simply does not try to interfere.

When a program opens any file or terminal it receives a file descriptor which it uses to read and write. The child inherits copies of the parent's set of open file descriptors.

When you type something at the terminal, it is passed to the process via it's stdin. When it writes something to the user it does to by writing to either the stdout or stderr. Stdin, stdout and stderr are all file descriptors with predictable IDs: by POSIX standard these are numbered 0 1 2 respectively. So when bash runs a program, it first creates the child process with fork and the child automatically inherits the same stdin, stdout and stderr FDs. So the child will automatically read from and write to the exact same terminal.

Note "running a program" is done by calling fork then execve. Pipes and redirects are achieved by replacing stdin, stdout and stderr by calling dup2 between fork and execve.

So the "program" can read directly from the same terminal as bash. This does not stop bash or anything else reading and writing to the same terminal. If bash actually tried to, it could cause a mess. Multiple processes writing results in everything being written in an unpredictable order. Multiple processes reading results in some bytes (key strokes) going to one process and some going to another.

Does bash just freeze in the background, waiting for the program you started to close, or is it doing stuff?

It effectively freezes. More accurately it waits. As far as I know it explicitly calls waitpid() or wait3() (depending on what Unix you run the shell on) which waits for the child to terminate.

When I close a terminal window, am I sending a signal to bash, which in turn sends a signal to the foreground process closing both of them? Or am I sending a signal to the foreground process, which propagates upwards to bash?

Sorry I can't remember this behavior off the top of my head. I believe closing the terminal [window] will usually kill the running process even if it does not read or write anything so I don't believe it's based on a terminal read causing an EOF. I believe closing the terminal causes a signal. I'll edit the answer if I find the right answer.

I do know that some children can effectively intercept keyboard interrupt key sequences preventing bash from receiving them. I'm not sure if that means they are intercepting the signal or just disabling the terminal from generating signals all together.