Modify to limit the size of message for socket ipc 86/309886/9 accepted/tizen/unified/20240424.063525 accepted/tizen/unified/x/20240425.051112
authorJiyong <jiyong.min@samsung.com>
Wed, 17 Apr 2024 23:47:42 +0000 (08:47 +0900)
committerJiyong <jiyong.min@samsung.com>
Tue, 23 Apr 2024 00:54:37 +0000 (09:54 +0900)
[Problem]
  DoS is available by calling g_malloc0 with too big msg_size value.

[Solution]
  The size of messages with socket has been limited to 10kbytes and
  large messages will be sent as file.

Change-Id: Ie2cf9f4f3a3ec111fcf220724427f29b5157729a

include/media_controller_private.h
packaging/capi-media-controller.spec
src/media_controller_db.c
src/media_controller_ipc.c
src/media_controller_util.c
svc/include/media_controller_socket.h
svc/media_controller_cynara.c
svc/media_controller_db_util.c
svc/media_controller_svc.c

index a9c0278..a925a4c 100644 (file)
@@ -409,6 +409,7 @@ gboolean _mc_util_is_valid_subscription_type(const mc_subscription_type_e subscr
 void _mc_util_set_bit(int bit_num, gboolean set, unsigned long long *value);
 gboolean _mc_util_is_true_bit(unsigned long long value, int bit_num);
 const char * _mc_util_replace_null(const char *data);
+gchar *_mc_util_write_message_to_file(const gchar *data, gssize size);
 
 /* for d-bus IPC */
 int _mc_ipc_get_dbus_connection(GDBusConnection **conn, int *dref_count);
index 2df010e..279322b 100644 (file)
@@ -1,6 +1,6 @@
 Name:       capi-media-controller
 Summary:    A media controller library in Tizen Native API
-Version:    0.2.46
+Version:    0.2.47
 Release:    1
 Group:      Multimedia/API
 License:    Apache-2.0
index c77a5e2..ddf7f23 100644 (file)
@@ -17,6 +17,7 @@
 #include <unistd.h>
 #include <string.h>
 #include <stdio.h>
+#include <glib/gstdio.h>
 
 #include "media_controller_private.h"
 #include "media_controller_db.h"
@@ -149,10 +150,12 @@ int _mc_db_update_whole_metadata(const char *server_name,
 {
        int ret = MEDIA_CONTROLLER_ERROR_NONE;
        char *sql_str = NULL;
+       gchar *message = NULL;
+       gchar *message_file = NULL;
 
        mc_retvm_if(!server_name, MEDIA_CONTROLLER_ERROR_INVALID_PARAMETER, "Invalid server_name");
 
-       sql_str = g_strdup_printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", MC_DB_CMD_UPDATE_META, MC_STRING_DELIMITER, server_name,  MC_STRING_DELIMITER,
+       message = g_strdup_printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", server_name,  MC_STRING_DELIMITER,
                                        title, MC_STRING_DELIMITER,
                                        artist, MC_STRING_DELIMITER,
                                        album, MC_STRING_DELIMITER,
@@ -168,8 +171,20 @@ int _mc_db_update_whole_metadata(const char *server_name,
                                        episode, MC_STRING_DELIMITER,
                                        resolution);
 
+       mc_retvm_if(!message, MEDIA_CONTROLLER_ERROR_INVALID_OPERATION, "message is NULL");
+
+       message_file = _mc_util_write_message_to_file(message, strlen(message));
+       g_free(message);
+       mc_retvm_if(!message_file, MEDIA_CONTROLLER_ERROR_INVALID_OPERATION, "message_file is NULL");
+
+       sql_str = g_strdup_printf("%s%s%s", MC_DB_CMD_UPDATE_META, MC_STRING_DELIMITER, message_file);
+
        ret = __mc_db_update_db(MC_PRIV_TYPE_SERVER, sql_str);
 
+       if (g_remove(message_file) != 0)
+               mc_secure_debug("Temporary message_file has not been removed [%s]", message_file);
+
+       g_free(message_file);
        g_free(sql_str);
 
        return ret;
@@ -925,16 +940,24 @@ int _mc_db_update_playlist(const char *server_name, const char *playlist_name, b
 {
        int ret = MEDIA_CONTROLLER_ERROR_NONE;
        char *sql_str = NULL;
+       gchar *message_file = NULL;
 
        mc_retvm_if(!server_name, MEDIA_CONTROLLER_ERROR_INVALID_PARAMETER, "server_name is NULL");
        mc_retvm_if(!playlist_name, MEDIA_CONTROLLER_ERROR_INVALID_PARAMETER, "playlist_name is NULL");
        mc_retvm_if(!bundle_data, MEDIA_CONTROLLER_ERROR_INVALID_PARAMETER, "bundle_data is NULL");
 
-       sql_str = g_strdup_printf("%s%s%s%s%s%s%d%s%s", MC_DB_CMD_UPDATE_PLAYLIST, MC_STRING_DELIMITER, server_name,
-                                               MC_STRING_DELIMITER, playlist_name, MC_STRING_DELIMITER, bundle_size, MC_STRING_DELIMITER, bundle_data);
+       message_file = _mc_util_write_message_to_file((gchar *)bundle_data, bundle_size);
+       mc_retvm_if(!message_file, MEDIA_CONTROLLER_ERROR_INVALID_OPERATION, "message_file is NULL");
+
+       sql_str = g_strdup_printf("%s%s%s%s%s%s%s", MC_DB_CMD_UPDATE_PLAYLIST, MC_STRING_DELIMITER, server_name,
+                                               MC_STRING_DELIMITER, playlist_name, MC_STRING_DELIMITER, message_file);
 
        ret = __mc_db_update_db(MC_PRIV_TYPE_SERVER, sql_str);
 
+       if (g_remove(message_file) != 0)
+               mc_secure_debug("Temporary message_file has not been removed [%s]", message_file);
+
+       g_free(message_file);
        g_free(sql_str);
 
        return ret;
index 94acfa3..c27f314 100644 (file)
@@ -333,25 +333,26 @@ static int __make_service_connection(mc_priv_type_e priv_type)
 int _mc_ipc_send_message_to_server(mc_msg_type_e msg_type, mc_priv_type_e priv_type, const char *request_msg)
 {
        int ret = MEDIA_CONTROLLER_ERROR_NONE;
-       int request_msg_size = 0;
        int sockfd = -1;
        struct sockaddr_un serv_addr;
+       mc_comm_msg_s send_msg;
+       int recv_msg = -1;
        unsigned int retry_count = 0;
 
-       mc_retvm_if(!MC_STRING_VALID(request_msg), MEDIA_CONTROLLER_ERROR_INVALID_PARAMETER, "invalid query");
-
-       request_msg_size = strlen(request_msg);
+       mc_retvm_if(!MC_STRING_VALID(request_msg), MEDIA_CONTROLLER_ERROR_INVALID_PARAMETER,
+                       "invalid request_msg");
 
        mc_secure_debug("msg_type[%d] priv_type[%d], message[%s]", msg_type, priv_type, request_msg);
 
-       mc_comm_msg_s send_msg;
        memset((void *)&send_msg, 0, sizeof(mc_comm_msg_s));
 
        send_msg.msg_type = msg_type;
        send_msg.priv_type = priv_type;
        send_msg.pid = getpid();
        send_msg.uid = getuid();
-       send_msg.msg_size = request_msg_size;
+       send_msg.msg_size = g_strlcpy(send_msg.msg, request_msg, MAX_MSG_SIZE);
+       mc_retvm_if(send_msg.msg_size >= MAX_MSG_SIZE, MEDIA_CONTROLLER_ERROR_INVALID_PARAMETER,
+                       "invalid request_msg size(%zu)", send_msg.msg_size);
 
        /* Create Socket */
        ret = mc_ipc_create_client_socket(MC_TIMEOUT_SEC_5, &sockfd);
@@ -369,62 +370,25 @@ int _mc_ipc_send_message_to_server(mc_msg_type_e msg_type, mc_priv_type_e priv_t
                return MEDIA_CONTROLLER_ERROR_INVALID_OPERATION;
        }
 
-       size_t full_msg_size = 0;
-       size_t head_msg_size = 0;
-       size_t send_msg_size = 0;
-       size_t temp_buf_index = 0;
-       char *temp_buf = NULL;
-
-       head_msg_size = sizeof(send_msg) - sizeof(send_msg.msg);
-       full_msg_size = head_msg_size + request_msg_size;
-
-       temp_buf = g_malloc0(full_msg_size + 1);
-
-       memcpy(temp_buf, &send_msg, head_msg_size);
-       memcpy(temp_buf + head_msg_size, request_msg, request_msg_size);
-
-       if (full_msg_size <= MAX_MSG_SIZE)
-               send_msg_size = full_msg_size;
-       else
-               send_msg_size = head_msg_size;
-
-       while (temp_buf_index < full_msg_size) {
-               size_t send_result = 0;
-               /* Send request */
-               send_result = send(sockfd, temp_buf + temp_buf_index, send_msg_size, 0);
-               if (send_result < send_msg_size) {
-                       mc_stderror("send failed");
-                       close(sockfd);
-                       g_free(temp_buf);
-                       return MEDIA_CONTROLLER_ERROR_INVALID_OPERATION;
-               }
-               temp_buf_index += send_result;
-               if ((full_msg_size - temp_buf_index) > MAX_MSG_SIZE)
-                       send_msg_size = MAX_MSG_SIZE;
-               else
-                       send_msg_size = full_msg_size - temp_buf_index;
+       if (send(sockfd, &send_msg, sizeof(send_msg), 0) != sizeof(send_msg)) {
+               mc_stderror("send failed");
+               close(sockfd);
+               return MEDIA_CONTROLLER_ERROR_INVALID_OPERATION;
        }
 
-       g_free(temp_buf);
+       mc_debug("SEND MESSAGE OK");
 
        /* Receive Response */
-       int recv_msg_size = -1;
-       int recv_msg = -1;
-
-       while ((recv_msg_size = recv(sockfd, &recv_msg, sizeof(recv_msg), 0)) < 0) {
-
+       while (recv(sockfd, &recv_msg, sizeof(recv_msg), 0) < 0) {
                if (errno == EINTR) {
                        mc_stderror("catch interrupt");
                        continue;
-
                } else if (errno == EWOULDBLOCK) {
                        if (retry_count++ < MAX_RETRY_COUNT) {
                                mc_error("[No-Error] Time Out. retry_count [%d]", retry_count);
                                continue;
                        }
-
                        mc_error("Timeout. Can't try any more");
-
                } else {
                        mc_stderror("recv failed");
                }
@@ -434,10 +398,9 @@ int _mc_ipc_send_message_to_server(mc_msg_type_e msg_type, mc_priv_type_e priv_t
        }
 
        mc_debug("RECEIVE OK [%d]", recv_msg);
-       ret = recv_msg;
        close(sockfd);
 
-       return ret;
+       return recv_msg;
 }
 
 #ifdef _ON_DEMAND_SOCKET_ACTIVATION
index a651be2..f3cd2f7 100644 (file)
@@ -299,3 +299,48 @@ const char * _mc_util_replace_null(const char *data)
        else
                return data;
 }
+
+static gchar *_mc_util_make_message_file(void)
+{
+       int fd = 0;
+       gchar *path = NULL;
+       const char *template = "XXXXXX.mc";
+       GError *error = NULL;
+
+       fd = g_file_open_tmp(template, &path, &error);
+       if (fd < 0) {
+               mc_secure_error("g_file_open_tmp error [%s]", (error ? error->message : "none"));
+               g_error_free(error);
+               return NULL;
+       }
+
+       mc_secure_debug("make temp file [%s]", path);
+
+       close(fd);
+
+       return path;
+}
+
+gchar *_mc_util_write_message_to_file(const gchar *data, gssize size)
+{
+       gchar *path = _mc_util_make_message_file();
+       GError *error = NULL;
+
+       mc_retvm_if(!MC_STRING_VALID(path), NULL, "invalid path %s", path);
+       mc_retvm_if(!data, NULL, "data is null");
+       mc_retvm_if(size == 0, NULL, "size is 0");
+
+       mc_debug_fenter();
+
+       if (!g_file_set_contents(path, data, size, &error)) {
+               mc_secure_error("g_file_set_contents error(%s: %s)", path, (error ? error->message : "none"));
+               if (error)
+                       g_error_free(error);
+               g_free(path);
+               return NULL;
+       }
+
+       mc_debug_fleave();
+
+       return path;
+}
index d9f4f00..d7db351 100755 (executable)
@@ -53,7 +53,7 @@ typedef struct {
        uid_t uid;
        int result;
        size_t msg_size;
-       char *msg;
+       char msg[MAX_MSG_SIZE];
 } mc_comm_msg_s;
 
 int mc_ipc_create_client_socket(int timeout_sec, int *sock_fd);
index b0d7028..2465f51 100755 (executable)
@@ -68,14 +68,11 @@ void mc_cynara_finish(void)
 int mc_cynara_receive_untrusted_message(int sockfd, mc_comm_msg_s *recv_msg, mc_peer_creds *credentials)
 {
        int ret = 0;
-       size_t recv_msg_size = 0;
-       size_t head_size = 0;
 
        if (!recv_msg || !credentials)
                return MEDIA_CONTROLLER_ERROR_INVALID_PARAMETER;
 
-       head_size = sizeof(mc_comm_msg_s) - sizeof(recv_msg->msg);
-       if ((recv_msg_size = read(sockfd, recv_msg, head_size)) < head_size) {
+       if (read(sockfd, recv_msg, sizeof(mc_comm_msg_s)) != sizeof(mc_comm_msg_s)) {
                if (errno == EWOULDBLOCK) {
                        mc_error("Timeout. Can't try any more");
                        return MEDIA_CONTROLLER_ERROR_INVALID_OPERATION;
@@ -85,52 +82,6 @@ int mc_cynara_receive_untrusted_message(int sockfd, mc_comm_msg_s *recv_msg, mc_
                }
        }
 
-       if ((recv_msg->msg_size > 0) && (recv_msg->msg_size <= SIZE_MAX - 1)) {
-               size_t remain_size = recv_msg->msg_size;
-               size_t block_size = 0;
-               size_t msg_index = 0;
-               char *recv_buf = NULL;
-
-               recv_buf = g_malloc0(MAX_MSG_SIZE + 1);
-               recv_msg->msg = g_malloc0(recv_msg->msg_size + 1);
-
-               while (remain_size > 0) {
-                       memset(recv_buf, 0, MAX_MSG_SIZE + 1);
-                       if (remain_size < MAX_MSG_SIZE)
-                               block_size = remain_size;
-                       else
-                               block_size = MAX_MSG_SIZE;
-
-                       if ((recv_msg_size = read(sockfd, recv_buf, block_size)) < block_size) {
-                               g_free(recv_buf);
-                               g_free(recv_msg->msg);
-                               if (errno == EWOULDBLOCK) {
-                                       mc_error("Timeout. Can't try any more");
-                                       return MEDIA_CONTROLLER_ERROR_INVALID_OPERATION;
-                               } else {
-                                       mc_stderror("recv failed");
-                                       return MEDIA_CONTROLLER_ERROR_INVALID_OPERATION;
-                               }
-                       }
-
-                       if (recv_msg_size > remain_size) {
-                               mc_error("recv_msg_size [%zu] remain_size [%zu]", recv_msg_size, remain_size);
-                               break;
-                       }
-
-                       memcpy(recv_msg->msg + msg_index, recv_buf, recv_msg_size);
-                       msg_index += recv_msg_size;
-
-                       remain_size -= recv_msg_size;
-               }
-
-               g_free(recv_buf);
-       } else {
-               mc_error("wrong msg_size [%zu]", recv_msg->msg_size);
-               recv_msg->msg = NULL;
-               return MEDIA_CONTROLLER_ERROR_INVALID_OPERATION;
-       }
-
 /*     mc_debug("receive msg[%d] from [%d(%d)] %d, %s", recv_msg_size, recv_msg->pid, recv_msg->uid, recv_msg->msg_type, recv_msg->msg); */
 
        ret = cynara_creds_socket_get_pid(sockfd, &(credentials->pid));
index 4985224..188d816 100644 (file)
@@ -640,6 +640,31 @@ static void __sqlite3_safe_free(gpointer data)
        SQLITE3_SAFE_FREE(data);
 }
 
+int __read_message_from_file(const gchar *path, gchar **data, size_t *size)
+{
+       GError *error = NULL;
+       gsize read_n = 0;
+
+       mc_retvm_if(!MC_STRING_VALID(path), MEDIA_CONTROLLER_ERROR_INVALID_PARAMETER, "invalid path %s", path);
+       mc_retvm_if(!data, MEDIA_CONTROLLER_ERROR_INVALID_PARAMETER, "data is null");
+       mc_retvm_if(!size, MEDIA_CONTROLLER_ERROR_INVALID_PARAMETER, "size is null");
+
+       mc_debug_fenter();
+
+       if (!g_file_get_contents(path, data, &read_n, &error)) {
+               mc_secure_error("g_file_get_contents error(%s: %s)", path, (error ? error->message : "none"));
+               if (error)
+                       g_error_free(error);
+               return MEDIA_CONTROLLER_ERROR_INVALID_OPERATION;
+       }
+
+       *size = read_n;
+
+       mc_debug_fleave();
+
+       return MEDIA_CONTROLLER_ERROR_NONE;
+}
+
 static int __parse_db_request(gchar **params, char **sql_str)
 {
        int ret = MEDIA_CONTROLLER_ERROR_NONE;
@@ -675,13 +700,26 @@ static int __parse_db_request(gchar **params, char **sql_str)
                }
 
        } else if (strncmp(MC_DB_CMD_UPDATE_META, params[0], strlen(MC_DB_CMD_UPDATE_META)) == 0) {
-               _sql_str = sqlite3_mprintf("INSERT OR REPLACE INTO %q VALUES (%Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q)",
-                               MC_DB_TABLE_LATEST_META, params[1],
-                               __replace_null(params[2]), __replace_null(params[3]), __replace_null(params[4]), __replace_null(params[5]),
-                               __replace_null(params[6]), __replace_null(params[7]), __replace_null(params[8]), __replace_null(params[9]),
-                               __replace_null(params[10]), __replace_null(params[11]), __replace_null(params[12]), __replace_null(params[13]),
-                               __replace_null(params[14]), __replace_null(params[15]));
+               gchar *message = NULL;
+               size_t message_size = 0;
+               gchar **meta_params = NULL;
 
+               mc_retvm_if((__read_message_from_file(params[1], &message, &message_size) != MEDIA_CONTROLLER_ERROR_NONE),
+                                       MEDIA_CONTROLLER_ERROR_INVALID_OPERATION, "__read_message_from_file failed");
+
+               meta_params = g_strsplit(message, MC_STRING_DELIMITER, 0);
+               g_free(message);
+               mc_retvm_if(!meta_params, MEDIA_CONTROLLER_ERROR_INVALID_OPERATION, "fail to parsing message");
+
+               _sql_str = sqlite3_mprintf("INSERT OR REPLACE INTO %q VALUES (%Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q)",
+                               MC_DB_TABLE_LATEST_META, meta_params[0],
+                               __replace_null(meta_params[1]), __replace_null(meta_params[2]), __replace_null(meta_params[3]),
+                               __replace_null(meta_params[4]), __replace_null(meta_params[5]), __replace_null(meta_params[6]),
+                               __replace_null(meta_params[7]), __replace_null(meta_params[8]), __replace_null(meta_params[9]),
+                               __replace_null(meta_params[10]), __replace_null(meta_params[11]), __replace_null(meta_params[12]),
+                               __replace_null(meta_params[13]), __replace_null(meta_params[14]));
+
+               g_strfreev(meta_params);
        } else if (strncmp(MC_DB_CMD_UPDATE_SHUFFLE, params[0], strlen(MC_DB_CMD_UPDATE_SHUFFLE)) == 0) {
                mc_retvm_if(!params[2], MEDIA_CONTROLLER_ERROR_INVALID_OPERATION, "invalid query");
 
@@ -704,15 +742,19 @@ static int __parse_db_request(gchar **params, char **sql_str)
                _sql_str = sqlite3_mprintf("INSERT INTO %q(server_name, playlist_name) VALUES (%Q, %Q)", MC_DB_TABLE_PLAYLIST, params[1], params[2]);
 
        } else if (strncmp(MC_DB_CMD_UPDATE_PLAYLIST, params[0], strlen(MC_DB_CMD_UPDATE_PLAYLIST)) == 0) {
+               gchar *message = NULL;
+               size_t message_size = 0;
                bundle *bundle = NULL;
                playlist_query_s playlist_query = { NULL, NULL, NULL, 0 };
                GSList *iter = NULL;
 
-               mc_retvm_if((!params[2] || !params[3] || !params[4]),
+               mc_retvm_if((!params[2] || !params[3]),
                                        MEDIA_CONTROLLER_ERROR_INVALID_OPERATION, "invalid query");
+               mc_retvm_if((__read_message_from_file(params[3], &message, &message_size) != MEDIA_CONTROLLER_ERROR_NONE),
+                                       MEDIA_CONTROLLER_ERROR_INVALID_OPERATION, "__read_message_from_file failed");
 
-               mc_safe_strtoi(params[3], &i_value);
-               bundle = bundle_decode((bundle_raw *)params[4], i_value);
+               bundle = bundle_decode((bundle_raw *)message, (int)message_size);
+               g_free(message);
                mc_retvm_if(!bundle, MEDIA_CONTROLLER_ERROR_INVALID_OPERATION, "invalid bundle_data");
 
                mc_debug("bundle item count [%d]", bundle_get_count(bundle));
index bdce471..3d0047f 100644 (file)
@@ -94,8 +94,6 @@ static void __mc_destroy_queue(gpointer data)
        mc_service_request *req = (mc_service_request *)data;
        mc_retm_if_failed(req);
 
-       if (req->req_msg)
-               g_free(req->req_msg->msg);
        g_free(req->req_msg);
        g_free(req);
 }