New to buffer overflow through image parsing. How can one design a secure library that parses images, and ensure there are no security vulnerabilities in it? It is common knowledge that image parsing libraries are vulnerable to Buffer Overflow, so I would appreciate it if someone could specifically explain how to secure image parsing libraries against buffer overflow.
There are a couple of obvious things which are not limited to image parsing libraries:
- Don't assume that the input is well-formed but actually check it. It is actually a common problem with image or video libraries that they were not designed with deliberately malformed input in mind but which are nevertheless used to process input from dubious origins.
- Use a safe programming language which by design is not affected by buffer overflows or makes it at least very unlikely. This means use a language which does not allow to write out of array boundaries and which does not allow to double free memory or similar memory management problems. Most higher level languages don't have this kind of problems though they might affect the performance more than you like. But there are also lower level languages like Rust which provide both memory safety and high performance at the same time.
- Limit impact of programming errors by using compiler-specific or system-wide mechanisms which protect the stack (canaries), prevent code execution from the stack, provide some kind of sandbox around the application etc.
To expand on one point from Steffen's answer: whenever you have code that is consuming untrusted input and considered an exploitation risk - such as an image library consuming files from untrusted sources - you should look at sandboxing that code. There are a number of ways to do this, varying by things like language, OS, and CPU architecture, but here are some of the most common:
- Run the code as a special, low-privilege user account that has no read or write access outside of what it needs to do its job. All modern general-purpose operating systems support this, though it can be a pain to set up such a user with sufficiently-restricted access and securely hand off the files and so on. There's also more attack surface exposed through such techniques than most other options.
- Run the code in an OS-provided low-privilege sandbox that prevents harmful behavior while still allowing controlled interaction with other programs. This one is extremely OS-specific, but most modern OSes support it in some form; you can use AppContainers (such as are used by "Modern" Windows Store apps) on Windows 8 or later, you can use App Sandboxes on OS X, you can use containers on Linux and possibly other Unix-like OSes, you can use jails on *BSD, etc. This is usually one of the simplest and best-supported options (Windows, Mac, Android, and iOS dev tools all support creating such sandboxes with little developer effort) and has good performance, but is very platform-specific and won't work on stuff like Windows 7.
- You can also manually create such sandboxes by using access-restricting features such as SELinux or AppArmor (both for Linux), or chroot (available on most Unix-like OSes), or CreateRestrictedToken (a Windows API) plus other Windows security features such as Mandatory Integrity Control. This approach is a lot of work to do truly securely, and is still highly platform-specific, but can be set up such that it will work on a very wide range of operating systems with more security than simply using a limited-access user account. This is how some apps that need a lot of security on lots of different systems but still need good performance, such as Chrome and IE7+, are sandboxed.
- Run the code in a virtual machine that has minimal access to the host and limited resources. Even if the code completely takes over the VM, the host can just kill that instance and start a new one from a clean image. This is relatively expensive in compute resources but pretty simple to set up, and offers very good security.
- Take advantage of language-level sandboxing. For example, the Java runtime allows creating a "SecurityManager" that restricts what the code can do; this is how things like the Java applet sandbox are implemented. As anybody familiar with the history of Java applet security can tell you, it's not very secure when the code being executed is actively malicious - too many ways to attack the system - but when executing expected-to-be-non-malicious code written in the already-memory-safe Java language, it's a decent additional defense-in-depth to protect against logic errors that might result in the code doing something like writing a file to an attacker-chosen location.