ed5d636c2e57b96aec4c43242d5479f5cd5a5306
[platform/core/appfw/debug-launchpad.git] / src / debug-launchpad.c
1 /*
2  * Copyright (c) 2015 - 2016 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
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <fcntl.h>
24 #include <sys/prctl.h>
25 #include <sys/socket.h>
26 #include <sys/un.h>
27 #include <sys/wait.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <sys/signalfd.h>
31 #include <linux/limits.h>
32 #include <glib.h>
33 #include <dlog.h>
34 #include <bundle.h>
35 #include <bundle_internal.h>
36
37 #include "common.h"
38 #include "signal_util.h"
39 #include "security_util.h"
40 #include "file_util.h"
41 #include "debug_util.h"
42 #include "perf.h"
43 #include "defs.h"
44
45 #define AUL_PR_NAME 16
46
47 static int __real_send(int clifd, int ret)
48 {
49         if (send(clifd, &ret, sizeof(int), MSG_NOSIGNAL) < 0) {
50                 if (errno == EPIPE) {
51                         _E("send failed due to EPIPE.\n");
52                         close(clifd);
53                         return -1;
54                 }
55
56                 _E("send fail to client");
57         }
58
59         close(clifd);
60
61         return 0;
62 }
63
64 static void __send_result_to_caller(int clifd, int ret)
65 {
66         int res;
67
68         _W("Check app launching");
69
70         if (clifd == -1)
71                 return;
72
73         if (ret <= 1) {
74                 _E("launching failed");
75                 __real_send(clifd, ret);
76                 return;
77         }
78
79         res = _proc_check_cmdline_bypid(ret);
80         if (res < 0) {
81                 _E("The app process might be terminated "
82                                 "while we are wating %d", ret);
83                 __real_send(clifd, -1); /* abnormally launched */
84                 return;
85         }
86
87         if (__real_send(clifd, ret) < 0) {
88                 if (kill(ret, SIGKILL) == -1)
89                         _E("Failed to send SIGKILL: %d", errno);
90         }
91
92         return;
93 }
94
95 static int __prepare_exec(const char *appid, const char *app_path,
96                 appinfo_t *appinfo, bundle *kb)
97 {
98         char *file_name;
99         char process_name[AUL_PR_NAME];
100         int ret;
101
102         /* Set new session ID & new process group ID */
103         /* In linux, child can set new session ID without check permission */
104         setsid();
105
106         /* SET PRIVILEGES */
107         _D("appid: %s / pkg_type: %s / app_path: %s",
108                         appid, appinfo->pkg_type, app_path);
109         if ((ret = _set_access(appid)) != 0) {
110                 _E("Failed to set privileges "
111                                 "- check your package's credential: %d", ret);
112                 return -1;
113         }
114
115         /* SET DUMPABLE - for coredump */
116         prctl(PR_SET_DUMPABLE, 1);
117
118         /* SET PROCESS NAME */
119         if (app_path == NULL) {
120                 _D("app_path should not be NULL - check menu db");
121                 return -1;
122         }
123
124         file_name = strrchr(app_path, '/') + 1;
125         if (file_name == NULL) {
126                 _D("can't locate file name to execute");
127                 return -1;
128         }
129
130         memset(process_name, '\0', AUL_PR_NAME);
131         snprintf(process_name, AUL_PR_NAME, "%s", file_name);
132         prctl(PR_SET_NAME, process_name);
133
134         /* SET ENVIROMENT */
135         _set_env(appinfo, kb);
136
137         return 0;
138 }
139
140 static int __prepare_fork(bundle *kb, const char *appid)
141 {
142         const char *str;
143         const char **str_array = NULL;
144         int len = 0;
145
146         if (bundle_get_type(kb, AUL_K_SDK) & BUNDLE_TYPE_ARRAY) {
147                 str_array = bundle_get_str_array(kb, AUL_K_SDK, &len);
148                 if (str_array == NULL)
149                         return -1;
150         } else {
151                 str = bundle_get_val(kb, AUL_K_SDK);
152                 if (str) {
153                         str_array = &str;
154                         len = 1;
155                 }
156         }
157
158         _prepare_debug_tool(kb, appid, str_array, len);
159
160         return 0;
161 }
162
163 static int __get_caller_pid(bundle *kb)
164 {
165         const char *str;
166         int pid;
167
168         str = bundle_get_val(kb, AUL_K_ORG_CALLER_PID);
169         if (str)
170                 goto end;
171
172         str = bundle_get_val(kb, AUL_K_CALLER_PID);
173         if (str == NULL)
174                 return -1;
175
176 end:
177         pid = atoi(str);
178         if (pid <= 1)
179                 return -1;
180
181         return pid;
182 }
183
184 static int __redirect_stdfds(int caller_pid)
185 {
186         char buf[PATH_MAX];
187         int fd;
188         int ret = 0;
189
190         /* stdout */
191         snprintf(buf, sizeof(buf), "/proc/%d/fd/1", caller_pid);
192         fd = open(buf, O_WRONLY);
193         if (fd < 0) {
194                 _E("Failed to open caller(%d) stdout", caller_pid);
195                 ret = 1;
196         } else {
197                 dup2(fd, 1);
198                 close(fd);
199         }
200
201         /* stderr */
202         snprintf(buf, sizeof(buf), "/proc/%d/fd/2", caller_pid);
203         fd = open(buf, O_WRONLY);
204         if (fd < 0) {
205                 _E("Failed to open caller(%d) stderr", caller_pid);
206                 ret += 2;
207         } else {
208                 dup2(fd, 2);
209                 close(fd);
210         }
211
212         return ret;
213 }
214
215 static int __normal_fork_exec(int argc, char **argv)
216 {
217         _D("start real fork and exec\n");
218
219         if (execv(argv[0], argv) < 0) { /* Flawfinder: ignore */
220                 if (errno == EACCES)
221                         _E("such a file is no executable - %s", argv[0]);
222                 else
223                         _E("unknown executable error - %s", argv[0]);
224
225                 return -1;
226         }
227
228         /* never reach */
229         return 0;
230 }
231
232 static void __real_launch(const char *app_path, bundle *kb)
233 {
234         int app_argc;
235         char **app_argv;
236         int i;
237
238         app_argv = _create_argc_argv(kb, &app_argc, app_path);
239         if (app_argv == NULL)
240                 return;
241
242         for (i = 0; i < app_argc; i++)
243                 _D("input argument %d : %s##", i, app_argv[i]);
244
245         PERF("setup argument done");
246
247         __normal_fork_exec(app_argc, app_argv);
248 }
249
250 static int __start_process(const char *appid, const char *app_path,
251                 bundle *kb, appinfo_t *appinfo)
252 {
253         char sock_path[PATH_MAX];
254         int pid;
255         int max_fd;
256         int iter_fd;
257
258         if (__prepare_fork(kb, appinfo->debug_appid) < 0)
259                 return -1;
260
261         pid = fork();
262         if (pid == 0) {
263                 PERF("fork done");
264                 _D("lock up test log(no error): fork done");
265
266                 _signal_unblock_sigchld();
267                 _signal_fini();
268
269                 max_fd = sysconf(_SC_OPEN_MAX);
270                 for (iter_fd = 3; iter_fd <= max_fd; iter_fd++)
271                         close(iter_fd);
272
273                 snprintf(sock_path, sizeof(sock_path), "%s/%d/%d",
274                                 SOCKET_PATH, getuid(), getpid());
275                 unlink(sock_path);
276
277                 if (__redirect_stdfds(__get_caller_pid(kb)))
278                         _E("Failed to redirect caller fds");
279
280                 PERF("prepare exec - fisrt done");
281                 _D("lock up test log(no error): prepare exec - first done");
282
283                 if (__prepare_exec(appid, app_path, appinfo, kb) < 0) {
284                         _E("preparing work fail to launch "
285                                         "- can not launch %s", appid);
286                         exit(-1);
287                 }
288
289                 PERF("prepare exec - second done");
290                 _D("lock up test log(no error): prepare exec - second done");
291                 __real_launch(app_path, kb);
292
293                 exit(-1);
294         }
295
296         _D("==> real launch pid: %d %s", pid, app_path);
297
298         return pid;
299 }
300
301 static gboolean __handle_sigchld(gpointer data)
302 {
303         GPollFD *gpollfd = (GPollFD *)data;
304         int fd = gpollfd->fd;
305         struct signalfd_siginfo siginfo;
306         ssize_t s;
307
308         do {
309                 s = read(fd, &siginfo, sizeof(struct signalfd_siginfo));
310                 if (s == 0)
311                         break;
312
313                 if (s != sizeof(struct signalfd_siginfo)) {
314                         _E("error reading sigchld info");
315                         break;
316                 }
317
318                 _debug_launchpad_sigchld(&siginfo);
319         } while (s > 0);
320
321         return TRUE;
322 }
323
324 static gboolean __handle_launch_event(gpointer data)
325 {
326         GPollFD *gpollfd = (GPollFD *)data;
327         int fd = gpollfd->fd;
328         bundle *kb = NULL;
329         app_pkt_t *pkt = NULL;
330         appinfo_t *appinfo = NULL;
331         const char *app_path = NULL;
332         int pid = -1;
333         int clifd = -1;
334         struct ucred cr;
335
336         pkt = _recv_pkt_raw(fd, &clifd, &cr);
337         if (pkt == NULL) {
338                 _E("packet is NULL");
339                 return TRUE;
340         }
341
342         kb = bundle_decode(pkt->data, pkt->len);
343         if (kb == NULL) {
344                 _E("bundle decode error");
345                 goto end;
346         }
347
348         INIT_PERF(kb);
349         PERF("packet processing start");
350
351         appinfo = _appinfo_create(kb);
352         if (appinfo == NULL) {
353                 _E("_appinfo_create() is failed.");
354                 goto end;
355         }
356
357         app_path = appinfo->app_path;
358         if (app_path == NULL) {
359                 _E("app_path is NULL");
360                 goto end;
361         }
362
363         if (app_path[0] != '/') {
364                 _E("app_path is not absolute path: %s", app_path);
365                 goto end;
366         }
367
368         _D("appid: %s", appinfo->appid);
369         _D("exec: %s", appinfo->app_path);
370         _D("debug appid: %s", appinfo->debug_appid);
371         _D("hwacc: %s", appinfo->hwacc);
372
373         _modify_bundle(kb, cr.pid, appinfo, pkt->cmd);
374         if (appinfo->appid == NULL) {
375                 _E("unable to get appid from appinfo");
376                 goto end;
377         }
378
379         PERF("get package infomation & modify bundle done");
380
381         pid = __start_process(appinfo->appid, app_path, kb, appinfo);
382
383 end:
384         __send_result_to_caller(clifd, pid);
385
386         if (pid > 0)
387                 _send_app_launch_signal(pid, appinfo->appid);
388         if (appinfo)
389                 _appinfo_free(appinfo);
390         if (kb)
391                 bundle_free(kb);
392         if (pkt)
393                 free(pkt);
394         if (_get_valgrind_option())
395                 _wait_for_valgrind_output();
396
397         return TRUE;
398 }
399
400 static gboolean __glib_check(GSource *src)
401 {
402         GSList *fd_list;
403         GPollFD *tmp;
404
405         fd_list = src->poll_fds;
406         do {
407                 tmp = (GPollFD *)fd_list->data;
408                 if ((tmp->revents &
409                                 (G_IO_IN | G_IO_PRI | G_IO_HUP | G_IO_NVAL)))
410                         return TRUE;
411                 fd_list = fd_list->next;
412         } while (fd_list);
413
414         return FALSE;
415 }
416
417 static gboolean __glib_dispatch(GSource *src, GSourceFunc callback,
418                 gpointer data)
419 {
420         return callback(data);
421 }
422
423 static gboolean __glib_prepare(GSource *src, gint *timeout)
424 {
425         return FALSE;
426 }
427
428 static void __glib_finalize(GSource *src)
429 {
430         GSList *fd_list;
431         GPollFD *gpollfd;
432
433         fd_list = src->poll_fds;
434         do {
435                 gpollfd = (GPollFD *)fd_list->data;
436                 close(gpollfd->fd);
437                 g_free(gpollfd);
438
439                 fd_list = fd_list->next;
440         } while (fd_list);
441 }
442
443 static GSourceFuncs funcs = {
444         .prepare = __glib_prepare,
445         .check = __glib_check,
446         .dispatch = __glib_dispatch,
447         .finalize = __glib_finalize
448 };
449
450 static int __poll_fd(int fd, GSourceFunc callback)
451 {
452         int r;
453         GPollFD *gpollfd;
454         GSource *src;
455
456         src = g_source_new(&funcs, sizeof(GSource));
457         if (src == NULL) {
458                 _E("out of memory");
459                 return -1;
460         }
461
462         gpollfd = (GPollFD *)g_malloc(sizeof(GPollFD));
463         if (gpollfd == NULL) {
464                 _E("out of memory");
465                 g_source_destroy(src);
466                 return -1;
467         }
468
469         gpollfd->fd = fd;
470         gpollfd->events = G_IO_IN;
471
472         g_source_add_poll(src, gpollfd);
473         g_source_set_callback(src, callback, (gpointer)gpollfd, NULL);
474         g_source_set_priority(src, G_PRIORITY_DEFAULT);
475
476         r = g_source_attach(src, NULL);
477         if (r == 0) {
478                 g_free(gpollfd);
479                 g_source_destroy(src);
480                 return -1;
481         }
482
483         return r;
484 }
485
486 static int __init_sigchld_fd(void)
487 {
488         int fd;
489
490         fd = _signal_get_sigchld_fd();
491         if (fd < 0) {
492                 _E("Failed to get sigchld fd");
493                 return -1;
494         }
495
496         if (__poll_fd(fd, (GSourceFunc)__handle_sigchld) < 0) {
497                 close(fd);
498                 return -1;
499         }
500
501         return 0;
502 }
503
504 static int __init_debug_launchpad_fd(int argc, char **argv)
505 {
506         int fd;
507
508         /* signal init */
509         _signal_init();
510
511         /* create debug-launchpad socket */
512         fd = _create_server_sock();
513         if (fd < 0) {
514                 _E("Failed to create server socket");
515                 return -1;
516         }
517
518         if (__poll_fd(fd, (GSourceFunc)__handle_launch_event) < 0) {
519                 close(fd);
520                 return -1;
521         }
522
523         return 0;
524 }
525
526 static int __before_loop(int argc, char **argv)
527 {
528         if (__init_sigchld_fd() < 0) {
529                 _E("Failed to initialize sigchld fd.");
530                 return -1;
531         }
532
533         if (__init_debug_launchpad_fd(argc, argv) < 0) {
534                 _E("Failed to initialize launchpad fd.");
535                 return -1;
536         }
537
538         return 0;
539 }
540
541 int main(int argc, char **argv)
542 {
543         GMainLoop *loop;
544
545         loop = g_main_loop_new(NULL, FALSE);
546         if (loop == NULL) {
547                 _E("Failed to create glib main loop.");
548                 return -1;
549         }
550
551         if (__before_loop(argc, argv) < 0) {
552                 _E("Failed to initiailze debug-launchapd.");
553                 return -1;
554         }
555
556         g_main_loop_run(loop);
557
558         return 0;
559 }
560