Executable path retrieval moved to security-server
authorKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Fri, 24 May 2013 15:24:46 +0000 (17:24 +0200)
committerBartlomiej Grzelewski <b.grzelewski@samsung.com>
Thu, 6 Feb 2014 16:10:17 +0000 (17:10 +0100)
[Issue#] SSDWSSP-274
[Feature/Bug] N/A
[Problem] security_server_check_privilege_by_sockfd should not require root privileges
[Cause] The function reads /proc/[pid]/exe
[Solution] Executable retrieval moved to security-server.

[Verification] Build & install. Run security-server-tests-client-smack --regexp=tc06_check_privilege_by_sockfd
Security server logs should contain valid executable path in lines starting with SS_SMACK

Change-Id: Ib06414e80c9ee992108b7c49b33914e9047e5871

src/client/security-server-client.c
src/communication/security-server-comm.c
src/include/security-server-comm.h
src/server/security-server-main.c

index 4e74132..1391a2b 100644 (file)
@@ -30,6 +30,7 @@
 #include <fcntl.h>
 #include <sys/socket.h>
 #include <sys/un.h>
+#include <sys/poll.h>
 
 #include "smack-check.h"
 #include "security-server.h"
@@ -104,6 +105,137 @@ int convert_to_public_error_code(int err_code)
        return err_code;
 }
 
+static int send_exec_path_request(int sock_fd, pid_t pid)
+{
+       basic_header hdr;
+       int retval;
+       unsigned char buf[sizeof(hdr) + sizeof(pid)];
+
+       /* Assemble header */
+       hdr.version = SECURITY_SERVER_MSG_VERSION;
+       hdr.msg_id = SECURITY_SERVER_MSG_TYPE_EXE_PATH_REQUEST;
+       hdr.msg_len = sizeof(pid);
+
+       memcpy(buf, &hdr, sizeof(hdr));
+       memcpy(buf + sizeof(hdr), &pid, sizeof(pid));
+
+       /* Check poll */
+       retval = check_socket_poll(sock_fd, POLLOUT, SECURITY_SERVER_SOCKET_TIMEOUT_MILISECOND);
+       if(retval == SECURITY_SERVER_ERROR_POLL)
+       {
+               SEC_SVR_ERR("%s", "poll() error");
+               return SECURITY_SERVER_ERROR_SEND_FAILED;
+       }
+       if(retval == SECURITY_SERVER_ERROR_TIMEOUT)
+       {
+               SEC_SVR_ERR("%s", "poll() timeout");
+               return SECURITY_SERVER_ERROR_SEND_FAILED;
+       }
+
+       /* Send to server */
+       retval = TEMP_FAILURE_RETRY(write(sock_fd, buf, sizeof(buf)));
+       if(retval < (ssize_t)sizeof(buf))
+       {
+               /* Write error */
+               SEC_SVR_ERR("Error on write(): %d", retval);
+               return SECURITY_SERVER_ERROR_SEND_FAILED;
+       }
+       return SECURITY_SERVER_SUCCESS;
+}
+
+static int recv_exec_path_response(int sockfd, response_header *hdr, char** path)
+{
+       size_t size = 0;
+       char* buf = NULL;
+       int retval;
+
+       if (*path)
+       {
+               SEC_SVR_ERR("path should be NULL");
+               return SECURITY_SERVER_ERROR_INPUT_PARAM;
+       }
+
+       retval = recv_generic_response(sockfd, hdr);
+       if(retval != SECURITY_SERVER_SUCCESS)
+       {
+               SEC_SVR_ERR("Failed to get response: %d", retval);
+               return return_code_to_error_code(hdr->return_code);
+       }
+
+       retval = TEMP_FAILURE_RETRY(read(sockfd, &size, sizeof(size_t)));
+       if(retval < (ssize_t)sizeof(size_t) || size == 0)
+       {
+               /* Error on socket */
+               SEC_SVR_ERR("read() failed: %d", retval);
+               return SECURITY_SERVER_ERROR_RECV_FAILED;
+       }
+       buf = (char*)malloc((size+1)*sizeof(char));
+       if(!buf)
+       {
+               SEC_SVR_ERR("malloc() failed. Size requested: %d", size*sizeof(char));
+               return SECURITY_SERVER_ERROR_OUT_OF_MEMORY;
+       }
+
+       retval = TEMP_FAILURE_RETRY(read(sockfd, buf, size));
+       if(retval < (ssize_t)size)
+       {
+               /* Error on socket */
+               SEC_SVR_ERR("read() failed: %d", retval);
+               free(buf);
+               return SECURITY_SERVER_ERROR_RECV_FAILED;
+       }
+       // terminate string
+       buf[size] = '\0';
+
+       *path = buf;
+       return SECURITY_SERVER_SUCCESS;
+}
+
+static int get_exec_path(pid_t pid, char** exe)
+{
+       int sockfd = -1;
+       int ret = 0;
+       char* path = NULL;
+       response_header hdr;
+       if (SECURITY_SERVER_SUCCESS != connect_to_server(&sockfd))
+               goto out;
+
+       ret = send_exec_path_request(sockfd, pid);
+       if (ret != SECURITY_SERVER_SUCCESS)
+       {
+               /* Error on socket */
+               SEC_SVR_ERR("Client: Send failed: %d", ret);
+               goto out;
+       }
+
+       ret = recv_exec_path_response(sockfd, &hdr, &path);
+       if (ret != SECURITY_SERVER_SUCCESS)
+       {
+               SEC_SVR_ERR("Client: Recv failed: %d", ret);
+               goto out;
+       }
+
+       ret = return_code_to_error_code(hdr.return_code);
+       if (hdr.basic_hdr.msg_id == SECURITY_SERVER_MSG_TYPE_GENERIC_RESPONSE)
+               SEC_SVR_ERR("Client: Error has been received. return code:%d", hdr.return_code);
+       else if (hdr.basic_hdr.msg_id != SECURITY_SERVER_MSG_TYPE_EXE_PATH_RESPONSE)
+       {
+               SEC_SVR_ERR("Client: Wrong response type.");
+               ret = SECURITY_SERVER_ERROR_BAD_RESPONSE;
+       }
+
+out:
+       if (sockfd != -1)
+               close(sockfd);
+
+       if (ret == SECURITY_SERVER_SUCCESS)
+       {
+               *exe = path;
+               path = NULL;
+       }
+       free(path);
+       return ret;
+}
 
 
        SECURITY_SERVER_API
@@ -473,9 +605,7 @@ int security_server_check_privilege_by_sockfd(int sockfd,
 
     ret = smack_new_label_from_socket(sockfd, &subject);
     if (ret != 0)
-    {
         return SECURITY_SERVER_API_ERROR_SERVER_ERROR;
-    }
 
     ret = getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &cr, &len);
     if (ret < 0) {
@@ -483,7 +613,9 @@ int security_server_check_privilege_by_sockfd(int sockfd,
         ret = 0;
         goto err;
     }
-    path = read_exe_path_from_proc(cr.pid);
+    ret = get_exec_path(cr.pid, &path);
+    if (SECURITY_SERVER_SUCCESS != ret)
+        SEC_SVR_ERR("Failed to read executable path for process %d", cr.pid);
 
     ret = security_server_check_privilege_by_pid(cr.pid, object, access_rights);
     if (ret == SECURITY_SERVER_RETURN_CODE_SUCCESS)
@@ -493,14 +625,13 @@ int security_server_check_privilege_by_sockfd(int sockfd,
 
 err:
 
-    SEC_SVR_DBG("SMACK have access returned %d", ret);
+    SEC_SVR_DBG("security_server_check_privilege_by_pid returned %d", ret);
     if (ret > 0)
         SEC_SVR_DBG("SS_SMACK: caller_pid=%d, subject=%s, object=%s, access=%s, result=%d, caller_path=%s", cr.pid, subject, object, access_rights, ret, path);
     else
         SEC_SVR_ERR("SS_SMACK: caller_pid=%d, subject=%s, object=%s, access=%s, result=%d, caller_path=%s", cr.pid, subject, object, access_rights, ret, path);
 
-    if (path != NULL)
-        free(path);
+    free(path);
     free(subject);
     if (ret == 1)
     {
index 8c675cf..10e78bd 100644 (file)
@@ -34,7 +34,6 @@
 #include <sys/stat.h>
 #include <limits.h>
 #include <ctype.h>
-#include <stdint.h>
 
 #include "security-server-common.h"
 #include "security-server-comm.h"
@@ -54,51 +53,6 @@ void printhex(const unsigned char *data, int size)
        printf("\n");
 }
 
-char *read_exe_path_from_proc(pid_t pid)
-{
-       char link[32];
-       char *exe = NULL;
-       size_t size = 64;
-       ssize_t cnt = 0;
-
-       // get link to executable
-       snprintf(link, sizeof(link), "/proc/%d/exe", pid);
-
-       for (;;)
-       {
-        exe = malloc(size);
-        if (exe == NULL) {
-            SEC_SVR_ERR("Out of memory");
-            return NULL;
-        }
-
-        // read link target
-        cnt = readlink(link, exe, size);
-
-        // error
-        if (cnt < 0 || (size_t)cnt > size) {
-            SEC_SVR_ERR("Can't locate process binary for pid[%d]", pid);
-            free(exe);
-            return NULL;
-        }
-
-        // read less than requested
-        if ((size_t)cnt < size)
-            break;
-
-        // read exactly the number of bytes requested
-        free(exe);
-        if (size > (SIZE_MAX >> 1)) {
-            SEC_SVR_ERR("Exe path too long (more than %d characters)", size);
-            return NULL;
-        }
-        size <<= 1;
-    }
-       // readlink does not append null byte to buffer.
-       exe[cnt] = '\0';
-       return exe;
-}
-
 /* Return code in packet is positive integer *
  * We need to convert them to error code which are negative integer */
 int return_code_to_error_code(int ret_code)
@@ -2646,58 +2600,6 @@ int get_client_gid_list(int sockfd, int ** privileges)
     return ret;
 }
 
-/* Authenticate the application is middleware daemon
- * The middleware must run as root and the cmd line must be pre listed */
-int authenticate_developer_shell(int sockfd)
-{
-       int retval = SECURITY_SERVER_ERROR_AUTHENTICATION_FAILED;
-       struct ucred cr;
-       unsigned int cl = sizeof(cr);
-       char *exe = NULL;
-
-       /* get PID of socket peer */
-       if(getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &cr, &cl) != 0)
-       {
-               retval = SECURITY_SERVER_ERROR_SOCKET;
-               SEC_SVR_ERR("%s", "Error on getsockopt");
-               goto error;
-       }
-
-       /* All middlewares will run as root */
-       if(cr.uid != SECURITY_SERVER_DEVELOPER_UID)
-       {
-               retval = SECURITY_SERVER_ERROR_AUTHENTICATION_FAILED;
-               SEC_SVR_ERR("Non root process has called API: %d", cr.uid);
-               goto error;
-       }
-
-       /* Read executable path of the PID from proc fs */
-       exe = read_exe_path_from_proc(cr.pid);
-       if(exe  == NULL)
-       {
-               /* It's weired. no file in proc file system, */
-               retval = SECURITY_SERVER_ERROR_FILE_OPERATION;
-               SEC_SVR_ERR("Error on opening /proc/%d/exe", cr.pid);
-               goto error;
-       }
-
-       /* Search exe of the peer that is really debug tool */
-       if(strcmp(exe, SECURITY_SERVER_DEBUG_TOOL_PATH) != 0)
-       {
-               SEC_SVR_ERR("Error: Wrong exe path [%s]", exe);
-               retval = SECURITY_SERVER_ERROR_AUTHENTICATION_FAILED;
-               goto error;
-       }
-       retval = SECURITY_SERVER_SUCCESS;
-       SEC_SVR_DBG("%s", "Client Authenticated");
-
-error:
-       if(exe != NULL)
-               free(exe);
-
-       return retval;
-}
-
 int free_argv(char **argv, int argc)
 {
        int i;
@@ -2770,4 +2672,3 @@ error:
     free(buff);
     return retval;
 }
-
index 873a4fe..a131994 100644 (file)
@@ -71,6 +71,10 @@ typedef struct
 #define SECURITY_SERVER_MSG_TYPE_SMACK_RESPONSE        0x1e
 #define SECURITY_SERVER_MSG_TYPE_APP_GIVE_ACCESS_REQUEST 0x1f
 #define SECURITY_SERVER_MSG_TYPE_APP_GIVE_ACCESS_RESPONSE 0x20
+#define SECURITY_SERVER_MSG_TYPE_CHECK_PID_PRIVILEGE_REQUEST    0x21
+#define SECURITY_SERVER_MSG_TYPE_CHECK_PID_PRIVILEGE_RESPONSE   0x22
+#define SECURITY_SERVER_MSG_TYPE_EXE_PATH_REQUEST      0x23
+#define SECURITY_SERVER_MSG_TYPE_EXE_PATH_RESPONSE     0x24
 #define SECURITY_SERVER_MSG_TYPE_GENERIC_RESPONSE      0xff
 
 /* Return code */
@@ -99,7 +103,6 @@ int authenticate_client_application(int sockfd, int *pid, int *uid);
 int authenticate_client_middleware(int sockfd, int *pid);
 int get_client_gid_list(int sockfd, int ** privileges);
 int authenticate_developer_shell(int sockfd);
-char *read_exe_path_from_proc(pid_t pid);
 int send_generic_response (int sockfd, unsigned char msgid, unsigned char return_code);
 int send_cookie(int sockfd, unsigned char *cookie);
 int send_object_name(int sockfd, char *obj);
index 5e4b472..7e0e218 100644 (file)
@@ -37,6 +37,7 @@
 #include <sys/wait.h>
 #include <poll.h>
 #include <grp.h>
+#include <stdint.h>
 
 #include <privilege-control.h>
 #include <security-server-system-observer.h>
@@ -105,6 +106,55 @@ void print_cookie(cookie_list *list)
 }
 #endif
 
+char *read_exe_path_from_proc(pid_t pid)
+{
+       char link[32];
+       char *exe = NULL;
+       size_t size = 64;
+       ssize_t cnt = 0;
+
+       // get link to executable
+       snprintf(link, sizeof(link), "/proc/%d/exe", pid);
+
+       for (;;)
+       {
+               exe = malloc(size);
+               if (exe == NULL )
+               {
+                       SEC_SVR_ERR("Out of memory");
+                       return NULL ;
+               }
+
+               // read link target
+               cnt = readlink(link, exe, size);
+
+               // error
+               if (cnt < 0 || (size_t) cnt > size)
+               {
+                       SEC_SVR_ERR("Can't locate process binary for pid[%d]", pid);
+                       free(exe);
+                       return NULL ;
+               }
+
+               // read less than requested
+               if ((size_t) cnt < size)
+                       break;
+
+               // read exactly the number of bytes requested
+               free(exe);
+               if (size > (SIZE_MAX >> 1))
+               {
+                       SEC_SVR_ERR("Exe path too long (more than %d characters)", size);
+                       return NULL ;
+               }
+               size <<= 1;
+       }
+       // readlink does not append null byte to buffer.
+       exe[cnt] = '\0';
+       return exe;
+}
+
+
 /* Object name is actually name of a Group ID *
  * This function opens /etc/group file and search group ID and
  * returns the string */
@@ -324,6 +374,58 @@ int execute_debug_tool(int argc, char *const *argv, int server_sockfd, int clien
     return SECURITY_SERVER_SUCCESS;
 }
 
+/* Authenticate the application is middleware daemon
+ * The middleware must run as root and the cmd line must be pre listed */
+int authenticate_developer_shell(int sockfd)
+{
+       int retval = SECURITY_SERVER_ERROR_AUTHENTICATION_FAILED;
+       struct ucred cr;
+       unsigned int cl = sizeof(cr);
+       char *exe = NULL;
+
+       /* get PID of socket peer */
+       if(getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &cr, &cl) != 0)
+       {
+               retval = SECURITY_SERVER_ERROR_SOCKET;
+               SEC_SVR_ERR("%s", "Error on getsockopt");
+               goto error;
+       }
+
+       /* All middlewares will run as root */
+       if(cr.uid != SECURITY_SERVER_DEVELOPER_UID)
+       {
+               retval = SECURITY_SERVER_ERROR_AUTHENTICATION_FAILED;
+               SEC_SVR_ERR("Non root process has called API: %d", cr.uid);
+               goto error;
+       }
+
+       /* Read executable path of the PID from proc fs */
+       exe = read_exe_path_from_proc(cr.pid);
+       if(exe  == NULL)
+       {
+               /* It's weired. no file in proc file system, */
+               retval = SECURITY_SERVER_ERROR_FILE_OPERATION;
+               SEC_SVR_ERR("Error on opening /proc/%d/exe", cr.pid);
+               goto error;
+       }
+
+       /* Search exe of the peer that is really debug tool */
+       if(strcmp(exe, SECURITY_SERVER_DEBUG_TOOL_PATH) != 0)
+       {
+               SEC_SVR_ERR("Error: Wrong exe path [%s]", exe);
+               retval = SECURITY_SERVER_ERROR_AUTHENTICATION_FAILED;
+               goto error;
+       }
+       retval = SECURITY_SERVER_SUCCESS;
+       SEC_SVR_DBG("%s", "Client Authenticated");
+
+error:
+       if(exe != NULL)
+               free(exe);
+
+       return retval;
+}
+
 int process_cookie_request(int sockfd)
 {
        int retval, client_pid, client_uid;
@@ -1096,6 +1198,134 @@ error:
     return retval;
 }
 
+
+/* Send exe path response to client
+ *
+ * Get exe path response packet format
+ *  0                   1                   2                   3
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * |---------------------------------------------------------------|
+ * | version=0x01  |MessageID=0x24 |Message Length = 4+path length |
+ * |---------------------------------------------------------------|
+ * |  return code  |  Path length  |             Path              |
+ * |---------------------------------------------------------------|
+
+*/
+int send_exe_path_response(int sockfd, const char* path)
+{
+       response_header hdr;
+       unsigned char* msg = NULL;
+       unsigned char* ptr = NULL;
+       int ret;
+       size_t path_len = 0;
+       unsigned short msg_len = 0;
+
+       if (!path) {
+               SEC_SVR_ERR("Path is NULL");
+               return SECURITY_SERVER_ERROR_INPUT_PARAM;
+       }
+
+       path_len = strlen(path);
+       msg_len = sizeof(hdr) + sizeof(size_t) + path_len;
+       msg = (unsigned char*)malloc(msg_len*sizeof(unsigned char));
+       if (!msg) {
+               SEC_SVR_ERR("malloc failed");
+               return SECURITY_SERVER_ERROR_OUT_OF_MEMORY;
+       }
+
+       /* Assemble header */
+       hdr.basic_hdr.version = SECURITY_SERVER_MSG_VERSION;
+       hdr.basic_hdr.msg_id = SECURITY_SERVER_MSG_TYPE_EXE_PATH_RESPONSE;
+       hdr.basic_hdr.msg_len = sizeof(size_t) + path_len;
+       hdr.return_code = SECURITY_SERVER_RETURN_CODE_SUCCESS;
+
+       /* Prepare packet */
+       ptr = msg;
+       memcpy(ptr, &hdr, sizeof(hdr));
+       ptr += sizeof(hdr);
+       memcpy(ptr, &path_len, sizeof(size_t));
+       ptr += sizeof(size_t);
+       memcpy(ptr, path, path_len);
+
+       /* Check poll */
+       ret = check_socket_poll(sockfd, POLLOUT, SECURITY_SERVER_SOCKET_TIMEOUT_MILISECOND);
+       if(ret == SECURITY_SERVER_ERROR_POLL)
+       {
+               SEC_SVR_ERR("%s", "poll() error");
+               ret = SECURITY_SERVER_ERROR_SEND_FAILED;
+               goto out;
+       }
+       if(ret == SECURITY_SERVER_ERROR_TIMEOUT)
+       {
+               SEC_SVR_ERR("%s", "poll() timeout");
+               ret = SECURITY_SERVER_ERROR_SEND_FAILED;
+               goto out;
+       }
+
+       /* Send it */
+       ret = TEMP_FAILURE_RETRY(write(sockfd, msg, msg_len));
+       if(ret <  msg_len)
+       {
+               SEC_SVR_ERR("Error on write(): %d", ret);
+               ret = SECURITY_SERVER_ERROR_SEND_FAILED;
+               goto out;
+       }
+       ret = SECURITY_SERVER_SUCCESS;
+
+out:
+       free(msg);
+       return ret;
+}
+
+
+int process_exe_path_request(int sockfd)
+{
+       pid_t pid;
+       int retval;
+       char* exe = NULL;
+
+       // read pid
+       retval = TEMP_FAILURE_RETRY(read(sockfd, &pid, sizeof(pid_t)));
+       if (retval < (ssize_t) sizeof(pid_t))
+       {
+               SEC_SVR_ERR("Server Error: recieve failed: %d", retval);
+               retval = send_generic_response(
+                               sockfd,
+                               SECURITY_SERVER_MSG_TYPE_EXE_PATH_RESPONSE,
+                               SECURITY_SERVER_RETURN_CODE_BAD_REQUEST);
+
+               if (retval != SECURITY_SERVER_SUCCESS)
+                       SEC_SVR_ERR("Server ERROR: Cannot send generic response: %d", retval);
+               goto error;
+       }
+
+       SEC_SVR_DBG("Server: Get exe path request for pid %d", pid);
+
+       // get executable path
+       exe = read_exe_path_from_proc(pid);
+       if (!exe)
+       {
+               SEC_SVR_ERR("Server: Failed to read executable path for pid %d", pid);
+               retval = send_generic_response(
+                               sockfd,
+                               SECURITY_SERVER_MSG_TYPE_EXE_PATH_RESPONSE,
+                               SECURITY_SERVER_RETURN_CODE_SERVER_ERROR);
+
+               if (retval != SECURITY_SERVER_SUCCESS)
+                       SEC_SVR_ERR("Server ERROR: Cannot send generic response: %d", retval);
+               goto error;
+       }
+
+       // send response
+       retval = send_exe_path_response(sockfd, exe);
+       if (retval != SECURITY_SERVER_SUCCESS)
+               SEC_SVR_ERR("ERROR: Cannot send exe path response: %d", retval);
+
+error:
+       free(exe);
+       return retval;
+}
+
 int client_has_access(int sockfd, const char *object) {
     char *label = NULL;
     int ret = 0;
@@ -1259,6 +1489,11 @@ void *security_server_thread(void *param)
             SEC_SVR_DBG("%s", "Server: app give access requset received");
             process_app_get_access_request(client_sockfd, basic_hdr.msg_len - sizeof(basic_hdr));
             break;
+
+               case SECURITY_SERVER_MSG_TYPE_EXE_PATH_REQUEST:
+                       SEC_SVR_DBG("Server: get executable path by pid request received");
+                       process_exe_path_request(client_sockfd);
+                       break;
 /************************************************************************************************/
 /* Just for test. This code must be removed on release */
                case SECURITY_SERVER_MSG_TYPE_GET_ALL_COOKIES_REQUEST: