hal-api: common: Check value validation for current platform HAL ABI version
[platform/hal/api/common.git] / src / hal-api-common.c
1 /*
2  * HAL Common API
3  *
4  * Copyright (c) 2020 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include <stdio.h>
20 #include <stdint.h>
21 #include <stdbool.h>
22 #include <dlfcn.h>
23 #include <dirent.h>
24
25 #define _GNU_SOURCE
26 #include <errno.h>
27
28 #include <glib-object.h>
29
30 #include "common.h"
31 #include "hal-api-conf.h"
32
33 extern char *program_invocation_name;
34
35 #ifndef EXPORT
36 #define EXPORT __attribute__ ((visibility("default")))
37 #endif
38
39 static enum hal_abi_version g_platform_curr_abi_version;
40 G_LOCK_DEFINE_STATIC(hal_common_lock);
41
42 EXPORT
43 int hal_common_get_backend_library_name(enum hal_module module, char *name, int size)
44 {
45         const char *library_name = NULL;
46         struct __hal_module_info *info = NULL;
47         int ret;
48         int len_library_name;
49
50         /* Check parameter whether is valid or not */
51         if (module <= HAL_MODULE_UNKNOWN || module >= HAL_MODULE_END) {
52                 _E("Invalid parameter of HAL module (%d)\n", module);
53                 return -EINVAL;
54         }
55
56         if (_hal_api_conf_init())
57                 return -EINVAL;
58
59         info = _hal_api_conf_get_module_info(module, NULL);
60         if (info == NULL) {
61                 _E("Failed to get HAL module(%d) information\n", module);
62                 ret = -EINVAL;
63                 goto out;
64         }
65
66         library_name = get_backend_library_name(info);
67         if (!library_name) {
68                 _E("%s backend library name is NULL\n", info->module_name);
69                 ret = 0;
70                 goto out;
71         }
72
73         len_library_name = strlen(library_name);
74         if (!name || (len_library_name + 1 > size)) {
75                 ret = -EINVAL;
76                 name = NULL;
77                 goto out;
78         }
79         strncpy(name, library_name, len_library_name);
80         name[len_library_name] = '\0';
81
82         ret = 0;
83 out:
84         _hal_api_conf_exit();
85
86         return ret;
87 }
88
89 EXPORT
90 int hal_common_get_backend_symbol_name(enum hal_module module, char *name, int size)
91 {
92         struct __hal_module_info *info = NULL;
93         char *symbol_name = NULL;
94         int ret;
95         int len_symbol_name;
96
97         /* Check parameter whether is valid or not */
98         if (module <= HAL_MODULE_UNKNOWN || module >= HAL_MODULE_END) {
99                 _E("Invalid paramer of HAL module (%d)\n", module);
100                 return -EINVAL;
101         }
102
103         if (_hal_api_conf_init())
104                 return -EINVAL;
105
106         info = _hal_api_conf_get_module_info(module, NULL);
107         if (info == NULL) {
108                 _E("Failed to get HAL module(%d) information\n", module);
109                 ret = -EINVAL;
110                 goto out;
111         }
112         symbol_name = info->symbol_name;
113         if (!symbol_name) {
114                 _E("%s backend symbol name is NULL\n", info->module_name);
115                 ret = 0;
116                 goto out;
117         }
118
119         len_symbol_name = strlen(symbol_name);
120         if (!name || (len_symbol_name + 1 > size)) {
121                 ret = -EINVAL;
122                 name = NULL;
123                 goto out;
124         }
125         strncpy(name, symbol_name, len_symbol_name);
126         name[len_symbol_name] = '\0';
127
128         ret = 0;
129 out:
130         _hal_api_conf_exit();
131
132         return ret;
133 }
134
135 static int __open_backend(struct __hal_module_info *info)
136 {
137         const char *backend_library_name = NULL;
138         int ret;
139
140         if (info->backend && info->handle)
141                 return 0;
142
143         backend_library_name = get_backend_library_name(info);
144         if (!backend_library_name) {
145                 _E("%s: Failed to get backend library name\n",
146                                 info->module_name);
147                 ret = -EINVAL;
148                 goto err;
149         }
150
151         if (!info->symbol_name) {
152                 _E("%s: Failed to get backend symbol name\n",
153                                 info->module_name);
154                 ret = -EINVAL;
155                 goto err;
156         }
157
158         info->handle = dlopen(backend_library_name, RTLD_LAZY);
159         if (!info->handle) {
160                 _E("%s: Failed to load backend library (%s)\n",
161                                 info->module_name, dlerror());
162                 ret = -EINVAL;
163                 goto err;
164         }
165
166         info->backend = dlsym(info->handle, info->symbol_name);
167         if (!info->backend) {
168                 _E("%s: Failed to find backend data (%s)\n",
169                                 info->module_name, dlerror());
170                 ret = -EINVAL;
171                 goto err_dlclose;
172         }
173
174         _I("%s: Open HAL backend: name(%s)/vendor(%s)/library(%s)/count(%d) by %s\n",
175                 info->module_name, info->backend->name, info->backend->vendor,
176                 backend_library_name, info->usage_count,
177                 program_invocation_name);
178
179         return 0;
180
181 err_dlclose:
182         dlclose(info->handle);
183 err:
184         info->backend = NULL;
185         info->handle = NULL;
186
187         return ret;
188 }
189
190 static void __close_backend(struct __hal_module_info *info)
191 {
192         if (!info->backend || !info->handle)
193                 return;
194
195         _I("%s: Close HAL backend: name(%s)/vendor(%s)/library(%s)/count(%d) by %s\n",
196                 info->module_name, info->backend->name, info->backend->vendor,
197                 get_backend_library_name(info), info->usage_count,
198                 program_invocation_name);
199
200         if (info->handle)
201                 dlclose(info->handle);
202
203         info->backend = NULL;
204         info->handle = NULL;
205 }
206
207 static int __init_backend(struct __hal_module_info *info, void **data,
208                                 const char *library_name)
209 {
210         int ret;
211
212         if (!info->handle || !info->backend) {
213                 _I("%s: Has not yet dlopend backend\n", info->module_name);
214                 return 0;
215         }
216
217         if (!info->backend->init) {
218                 _E("%s: hal_backend->init() is NULL\n", info->module_name);
219                 return -EINVAL;
220         }
221
222         /* Check HAL ABI Version */
223         ret = hal_common_check_backend_abi_version(info->module,
224                                                 info->backend->abi_version);
225         if (ret < 0) {
226                 _E("%s: Failed to check ABI version\n", info->module_name);
227                 return -EINVAL;
228         }
229
230         /* Initialize backend */
231         ret = info->backend->init(data);
232         if (ret < 0) {
233                 _E("%s: Failed to initialize backend: name(%s)/vendor(%s)\n",
234                         info->module_name, info->backend->name,
235                         info->backend->vendor);
236                 return -EINVAL;
237         }
238
239         return 0;
240 }
241
242 static int __exit_backend(struct __hal_module_info *info, void *data,
243                                 const char *library_name)
244 {
245         int ret;
246
247         if (!info->handle || !info->backend) {
248                 _I("%s: Has not yet dlopend backend\n", info->module_name);
249                 return 0;
250         }
251
252         /* Exit backend */
253         if (info->backend->exit) {
254                 ret = info->backend->exit(data);
255                 if (ret < 0) {
256                         _E("%s: Failed to exit backend: name(%s)/vendor(%s)\n",
257                                 info->module_name, info->backend->name,
258                                 info->backend->vendor);
259                         return -EINVAL;
260                 }
261         }
262
263         return 0;
264 }
265
266 static int __get_backend(enum hal_module module, void **data,
267                                 const char *library_name)
268 {
269         struct __hal_module_info *info = NULL;
270         int ret;
271
272         if (module <= HAL_MODULE_UNKNOWN || module >= HAL_MODULE_END) {
273                 _E("Invalid parameter of HAL module (%d)\n", module);
274                 return -EINVAL;
275         }
276
277         G_LOCK(hal_common_lock);
278         if (_hal_api_conf_init()) {
279                 ret = -EINVAL;
280                 goto err;
281         }
282
283         info = _hal_api_conf_get_module_info(module, library_name);
284         if (info == NULL) {
285                 if (!library_name)
286                         _E("Failed to get HAL module(%d) information\n", module);
287                 else
288                         _E("Failed to get HAL module(%d) information (%s)\n",
289                                 module, library_name);
290                 ret = -EINVAL;
291                 goto err;
292         }
293
294         ret = __open_backend(info);
295         if (ret < 0) {
296                 _E("%s: Failed to get the backend library by dlopen\n",
297                                 info->module_name);
298                 ret = -EINVAL;
299                 goto err;
300         }
301
302         ret = __init_backend(info, data, NULL);
303         if (ret < 0) {
304                 _E("%s: Failed to initialize the backend library\n",
305                                 info->module_name);
306                 ret = -EINVAL;
307                 goto err_dlclose;
308         }
309
310         info->usage_count++;
311
312         _I("%s: Get HAL backend: name(%s)/vendor(%s)/library(%s)/count(%d) by %s\n",
313                 info->module_name, info->backend->name, info->backend->vendor,
314                 get_backend_library_name(info), info->usage_count,
315                 program_invocation_name);
316
317         G_UNLOCK(hal_common_lock);
318         return 0;
319
320 err_dlclose:
321         _hal_api_conf_exit();
322         __close_backend(info);
323 err:
324         G_UNLOCK(hal_common_lock);
325         return ret;
326 }
327
328 static int __put_backend(enum hal_module module, void *data,
329                                 const char *library_name)
330 {
331         struct __hal_module_info *info = NULL;
332         int ret;
333
334         /* Check parameter whether is valid or not */
335         if (module <= HAL_MODULE_UNKNOWN || module >= HAL_MODULE_END) {
336                 _E("Invalid parameter of HAL module (%d)\n", module);
337                 return -EINVAL;
338         }
339
340         G_LOCK(hal_common_lock);
341
342         info = _hal_api_conf_get_module_info(module, library_name);
343         if (info == NULL) {
344                 _E("Failed to get HAL module(%d) information\n", module);
345                 ret =  -EINVAL;
346                 goto out;
347         }
348
349         if (!info->handle || !info->backend) {
350                 _I("%s: Has not yet dlopend backend\n", info->module_name);
351                 ret = 0;
352                 goto out;
353         }
354
355         if (!info->usage_count) {
356                 _I("%s: Already fully put for HAL module\n", info->module_name);
357                 ret =  0;
358                 goto out;
359         }
360
361         ret = __exit_backend(info, data, NULL);
362         if (ret < 0) {
363                 _E("%s: Failed to exit the backend library\n",
364                                 info->module_name);
365                 ret = -EINVAL;
366                 goto out;
367         }
368
369         info->usage_count--;
370
371         _I("%s: Put HAL backend: name(%s)/vendor(%s)/library(%s)/count(%d) by %s\n",
372                 info->module_name, info->backend->name, info->backend->vendor,
373                 get_backend_library_name(info), info->usage_count,
374                 program_invocation_name);
375
376         if (info->usage_count > 0) {
377                 ret = 0;
378                 goto out;
379         }
380
381         __close_backend(info);
382         _hal_api_conf_exit();
383
384         ret = 0;
385
386 out:
387         G_UNLOCK(hal_common_lock);
388         return ret;
389 }
390
391 static int __get_backend_data(enum hal_module module, unsigned int *abi_version,
392                         char *name, int name_size, char *vendor, int vendor_size)
393 {
394         struct __hal_module_info *info = NULL;
395         int ret, len;
396
397         if (module <= HAL_MODULE_UNKNOWN || module >= HAL_MODULE_END) {
398                 _E("Invalid parameter of HAL module (%d)\n", module);
399                 return 0;
400         }
401
402         G_LOCK(hal_common_lock);
403
404         if (_hal_api_conf_init()) {
405                 ret = HAL_ABI_VERSION_UNKNOWN;
406                 goto err_unlock;
407         }
408
409         info = _hal_api_conf_get_module_info(module, NULL);
410         if (info == NULL) {
411                 _E("Failed to get HAL module(%d) information\n", module);
412                 ret = HAL_ABI_VERSION_UNKNOWN;
413                 goto err_conf_exit;
414         }
415
416         ret = __open_backend(info);
417         if (ret < 0) {
418                 _E("%s: Failed to get the backend library by dlopen\n",
419                                 info->module_name);
420                 ret = -EINVAL;
421                 goto err_conf_exit;
422         }
423
424         /* Return abi_verion of hal_backend structure */
425         if (!name_size && !vendor_size) {
426                 *abi_version = info->backend->abi_version;
427
428         /* Return name of hal_backend structure */
429         } else if (info->backend->name && name_size && !vendor_size) {
430                 len = strlen(info->backend->name);
431
432                 if (!info->backend->name || (len + 1 > name_size)) {
433                         _E("%s: Invalid size of name[] array\n", info->module_name);
434                         ret = -EINVAL;
435                         goto err_conf_exit;
436                 }
437
438                 strncpy(name, info->backend->name, len);
439                 name[len] = '\0';
440
441         /* Return vendor of hal_backend structure */
442         } else if (info->backend->vendor && !name_size && vendor_size) {
443                 len = strlen(info->backend->vendor);
444
445                 if (!info->backend->vendor || (len + 1 > vendor_size)) {
446                         _E("%s: Invalid size of vendor[] array\n", info->module_name);
447                         ret = -EINVAL;
448                         goto err_conf_exit;
449                 }
450
451                 strncpy(vendor, info->backend->vendor, len);
452                 vendor[len] = '\0';
453         } else {
454                 _E("%s: Failed to get backend data\n", info->module_name);
455                 ret = -EINVAL;
456                 goto err_conf_exit;
457         }
458         ret = 0;
459
460 err_conf_exit:
461         _hal_api_conf_exit();
462 err_unlock:
463         G_UNLOCK(hal_common_lock);
464         return ret;
465 }
466
467 EXPORT
468 int hal_common_get_backend(enum hal_module module, void **data)
469 {
470         return __get_backend(module, data, NULL);
471 }
472
473 EXPORT
474 int hal_common_put_backend(enum hal_module module, void *data)
475 {
476         return __put_backend(module, data, NULL);
477 }
478
479 EXPORT
480 int hal_common_get_backend_with_library_name(enum hal_module module,
481                                         void **data, const char *library_name)
482 {
483         return __get_backend(module, data, library_name);
484 }
485
486 EXPORT
487 int hal_common_put_backend_with_library_name(enum hal_module module,
488                                         void *data, const char *library_name)
489 {
490         return __put_backend(module, data, library_name);
491 }
492
493 EXPORT
494 int hal_common_check_backend_abi_version(enum hal_module module,
495                                 enum hal_abi_version abi_version)
496 {
497         struct __hal_module_info *info = NULL;
498         int i;
499         int ret;
500
501         /* Check parameter whether is valid or not */
502         if (module <= HAL_MODULE_UNKNOWN || module >= HAL_MODULE_END) {
503                 _E("Invalid paramer of HAL module(%d)\n", module);
504                 return -EINVAL;
505         }
506
507         if (abi_version <= HAL_ABI_VERSION_UNKNOWN
508                         || abi_version >= HAL_ABI_VERSION_END) {
509                 _E("Invalid paramer of HAL ABI version(%d) for HAL module(%d)\n",
510                                 abi_version, module);
511                 return -EINVAL;
512         }
513
514         if (_hal_api_conf_init())
515                 return -EINVAL;
516
517         info = _hal_api_conf_get_module_info(module, NULL);
518         if (info == NULL) {
519                 _E("Failed to get HAL module(%d) information\n", module);
520                 ret = -EINVAL;
521                 goto out;
522         }
523
524         /* Check abi_version whether is supported or not */
525         if (!info->hal_api) {
526                 _E("%s: Doesn't support HAL API\n", info->module_name);
527                 ret = -EINVAL;
528                 goto out;
529         }
530
531         if (!info->num_abi_versions
532                         || !info->abi_versions) {
533                 _E("%s: Doesn't have the ABI version information\n",
534                                                 info->module_name);
535                 ret = -EINVAL;
536                 goto out;
537         }
538
539         g_platform_curr_abi_version = _hal_api_conf_get_platform_abi_version();
540
541         if (g_platform_curr_abi_version <= HAL_ABI_VERSION_UNKNOWN
542                         || g_platform_curr_abi_version >= HAL_ABI_VERSION_END) {
543                 _E("Invalid paramer of current HAL ABI version(%d)(%d)\n",
544                                 g_platform_curr_abi_version, module);
545                 ret = -EINVAL;
546                 goto out;
547         }
548
549         for (i = 0; i < info->num_abi_versions; i++) {
550                 struct hal_abi_version_match *data
551                                 = &info->abi_versions[i];
552
553                 if (g_platform_curr_abi_version != data->platform_abi_version)
554                         continue;
555
556                 if (data->backend_min_abi_version <= HAL_ABI_VERSION_UNKNOWN ||
557                         data->backend_min_abi_version >= HAL_ABI_VERSION_END) {
558                         _E("%s: abi_versions[%d].backend_min_abi_version(%d) is invalid\n",
559                                 info->module_name, i, data->backend_min_abi_version);
560                         ret = -EINVAL;
561                         goto out;
562                 }
563
564                 if (abi_version <= data->platform_abi_version
565                                 && abi_version >= data->backend_min_abi_version) {
566                         ret = 0;
567                         goto out;
568                 }
569
570                 _E("%s: \'%s\' doesn't support \'%s\'\n",
571                                 info->module_name,
572                                 hal_abi_version_str[g_platform_curr_abi_version],
573                                 hal_abi_version_str[abi_version]);
574                 _E("%s: Must use ABI versions from \'%s\' to \'%s\'\n",
575                                 info->module_name,
576                                 hal_abi_version_str[data->backend_min_abi_version],
577                                 hal_abi_version_str[data->platform_abi_version]);
578         }
579         ret = -EINVAL;
580
581 out:
582         _hal_api_conf_exit();
583         return ret;
584 }
585
586 EXPORT
587 unsigned int hal_common_get_backend_abi_version(enum hal_module module)
588 {
589         unsigned int abi_version;
590         int ret;
591
592         ret = __get_backend_data(module, &abi_version, NULL, 0, NULL, 0);
593         if (ret < 0)
594                 return HAL_ABI_VERSION_UNKNOWN;
595
596         return abi_version;
597 }
598
599 EXPORT
600 int hal_common_get_backend_name(enum hal_module module, char *name, int size)
601 {
602         return __get_backend_data(module, NULL, name, size, NULL, 0);
603 }
604
605 EXPORT
606 int hal_common_get_backend_vendor(enum hal_module module, char *vendor, int size)
607 {
608         return __get_backend_data(module, NULL, NULL, 0, vendor, size);
609 }
610
611
612 static int __get_backend_library_data(enum hal_module module,
613                                         char **lib_names,
614                                         int lib_count,
615                                         int lib_name_size)
616 {
617         struct __hal_module_info *info = NULL;
618         struct dirent *de;
619         DIR *dir;
620         char *backend_module_name = NULL;
621         int count, i, ret, len;
622 #if defined(__aarch64__) || defined(__x86_64__)
623         const char hal_backend_path[] = "/hal/lib64";
624 #else
625         const char hal_backend_path[] = "/hal/lib";
626 #endif
627
628         /* Check parameter whether is valid or not */
629         if (module <= HAL_MODULE_UNKNOWN || module >= HAL_MODULE_END) {
630                 _E("Invalid parameter of HAL module (%d)\n", module);
631                 return -EINVAL;
632         }
633
634         if (_hal_api_conf_init())
635                 return -EINVAL;
636
637         info = _hal_api_conf_get_module_info(module, NULL);
638         if (info == NULL) {
639                 _E("Failed to get HAL module(%d) information\n", module);
640                 ret = -EINVAL;
641                 goto err;
642         }
643
644         if (info->backend_module_name == NULL) {
645                 _E("Don't support HAL backend of HAL module(%s)\n",
646                                         info->module_name);
647                 ret = -EINVAL;
648                 goto err;
649         }
650         backend_module_name = g_strdup_printf("libhal-backend-%s",
651                                         info->backend_module_name);
652         if (!backend_module_name) {
653                 _E("Failed to allocate the backend_module_name of HAL module(%s)\n",
654                                         info->module_name);
655                 ret = -EINVAL;
656                 goto err;
657         }
658
659         /* Find HAL backend libraries */
660         dir = opendir(hal_backend_path);
661         if (!dir) {
662                 _E("Failed to find HAL backend path(%s) for HAL module(%s)\n",
663                                         hal_backend_path, info->module_name);
664                 ret = -EINVAL;
665                 goto err_free_backend_module_name;
666         }
667
668         count = 0;
669         while ((de = readdir(dir)) != NULL) {
670                 if (!g_str_has_prefix(de->d_name, backend_module_name))
671                         continue;
672
673                 if (lib_count == 0)
674                         count++;
675                 else if (lib_count > 0) {
676                         len = strlen(de->d_name) + 1;
677
678                         if (len > lib_name_size)
679                                 len = lib_name_size;
680
681                         strncpy(lib_names[count++], de->d_name, len);
682                 }
683         }
684
685         if (lib_count > 0 && count != lib_count) {
686                 ret = -EINVAL;
687                 goto err_mismatch_count;
688         }
689
690         closedir(dir);
691         _hal_api_conf_exit();
692         g_free(backend_module_name);
693
694         return count;
695
696 err_mismatch_count:
697         for (i = count - 1; i >= 0; i--)
698                 memset(lib_names[i], 0, strlen(lib_names[i]));
699
700         closedir(dir);
701 err_free_backend_module_name:
702         g_free(backend_module_name);
703 err:
704         _hal_api_conf_exit();
705         return ret;
706 }
707
708 EXPORT
709 int hal_common_get_backend_count(enum hal_module module)
710 {
711         return __get_backend_library_data(module, NULL, 0, 0);
712 }
713
714 EXPORT
715 int hal_common_get_backend_library_names(enum hal_module module,
716                                         char **library_names,
717                                         int library_count,
718                                         int library_name_size)
719 {
720         int ret = __get_backend_library_data(module, library_names,
721                                         library_count, library_name_size);
722         return (ret < 0) ? ret : 0;
723 }