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 $command->setLogger( $this->logger );
148 if ( $allUsers ) {
149 $command->allowPath( '/home' );
150 }
151 return $command
152 ->limits( $this->limits )
153 ->logStderr( $this->doLogStderr );
154 }
155
166 public function createBoxed( ?string $service = null, $wallTimeLimit = null ): BoxedCommand {
167 $wallTimeLimit ??= $this->limits['walltime'];
168 if ( $this->shellboxClientFactory->isEnabled( $service ) ) {
169 $client = $this->shellboxClientFactory->getClient( [
170 'timeout' => $wallTimeLimit + 1,
171 'service' => $service,
172 ] );
173 $executor = new RemoteBoxedExecutor( $client );
174 $executor->setLogger( $this->logger );
175 } else {
176 $executor = Shellbox::createBoxedExecutor(
177 $this->getLocalShellboxOptions(),
178 $this->logger );
179 }
180 return $executor->createCommand()
181 ->cpuTimeLimit( $this->limits['time'] )
182 ->wallTimeLimit( $wallTimeLimit )
183 ->memoryLimit( $this->limits['memory'] * 1024 )
184 ->fileSizeLimit( $this->limits['filesize'] * 1024 )
185 ->logStderr( $this->doLogStderr );
186 }
187}
wfTempDir()
Tries to get the system directory for temporary files.
if(!defined('MEDIAWIKI')) if(!defined( 'MW_ENTRY_POINT')) global $IP
Environment checks.
Definition Setup.php:90
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.