One way to prevent a program from doing wrong would be to restrict the authority it gets from its identity. If a user would only hand over a partial set of her rights to the program the program itself could do less harm. Still, it could use the existing rights for illegal actions. Capability based systems use the approach of transfering only the rights needed for an operation to a program. But to prevent the abuse of even those rights they typically follow a programming style that tries to restrict resource access to objects which the program got from the user directly - so called call inversion pattern.
Another way to prevent right abuse by programs would be to restrict the actions of the program. Say by defining a policy which describes which resources a program can access in which way. This puts a program into a sandbox like structure which it cannot leave no matter how powerful the users identity otherwise is. SELinux follows this approach.
All access control needs to create restrictions and by doing so faces the problem of the granularity of restrictions. Restricting access on class base (e.g. allow socket access) is different from restricting access on instance level (port 80 or socket number 4711). While we would certainly always prefer instance level based restrictions we will not be able to do so in all cases due to the complexity of configuration.