Progamming language PHP allows one to limit executing of external commands
via configuration directive
safe_mode_exec_dir.
This directive should contain full path to a directory conatining programs
which PHP script can run. If the script tries to execute a command not
located in this directory, the command is not executed. This configuration
directive is active only if safe mode is enabled, which means more
and sometimes unwanted restrictions to users.
PHP has no known possibility to limit executing of external commands with
disabled safe mode. Teherefore, here is a patch adding special
directive exec_dir straightly into PHP. This directive is very
similar to safe_mode_exec_dir, but safe mode has not to be enabled.

This patch limits or corrects the behavior of these functions:

exec()

passthru()

proc_open()

shell_exec()

system()

popen()

is_executable()

The patch was created for purposes of limit execution of external commands
of users on a multidomain apache server, first for PHP version 4.2.1.
The patch was sent to PHP developers so it could be a part of PHP,
but no one of PHP developers was interested in. On the other side, some
PHP users wanted this patch, therefore this site was created.

Note:
The message to the PHP-DEV mailing list
has been sent on 2002-06-21.

This patch modifies PHP source, so first of all you need the PHP source, download it
from from
official PHP site.
After unpacking the archive, step into the directory witch PHP unpacked and apply the patch:

Note:Patch is being compressed with gzip,
so you have to use zcat to decompress it for the patch program
or gunzip to decompress the patch as such.

All you have to do is set the directive exec_dir. You can do this
in php.ini or in configuration files of http server
Apache. Beacause of some
security reasons, this variable cannot be changed while running PHP script.
The directive should contain full path to an existing directory which
contains files or symlinks to files which can be executed.

For example, let's imagine a server with http Apache server, which
serves 2 virtuals: virtual1.tld and virtual2.tld, each of
these being maintained by other person. Maintainer of virtual1.tld wants to
execute cp, rm and mv, maintainer of virtual2.tld
wants to execute mysqldump.
The most clean solution now is to create one directory for
virtual1.tld, i.e. /usr/local/php/bin/virtual1.tld and place binaries
cp, rm and mv into it (or create symlinks to them). Similary we should
create /usr/local/php/bin/virtual2.tld with mysqldump in it.
Of cource it is better to create symlinks than to copy raw files, because of
upgrades. Now we have to configure Apache:

A bit more simple is to create one directory for whole server containing
trusted commands. In our example we can create directory /usr/local/php
and place (or create symlinks) cp, mv, rm and mysqldump in it. Now it is
enough to edit the php.ini file, where should be this line:

exec_dir = /usr/local/php

Note:After editing php.ini or Apache configuration
files, the Apache server has to be restarted.

Now we have to describe how the executing works. The name of the command to
be executed will be modified, first it will be shorted:
only characters behind last occurence of '/' will rest.
Before this new command name, the contents of exec_dir will be placed.
For example, if we call /bin/cp and directive exec_dir conatins
/usr/local/php, the command /bin/cp will be modified to
cp and then to /usr/local/bin/cp. This command will be
executed.

PHP behavior is influenced by these settings:

if the exec_dir directive is not set or is set to an empty string,
functions exec(), popen() etc. are running without
any restrictions

if safe mode is enabled and safe_mode_exec_dir is set,
exec_dir is ignored

if exec_dir is set, the called command cannot contain strings ".."
and ";", similar functionality offers safe_mode_exec_dir

If you want to disable exec_dir in a directory for any reason,
just set the value of the directive to none:

There are no known bugs at this moment. If you have exec_dir set to some
directory and you will execute command out of it, please let me know at
mccohy@kyberdigi.cz.

2014-03-10

Martijn Grendelman requested fix of bug reported on 2012-08-22, mainly
because Debain Weezy is shipped with PHP 5.4.4. Patches have been fixed,
you can now download valid files.

2012-08-22

Manuel Mausz has discovered a bug in versions 5.4.0 - 5.4.4 inclusive. Bad
placing of a new block into original code made some functions (file_exists,
is_executable etc.) to return false unless these tested files were placed in
directory defined in the exec_dir directive. Thanks for reporting
and an attached patch. Please upgrade to version 5.4.5 or higher.

2011-01-03

Antihack000 informed, that calling of PHP function proc_open()
completely ignores any value set in variable exec_dir. This bug
was fixed in patches for versions 5.2.15 and higher. If you are using
lower version, please upgrade.

2008-03-16

Possible memory leak has been found by Manuel Mausz. He also sent a
patch for exec_dir patch solving the issue (thanks!). All versions of the exec_dir
patch bellow 5.2.11 include the leak, so please upgrade to 5.2.11, patch
for this version is secure.

2004-08-16

A minimalistic bug about disabling exec_dir has been discovered by myself.
If you want to disable the exec_dir in (i.e.) httpd.conf, you have to add
this line somewhere:

php_admin_value exec_dir none

Although you set it so, it does not disable the usability of exec_dir,
but it tries to run binaries as if they were in the root directory
of the filesystem (/ls, /df etc.). If you are
in trouble with this, please download new patch for your version of
PHP. All patches listed in section download are
correct ones, so check the MD5 of the patch you have to those in the list.
Vulnerable versions: 4.3.2 - 4.3.8 (inclusive), 5.0.0 and 5.0.1. This
is not a really dramatical bug you should really worry about.

2004-06-24

VeNoMouS reported that you can execute commands out of specified
directories if you prepend a ';', '|', '&'
or may other ugly character to the beginning
of the command and try to execute it with the backtick operator.
In original safe_mode_exec_dir the backtick operator is turned off,
in this patch it is not. Therefore, all the patches listed here were
updated with a simple fix that escapes these and other characters
the same way as other commands (as exec() or popen()) do.
You are strongly encouraged to download new patch for your version of
PHP. The patches listed in section download are
correct ones, so check the MD5 of the patch you have to those in the list.
All version from 4.3.2 to 4.3.7 (inclusive) were vulnerable.

Note:The patch has not been tested on Windows
platform yet. If you test it and it will work,
let me know.