MediaWiki master
CommandFactory.php
Go to the documentation of this file.
1<?php
7namespace MediaWiki\Shell;
8
10use Psr\Log\LoggerAwareTrait;
11use Psr\Log\NullLogger;
12use Shellbox\Command\BoxedCommand;
13use Shellbox\Command\RemoteBoxedExecutor;
14use Shellbox\Shellbox;
15
22 use LoggerAwareTrait;
23
25 private $limits;
26
28 private $cgroup;
29
31 private $doLogStderr = false;
32
36 private $restrictionMethod;
37
41 private $firejail;
42
44 private $useAllUsers;
45
47 private $shellboxClientFactory;
48
55 public function __construct( ShellboxClientFactory $shellboxClientFactory,
56 array $limits, $cgroup, $restrictionMethod
57 ) {
58 $this->shellboxClientFactory = $shellboxClientFactory;
59 $this->limits = $limits;
60 $this->cgroup = $cgroup;
61 if ( $restrictionMethod === 'autodetect' ) {
62 // On Linux systems check for firejail
63 if ( PHP_OS === 'Linux' && $this->findFirejail() ) {
64 $this->restrictionMethod = 'firejail';
65 } else {
66 $this->restrictionMethod = false;
67 }
68 } else {
69 $this->restrictionMethod = $restrictionMethod;
70 }
71 $this->setLogger( new NullLogger() );
72 }
73
77 protected function findFirejail() {
78 if ( $this->firejail === null ) {
79 $this->firejail = ExecutableFinder::findInDefaultPaths( 'firejail' );
80 }
81
82 return $this->firejail;
83 }
84
91 public function logStderr( bool $yesno = true ): void {
92 $this->doLogStderr = $yesno;
93 }
94
102 private function getLocalShellboxOptions() {
103 $options = [
104 'tempDir' => wfTempDir(),
105 'useBashWrapper' => file_exists( '/bin/bash' ),
106 'cgroup' => $this->cgroup
107 ];
108 if ( $this->restrictionMethod === 'firejail' ) {
109 $firejailPath = $this->findFirejail();
110 if ( !$firejailPath ) {
111 throw new \RuntimeException( 'firejail is enabled, but cannot be found' );
112 }
113 $options['useFirejail'] = true;
114 $options['firejailPath'] = $firejailPath;
115 $options['firejailProfile'] = __DIR__ . '/firejail.profile';
116 }
117 return $options;
118 }
119
123 public function create(): Command {
124 $allUsers = false;
125 if ( $this->restrictionMethod === 'firejail' ) {
126 if ( $this->useAllUsers === null ) {
127 global $IP;
128 // In case people are doing funny things with symlinks
129 // or relative paths, resolve them all.
130 $realIP = realpath( $IP );
131 $currentUser = posix_getpwuid( posix_geteuid() );
132 $this->useAllUsers = str_starts_with( $realIP, '/home/' )
133 && !str_starts_with( $realIP, $currentUser['dir'] );
134 if ( $this->useAllUsers ) {
135 $this->logger->warning( 'firejail: MediaWiki is located ' .
136 'in a home directory that does not belong to the ' .
137 'current user, so allowing access to all home ' .
138 'directories (--allusers)' );
139 }
140 }
141 $allUsers = $this->useAllUsers;
142 }
143 $executor = Shellbox::createUnboxedExecutor(
144 $this->getLocalShellboxOptions(), $this->logger );
145
146 $command = new Command( $executor );
147 if ( $this->logger ) {
148 $command->setLogger( $this->logger );
149 }
150 if ( $allUsers ) {
151 $command->allowPath( '/home' );
152 }
153 return $command
154 ->limits( $this->limits )
155 ->logStderr( $this->doLogStderr );
156 }
157
168 public function createBoxed( ?string $service = null, $wallTimeLimit = null ): BoxedCommand {
169 $wallTimeLimit ??= $this->limits['walltime'];
170 if ( $this->shellboxClientFactory->isEnabled( $service ) ) {
171 $client = $this->shellboxClientFactory->getClient( [
172 'timeout' => $wallTimeLimit + 1,
173 'service' => $service,
174 ] );
175 $executor = new RemoteBoxedExecutor( $client );
176 if ( $this->logger ) {
177 $executor->setLogger( $this->logger );
178 }
179 } else {
180 $executor = Shellbox::createBoxedExecutor(
181 $this->getLocalShellboxOptions(),
182 $this->logger );
183 }
184 return $executor->createCommand()
185 ->cpuTimeLimit( $this->limits['time'] )
186 ->wallTimeLimit( $wallTimeLimit )
187 ->memoryLimit( $this->limits['memory'] * 1024 )
188 ->fileSizeLimit( $this->limits['filesize'] * 1024 )
189 ->logStderr( $this->doLogStderr );
190 }
191}
wfTempDir()
Tries to get the system directory for temporary files.
if(!defined('MEDIAWIKI')) if(!defined( 'MW_ENTRY_POINT')) $IP
Environment checks.
Definition Setup.php:102
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:25
This is a service which provides a configured client to access a remote Shellbox installation.
Utility class to find executables in likely places.