Implement checking of Tizen policies on TA loading. 25/136225/31
authoru.harbuz <u.harbuz@samsung.com>
Wed, 28 Jun 2017 15:29:28 +0000 (17:29 +0200)
committerUladzislau Harbuz <u.harbuz@samsung.com>
Wed, 4 Oct 2017 13:23:46 +0000 (15:23 +0200)
Check if client has Tizen privelege to use TEE.
Allow client to load only TA from its subdirectories.
Allow system applications load TA from system directies.
Add unix socket connection between tee-supplicant and libteec to
allow identify client with cynara.

Change-Id: I8bfecbb4f58f1397d5706cb9af90e0641fbfdec4

libteec/src/tee_client_api.c
packaging/optee-client.spec
tee-supplicant/Makefile
tee-supplicant/src/security.c [new file with mode: 0644]
tee-supplicant/src/security.h [new file with mode: 0644]
tee-supplicant/src/tee_supplicant.c
tee-supplicant/src/unix_socket.c [new file with mode: 0644]
tee-supplicant/src/unix_socket.h [new file with mode: 0644]

index a777aeb..2f30a27 100644 (file)
 #include <stdbool.h>
 #include <unistd.h>
 #include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <signal.h>
 
 #ifndef __aligned
 #define __aligned(x) __attribute__((__aligned__(x)))
 
 /* How many device sequence numbers will be tried before giving up */
 #define TEEC_MAX_DEV_SEQ       10
+#define N_MAX_TRY 100000
+/* Time of waiting for server responce, seconds */
+#define WAITING_TIME 90
+#define SOCKET_NAME_LENGTH 100
 
 static pthread_mutex_t teec_mutex = PTHREAD_MUTEX_INITIALIZER;
 
@@ -456,6 +464,55 @@ static void uuid_to_octets(uint8_t d[TEE_IOCTL_UUID_LEN], const TEEC_UUID *s)
        memcpy(d + 8, s->clockSeqAndNode, sizeof(s->clockSeqAndNode));
 }
 
+static int try_connect_to_server(const char* sock_path)
+{
+
+       int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (sockfd < 0) {
+               EMSG("Error of creating socket.");
+               return -1;
+       }
+
+       struct sockaddr_un host_addr;
+       memset(&host_addr, 0, sizeof(host_addr));
+       host_addr.sun_family = AF_UNIX;
+       strncpy(host_addr.sun_path, sock_path, sizeof(host_addr.sun_path));
+
+       int res = -1;
+
+       for (int i = 0; i < N_MAX_TRY; ++i) {
+               res = connect(sockfd, &host_addr, sizeof(host_addr));
+               if (res == 0) return sockfd;
+       }
+
+       EMSG("FAILED: %s", strerror(errno));
+       close(sockfd);
+       return -1;
+}
+
+
+struct ioctl_params {
+       int fd;
+       unsigned long request;
+       void* buf;
+       int ret;
+};
+
+/*
+ * It is mechanism of opening dummy unix socket for allow supplicant
+ * use it for cynara operations.
+ * It calls ioctl from new thread, supplicant opens socket for this session
+ * and waits for connection from client, and simultaneously
+ * current thread of client lib try to connect this socket.
+ */
+static void* run_ioctl_command(void* data)
+{
+       struct ioctl_params* params = (struct ioctl_params*)data;
+       params->ret = ioctl(params->fd, params->request, params->buf);
+       pthread_exit(NULL);
+}
+
+
 TEEC_Result TEEC_OpenSession(TEEC_Context *ctx, TEEC_Session *session,
                        const TEEC_UUID *destination,
                        uint32_t connection_method, const void *connection_data,
@@ -472,6 +529,7 @@ TEEC_Result TEEC_OpenSession(TEEC_Context *ctx, TEEC_Session *session,
        uint32_t eorig;
        TEEC_SharedMemory shm[TEEC_CONFIG_PAYLOAD_REF_COUNT];
        int rc;
+       int sockfd = -1;
 
        (void)&connection_data;
 
@@ -491,19 +549,69 @@ TEEC_Result TEEC_OpenSession(TEEC_Context *ctx, TEEC_Session *session,
        uuid_to_octets(arg->uuid, destination);
        arg->clnt_login = connection_method;
 
+       char s_uuid[SOCKET_NAME_LENGTH] = {0};
+       sprintf(s_uuid, "/tmp/%.8x-%.4x-%.4x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x",
+               destination->timeLow,
+               destination->timeMid,
+               destination->timeHiAndVersion,
+               destination->clockSeqAndNode[0],
+               destination->clockSeqAndNode[1],
+               destination->clockSeqAndNode[2],
+               destination->clockSeqAndNode[3],
+               destination->clockSeqAndNode[4],
+               destination->clockSeqAndNode[5],
+               destination->clockSeqAndNode[6],
+               destination->clockSeqAndNode[7]
+       );
+
        res = teec_pre_process_operation(ctx, operation, params, shm);
        if (res != TEEC_SUCCESS) {
                eorig = TEEC_ORIGIN_API;
                goto out_free_temp_refs;
        }
 
-       rc = ioctl(ctx->fd, TEE_IOC_OPEN_SESSION, &buf_data);
+       /* Run ioctl in new thread for allow client go to code with connection to
+        * waiting server*/
+
+       pthread_t thread;
+
+       struct ioctl_params ioparam;
+       ioparam.fd = ctx->fd;
+       ioparam.request = TEE_IOC_OPEN_SESSION;
+       ioparam.buf = &buf_data;
+
+       rc = pthread_create(&thread, NULL, run_ioctl_command, &ioparam);
        if (rc) {
-               EMSG("TEE_IOC_OPEN_SESSION failed");
+               EMSG("Can't create thread");
+               goto out_free_temp_refs;
+       }
+
+       sockfd = try_connect_to_server(s_uuid);
+
+       struct timespec ts;
+       clock_gettime(CLOCK_REALTIME, &ts);
+       ts.tv_sec += WAITING_TIME;
+
+       rc = pthread_timedjoin_np(thread, NULL, &ts);
+       if (rc != 0) {
+               EMSG("No responce from server");
+               res = TEEC_ERROR_GENERIC;
+               goto out_free_temp_refs;
+       }
+
+       if (sockfd < 0) {
+               EMSG("Connection to server failed");
+               goto out_free_temp_refs;
+       }
+
+       rc = ioparam.ret;
+       if (rc) {
+               EMSG("TEE_IOC_OPEN_SESSION failed: %d", errno);
                eorig = TEEC_ORIGIN_COMMS;
                res = ioctl_errno_to_res(errno);
                goto out_free_temp_refs;
        }
+
        res = arg->ret;
        eorig = arg->ret_origin;
        if (res == TEEC_SUCCESS) {
@@ -513,6 +621,8 @@ TEEC_Result TEEC_OpenSession(TEEC_Context *ctx, TEEC_Session *session,
        teec_post_process_operation(operation, params, shm);
 
 out_free_temp_refs:
+       close(sockfd);
+       unlink(s_uuid);
        teec_free_temp_refs(operation, shm);
 out:
        if (ret_origin)
index 3b31ee9..72223aa 100644 (file)
@@ -12,6 +12,12 @@ Source0:    %{name}-%{version}.tar.gz
 Provides: libteec
 
 BuildRequires: make
+BuildRequires: pkgconfig(cynara-client)
+BuildRequires: pkgconfig(cynara-creds-socket)
+BuildRequires: pkgconfig(cynara-session)
+BuildRequires: pkgconfig(security-manager)
+BuildRequires: pkgconfig(security-privilege-manager)
+BuildRequires: pkgconfig(libtzplatform-config)
 
 %description
 Library for applications which use OPTEE functions.
@@ -20,7 +26,7 @@ Library for applications which use OPTEE functions.
 %setup -q
 
 %build
-make build CROSS_COMPILE="" MAJOR_VERSION=%{major_version} MINOR_VERSION=%{minor_version}
+make build CROSS_COMPILE="" MAJOR_VERSION=%{major_version} MINOR_VERSION=%{minor_version} CFLAGS='-fPIC -D_GNU_SOURCE -DTEEC_LOAD_PATH="\"\"" -I%{_includedir}/cynara -L%{_libdir}'
 
 %install
 make CROSS_COMPILE="" MAJOR_VERSION=%{major_version} MINOR_VERSION=%{minor_version} DESTDIR=%{buildroot}/%{_prefix} install
index 204273f..032f5e8 100644 (file)
@@ -18,7 +18,9 @@ TEES_SRCS     := tee_supplicant.c \
                   teec_ta_load.c \
                   tee_supp_fs.c \
                   rpmb.c \
-                  handle.c
+                  handle.c \
+                  security.c \
+                  unix_socket.c
 
 
 ifeq ($(CFG_GP_SOCKETS),y)
@@ -77,6 +79,11 @@ endif
 TEES_LDFLAGS   += -lpthread
 # Needed to get clock_gettime() for for glibc versions before 2.17
 TEES_LDFLAGS   += -lrt
+TEES_LDFLAGS   += -lcynara-creds-socket
+TEES_LDFLAGS   += -lcynara-client
+TEES_LDFLAGS   += -lcynara-session
+TEES_LDFLAGS   += -lsecurity-manager-client
+TEES_LDFLAGS   += -ltzplatform-config-2.0
 
 tee-supplicant: $(TEES_FILE)
 
diff --git a/tee-supplicant/src/security.c b/tee-supplicant/src/security.c
new file mode 100644 (file)
index 0000000..2c0bb75
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2017, Samsung Electronics
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include <teec_trace.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <unistd.h>
+#include <cynara/cynara-creds-socket.h>
+#include <cynara/cynara-client.h>
+#include <cynara/cynara-session.h>
+#include <security-manager/app-runtime.h>
+#include "security.h"
+#include <pthread.h>
+#include <tzplatform_config.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+
+/* Global instance of cynara. Get it by function get_cynara_instance, DO NOT USE IT directly! */
+static cynara *p_cynara = NULL;
+
+#define CYNARA_CACHE_SIZE 100U
+#define RETURN_UNLOCK(ret, mtx) {pthread_mutex_unlock(&mtx); return ret; }
+
+static const char* system_ta_paths[] = {
+       SYS_TA_PATH,
+};
+
+pthread_mutex_t cynara_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+const size_t n_sys_ta_paths = sizeof(system_ta_paths)/sizeof(system_ta_paths[0]);
+
+
+/* Call it before locking cynara */
+static cynara* get_cynara_instance()
+{
+       if (p_cynara == NULL) {
+               pthread_mutex_lock(&cynara_mutex);
+               int ret = -1;
+               cynara_configuration *p_conf = NULL;
+
+               ret = cynara_configuration_create(&p_conf);
+               if (ret != CYNARA_API_SUCCESS) {
+                       EMSG("Cynara configuration initialization failed");
+                       RETURN_UNLOCK(NULL, cynara_mutex);
+               }
+
+               ret = cynara_configuration_set_cache_size(p_conf, CYNARA_CACHE_SIZE);
+               if (ret != CYNARA_API_SUCCESS) {
+                       EMSG("Set cynara cache size failed");
+                       RETURN_UNLOCK(NULL, cynara_mutex);
+               }
+
+               ret = cynara_initialize(&p_cynara, p_conf);
+               if (ret != CYNARA_API_SUCCESS) {
+                       p_cynara = NULL;
+                       EMSG("Cynara initialize faied");
+                       RETURN_UNLOCK(NULL, cynara_mutex);
+               }
+
+               RETURN_UNLOCK(p_cynara, cynara_mutex);
+       }
+
+       return p_cynara;
+}
+
+
+static bool file_exists(const char* fname)
+{
+       return access(fname, F_OK) == 0;
+}
+
+
+static bool get_ca_full_path_from_fd(int caFd, char* path)
+{
+
+       pid_t ca_pid = -1;
+       int ret = -1;
+
+       char ca_path[MAX_PATH_LENGTH] = {0};
+
+       enum tzplatform_variable ids[] = {TZ_USER_APP, TZ_SYS_RW_APP, TZ_SYS_RO_APP};
+       const size_t N_IDS = sizeof(ids)/sizeof(*ids);
+
+       struct ucred ucred;
+       int len = sizeof(struct ucred);
+
+       if (getsockopt(caFd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == -1) {
+               EMSG("Can't get client's uid");
+               return false;
+       }
+
+       struct tzplatform_context *ctx;
+       if (tzplatform_context_create(&ctx) != 0) {
+               EMSG("Can not create tizen context");
+               return false;
+       }
+
+       if (tzplatform_context_set_user(ctx, ucred.uid) != 0) {
+               EMSG("Can not set user for context");
+               tzplatform_context_destroy(ctx);
+               return false;
+       }
+
+       for (int i = 0; i < N_IDS; ++i) {
+               strncpy(ca_path, tzplatform_context_getenv(ctx, ids[i]), MAX_PATH_LENGTH);
+               if (strlen(ca_path) > 0) break;
+       }
+
+       ret = readlink(ca_path, path, MAX_PATH_LENGTH);
+
+       if (ret == -1) {
+               EMSG("readlink() failed");
+               tzplatform_context_destroy(ctx);
+               return false;
+       }
+
+       tzplatform_context_destroy(ctx);
+       return true;
+}
+
+
+bool find_requested_ta(int ca_fd, const char* ta_name, char** allowed_path)
+{
+       int ret;
+       char* pkg_id_ca;
+       *allowed_path = NULL;
+
+       ret = security_manager_identify_app_from_socket(ca_fd, &pkg_id_ca, NULL);
+
+       if (ret == SECURITY_MANAGER_ERROR_NO_SUCH_OBJECT) {
+               DMSG("Owner of socket has no pkgid");
+
+               char ta_full_path[MAX_PATH_LENGTH] = {0};
+
+               /* Check if any of system ta directories contains our ta */
+               for (int i = 0; i < n_sys_ta_paths; ++i) {
+                       snprintf(ta_full_path, MAX_PATH_LENGTH, "%s/%s", system_ta_paths[i], ta_name);
+
+                       if (file_exists(ta_full_path)) {
+                               *allowed_path = (char*)calloc(strlen(system_ta_paths[i])+1, sizeof(**allowed_path));
+                               strcpy(*allowed_path, system_ta_paths[i]);
+                               return true;
+                       }
+
+                       memset(ta_full_path, 0, MAX_PATH_LENGTH);
+               }
+
+               return false;
+       }
+
+       if (ret != SECURITY_MANAGER_SUCCESS) {
+               EMSG("security_manager_identify_app_from_socket failed with CA");
+               return false;
+       }
+
+       free(pkg_id_ca);
+
+       char ca_pkg_path[MAX_PATH_LENGTH];
+       if (!get_ca_full_path_from_fd(ca_fd, ca_pkg_path)) {
+               EMSG("Error while loading client's path");
+               return false;
+       }
+
+       strncat(ca_pkg_path, TA_LOCAL_PATH, MAX_PATH_LENGTH - strlen(ca_pkg_path));
+       char ta_full_path[MAX_PATH_LENGTH] = {0};
+       snprintf(ta_full_path, MAX_PATH_LENGTH, "%s/%s", ca_pkg_path, ta_name);
+
+       if (!file_exists(ta_full_path)) {
+               EMSG("TA %s not found in res/tee/", ta_name);
+               return false;
+       }
+
+       return true;
+}
+
+
+bool client_has_cynara_permission(int ca_fd, const char *privelege)
+{
+       cynara *cynara = get_cynara_instance();
+       if (cynara == NULL) {
+               EMSG("Cynara is not initialized");
+               return false;
+       }
+
+       int ret = -1;
+       char *user = NULL;
+       char *session = NULL;
+       char *label = NULL;
+       pid_t ca_pid = -1;
+
+       pthread_mutex_lock(&cynara_mutex);
+
+       ret = cynara_creds_socket_get_client(ca_fd, CLIENT_METHOD_SMACK, &label);
+       if (ret != CYNARA_API_SUCCESS) {
+               EMSG("Couldn't get smack label of the client. Error code: %d", ret);
+               goto exit_error3;
+       }
+
+       ret = cynara_creds_socket_get_pid(ca_fd, &ca_pid);
+       if (ret != CYNARA_API_SUCCESS) {
+               EMSG("Couldn't get pid of the client. Error code: %d", ret);
+               goto exit_error2;
+       }
+
+       session = cynara_session_from_pid(ca_pid);
+       if (!session) {
+               EMSG("Couldn't get client's cynara session.");
+               goto exit_error2;
+       }
+
+       ret = cynara_creds_socket_get_user(ca_fd, CLIENT_METHOD_SMACK, &user);
+       if (ret != CYNARA_API_SUCCESS) {
+               EMSG("Couldn't get user. Error code: %d", ret);
+               goto exit_error1;
+       }
+
+       ret = cynara_check(cynara, label, session, user, privelege);
+       if (ret == CYNARA_API_ACCESS_DENIED) {
+               EMSG("Cynara access denied.");
+               goto exit_error0;
+       } else
+       if (ret != CYNARA_API_ACCESS_ALLOWED) {
+               EMSG("Error during cynara_check(). Error code: %d", ret);
+               goto exit_error0;
+       }
+
+
+       ret = cynara_finish(cynara);
+       if (ret != CYNARA_API_SUCCESS) {
+               EMSG("Cynara finish failed with error code %d", ret);
+       }
+
+       free(session);
+       free(label);
+       free(user);
+       pthread_mutex_unlock(&cynara_mutex);
+
+       return true;
+
+exit_error0:
+       free(user);
+
+exit_error1:
+       free(session);
+
+exit_error2:
+       free(label);
+
+exit_error3:
+       pthread_mutex_unlock(&cynara_mutex);
+
+       return false;
+}
diff --git a/tee-supplicant/src/security.h b/tee-supplicant/src/security.h
new file mode 100644 (file)
index 0000000..a5f0944
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2017, Samsung Electronics
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+
+#ifndef SECURITY_H
+#define SECURITY_H
+
+#include <stdbool.h>
+
+#define MAX_PATH_LENGTH 100
+#define MAX_OPENED_FD 5
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SYS_TA_PATH "/usr/lib/optee_armtz"
+#define TA_LOCAL_PATH "/res/tee"
+
+/**
+ * This function try to find TA by its name in allowed for client (given by
+ * socket's file descriptor) by security policies directories.
+ *
+ * @param ca_fd             File descriptor to opened socket for client.
+ * @param ta_name           Name of ta to connect for.
+ * @param allowed_ta_path   Out parameter, if function returns true, it
+ *                          contains found path to TA with given name,
+ *                          otherwise pointer is NULL.
+ *                          User must free it after use.
+ * @return                   true if TA was found, otherwise false.
+ */
+bool find_requested_ta(int ca_fd, const char* ta_name, char** allowed_ta_path);
+
+/**
+ * Check if client given by socket file descriptor has Tizen permission
+ * for use TEE.
+ *
+ * @param ca_fd             File descriptor to opened socket for client.
+ * @param privelege         Privilege to check for.
+ * @return                  true if client has permission, otherwise false.
+ */
+bool client_has_cynara_permission(int ca_fd, const char* privilege);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* SECURITY_H */
index 79cb244..9258c47 100644 (file)
@@ -53,6 +53,8 @@
 #include <tee_supp_fs.h>
 #include <tee_supplicant.h>
 #include <unistd.h>
+#include <security.h>
+#include <unix_socket.h>
 
 #include "optee_msg_supplicant.h"
 
@@ -62,6 +64,7 @@
 #include <linux/tee.h>
 
 #define RPC_NUM_PARAMS 5
+#define MAX_TA_NAME_LENGTH 40
 
 #define RPC_BUF_SIZE   (sizeof(struct tee_iocl_supp_send_arg) + \
                         RPC_NUM_PARAMS * sizeof(struct tee_ioctl_param))
@@ -94,11 +97,11 @@ struct thread_arg {
        pthread_mutex_t mutex;
 };
 
+static struct sock_data* open_sock_list[MAX_TA_NUMBER];
+
 static pthread_mutex_t shm_mutex = PTHREAD_MUTEX_INITIALIZER;
 static struct tee_shm *shm_head;
 
-static const char *ta_dir;
-
 static void *thread_main(void *a);
 
 static size_t num_waiters_inc(struct thread_arg *arg)
@@ -257,6 +260,40 @@ static void uuid_from_octets(TEEC_UUID *d, const uint8_t s[TEE_IOCTL_UUID_LEN])
        memcpy(d->clockSeqAndNode, s + 8, sizeof(d->clockSeqAndNode));
 }
 
+/* Returns TEEC_SUCCESS if client with uuid has all needed permissions.
+ * Othwrwise returns TEEC_Result error code
+ * uuid - UUID of called TA.
+ * ta_dir - output parameter. If access for TA allowed, it will contain
+ * path for it, otherwise it is NULL.*/
+static TEEC_Result allow_access(char* uuid, char** ta_dir)
+{
+       int ca_fd = -1;
+       const char* permission = "http://tizen.org/privilege/tee.client";
+
+       ca_fd = open_socket_for_ca(uuid, &open_sock_list);
+       if (ca_fd < 0) {
+               EMSG("Open socket error");
+               return TEEC_ERROR_GENERIC;
+       }
+
+       char ta_name[MAX_TA_NAME_LENGTH];
+       snprintf(ta_name, MAX_TA_NAME_LENGTH, "%s.ta", uuid);
+
+       if (!client_has_cynara_permission(ca_fd, permission)) {
+               EMSG("Client has no permission to use TEE");
+               close(ca_fd);
+               return TEEC_ERROR_ACCESS_DENIED;
+       }
+
+       if (!find_requested_ta(ca_fd, ta_name, ta_dir)) {
+               EMSG("Access deny for TA %s", ta_name);
+               close(ca_fd);
+               return TEEC_ERROR_ITEM_NOT_FOUND;
+       }
+
+       return TEEC_SUCCESS;
+}
+
 static uint32_t load_ta(size_t num_params, struct tee_ioctl_param *params)
 {
        int ta_found = 0;
@@ -264,6 +301,7 @@ static uint32_t load_ta(size_t num_params, struct tee_ioctl_param *params)
        TEEC_UUID uuid;
        struct tee_ioctl_param_value *val_cmd;
        TEEC_SharedMemory shm_ta;
+       TEEC_Result res = -1;
 
        memset(&shm_ta, 0, sizeof(shm_ta));
 
@@ -273,10 +311,32 @@ static uint32_t load_ta(size_t num_params, struct tee_ioctl_param *params)
 
        uuid_from_octets(&uuid, (void *)val_cmd);
 
+       char s_uuid[MAX_TA_NAME_LENGTH] = {0};
+       sprintf(s_uuid, "%.8x-%.4x-%.4x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x",
+               uuid.timeLow,
+               uuid.timeMid,
+               uuid.timeHiAndVersion,
+               uuid.clockSeqAndNode[0],
+               uuid.clockSeqAndNode[1],
+               uuid.clockSeqAndNode[2],
+               uuid.clockSeqAndNode[3],
+               uuid.clockSeqAndNode[4],
+               uuid.clockSeqAndNode[5],
+               uuid.clockSeqAndNode[6],
+               uuid.clockSeqAndNode[7]
+       );
+
+       char *ta_dir = NULL;
+       res = allow_access(s_uuid, &ta_dir);
+       if (res != TEEC_SUCCESS) {
+               return res;
+       }
+
        size = shm_ta.size;
        ta_found = TEECI_LoadSecureModule(ta_dir, &uuid, shm_ta.buffer, &size);
+       free(ta_dir);
        if (ta_found != TA_BINARY_FOUND) {
-               EMSG("  TA not found");
+               EMSG(" TA not found");
                return TEEC_ERROR_ITEM_NOT_FOUND;
        }
 
@@ -330,6 +390,13 @@ static uint32_t process_free(size_t num_params, struct tee_ioctl_param *params)
        struct tee_shm *shm;
        int id;
 
+       /* Close all unlinked sockets */
+       for (int i = 0; i < MAX_TA_NUMBER; ++i) {
+               if (open_sock_list[i] && access(open_sock_list[i]->addr, F_OK) == -1) {
+                       close_socket_by_addr(open_sock_list[i]->addr, &open_sock_list);
+               }
+       }
+
        if (num_params != 1 || get_value(num_params, params, 0, &val))
                return TEEC_ERROR_BAD_PARAMETERS;
 
@@ -371,8 +438,6 @@ static int open_dev(const char *devname)
        if (vers.impl_id != TEE_IMPL_ID_OPTEE)
                goto err;
 
-       ta_dir = "optee_armtz";
-
        DMSG("using device \"%s\"", devname);
        return fd;
 err:
diff --git a/tee-supplicant/src/unix_socket.c b/tee-supplicant/src/unix_socket.c
new file mode 100644 (file)
index 0000000..d370dc4
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2017, Samsung Electronics
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+
+#include "unix_socket.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define WAIT_SEC 10
+#define SOCK_PATH_PREFIX "/tmp/"
+
+int open_socket_for_ca(const char *ca_id, struct sock_data* open_sockets[])
+{
+       int sockfd = -1;
+       int newsockfd = -1;
+       int portno = 0;
+       int free_index = -1;
+
+       char path[MAX_PATH_LENGTH] = {0};
+       sprintf(path, SOCK_PATH_PREFIX"%s", ca_id);
+
+       if (access(path, F_OK) == -1) {
+               DMSG("Socket file doesn't exist. Creating");
+               close_socket_by_addr(path, open_sockets);
+       }
+
+       /* check if this socket already open and find first free place in array */
+       for (int i = 0; i < MAX_TA_NUMBER; ++i) {
+               if (open_sockets[i] == NULL && free_index == -1) free_index = i;
+               if (open_sockets[i] && strcmp(path, open_sockets[i]->addr) == 0) {
+                       DMSG("Socket already exists");
+                       return open_sockets[i]->fd;
+               }
+       }
+
+       if (free_index < 0 || free_index >= MAX_TA_NUMBER) {
+               EMSG("Limit of simultaneously opened TA is reached");
+               return -1;
+       }
+
+       struct sockaddr_un serv_addr;
+       int ret = -1;
+
+       sockfd = socket(AF_UNIX, SOCK_STREAM, portno);
+       if (sockfd < 0) {
+               EMSG("Couldn't open socket");
+               return sockfd;
+       }
+
+       bzero((char*) &serv_addr, sizeof(serv_addr));
+
+       serv_addr.sun_family = AF_UNIX;
+       strncpy(serv_addr.sun_path, path, sizeof(serv_addr) - 1);
+
+       int yes = 1;
+       ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
+       if (ret < 0) {
+               EMSG("Configure socket error: %s", strerror(errno));
+               return ret;
+       }
+
+       ret = bind(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr));
+       if (ret < 0) {
+               EMSG("Binding of socket adress failed with error: %s", strerror(errno));
+               return ret;
+       }
+
+       char mode[] = "0777";
+       int imode = strtol(mode, NULL, 8);
+       ret = chmod(path, imode);
+       if (ret != 0) {
+               EMSG("Error changing permission for socket: %s", strerror(errno));
+               return -1;
+       }
+
+       listen(sockfd, N_CONNECTIONS);
+
+       DMSG("Waiting for accept...");
+
+       /* Set timeout for waiting for connection from client  */
+       struct timeval tv;
+       tv.tv_sec = WAIT_SEC;
+       tv.tv_usec = 0;
+       fd_set fds;
+
+       FD_ZERO(&fds);
+       FD_SET(sockfd, &fds);
+
+       ret = select(sockfd + 1, &fds, NULL, NULL, &tv);
+       if (ret == -1) {
+               EMSG("ERROR of select socket: %s", strerror(errno));
+               close(newsockfd);
+               close(sockfd);
+               unlink(path);
+               return -1;
+       }
+
+       if (ret == 0) {
+               EMSG("Server timeout");
+               close(newsockfd);
+               close(sockfd);
+               unlink(path);
+               return -1;
+       }
+
+       newsockfd = accept(sockfd, NULL, NULL);
+       if (newsockfd < 0) {
+               EMSG("Open socket failed");
+       }
+
+       open_sockets[free_index] = (struct sock_data*)malloc(sizeof(struct sock_data));
+       open_sockets[free_index]->addr = (char*)calloc(strlen(path), sizeof(char));
+       strcpy(open_sockets[free_index]->addr, path);
+       open_sockets[free_index]->fd = newsockfd;
+       open_sockets[free_index]->parent_fd = sockfd;
+
+       return newsockfd;
+}
+
+int close_socket_by_addr(const char* path, struct sock_data* open_sockets[])
+{
+       int index = -1;
+
+       for (int i = 0; i < MAX_TA_NUMBER; ++i) {
+               if (open_sockets[i] && strcmp(open_sockets[i]->addr, path) == 0) {
+                       index = i;
+                       break;
+               }
+       }
+
+       if (index < 0 || index >= MAX_TA_NUMBER) {
+               EMSG("Could't find socket %s", path);
+               return -1;
+       }
+
+       close(open_sockets[index]->fd);
+       close(open_sockets[index]->parent_fd);
+       unlink(open_sockets[index]->addr);
+
+       free(open_sockets[index]->addr);
+       open_sockets[index]->addr = NULL;
+       free(open_sockets[index]);
+       open_sockets[index] = NULL;
+
+       return 0;
+}
diff --git a/tee-supplicant/src/unix_socket.h b/tee-supplicant/src/unix_socket.h
new file mode 100644 (file)
index 0000000..fcd70de
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017, Samsung Electronics
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef __UNIX_SOCKET_H
+#define __UNIX_SOCKET_H
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <teec_trace.h>
+
+#define MAX_PATH_LENGTH 100
+#define N_CONNECTIONS 5
+#define MAX_TA_NUMBER 10
+
+struct sock_data
+{
+    int fd, parent_fd;
+    char* addr;
+};
+
+/* Open socket on adress /tmp/ca_id and add it to the list of open sockets
+ * Returns file descriptor of opened socket
+ * struct sock_data* conn_list[] - list of open sockets which add new socket to*/
+int open_socket_for_ca(const char* ca_id, struct sock_data* conn_list[] );
+
+/* Close socket by given path of its file. Returns 0 on success, -1 on error*/
+int close_socket_by_addr(const char* path, struct sock_data* conn_list[]);
+
+#endif /*__UNIX_SOCKET_H */