Linux is a multi-user operating system, in which full system privileges are solely invested in an administrative user called "root." In addition to the root user, there are many other user accounts and multiple groups. Many users can belong to one group, and one user can belong to many different groups. The file permissions are based on both users and groups, so that other users can't read your files unless they are explicitly given permission. Each file is associated to a user and a group, and permissions can be given out by the owner of the file. The three permissions are read, write, and execute, and they can be turned on or off in three fields: user, group, and other. The user field specifies what the owner of the file can do (read, write, or execute), the group field specifies what users in that group can do, and the other field specifies what everyone else can do. These permissions are displayed using the letters r, w, and x, in three sequential fields corresponding to user, group, and other. In the following example, the user has read and write permissions (the first bold field), the group has read and execute permissions (the middle field), and other has write and execute permissions (the last bold field).
-rw-r-x-wx 1 guest visitors 149 Jul 15 23:59 tmp
In some situations there is a need to allow a non-privileged user to perform a system function that requires root privileges, such as changing a password. One possible solution is to give the user root privileges; however, this also gives the user complete control over the system, which is generally bad from a security perspective. Instead, the program is given the ability to run as if it were the root user, so that the system function can be carried out properly and the user isn't actually given full system control. This type of permission is called the suid (set user ID) permission or bit. When a program with the suid permission is executed by any user, that user's euid (effective user ID) is changed to the uid of the program's owner, and the program is executed. After the program execution completes, the user's euid is changed back to its original value. This bit is denoted by the s in bold in the following file listing. There is also a sgid (set group ID) permission, which does the same thing with the effective group ID.
For example, if a user wanted to change her password, she would run /usr/bin/passwd, which is owned by root and has the suid bit on. The uid would then be changed to root's uid (which is 0) for the execution of passwd, and it would be switched back after the execution completes. Programs that have the suid permission turned on and that are owned by the root user are typically called suid root programs.
This is where changing the flow of program execution becomes very powerful. If the flow of a suid root program can be changed to execute an injected piece of arbitrary code, then the attacker could get the program to do anything as the root user. If the attacker decides to cause a suid root program to spawn a new user shell that she can access, the attacker will have root privileges at a user level. As mentioned earlier, this is generally bad from a security perspective, as it gives the attacker full control of the system as the root user.
I know what you're thinking: "That sounds amazing, but how can the flow of a program be changed if a program is a strict set of rules?" Most programs are written in high-level languages, such as C, and when working in this higher level, the programmer doesn't always see the bigger picture, which involves variable memory, stack calls, execution pointers, and other low-level machine commands that aren't as apparent in the high-level language. A hacker with an understanding of the low-level machine commands that the high-level program compiles into will have a better understanding of the actual execution of the program than the high-level programmer who wrote it without that understanding. So hacking to change the execution flow of a program still isn't actually breaking any of the program rules; it's just knowing more of the rules and using them in ways never anticipated. To carry out these methods of exploitation, and to write programs to prevent these types of exploits, requires a greater understanding of the lower-level programming rules, such as program memory.