Fix resource leak
[platform/core/appfw/debug-launchpad.git] / src / common.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 <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <sys/xattr.h>
26 #include <sys/socket.h>
27 #include <sys/un.h>
28 #include <errno.h>
29 #include <dirent.h>
30 #include <bundle.h>
31 #include <bundle_internal.h>
32 #ifdef _APPFW_FEATURE_SOCKET_ACTIVATION
33 #include <systemd/sd-daemon.h>
34 #endif /* _APPFW_FEATURE_SOCKET_ACTIVATION */
35
36 #include "common.h"
37 #include "debug_util.h"
38 #include "defs.h"
39
40 #define MAX_PATH_LEN 1024
41 #define MAX_CMD_BUFSZ 1024
42 #define PATH_TMP "/tmp"
43 #define PATH_DATA "/data"
44 #define AUL_PKT_HEADER_SIZE (sizeof(int) + sizeof(int) + sizeof(int))
45
46 static void __set_sock_option(int fd, int cli)
47 {
48         int size;
49         struct timeval tv = { 5, 200 * 1000 };  /* 5.2 sec */
50
51         size = AUL_SOCK_MAXBUFF;
52         setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
53         setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
54         if (cli)
55                 setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
56 }
57
58 #ifdef _APPFW_FEATURE_SOCKET_ACTIVATION
59 static int __create_sock_activation(void)
60 {
61         int listen_fds;
62
63         listen_fds = sd_listen_fds(0);
64         if (listen_fds == 1)
65                 return SD_LISTEN_FDS_START;
66         else if (listen_fds > 1)
67                 _E("Too many file descriptors received.");
68         else
69                 _E("There is no socket stream");
70
71         return -1;
72 }
73 #endif /* _APPFW_FEATURE_SOCKET_ACTIVATION */
74
75 static int __create_server_socket(void)
76 {
77         struct sockaddr_un saddr;
78         int fd;
79
80         fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
81         /* support above version 2.6.27 */
82         if (fd < 0) {
83                 if (errno == EINVAL) {
84                         fd = socket(AF_UNIX, SOCK_STREAM, 0);
85                         if (fd < 0) {
86                                 _E("second chance - socket create error");
87                                 return -1;
88                         }
89                 } else {
90                         _E("socket error");
91                         return -1;
92                 }
93         }
94
95         memset(&saddr, 0, sizeof(saddr));
96         saddr.sun_family = AF_UNIX;
97         snprintf(saddr.sun_path, sizeof(saddr.sun_path),
98                         "%s/%d/.debug-launchpad-sock",
99                         SOCKET_PATH, getuid());
100         unlink(saddr.sun_path);
101
102         if (bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
103                 _E("bind error");
104                 close(fd);
105                 return -1;
106         }
107
108         if (chmod(saddr.sun_path, (S_IRWXU | S_IRWXG | S_IRWXO)) < 0) {
109                 /* Flawfinder: ignore */
110                 _E("Failed to change the socket permission");
111                 close(fd);
112                 return -1;
113         }
114
115         __set_sock_option(fd, 0);
116
117         if (listen(fd, 128) == -1) {
118                 _E("listen error");
119                 close(fd);
120                 return -1;
121         }
122
123         return fd;
124 }
125
126 int _create_server_sock(void)
127 {
128         int fd = -1;
129
130 #ifdef _APPFW_FEATURE_SOCKET_ACTIVATION
131         fd = __create_sock_activation();
132 #endif /* _APPFW_FEATURE_SOCKET_ACTIAVTION */
133         if (fd < 0) {
134                 fd = __create_server_socket();
135                 if (fd < 0) {
136                         _E("server sock error %d", fd);
137                         return -1;
138                 }
139         }
140
141         return fd;
142 }
143
144 app_pkt_t *_recv_pkt_raw(int fd, int *clifd, struct ucred *cr)
145 {
146         int len;
147         int ret;
148         struct sockaddr_un aul_addr = {0, };
149         int sun_size;
150         app_pkt_t *pkt = NULL;
151         int cl = sizeof(struct ucred);
152         unsigned char buf[AUL_SOCK_MAXBUFF];
153         int cmd;
154         int datalen;
155         int opt;
156
157         sun_size = sizeof(struct sockaddr_un);
158
159         if ((*clifd = accept(fd, (struct sockaddr *)&aul_addr,
160                                         (socklen_t *)&sun_size)) == -1) {
161                 if (errno != EINTR)
162                         _E("accept error");
163                 return NULL;
164         }
165
166         if (getsockopt(*clifd, SOL_SOCKET, SO_PEERCRED, cr,
167                                 (socklen_t *)&cl) < 0) {
168                 _E("peer information error");
169                 close(*clifd);
170                 return NULL;
171         }
172
173         __set_sock_option(*clifd, 1);
174
175 retry_recv:
176         /* receive header(cmd, datalen) */
177         len = recv(*clifd, buf, AUL_PKT_HEADER_SIZE, 0);
178         if (len < 0)
179                 if (errno == EINTR)
180                         goto retry_recv;
181
182         if (len < AUL_PKT_HEADER_SIZE) {
183                 _E("recv error");
184                 close(*clifd);
185                 return NULL;
186         }
187         memcpy(&cmd, buf, sizeof(int));
188         memcpy(&datalen, buf + sizeof(int), sizeof(int));
189         memcpy(&opt, buf + sizeof(int) + sizeof(int), sizeof(int));
190
191         /* allocate for a null byte */
192         pkt = (app_pkt_t *)calloc(1, AUL_PKT_HEADER_SIZE + datalen + 1);
193         if (pkt == NULL) {
194                 close(*clifd);
195                 return NULL;
196         }
197         pkt->cmd = cmd;
198         pkt->len = datalen;
199         pkt->opt = opt;
200
201         len = 0;
202         while (len != pkt->len) {
203                 ret = recv(*clifd, pkt->data + len, pkt->len - len, 0);
204                 if (ret < 0) {
205                         _E("recv error %d %d", len, pkt->len);
206                         free(pkt);
207                         close(*clifd);
208                         return NULL;
209                 }
210                 len += ret;
211                 _D("recv len %d %d", len, pkt->len);
212         }
213
214         return pkt;
215 }
216
217 static char *__appinfo_get_app_path(appinfo_t *appinfo)
218 {
219         int i = 0;
220         int path_len = -1;
221         char *tmp_app_path;
222
223         if (appinfo == NULL || appinfo->app_path == NULL)
224                 return NULL;
225
226         while (appinfo->app_path[i] != 0) {
227                 if (appinfo->app_path[i] == ' '
228                                 || appinfo->app_path[i] == '\t') {
229                         path_len = i;
230                         break;
231                 }
232
233                 i++;
234         }
235
236         if (path_len == 0) {
237                 free(appinfo->app_path);
238                 appinfo->app_path = NULL;
239         } else if (path_len > 0) {
240                 tmp_app_path = (char *)malloc(sizeof(char) * (path_len + 1));
241                 if (tmp_app_path == NULL)
242                         return NULL;
243
244                 snprintf(tmp_app_path, path_len + 1, "%s", appinfo->app_path);
245                 free(appinfo->app_path);
246                 appinfo->app_path = tmp_app_path;
247         }
248
249         return appinfo->app_path;
250 }
251
252 appinfo_t *_appinfo_create(bundle *kb)
253 {
254         appinfo_t *appinfo;
255         const char *ptr;
256
257         appinfo = (appinfo_t *)calloc(1, sizeof(appinfo_t));
258         if (appinfo == NULL)
259                 return NULL;
260
261         ptr = bundle_get_val(kb, AUL_K_APPID);
262         if (ptr)
263                 appinfo->appid = strdup(ptr);
264         ptr = bundle_get_val(kb, AUL_K_PACKAGETYPE);
265         if (ptr)
266                 appinfo->pkg_type = strdup(ptr);
267         ptr = bundle_get_val(kb, AUL_K_HWACC);
268         if (ptr)
269                 appinfo->hwacc = strdup(ptr);
270         ptr = bundle_get_val(kb, AUL_K_PKGID);
271         if (ptr)
272                 appinfo->debug_appid = strdup(ptr);
273         ptr = bundle_get_val(kb, AUL_K_TASKMANAGE);
274         if (ptr)
275                 appinfo->taskmanage = strdup(ptr);
276         ptr = bundle_get_val(kb, AUL_K_COMP_TYPE);
277         if (ptr)
278                 appinfo->comp_type = strdup(ptr);
279         ptr = bundle_get_val(kb, AUL_K_EXEC);
280         if (ptr)
281                 appinfo->app_path = strdup(ptr);
282         if (appinfo->app_path)
283                 appinfo->original_app_path = strdup(appinfo->app_path);
284
285         if (__appinfo_get_app_path(appinfo) == NULL) {
286                 _appinfo_free(appinfo);
287                 return NULL;
288         }
289
290         return appinfo;
291 }
292
293 void _appinfo_free(appinfo_t *appinfo)
294 {
295         if (appinfo == NULL)
296                 return;
297
298         if (appinfo->appid)
299                 free(appinfo->appid);
300         if (appinfo->app_path)
301                 free(appinfo->app_path);
302         if (appinfo->original_app_path)
303                 free(appinfo->original_app_path);
304         if (appinfo->pkg_type)
305                 free(appinfo->pkg_type);
306         if (appinfo->hwacc)
307                 free(appinfo->hwacc);
308         if (appinfo->taskmanage)
309                 free(appinfo->taskmanage);
310         if (appinfo->debug_appid)
311                 free(appinfo->debug_appid);
312         if (appinfo->comp_type)
313                 free(appinfo->comp_type);
314
315         free(appinfo);
316 }
317
318 static int __parse_app_path(const char *arg, char *out, int out_size)
319 {
320         register int i;
321         int state = 1;
322         char *start_out = out;
323
324         if (arg == NULL || out == NULL)
325                 return 0;
326
327         for (i = 0; out_size > 1; i++) {
328                 switch (state) {
329                 case 1:
330                         switch (arg[i]) {
331                         case ' ':
332                         case '\t':
333                                 state = 5;
334                                 break;
335                         case '\0':
336                                 state = 7;
337                                 break;
338                         case '\"':
339                                 state = 2;
340                                 break;
341                         case '\\':
342                                 state = 4;
343                                 break;
344                         default:
345                                 *out = arg[i];
346                                 out++;
347                                 out_size--;
348                                 break;
349                         }
350                         break;
351                 case 2: /* escape start */
352                         switch (arg[i]) {
353                         case '\0':
354                                 state = 6;
355                                 break;
356                         case '\"':
357                                 state = 1;
358                                 break;
359                         default:
360                                 *out = arg[i];
361                                 out++;
362                                 out_size--;
363                                 break;
364                         }
365                         break;
366                 case 4: /* character escape */
367                         if (arg[i] == '\0')
368                                 state = 6;
369                         else {
370                                 *out = arg[i];
371                                 out++;
372                                 out_size--;
373                                 state = 1;
374                         }
375                         break;
376                 case 5: /* token */
377                         if (out != start_out) {
378                                 *out = '\0';
379                                 out_size--;
380                                 return i;
381                         }
382                         i--;
383                         state = 1;
384                         break;
385                 case 6:
386                         return -1;  /* error */
387                 case 7: /* terminate */
388                         *out = '\0';
389                         out_size--;
390                         return 0;
391                 default:
392                         state = 6;
393                         break;  /* error */
394                 }
395         }
396
397         if (out_size == 1)
398                 *out = '\0';
399
400         /* Buffer overflow*/
401         return -2;
402 }
403
404 void _modify_bundle(bundle *kb, int caller_pid, appinfo_t *appinfo, int cmd)
405 {
406         char *ptr;
407         char exe[MAX_PATH_LEN];
408         int flag;
409         char key[256];
410         char value[256];
411
412         bundle_del(kb, AUL_K_APPID);
413         bundle_del(kb, AUL_K_EXEC);
414         bundle_del(kb, AUL_K_PACKAGETYPE);
415         bundle_del(kb, AUL_K_HWACC);
416         bundle_del(kb, AUL_K_PKGID);
417         bundle_del(kb, AUL_K_TASKMANAGE);
418         bundle_del(kb, AUL_K_COMP_TYPE);
419
420         /* Parse app_path to retrieve default bundle */
421         if (cmd == PAD_CMD_LAUNCH) {
422                 ptr = appinfo->original_app_path;
423                 flag = __parse_app_path(ptr, exe, sizeof(exe));
424                 if (flag > 0) {
425                         ptr += flag;
426                         SECURE_LOGD("parsing app_path: EXEC - %s", exe);
427
428                         do {
429                                 flag = __parse_app_path(ptr, key, sizeof(key));
430                                 if (flag <= 0)
431                                         break;
432                                 ptr += flag;
433
434                                 flag = __parse_app_path(ptr, value,
435                                                 sizeof(value));
436                                 if (flag < 0)
437                                         break;
438                                 ptr += flag;
439
440                                 /* bundle_del(kb, key); */
441                                 bundle_add(kb, key, value);
442                         } while (flag > 0);
443                 } else if (flag == 0) {
444                         _D("parsing app_path: No arguments");
445                 } else {
446                         _D("parsing app_path: Invalid argument");
447                 }
448
449         }
450 }
451
452 static void __set_sdk_env(const char *appid, const char *value)
453 {
454         char buf[MAX_LOCAL_BUFSZ];
455         char *token = NULL;
456
457         _D("key: %s / value: %s", AUL_K_SDK, value);
458         /* http://gcc.gnu.org/onlinedocs/gcc/Cross_002dprofiling.html*/
459         /* GCOV_PREFIX contains the prefix to add to the absolute paths */
460         /*      in the object file. Prefix can be absolute, or relative.*/
461         /*      The default is no prefix.  */
462         /* GCOV_PREFIX_STRIP indicates the how many initial directory names */
463         /*      to stripoff the hardwired absolute paths. Default value is 0. */
464         if (strncmp(value, SDK_CODE_COVERAGE, strlen(value)) == 0) {
465                 token = strrchr(appid, '.');
466                 if (token == NULL)
467                         return;
468                 token++;
469
470                 snprintf(buf, sizeof(buf), PATH_TMP"/%s"PATH_DATA, token);
471                 setenv("GCOV_PREFIX", buf, 1);
472                 setenv("GCOV_PREFIX_STRIP", "0", 1);
473         } else if (strncmp(value, SDK_DYNAMIC_ANALYSIS, strlen(value)) == 0) {
474                 setenv("LD_PRELOAD", PATH_DA_SO, 1);
475         }
476 }
477
478 void _set_env(appinfo_t *appinfo, bundle *kb)
479 {
480         const char *str;
481         const char **str_array = NULL;
482         int len = 0;
483         int i;
484
485         setenv("PKG_NAME", appinfo->appid, 1);
486
487         str = bundle_get_val(kb, AUL_K_STARTTIME);
488         if (str)
489                 setenv("APP_START_TIME", str, 1);
490         if (appinfo->hwacc)
491                 setenv("HWACC", appinfo->hwacc, 1);
492         if (appinfo->taskmanage)
493                 setenv("TASKMANAGE", appinfo->taskmanage, 1);
494
495         if (bundle_get_type(kb, AUL_K_SDK) & BUNDLE_TYPE_ARRAY)
496                 str_array = bundle_get_str_array(kb, AUL_K_SDK, &len);
497         else {
498                 str = bundle_get_val(kb, AUL_K_SDK);
499                 if (str) {
500                         str_array = &str;
501                         len = 1;
502                 }
503         }
504
505         for (i = 0; i < len; i++)
506                 __set_sdk_env(appinfo->appid, str_array[i]);
507 }
508
509 static char **__add_arg(bundle *kb, char **argv, int *margc, const char *key)
510 {
511         const char *str = NULL;
512         const char **str_array = NULL;
513         int len = 0;
514         int i;
515         char **new_argv = NULL;
516
517         if (bundle_get_type(kb, key) & BUNDLE_TYPE_ARRAY) {
518                 str_array = bundle_get_str_array(kb, key, &len);
519         } else {
520                 str = bundle_get_val(kb, key);
521                 if (str) {
522                         str_array = &str;
523                         len = 1;
524                 }
525         }
526
527         if (str_array) {
528                 if (strncmp(key, DLP_K_DEBUG_ARG, strlen(key)) == 0
529                         || strncmp(key, DLP_K_VALGRIND_ARG, strlen(key)) == 0) {
530                         new_argv = (char **)realloc(argv,
531                                         sizeof(char *) * (*margc + len + 2));
532                         if (new_argv == NULL) {
533                                 _E("Failed to realloc (key: %s)", key);
534                                 exit(-1);
535                         }
536
537                         for (i = *margc + len + 1; i - (len + 1) >= 0; i--)
538                                 new_argv[i] = new_argv[i - (len + 1)];
539
540                         /* need to add new_argv[0] */
541                         for (i = 0; i < len; i++)
542                                 new_argv[1 + i] = strdup(str_array[i]);
543
544                         len++; /* gdbserver or valgrind */
545                 } else if (strncmp(key, DLP_K_ATTACH_ARG, strlen(key)) == 0) {
546                         new_argv = (char **)malloc((len + 2) * sizeof(char *));
547                         if (new_argv == NULL) {
548                                 _E("Failed to malloc (key: %s)", key);
549                                 exit(-1);
550                         }
551
552                         for (i = 0; i < len; i++)
553                                 new_argv[1 + i] = strdup(str_array[i]);
554
555                         *margc = 0;
556                         len = len + 1;
557                 } else {
558                         new_argv = (char **)realloc(argv,
559                                         sizeof(char *) * (*margc + len + 1));
560                         if (new_argv == NULL) {
561                                 _E("Failed to realloc (key: %s)", key);
562                                 exit(-1);
563                         }
564
565                         for (i = 0; i < len; i++)
566                                 new_argv[*margc + i] = strdup(str_array[i]);
567                 }
568
569                 new_argv[*margc + len] = NULL;
570                 *margc += len;
571         } else {
572                 if (strncmp(key, DLP_K_DEBUG_ARG, strlen(key)) == 0
573                         || strncmp(key, DLP_K_VALGRIND_ARG, strlen(key)) == 0) {
574                         new_argv = (char **)realloc(argv,
575                                         sizeof(char *) * (*margc + 2));
576                         if (new_argv == NULL) {
577                                 _E("Failed to realloc (key: %s)", key);
578                                 exit(-1);
579                         }
580
581                         for (i = *margc + 1; i - 1 >= 0; i--)
582                                 new_argv[i] = new_argv[i - 1];
583
584                         /* need to add new_argv[0] */
585                         (*margc)++;
586                 }
587         }
588
589         if (new_argv == NULL)
590                 return argv;
591
592         return new_argv;
593 }
594
595 char **_create_argc_argv(bundle *kb, int *margc, const char *app_path)
596 {
597         char **argv = NULL;
598         char **new_argv = NULL;
599         int argc;
600         int i;
601         char buf[MAX_LOCAL_BUFSZ];
602         const char *str;
603         const char **str_array = NULL;
604         int len = 0;
605         const char *path;
606
607         argc = bundle_export_to_argv(kb, &argv);
608         if (argv) {
609                 argv[0] = strdup(app_path);
610         } else {
611                 _E("bundle_export_to_argv() is failed.");
612                 return NULL;
613         }
614
615         if (bundle_get_type(kb, AUL_K_SDK) & BUNDLE_TYPE_ARRAY) {
616                 str_array = bundle_get_str_array(kb, AUL_K_SDK, &len);
617         } else {
618                 str = bundle_get_val(kb, AUL_K_SDK);
619                 if (str) {
620                         str_array = &str;
621                         len = 1;
622                 }
623         }
624
625         for (i = 0; i < len; i++) {
626                 if (str_array[i] == NULL)
627                         break;
628
629                 if (strncmp(str_array[i], SDK_DEBUG,
630                                         strlen(str_array[i])) == 0) {
631                         if (argv[0])
632                                 free(argv[0]);
633                         snprintf(buf, sizeof(buf), "%s.exe", app_path);
634                         /* this code is added because core app don't have '.exe' excutable */
635                         /* if '.exe' not exist then use app_path */
636                         if (access(buf, F_OK) != 0)
637                                 argv[0] = strdup(app_path);
638                         else
639                                 argv[0] = strdup(buf);
640
641                         path = bundle_get_val(kb, DLP_K_GDBSERVER_PATH);
642                         if (path == NULL) {
643                                 _E("Failed to get gdbserver path");
644                                 if (argv[0])
645                                         free(argv[0]);
646                                 bundle_free_exported_argv(argc, &argv);
647                                 *margc = 0;
648                                 return NULL;
649                         }
650                         new_argv = __add_arg(kb, argv, &argc, DLP_K_DEBUG_ARG);
651                         new_argv[0] = strdup(path);
652                         argv = new_argv;
653                 } else if (strncmp(str_array[i], SDK_VALGRIND,
654                                         strlen(str_array[i])) == 0) {
655                         path = bundle_get_val(kb, DLP_K_VALGRIND_PATH);
656                         if (path == NULL) {
657                                 _E("Failed to get valgrind path");
658                                 if (argv[0])
659                                         free(argv[0]);
660                                 bundle_free_exported_argv(argc, &argv);
661                                 *margc = 0;
662                                 return NULL;
663                         }
664                         new_argv = __add_arg(kb, argv, &argc,
665                                         DLP_K_VALGRIND_ARG);
666                         new_argv[0] = strdup(path);
667                         argv = new_argv;
668                 } else if (strncmp(str_array[i], SDK_UNIT_TEST,
669                                         strlen(str_array[i])) == 0) {
670                         new_argv = __add_arg(kb, argv, &argc,
671                                         DLP_K_UNIT_TEST_ARG);
672                         argv = new_argv;
673                 } else if (strncmp(str_array[i], SDK_ATTACH,
674                                         strlen(str_array[i])) == 0) {
675                         if (argv[0])
676                                 free(argv[0]);
677                         bundle_free_exported_argv(argc, &argv);
678                         *margc = 0;
679                         path = bundle_get_val(kb, DLP_K_GDBSERVER_PATH);
680                         if (path == NULL) {
681                                 _E("Failed to get gdbserver path");
682                                 return NULL;
683                         }
684                         new_argv = __add_arg(kb, argv, &argc, DLP_K_ATTACH_ARG);
685                         new_argv[0] = strdup(path);
686                         argv = new_argv;
687                 }
688         }
689
690         *margc = argc;
691
692         return argv;
693 }
694
695 static int __read_proc(const char *path, char *buf, int size)
696 {
697         int fd;
698         int ret;
699
700         if (buf == NULL || path == NULL)
701                 return -1;
702
703         fd = open(path, O_RDONLY);
704         if (fd < 0)
705                 return -1;
706
707         ret = read(fd, buf, size - 1);
708         if (ret <= 0) {
709                 close(fd);
710                 return -1;
711         } else {
712                 buf[ret] = 0;
713         }
714
715         close(fd);
716
717         return ret;
718 }
719
720 int _proc_check_cmdline_bypid(int pid)
721 {
722         char buf[MAX_CMD_BUFSZ];
723         int ret;
724
725         snprintf(buf, sizeof(buf), "/proc/%d/cmdline", pid);
726         ret = __read_proc(buf, buf, sizeof(buf));
727         if (ret <= 0)
728                 return -1;
729
730         _D("cmdline: %s", buf);
731
732         return 0;
733 }
734