Day 22: Safer system() alternative (Sys::Run::Safer)

About the series: perlancar's 2014 Advent Calendar: Introduction to a selection of 24 modules which I published in 2014. Table of contents.

Sys::Run::Safer is an attempt to create a safer API for running programs.

As we might already know, Perl's system() may or may not call a shell depending on a number of things. If we want to avoid a shell, doing system @ary or even system $cmd, @args is not enough as Perl might still invoke shell if @ary is only 1-element long or when @args is empty. I realized and got reminded of this myself only recently, it was a long time ago since I read the documentation for system() and I've been system @ary all these years thinking it was enough. You actually need to do this ugly thing to make sure you avoid a shell: system { $ary[0] } @ary which I'm pretty sure a lot of people don't remember or bother to use. Thus, it's an API mistake.

The second problem does not have to do with shells or Perl: arguments/filenames might be interpreted by programs as options, leading to potential hackery by putting specially-crafted filenames on the filesystem. Even if you have avoided the shell, if you accept these filenames without preceding them with -- these will still be interpreted as options.

Sys::Run::Safer provides run() which tries to avoid the above problem by forcing you to specify arguments and options separately, e.g.:


run(
    prog => 'rm',
    opts => ['-rf', '--interactive=never'],
    args => ['file1', 'file2', 'dir1'],
);

And run() will construct this C command for you:


system('rm', '-rf', '--interactive=never', '--', 'file1', 'file2', 'dir1');

I'm still looking for ideas to make things more robust, e.g. how to prevent users accidentally putting arguments into opts. Ideas welcome.

Leave a comment

About perlancar

user-pic #perl #indonesia