MediaWiki  master
CommandFactory.php
Go to the documentation of this file.
1 <?php
21 namespace MediaWiki\Shell;
22 
24 use Psr\Log\LoggerAwareTrait;
25 use Psr\Log\NullLogger;
26 use Shellbox\Command\BoxedCommand;
27 use Shellbox\Command\RemoteBoxedExecutor;
28 use Shellbox\Shellbox;
29 
36  use LoggerAwareTrait;
37 
39  private $limits;
40 
42  private $cgroup;
43 
45  private $doLogStderr = false;
46 
50  private $restrictionMethod;
51 
55  private $firejail;
56 
58  private $useAllUsers;
59 
61  private $shellboxClientFactory;
62 
69  public function __construct( ShellboxClientFactory $shellboxClientFactory,
70  array $limits, $cgroup, $restrictionMethod
71  ) {
72  $this->shellboxClientFactory = $shellboxClientFactory;
73  $this->limits = $limits;
74  $this->cgroup = $cgroup;
75  if ( $restrictionMethod === 'autodetect' ) {
76  // On Linux systems check for firejail
77  if ( PHP_OS === 'Linux' && $this->findFirejail() ) {
78  $this->restrictionMethod = 'firejail';
79  } else {
80  $this->restrictionMethod = false;
81  }
82  } else {
83  $this->restrictionMethod = $restrictionMethod;
84  }
85  $this->setLogger( new NullLogger() );
86  }
87 
91  protected function findFirejail() {
92  if ( $this->firejail === null ) {
93  $this->firejail = ExecutableFinder::findInDefaultPaths( 'firejail' );
94  }
95 
96  return $this->firejail;
97  }
98 
105  public function logStderr( bool $yesno = true ): void {
106  $this->doLogStderr = $yesno;
107  }
108 
116  private function getLocalShellboxOptions() {
117  $options = [
118  'tempDir' => wfTempDir(),
119  'useBashWrapper' => file_exists( '/bin/bash' ),
120  'cgroup' => $this->cgroup
121  ];
122  if ( $this->restrictionMethod === 'firejail' ) {
123  $firejailPath = $this->findFirejail();
124  if ( !$firejailPath ) {
125  throw new \RuntimeException( 'firejail is enabled, but cannot be found' );
126  }
127  $options['useFirejail'] = true;
128  $options['firejailPath'] = $firejailPath;
129  $options['firejailProfile'] = __DIR__ . '/firejail.profile';
130  }
131  return $options;
132  }
133 
139  public function create(): Command {
140  $allUsers = false;
141  if ( $this->restrictionMethod === 'firejail' ) {
142  if ( $this->useAllUsers === null ) {
143  global $IP;
144  // In case people are doing funny things with symlinks
145  // or relative paths, resolve them all.
146  $realIP = realpath( $IP );
147  $currentUser = posix_getpwuid( posix_geteuid() );
148  $this->useAllUsers = ( strpos( $realIP, '/home/' ) === 0 )
149  && ( strpos( $realIP, $currentUser['dir'] ) !== 0 );
150  if ( $this->useAllUsers ) {
151  $this->logger->warning( 'firejail: MediaWiki is located ' .
152  'in a home directory that does not belong to the ' .
153  'current user, so allowing access to all home ' .
154  'directories (--allusers)' );
155  }
156  }
157  $allUsers = $this->useAllUsers;
158  }
159  $executor = Shellbox::createUnboxedExecutor(
160  $this->getLocalShellboxOptions(), $this->logger );
161 
162  $command = new Command( $executor );
163  $command->setLogger( $this->logger );
164  if ( $allUsers ) {
165  $command->allowPath( '/home' );
166  }
167  return $command
168  ->limits( $this->limits )
169  ->logStderr( $this->doLogStderr );
170  }
171 
179  public function createBoxed( ?string $service = null ): BoxedCommand {
180  if ( $this->shellboxClientFactory->isEnabled( $service ) ) {
181  $client = $this->shellboxClientFactory->getClient( [
182  'timeout' => $this->limits['walltime'] + 1,
183  'service' => $service,
184  ] );
185  $executor = new RemoteBoxedExecutor( $client );
186  $executor->setLogger( $this->logger );
187  } else {
188  $executor = Shellbox::createBoxedExecutor(
189  $this->getLocalShellboxOptions(),
190  $this->logger );
191  }
192  return $executor->createCommand()
193  ->cpuTimeLimit( $this->limits['time'] )
194  ->wallTimeLimit( $this->limits['walltime'] )
195  ->memoryLimit( $this->limits['memory'] * 1024 )
196  ->fileSizeLimit( $this->limits['filesize'] * 1024 )
197  ->logStderr( $this->doLogStderr );
198  }
199 }
wfTempDir()
Tries to get the system directory for temporary files.
if(!defined( 'MEDIAWIKI')) if(ini_get( 'mbstring.func_overload')) if(!defined( 'MW_ENTRY_POINT')) global $IP
Environment checks.
Definition: Setup.php:96
if(!defined('MW_SETUP_CALLBACK'))
Definition: WebStart.php:88
Utility class to find executables in likely places.
static findInDefaultPaths( $names, $versionInfo=false)
Same as locateExecutable(), but checks in getPossibleBinPaths() by default.
Factory facilitating dependency injection for Command.
logStderr(bool $yesno=true)
When enabled, text sent to stderr will be logged with a level of 'error'.
__construct(ShellboxClientFactory $shellboxClientFactory, array $limits, $cgroup, $restrictionMethod)
createBoxed(?string $service=null)
Instantiates a new BoxedCommand.
create()
Instantiates a new Command.
Class used for executing shell commands.
Definition: Command.php:39
This is a service which provides a configured client to access a remote Shellbox installation.