0

Background

I have an embedded Linux devices and need to invoke a subprocess. I try to avoid it but sometimes it's the most practical thing to do, e.g. calling networking commands like ip, networkmanager or doing data processing using an proprietary program.

The simplest thing to do is to call system(3) but then these bad things can happen:

  • Neither program name or arguments are sanitized.
  • PATH is modified by an attacker causing the wrong program to be executed
  • Another environment variable such as `IFS is modified by the attacker
  • If the attacker has been able to gain access to the child program, he may see open files which were not closed
  • And he/she may be able to gain elevated privileges if root privileges were not dropped.

So I probably should not rely on system(3) but write my own fork+exec function; pass the full path to the binary to be executed; make any arguments to the child process hard-coded; sanitize the environment variable; close open files; and drop privileges.

I've read the advice given in TAOSSA and John Viegas Secure Programming Cookbook. Thomas Ptacek gives a survey of sandboxing and isolation techniques for Linux in Sandboxing and Workflow Isolation but I haven't found anything discussing smaller, embedded systems. The OWASP Security guidelines discusses command injection but only mentions sanitizing of environment and ensuring that the path to the binary can't be altered.

My Question

  • Are these steps sufficient?
  • Can someone point to generic implementation of procedures for safely executing subprocesses in C and C++
  • Do I have to drop capabilities as well?
  • Should I consider running child processes in more isolation? If so, what options are available to me? seccomp filters? Namespace sandboxing?

The Generic Question

  • How should an embedded Linux system be partitioned? What isolation should exist between different processes? Is it worthwhile to implement a safe system(3) or is the isolation provided thereby to fine-grained to be meaningful?
  • 1
    Unless you're running a minimal kernel that has removed them (not sure how practical that is), the standard Linux sandboxing tools should be present. This includes things like dropping capabilities, namespaces, chroots, low-privilege users, and so on. Depending on the capacity of your embedded system, you might consider using SELinux or AppArmor profiles for sandboxing, or even configuring Docker containers (which are not sandboxes, but can be used to build them)... although for administrative tasks, many of these will still need considerable privileges. – CBHacking Aug 11 '20 at 08:05
  • 1
    You should consider which attacks you care about and which you don't (threat model). For example, attacker that can change PATH for your software, is usually already in position to execute anything they wish. – domen Aug 11 '20 at 10:25
  • @domen Yes, is it ever worth the effort to implement a safe system(3) replacement? A google search gives very few hits for such code. Maybe it's game over already if an attacker can do PATH/files exploits. – Daniel Näslund Aug 11 '20 at 10:55
  • This has some examples of good and bad code https://wiki.sei.cmu.edu/confluence/plugins/servlet/mobile?contentId=87152177#content/view/87152177 – multithr3at3d Aug 11 '20 at 12:02
  • Yes, of course it is. I've encountered many `system` that used data provided from less privileged contexts. I'm just saying that you should look at your system, check privileges of components, see how data flows. – domen Aug 11 '20 at 12:02

0 Answers0