Release version 0.15.20
[platform/core/appfw/launchpad.git] / src / hydra / src / launchpad_hydra.c
1 /*
2  * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #define _GNU_SOURCE
18 #include <dlfcn.h>
19 #include <errno.h>
20 #include <linux/limits.h>
21 #include <malloc.h>
22 #include <signal.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <sys/prctl.h>
26 #include <sys/socket.h>
27 #include <sys/types.h>
28 #include <sys/un.h>
29 #include <sys/wait.h>
30 #include <unistd.h>
31
32 #include <systemd/sd-event.h>
33
34 #include "launchpad_hydra.h"
35 #include "launchpad_sigchld.h"
36 #include "launchpad_types.h"
37 #include "log_private.h"
38
39 #ifndef API
40 #define API __attribute__ ((visibility("default")))
41 #endif
42
43 typedef enum {
44         LAUNCHPAD_TYPE_UNSUPPORTED = -1,
45         LAUNCHPAD_TYPE_USER = 1,
46         LAUNCHPAD_TYPE_DYNAMIC = 100,
47         LAUNCHPAD_TYPE_MAX
48 } launchpad_type_e;
49
50 typedef struct hydra_context_s {
51         sigset_t oldmask;
52         sd_event *event;
53         sd_event_source *fd_source;
54         sd_event_source *sig_source;
55         int signal_fd;
56         int client_fd;
57         int candidate_pid;
58         int argc;
59         char **argv;
60         hydra_lifecycle_callback_s *hydra_callbacks;
61         void *user_data;
62 } hydra_context_t;
63
64 static hydra_context_t __context;
65
66 static void __fini_hydra(void);
67
68 static int __init_signal(void)
69 {
70         sigset_t mask;
71         int sfd;
72
73         _D("[__HYDRA__] init signal");
74         sigemptyset(&mask);
75         sigaddset(&mask, SIGCHLD);
76
77         if (sigprocmask(SIG_BLOCK, &mask, &__context.oldmask) < 0)
78                 _E("sigprocmask() is failed. errno(%d)", errno);
79         else
80                 _D("SIGCHLD blocked");
81
82         sfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
83         if (sfd < 0) {
84                 _E("Failed to create SIGCHLD fd. errno(%d)", errno);
85                 return -1;
86         }
87
88         return sfd;
89 }
90
91 static void __fini_signal(void)
92 {
93         _D("[__HYDRA__] finish signal");
94         if (sigprocmask(SIG_SETMASK, &__context.oldmask, NULL) < 0)
95                 _E("sigprocmask() is failed. errno(%d)", errno);
96         else
97                 _D("SIGCHLD unblocked");
98 }
99
100 static int (*__security_manager_prepare_app_candidate)(void);
101 static int __load_security_manager_func(void)
102 {
103 #define PATH_SECURITY_MANAGER_CLIENT "/usr/lib/libsecurity-manager-client.so.3"
104         void *handle;
105
106         handle = dlopen(PATH_SECURITY_MANAGER_CLIENT, RTLD_LAZY | RTLD_LOCAL);
107         if (!handle) {
108                 _E("Failed to open security manager client library. error(%s)",
109                                 dlerror());
110                 return -1;
111         }
112
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()");
117                 return -1;
118         }
119
120         return 0;
121 }
122
123 static int __fork_process(int (*child_fn)(void *), void *arg)
124 {
125         int ret;
126         pid_t pid;
127
128         pid = fork();
129         if (pid < 0) {
130                 _E("[__HYDRA__] Failed to create a child process. errno(%d)",
131                                 errno);
132                 return pid;
133         }
134
135         if (pid == 0) {
136                 __load_security_manager_func();
137
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 --");
142                         if (ret != 0) {
143                                 _E("Failed to prepare app candidate process. error(%d)",
144                                                 ret);
145                                 exit(1);
146                         }
147                 }
148
149                 ret = child_fn(arg);
150                 _E("Failed to exec child process. errno(%d)", errno);
151                 exit(ret);
152         }
153
154         return pid;
155 }
156
157 static int __run_loader(void *arg)
158 {
159         int ret = 0;
160
161         _D("[__HYDRA__] Run loader. pid(%d)", getpid());
162         __fini_signal();
163
164         /* Set new sesssion ID & new process group ID */
165         setsid();
166
167         launchpad_hydra_exit();
168         __fini_hydra();
169
170         if (__context.hydra_callbacks->fork) {
171                 ret = __context.hydra_callbacks->fork(__context.argc,
172                                 __context.argv, __context.user_data);
173         }
174
175         return ret;
176 }
177
178 static int __handle_launch_event(sd_event_source *s,
179                 int fd, uint32_t revents, void *user_data)
180 {
181         enum hydra_cmd cmd = -1;
182         int len;
183
184 retry_recv:
185         len = recv(fd, &cmd, sizeof(cmd), MSG_WAITALL);
186         if (len < 0) {
187                 if (errno == EINTR)
188                         goto retry_recv;
189         }
190
191         if (len < sizeof(cmd)) {
192                 _E("[__HYDRA__] Failed to recv data. errno(%d)", errno);
193                 goto err;
194         }
195
196         if (cmd == LAUNCH_CANDIDATE) {
197                 _D("[__HYDRA__] Launch new child");
198         } else {
199                 _E("[__HYDRA__] Unknown command(%d)", cmd);
200                 goto err;
201         }
202
203         __context.candidate_pid = __fork_process(__run_loader, NULL);
204         _D("[__HYDRA__] candidate process(%d)", __context.candidate_pid);
205
206         return 0;
207 err:
208         __fini_hydra();
209         exit(-1);
210         return -1;
211 }
212
213 static int __process_sigchld(struct signalfd_siginfo *info)
214 {
215         int status;
216         pid_t child_pid;
217         pid_t child_pgid;
218
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,
222                         info->ssi_status);
223
224         while ((child_pid = waitpid(-1, &status, WNOHANG)) > 0) {
225                 if (child_pid == child_pgid)
226                         killpg(child_pgid, SIGKILL);
227
228                 _sigchld_send(child_pid);
229         }
230
231         return 0;
232 }
233
234 static int __handle_sigchld_event(sd_event_source *s,
235                 int fd, uint32_t revents, void *user_data)
236 {
237         struct signalfd_siginfo siginfo;
238         ssize_t size;
239
240         do {
241                 size = read(fd, &siginfo, sizeof(struct signalfd_siginfo));
242                 if (size == 0)
243                         break;
244
245                 if (size != sizeof(struct signalfd_siginfo))
246                         break;
247
248                 __process_sigchld(&siginfo);
249         } while (size > 0);
250
251         return 0;
252 }
253
254 static int __create_client_socket(int type, int id)
255 {
256         struct sockaddr_un addr = { 0, };
257         int retry = CONNECT_RETRY_COUNT;
258         int fd;
259
260         fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
261         if (fd < 0) {
262                 _E("Failed to create socket(%d:%d). errno(%d)",
263                                 type, id, errno);
264                 return -1;
265         }
266
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,
271                         type, id);
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);
276                         close(fd);
277                         return -1;
278                 }
279
280                 usleep(CONNECT_RETRY_TIME);
281                 retry--;
282                 _W("Retry(%d) to connect %s", retry, addr.sun_path);
283         }
284
285         return fd;
286 }
287
288 int __connect_to_launchpad_hydra(int type, int id)
289 {
290         int fd;
291         int send_ret;
292         pid_t client_pid;
293
294
295         _D("[hydra] enter, type: %d", type);
296
297         fd = __create_client_socket(type, id);
298         if (fd < 0)
299                 return -1;
300
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) {
305                 _E("send error");
306                 close(fd);
307                 return -1;
308         }
309
310         SECURE_LOGD("[hydra] done, connect fd: %d", fd);
311         return fd;
312 }
313
314 static int __init_hydra(int loader_type, int loader_id)
315 {
316         int ret;
317
318         _D("[__HYDRA__] init hydra");
319         __context.signal_fd = __init_signal();
320         if (__context.signal_fd < 0) {
321                 _E("Failed to initialize signal");
322                 return -1;
323         }
324
325         __context.client_fd = __connect_to_launchpad_hydra(loader_type,
326                         loader_id);
327         if (__context.client_fd < 0) {
328                 _E("Failed to connect to launchpad");
329                 return -1;
330         }
331
332         ret = sd_event_default(&__context.event);
333         if (ret < 0) {
334                 _E("Failed to create default sd event. error(%d)", ret);
335                 return ret;
336         }
337
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);
344
345         return 0;
346 }
347
348 static void __fini_hydra(void)
349 {
350         _D("[__HYDRA__] finish hydra");
351         if (__context.sig_source)
352                 sd_event_source_unref(__context.sig_source);
353
354         if (__context.fd_source)
355                 sd_event_source_unref(__context.fd_source);
356
357         if (__context.event)
358                 sd_event_unref(__context.event);
359
360         if (__context.client_fd > 0)
361                 close(__context.client_fd);
362
363         if (__context.signal_fd > 0)
364                 close(__context.signal_fd);
365 }
366
367 static void __run_loop(void)
368 {
369         int ret;
370
371         ret = sd_event_loop(__context.event);
372         if (ret < 0)
373                 _E("Failed to run sd event loop. error(%d)", ret);
374
375         _D("[__HYDRA__] Run main loop");
376 }
377
378 static void __exit_loop(void)
379 {
380         if (__context.event)
381                 sd_event_exit(__context.event, 0);
382
383         _D("[__HYDRA__] Exit main loop");
384 }
385
386 API int launchpad_hydra_main(int argc, char **argv,
387                 hydra_lifecycle_callback_s *hydra_callbacks,
388                 void *user_data)
389 {
390         int loader_type;
391         int loader_id;
392         int is_hydra;
393         int ret = 0;
394
395         if (argc < 4) {
396                 _E("[__HYDRA__] too few argument");
397                 return -EINVAL;
398         }
399
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);
403                 return -EINVAL;
404         }
405
406         if (!hydra_callbacks) {
407                 _E("[__HYDRA__] Invalid argument");
408                 return -EINVAL;
409         }
410
411         is_hydra = argv[LOADER_ARG_HYDRA][0] - '0';
412         _D("[__HYDRA__] mode: %d", is_hydra);
413         if (!is_hydra) {
414                 _W("Run in non hydra mode");
415                 return -EINVAL;
416         }
417
418         argv[LOADER_ARG_HYDRA] = "0";
419         loader_id = atoi(argv[LOADER_ARG_ID]);
420
421         __context.argc = argc;
422         __context.argv = argv;
423         __context.hydra_callbacks = hydra_callbacks;
424         __context.user_data = user_data;
425
426         ret = __init_hydra(loader_type, loader_id);
427         if (ret < 0) {
428                 _E("Failed to initialize hydra loader");
429                 return ret;
430         }
431
432         if (__context.hydra_callbacks->precreate)
433                 __context.hydra_callbacks->precreate(user_data);
434
435         if (__context.hydra_callbacks->create)
436                 __context.hydra_callbacks->create(__context.user_data);
437
438         __context.candidate_pid = __fork_process(__run_loader, NULL);
439         _D("[__HYDRA__] candidate process(%d)", __context.candidate_pid);
440
441         __run_loop();
442
443         if (__context.hydra_callbacks->terminate)
444                 ret = __context.hydra_callbacks->terminate(__context.user_data);
445
446         __fini_hydra();
447
448         return ret;
449 }
450
451 API void launchpad_hydra_exit(void)
452 {
453         __exit_loop();
454 }