MediaWiki master
CommandFactory.php
Go to the documentation of this file.
1<?php
21namespace MediaWiki\Shell;
22
24use Psr\Log\LoggerAwareTrait;
25use Psr\Log\NullLogger;
26use Shellbox\Command\BoxedCommand;
27use Shellbox\Command\RemoteBoxedExecutor;
28use 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
137 public function create(): Command {
138 $allUsers = false;
139 if ( $this->restrictionMethod === 'firejail' ) {
140 if ( $this->useAllUsers === null ) {
141 global $IP;
142 // In case people are doing funny things with symlinks
143 // or relative paths, resolve them all.
144 $realIP = realpath( $IP );
145 $currentUser = posix_getpwuid( posix_geteuid() );
146 $this->useAllUsers = str_starts_with( $realIP, '/home/' )
147 && !str_starts_with( $realIP, $currentUser['dir'] );
148 if ( $this->useAllUsers ) {
149 $this->logger->warning( 'firejail: MediaWiki is located ' .
150 'in a home directory that does not belong to the ' .
151 'current user, so allowing access to all home ' .
152 'directories (--allusers)' );
153 }
154 }
155 $allUsers = $this->useAllUsers;
156 }
157 $executor = Shellbox::createUnboxedExecutor(
158 $this->getLocalShellboxOptions(), $this->logger );
159
160 $command = new Command( $executor );
161 $command->setLogger( $this->logger );
162 if ( $allUsers ) {
163 $command->allowPath( '/home' );
164 }
165 return $command
166 ->limits( $this->limits )
167 ->logStderr( $this->doLogStderr );
168 }
169
180 public function createBoxed( ?string $service = null, $wallTimeLimit = null ): BoxedCommand {
181 $wallTimeLimit ??= $this->limits['walltime'];
182 if ( $this->shellboxClientFactory->isEnabled( $service ) ) {
183 $client = $this->shellboxClientFactory->getClient( [
184 'timeout' => $wallTimeLimit + 1,
185 'service' => $service,
186 ] );
187 $executor = new RemoteBoxedExecutor( $client );
188 $executor->setLogger( $this->logger );
189 } else {
190 $executor = Shellbox::createBoxedExecutor(
191 $this->getLocalShellboxOptions(),
192 $this->logger );
193 }
194 return $executor->createCommand()
195 ->cpuTimeLimit( $this->limits['time'] )
196 ->wallTimeLimit( $wallTimeLimit )
197 ->memoryLimit( $this->limits['memory'] * 1024 )
198 ->fileSizeLimit( $this->limits['filesize'] * 1024 )
199 ->logStderr( $this->doLogStderr );
200 }
201}
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:105
Utility class to find executables in likely places.
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)
create()
Instantiates a new Command.
createBoxed(?string $service=null, $wallTimeLimit=null)
Instantiates a new BoxedCommand.
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.