Unreviewed, rolling out r241620.
[WebKit-https.git] / Source / WebKit / UIProcess / Launcher / glib / ProcessLauncherGLib.cpp
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  * Portions Copyright (c) 2010 Motorola Mobility, Inc.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY MOTOROLA INC. AND ITS CONTRIBUTORS ``AS IS''
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MOTOROLA INC. OR ITS CONTRIBUTORS
18  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24  * THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28 #include "ProcessLauncher.h"
29
30 #include "BubblewrapLauncher.h"
31 #include "Connection.h"
32 #include "FlatpakLauncher.h"
33 #include "ProcessExecutablePath.h"
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <glib.h>
37 #include <wtf/FileSystem.h>
38 #include <wtf/RunLoop.h>
39 #include <wtf/UniStdExtras.h>
40 #include <wtf/glib/GLibUtilities.h>
41 #include <wtf/glib/GUniquePtr.h>
42 #include <wtf/text/CString.h>
43 #include <wtf/text/WTFString.h>
44
45 #if PLATFORM(WPE)
46 #include <wpe/wpe.h>
47 #endif
48
49 namespace WebKit {
50
51 static void childSetupFunction(gpointer userData)
52 {
53     int socket = GPOINTER_TO_INT(userData);
54     close(socket);
55 }
56
57 #if OS(LINUX)
58 static bool isInsideFlatpak()
59 {
60     static int ret = -1;
61     if (ret != -1)
62         return ret;
63
64     GUniquePtr<GKeyFile> infoFile(g_key_file_new());
65     if (!g_key_file_load_from_file(infoFile.get(), "/.flatpak-info", G_KEY_FILE_NONE, nullptr)) {
66         ret = false;
67         return ret;
68     }
69
70     // If we are in a `flatpak build` session we cannot launch ourselves since we aren't installed.
71     ret = !g_key_file_get_boolean(infoFile.get(), "Instance", "build", nullptr);
72     return ret;
73 }
74 #endif
75
76 void ProcessLauncher::launchProcess()
77 {
78     IPC::Connection::SocketPair socketPair = IPC::Connection::createPlatformConnection(IPC::Connection::ConnectionOptions::SetCloexecOnServer);
79
80     String executablePath;
81     CString realExecutablePath;
82 #if ENABLE(NETSCAPE_PLUGIN_API)
83     String pluginPath;
84     CString realPluginPath;
85 #endif
86     switch (m_launchOptions.processType) {
87     case ProcessLauncher::ProcessType::Web:
88         executablePath = executablePathOfWebProcess();
89         break;
90 #if ENABLE(NETSCAPE_PLUGIN_API)
91     case ProcessLauncher::ProcessType::Plugin64:
92     case ProcessLauncher::ProcessType::Plugin32:
93         executablePath = executablePathOfPluginProcess();
94 #if ENABLE(PLUGIN_PROCESS_GTK2)
95         if (m_launchOptions.extraInitializationData.contains("requires-gtk2"))
96             executablePath.append('2');
97 #endif
98         pluginPath = m_launchOptions.extraInitializationData.get("plugin-path");
99         realPluginPath = FileSystem::fileSystemRepresentation(pluginPath);
100         break;
101 #endif
102     case ProcessLauncher::ProcessType::Network:
103         executablePath = executablePathOfNetworkProcess();
104         break;
105     default:
106         ASSERT_NOT_REACHED();
107         return;
108     }
109
110     realExecutablePath = FileSystem::fileSystemRepresentation(executablePath);
111     GUniquePtr<gchar> processIdentifier(g_strdup_printf("%" PRIu64, m_launchOptions.processIdentifier.toUInt64()));
112     GUniquePtr<gchar> webkitSocket(g_strdup_printf("%d", socketPair.client));
113     unsigned nargs = 5; // size of the argv array for g_spawn_async()
114
115 #if PLATFORM(WPE)
116     GUniquePtr<gchar> wpeSocket;
117     CString wpeBackendLibraryParameter;
118     if (m_launchOptions.processType == ProcessLauncher::ProcessType::Web) {
119 #if defined(WPE_BACKEND_CHECK_VERSION) && WPE_BACKEND_CHECK_VERSION(0, 2, 0)
120         wpeBackendLibraryParameter = FileSystem::fileSystemRepresentation(wpe_loader_get_loaded_implementation_library_name());
121 #endif
122         nargs++;
123
124         wpeSocket = GUniquePtr<gchar>(g_strdup_printf("%d", wpe_renderer_host_create_client()));
125         nargs++;
126     }
127 #endif
128
129 #if ENABLE(DEVELOPER_MODE)
130     Vector<CString> prefixArgs;
131     if (!m_launchOptions.processCmdPrefix.isNull()) {
132         for (auto& arg : m_launchOptions.processCmdPrefix.split(' '))
133             prefixArgs.append(arg.utf8());
134         nargs += prefixArgs.size();
135     }
136 #endif
137
138     char** argv = g_newa(char*, nargs);
139     unsigned i = 0;
140 #if ENABLE(DEVELOPER_MODE)
141     // If there's a prefix command, put it before the rest of the args.
142     for (auto& arg : prefixArgs)
143         argv[i++] = const_cast<char*>(arg.data());
144 #endif
145     argv[i++] = const_cast<char*>(realExecutablePath.data());
146     argv[i++] = processIdentifier.get();
147     argv[i++] = webkitSocket.get();
148 #if PLATFORM(WPE)
149     if (m_launchOptions.processType == ProcessLauncher::ProcessType::Web) {
150         argv[i++] = const_cast<char*>(wpeBackendLibraryParameter.isNull() ? "-" : wpeBackendLibraryParameter.data());
151         argv[i++] = wpeSocket.get();
152     }
153 #endif
154 #if ENABLE(NETSCAPE_PLUGIN_API)
155     argv[i++] = const_cast<char*>(realPluginPath.data());
156 #else
157     argv[i++] = nullptr;
158 #endif
159     argv[i++] = nullptr;
160
161     GRefPtr<GSubprocessLauncher> launcher = adoptGRef(g_subprocess_launcher_new(G_SUBPROCESS_FLAGS_INHERIT_FDS));
162     g_subprocess_launcher_set_child_setup(launcher.get(), childSetupFunction, GINT_TO_POINTER(socketPair.server), nullptr);
163     g_subprocess_launcher_take_fd(launcher.get(), socketPair.client, socketPair.client);
164
165     GUniqueOutPtr<GError> error;
166     GRefPtr<GSubprocess> process;
167 #if OS(LINUX)
168     const char* sandboxEnv = g_getenv("WEBKIT_FORCE_SANDBOX");
169     bool sandboxEnabled = m_launchOptions.extraInitializationData.get("enable-sandbox") == "true";
170
171     if (sandboxEnv)
172         sandboxEnabled = !strcmp(sandboxEnv, "1");
173
174     if (sandboxEnabled && isInsideFlatpak())
175         process = flatpakSpawn(launcher.get(), m_launchOptions, argv, socketPair.client, &error.outPtr());
176 #if ENABLE(BUBBLEWRAP_SANDBOX)
177     else if (sandboxEnabled)
178         process = bubblewrapSpawn(launcher.get(), m_launchOptions, argv, &error.outPtr());
179 #endif
180     else
181 #endif
182         process = adoptGRef(g_subprocess_launcher_spawnv(launcher.get(), argv, &error.outPtr()));
183
184     if (!process.get())
185         g_error("Unable to fork a new child process: %s", error->message);
186
187     const char* processIdStr = g_subprocess_get_identifier(process.get());
188     m_processIdentifier = g_ascii_strtoll(processIdStr, nullptr, 0);
189     RELEASE_ASSERT(m_processIdentifier);
190
191     // Don't expose the parent socket to potential future children.
192     if (!setCloseOnExec(socketPair.client))
193         RELEASE_ASSERT_NOT_REACHED();
194
195     // We've finished launching the process, message back to the main run loop.
196     RunLoop::main().dispatch([protectedThis = makeRef(*this), this, serverSocket = socketPair.server] {
197         didFinishLaunchingProcess(m_processIdentifier, serverSocket);
198     });
199 }
200
201 void ProcessLauncher::terminateProcess()
202 {
203     if (m_isLaunching) {
204         invalidate();
205         return;
206     }
207
208     if (!m_processIdentifier)
209         return;
210
211     kill(m_processIdentifier, SIGKILL);
212     m_processIdentifier = 0;
213 }
214
215 void ProcessLauncher::platformInvalidate()
216 {
217 }
218
219 } // namespace WebKit