18

I am designing an C++ app that, among other things, executes a few scripts every now and then. The app should be efficient and preferably platform independent.

The issue is, however: is there a reason one shouldn't use system() call for launching scripts and use, for example, POSIX facilities instead? The discussion on the matter that I've seen so far usually boils down to:

  1. system() is less flexible. (Fine with me)
  2. It offers no control of the command being executed. (Fine with me, I just need a return value from the script)
  3. It is not quite platform independent. (Now, this would be a concern. I would really love to see an example where it behaves differently on different platforms)
  4. It is a security concern. (Again, this would be an issue. Can someone provide an example of a potential security problem with system()? )
  5. Any other issues?
Matvey Aksenov
  • 3,802
  • 3
  • 23
  • 45
AlexK
  • 1,279
  • 8
  • 19
  • 7
    I think there's a *huge* "it all depends" hanging over this. *What* is it that you need to do? How often does this happen? What's the Bigger Picture? Is it an option to run other programs and your program side-by-side from a controlling shell script rather than making the compiler program the controller? – Kerrek SB Nov 10 '11 at 20:48
  • 5
    Er. You're writing a platform-independent application that depends on shell scripts? – Michael Mrozek Nov 10 '11 at 20:49
  • @Michael you're right. Let's call them just "scripts", in a platform-neutral way. – AlexK Nov 10 '11 at 20:52
  • @Kerrek: Think executing zip/scp/rm commands triggered by a set of events that are really hard to trap out without a c++ control program, a functioning prototype of which already exists. The events are expected to happen every few hours, the scripts may take minutes to finish and must run asynchronously. – AlexK Nov 10 '11 at 21:12
  • 3
    I already wrote [a long rant](http://stackoverflow.com/questions/2923843/can-i-use-boost-library-for-crossplatform-application-executing/2925579#2925579) about the `system` function, check if you think that any of its points are relevant to you. – Matteo Italia Nov 10 '11 at 21:18
  • @AlexK: Are you sure that your platform doesn't offer some other sort of event handling that you can set up in a less rigid fashion? What sort of events do you want to trap? – Kerrek SB Nov 10 '11 at 21:27
  • @KerrekSB: Doubt it. An event in question is a specific field in a UDP broadcast message coming from a specific host. The facilities for parsing the message and detecting the event are already coded in C++, tested and working. – AlexK Nov 10 '11 at 21:35

5 Answers5

6

3) It is not quite platform independent (Now, this would be a concern. I would really love to see an example where it behaves differently on different platforms)

Well, for instance system("ls") would probably fail in Windows, since there is no ls command.

4) It is a security concern. (Again, this would be an issue. Can someone provide an example of a potential security problem with system() ? )

If the argument passed to system comes from user input, and not properly validated, it can be used to execute unwanted things with the privilege levels of the original executer. If its static content, its quite easy to find that within an executable image and modify it to do nasty things as well.

Captain Giraffe
  • 14,407
  • 6
  • 39
  • 67
K-ballo
  • 80,396
  • 20
  • 159
  • 169
  • 1) You're right but let's assume it has a layer (cygwin, perl etc. that allows scripts to proceed) 2) In your opinion, is there a more secure alternative that doesn't suffer from the same problem ? – AlexK Nov 10 '11 at 21:03
  • 3
    @AlexK: There is no *more secure* alternative, the problem comes from executing a string of code so its the same for every alternative. – K-ballo Nov 10 '11 at 21:10
  • @K-ballo: however, `system` suffers further from the fact that it is not possible to portably sanitize user input, since you don't know anything at all about the syntax of the shell you're passing it to. If you use a (less portable) function from the `exec` family then you can at least pass a fixed program name and a user-supplied argument without worrying that the argument contains a cunning sequence that escapes a quoted string and executes something nasty. So that's a more secure alternative. – Steve Jessop Nov 11 '11 at 02:36
4

(3) If you just want a counterexample, for example grep behaves differently on Solaris vs Linux vs whatever.

(4) Your program's privileges are inherited by its spawned programs. If your application ever runs as a privileged user, all someone has to do is put their own program with the name of the thing you shell out too, and then can execute arbitrary code (this implies you should never run a program that uses system as root or setuid root).

(5) It will probably be saner to maintain in the long run to use the posix facilities because you won't have to rely on a specific set of external scripts or binaries already existing wherever your program runs.

Mark B
  • 95,107
  • 10
  • 109
  • 188
1

Regarding security concerns, a classical example about (4) is the following scenario: imagine the user is prompted to give some directory name to be backed up into a std::string dirname; then you'll compute some backup directory name into a std::string backup and do

system((std::string{"cp -a "} + dirname + " " + backup).c_str())

Now think what happens if a malicious user enter foo bar; rm -rf $HOME; ls as the dirname and backup is /vol/backup_2015_fev/. The system command would execute

cp -a  foo bar; rm -rf $HOME; ls /vol/backup_2015_fev/

which is not what you expected (all the user's $HOME would be deleted!). This is an example of code injection, and when using system you should ensure that it never happens (e.g. by sanitizing and/or escaping every user input related string)

Also, the PATH might not be what you believe it is (e.g. starting with /tmp/ and a malicious user having done ln -s /bin/rm /tmp/cp before your system runs).

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
1

I maintain a system that consists of several separate executables. In this case I have control over the permissions, names, calling conventions, security over all supported platforms. In this case, system() works just fine. The applications communicate through a RDBMS.

Again, as others have noted "The Devil's in the details".

emsr
  • 15,539
  • 6
  • 49
  • 62
  • Maintaining the computational engines as separate executables allows a crude but effective process-based concurrency in my system. These systems are just too fugly and complex to reimplement them into thread safe or multi-threaded loaded libraries. – emsr Mar 03 '15 at 21:33
0

I used the system() call in my CGI C++ app under windows and Linux too.

One problem I had was when using system() was not having the proper access rights to execute my skript with the web user.

I did not have that problem any more when using the CreateProcess() method.

juergen d
  • 201,996
  • 37
  • 293
  • 362