2 * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
20 #include <linux/limits.h>
25 #include <sys/prctl.h>
26 #include <sys/socket.h>
27 #include <sys/types.h>
32 #include <systemd/sd-event.h>
34 #include "launchpad_hydra.h"
35 #include "launchpad_sigchld.h"
36 #include "launchpad_types.h"
37 #include "log_private.h"
40 #define API __attribute__ ((visibility("default")))
44 LAUNCHPAD_TYPE_UNSUPPORTED = -1,
45 LAUNCHPAD_TYPE_USER = 1,
46 LAUNCHPAD_TYPE_DYNAMIC = 100,
50 typedef struct hydra_context_s {
53 sd_event_source *fd_source;
54 sd_event_source *sig_source;
60 hydra_lifecycle_callback_s *hydra_callbacks;
64 static hydra_context_t __context;
66 static void __fini_hydra(void);
68 static int __init_signal(void)
73 _D("[__HYDRA__] init signal");
75 sigaddset(&mask, SIGCHLD);
77 if (sigprocmask(SIG_BLOCK, &mask, &__context.oldmask) < 0)
78 _E("sigprocmask() is failed. errno(%d)", errno);
80 _D("SIGCHLD blocked");
82 sfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
84 _E("Failed to create SIGCHLD fd. errno(%d)", errno);
91 static void __fini_signal(void)
93 _D("[__HYDRA__] finish signal");
94 if (sigprocmask(SIG_SETMASK, &__context.oldmask, NULL) < 0)
95 _E("sigprocmask() is failed. errno(%d)", errno);
97 _D("SIGCHLD unblocked");
100 static int (*__security_manager_prepare_app_candidate)(void);
101 static int __load_security_manager_func(void)
103 #define PATH_SECURITY_MANAGER_CLIENT "/usr/lib/libsecurity-manager-client.so.3"
106 handle = dlopen(PATH_SECURITY_MANAGER_CLIENT, RTLD_LAZY | RTLD_LOCAL);
108 _E("Failed to open security manager client library. error(%s)",
113 __security_manager_prepare_app_candidate = dlsym(handle,
114 "security_manager_prepare_app_candidate");
115 if (!__security_manager_prepare_app_candidate) {
116 _E("Failed to load security_manager_prepare_app_candidate()");
123 static int __fork_process(int (*child_fn)(void *), void *arg)
130 _E("[__HYDRA__] Failed to create a child process. errno(%d)",
136 __load_security_manager_func();
138 if (__security_manager_prepare_app_candidate) {
139 _W("security_manager_prepare_app_candidate ++");
140 ret = __security_manager_prepare_app_candidate();
141 _W("security_manager_prepare_app_candidate --");
143 _E("Failed to prepare app candidate process. error(%d)",
150 _E("Failed to exec child process. errno(%d)", errno);
157 static int __run_loader(void *arg)
161 _D("[__HYDRA__] Run loader. pid(%d)", getpid());
164 /* Set new sesssion ID & new process group ID */
167 launchpad_hydra_exit();
170 if (__context.hydra_callbacks->fork) {
171 ret = __context.hydra_callbacks->fork(__context.argc,
172 __context.argv, __context.user_data);
178 static int __handle_launch_event(sd_event_source *s,
179 int fd, uint32_t revents, void *user_data)
181 enum hydra_cmd cmd = -1;
185 len = recv(fd, &cmd, sizeof(cmd), MSG_WAITALL);
191 if (len < sizeof(cmd)) {
192 _E("[__HYDRA__] Failed to recv data. errno(%d)", errno);
196 if (cmd == LAUNCH_CANDIDATE) {
197 _D("[__HYDRA__] Launch new child");
199 _E("[__HYDRA__] Unknown command(%d)", cmd);
203 __context.candidate_pid = __fork_process(__run_loader, NULL);
204 _D("[__HYDRA__] candidate process(%d)", __context.candidate_pid);
213 static int __process_sigchld(struct signalfd_siginfo *info)
219 child_pgid = getpgid(info->ssi_pid);
220 _W("[__HYDRA__] Dead pid(%d), pgid(%d), signo(%d), status(%d)",
221 info->ssi_pid, child_pgid, info->ssi_signo,
224 while ((child_pid = waitpid(-1, &status, WNOHANG)) > 0) {
225 if (child_pid == child_pgid)
226 killpg(child_pgid, SIGKILL);
228 _sigchld_send(child_pid);
234 static int __handle_sigchld_event(sd_event_source *s,
235 int fd, uint32_t revents, void *user_data)
237 struct signalfd_siginfo siginfo;
241 size = read(fd, &siginfo, sizeof(struct signalfd_siginfo));
245 if (size != sizeof(struct signalfd_siginfo))
248 __process_sigchld(&siginfo);
254 static int __create_client_socket(int type, int id)
256 struct sockaddr_un addr = { 0, };
257 int retry = CONNECT_RETRY_COUNT;
260 fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
262 _E("Failed to create socket(%d:%d). errno(%d)",
267 addr.sun_family = AF_UNIX;
268 snprintf(addr.sun_path, sizeof(addr.sun_path),
269 "%s/daemons/%d/%s%d-%d",
270 SOCKET_PATH, getuid(), HYDRA_LOADER_SOCKET_NAME,
272 while (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
273 if (errno != ETIMEDOUT || retry <= 0) {
274 _E("Failed to connect socket(%s). errno(%d)",
275 addr.sun_path, errno);
280 usleep(CONNECT_RETRY_TIME);
282 _W("Retry(%d) to connect %s", retry, addr.sun_path);
288 int __connect_to_launchpad_hydra(int type, int id)
295 _D("[hydra] enter, type: %d", type);
297 fd = __create_client_socket(type, id);
301 client_pid = getpid();
302 send_ret = send(fd, &client_pid, sizeof(client_pid), MSG_NOSIGNAL);
303 _D("send(%d) : %d", client_pid, send_ret);
304 if (send_ret == -1) {
310 SECURE_LOGD("[hydra] done, connect fd: %d", fd);
314 static int __init_hydra(int loader_type, int loader_id)
318 _D("[__HYDRA__] init hydra");
319 __context.signal_fd = __init_signal();
320 if (__context.signal_fd < 0) {
321 _E("Failed to initialize signal");
325 __context.client_fd = __connect_to_launchpad_hydra(loader_type,
327 if (__context.client_fd < 0) {
328 _E("Failed to connect to launchpad");
332 ret = sd_event_default(&__context.event);
334 _E("Failed to create default sd event. error(%d)", ret);
338 sd_event_add_io(__context.event, &__context.fd_source,
339 __context.client_fd, EPOLLIN,
340 __handle_launch_event, NULL);
341 sd_event_add_io(__context.event, &__context.sig_source,
342 __context.signal_fd, EPOLLIN,
343 __handle_sigchld_event, NULL);
348 static void __fini_hydra(void)
350 _D("[__HYDRA__] finish hydra");
351 if (__context.sig_source)
352 sd_event_source_unref(__context.sig_source);
354 if (__context.fd_source)
355 sd_event_source_unref(__context.fd_source);
358 sd_event_unref(__context.event);
360 if (__context.client_fd > 0)
361 close(__context.client_fd);
363 if (__context.signal_fd > 0)
364 close(__context.signal_fd);
367 static void __run_loop(void)
371 ret = sd_event_loop(__context.event);
373 _E("Failed to run sd event loop. error(%d)", ret);
375 _D("[__HYDRA__] Run main loop");
378 static void __exit_loop(void)
381 sd_event_exit(__context.event, 0);
383 _D("[__HYDRA__] Exit main loop");
386 API int launchpad_hydra_main(int argc, char **argv,
387 hydra_lifecycle_callback_s *hydra_callbacks,
396 _E("[__HYDRA__] too few argument");
400 loader_type = argv[LOADER_ARG_TYPE][0] - '0';
401 if (loader_type < 0 || loader_type >= LAUNCHPAD_TYPE_MAX) {
402 _E("[__HYDRA__] Invalid argument. type(%d)", loader_type);
406 if (!hydra_callbacks) {
407 _E("[__HYDRA__] Invalid argument");
411 is_hydra = argv[LOADER_ARG_HYDRA][0] - '0';
412 _D("[__HYDRA__] mode: %d", is_hydra);
414 _W("Run in non hydra mode");
418 argv[LOADER_ARG_HYDRA] = "0";
419 loader_id = atoi(argv[LOADER_ARG_ID]);
421 __context.argc = argc;
422 __context.argv = argv;
423 __context.hydra_callbacks = hydra_callbacks;
424 __context.user_data = user_data;
426 ret = __init_hydra(loader_type, loader_id);
428 _E("Failed to initialize hydra loader");
432 if (__context.hydra_callbacks->precreate)
433 __context.hydra_callbacks->precreate(user_data);
435 if (__context.hydra_callbacks->create)
436 __context.hydra_callbacks->create(__context.user_data);
438 __context.candidate_pid = __fork_process(__run_loader, NULL);
439 _D("[__HYDRA__] candidate process(%d)", __context.candidate_pid);
443 if (__context.hydra_callbacks->terminate)
444 ret = __context.hydra_callbacks->terminate(__context.user_data);
451 API void launchpad_hydra_exit(void)