monitor: lib: Support Unix domain socket (UDS) and TCP/IP socket concurrently 03/280803/3
authorSung-hun Kim <sfoon.kim@samsung.com>
Fri, 2 Sep 2022 05:41:47 +0000 (14:41 +0900)
committerSung-hun Kim <sfoon.kim@samsung.com>
Mon, 5 Sep 2022 11:45:07 +0000 (20:45 +0900)
Previous TCP/IP socket-based IPC has a security issue that
anyone can access the opened port without credential. Since
UDS is exported as a file, we can apply file-based access
control to it. So, we use UDS instead of TCP/IP socket by
default.

At the same time, we also support TCP/IP socket for
resource-monitor-tool which is a web-based monitoring tool
in user space. In the future, we will support TCP/IP socket
only in debugging mode which is turned on/off by root-
privileged command line tool.

Change-Id: Id46a5e7560cf95d09f31222e5022ce3ea209753a
Signed-off-by: Sung-hun Kim <sfoon.kim@samsung.com>
CMakeLists.txt
lib/resource-monitor/resource-monitor.c
packaging/pass.spec
src/monitor/request-handler.c
systemd/pass-resource-monitor.socket.in [new file with mode: 0644]

index 4ea606a..18f595b 100644 (file)
@@ -123,6 +123,7 @@ INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/scripts/${PROJECT_NAME}.conf DESTINATI
 INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/scripts/pass-pmqos.json DESTINATION /etc/pass)
 INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/scripts/pass-thermal.json DESTINATION /etc/pass)
 CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/systemd/${PROJECT_NAME}.service.in ${CMAKE_SOURCE_DIR}/systemd/${PROJECT_NAME}.service @ONLY)
+CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/systemd/${PROJECT_NAME}-resource-monitor.socket.in ${CMAKE_SOURCE_DIR}/systemd/${PROJECT_NAME}-resource-monitor.socket @ONLY)
 INSTALL(FILES ${CMAKE_SOURCE_DIR}/systemd/org.tizen.system.pass.service DESTINATION /usr/share/dbus-1/system-services)
 INSTALL(FILES ${CMAKE_SOURCE_DIR}/systemd/org.tizen.system.thermal.service DESTINATION /usr/share/dbus-1/system-services)
 
@@ -131,6 +132,11 @@ INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/systemd/ DESTINATION lib/systemd/s
                PATTERN "${PROJECT_NAME}.service"
                )
 
+INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/systemd/ DESTINATION lib/systemd/system
+               FILES_MATCHING
+               PATTERN "${PROJECT_NAME}-resource-monitor.socket"
+               )
+
 ADD_SUBDIRECTORY(tests/integration-test)
 ADD_SUBDIRECTORY(tests/haltest)
 ADD_SUBDIRECTORY(tests/unittest)
index a7ab07e..7a08699 100644 (file)
 #include <arpa/inet.h>
 #include <sys/types.h>
 #include <sys/socket.h>
+#include <sys/un.h>
 #include <netinet/in.h>
 #include <sys/time.h>
 #include <fcntl.h>
 #include <unistd.h>
-
 #include <tizen.h>
 
 #include "resource-monitor.h"
@@ -289,8 +289,9 @@ static inline int handle_request(struct request_data *data)
 EXPORT
 int pass_resource_monitor_init(void)
 {
+       const char *server_socket_path = "/run/.pass-resource-monitor.socket";
        struct pass_resource_monitor_client *client;
-       struct sockaddr_in server_addr;
+       struct sockaddr_un server_addr;
        int ret = TIZEN_ERROR_NO_DATA;
 
        if (!is_privilege_supported(PRIVILEGE_SYSTEMMONITOR))
@@ -303,19 +304,16 @@ int pass_resource_monitor_init(void)
        }
 
        /* open socket to server */
-       client->id = socket(AF_INET, SOCK_STREAM, 0);
+       client->id = socket(AF_UNIX, SOCK_STREAM, 0);
        if (client->id < 0) {
                _E("[libpass] socket creation error");
                goto err_out_free;
        }
 
-       server_addr.sin_family = AF_INET;
-       server_addr.sin_port = htons(REQUEST_SERVER_PORT);
-
-       if (inet_pton(AF_INET, REQUEST_SERVER_IP, &server_addr.sin_addr) <= 0) {
-               _E("[libpass] invalid address");
-               goto err_out_close;
-       }
+       bzero(&server_addr, sizeof(server_addr));
+       server_addr.sun_family = AF_UNIX;
+       strncpy(server_addr.sun_path, server_socket_path, sizeof(server_addr.sun_path));
+       server_addr.sun_path[sizeof(server_addr.sun_path) - 1] = '\0';
 
        if (connect(client->id, (struct sockaddr *)&server_addr,
                                        sizeof(server_addr)) < 0) {
index 4444495..dac786f 100644 (file)
@@ -94,6 +94,7 @@ rm -rf %{buildroot}
 %make_install
 
 %install_service delayed.target.wants %{daemon_name}.service
+%install_service sockets.target.wants %{daemon_name}-resource-monitor.socket
 
 %post
 
@@ -119,7 +120,9 @@ systemctl daemon-reload
 %{_bindir}/%{daemon_name}
 %{_bindir}/resource-monitor
 %{_unitdir}/delayed.target.wants/%{daemon_name}.service
+%{_unitdir}/sockets.target.wants/%{daemon_name}-resource-monitor.socket
 %{_unitdir}/%{daemon_name}.service
+%{_unitdir}/%{daemon_name}-resource-monitor.socket
 %{_datadir}/dbus-1/system-services/org.tizen.system.pass.service
 %{_datadir}/dbus-1/system-services/org.tizen.system.thermal.service
 
index 5d30833..324d0fc 100644 (file)
@@ -35,6 +35,7 @@
 #include <arpa/inet.h>
 #include <sys/types.h>
 #include <sys/socket.h>
+#include <sys/un.h>
 #include <netinet/in.h>
 #include <sys/time.h>
 #include <assert.h>
@@ -1078,53 +1079,129 @@ static int create_request_client(int socket_fd)
        return 0;
 }
 
-static int request_server_func(void *ctx, void **result)
+static int init_unix_socket(int *sock, struct sockaddr_un *address, int *addrlen)
 {
-       struct sockaddr_in address;
-       struct timeval wait;
+       const char *server_unix_socket_path = "/run/.pass-resource-monitor.socket";
        int opt = true;
-       int server_socket;
-       int addrlen;
-       int ret;
-       fd_set fds;
 
-       if (!g_request_server_run)
-               return THREAD_RETURN_DONE;
-
-       init_resource_id();
+       if (!sock || !address || !addrlen)
+               return -EINVAL;
 
-       /* 0. initialize server socket */
-       server_socket = socket(AF_INET, SOCK_STREAM, 0);
-       if (server_socket < 0) {
+       *sock = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (*sock < 0) {
                _E("Failed to initialize socket");
                goto error_out;
        }
 
-       if (setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR,
+       if (setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR,
                        (char *)&opt, sizeof(opt)) < 0) {
                _E("Failed to setsockopt");
                goto error_out_close;
        }
 
-       address.sin_family = AF_INET;
-       address.sin_addr.s_addr = INADDR_ANY;
-       address.sin_port = htons(REQUEST_SERVER_PORT);
+       bzero(address, sizeof(*address));
+       address->sun_family = AF_UNIX;
+       strncpy(address->sun_path, server_unix_socket_path, sizeof(address->sun_path));
+       address->sun_path[sizeof(address->sun_path) - 1] = '\0';
+
+       if (!access(server_unix_socket_path, F_OK))
+               unlink(server_unix_socket_path);
 
-       if (bind(server_socket, (struct sockaddr *)&address, sizeof(address)) < 0) {
+       if (bind(*sock, (struct sockaddr *)address, sizeof(*address)) < 0) {
                _E("Failed to bind");
                goto error_out_close;
        }
 
-       if (listen(server_socket, PENDING_MAX) < 0) {
+       if (listen(*sock, PENDING_MAX) < 0) {
                _E("Failed to begin listenning");
                goto error_out_close;
        }
 
-       addrlen = sizeof(address);
+       *addrlen = sizeof(*address);
+
+       return 0;
+
+error_out_close:
+       close(*sock);
+error_out:
+       return -EIO;
+}
+
+int init_ip_socket(int *sock, struct sockaddr_in *address, int *addrlen)
+{
+       int opt = true;
+
+       if (!sock || !address || !addrlen)
+               return -EINVAL;
+
+       *sock = socket(AF_INET, SOCK_STREAM, 0);
+       if (*sock < 0) {
+               _E("Failed to initialize TCP/IP socket");
+               goto error_out;
+       }
+
+       if (setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR,
+                       (char *)&opt, sizeof(opt)) < 0) {
+               _E("Failed to setsockopt for TCP/IP socket");
+               goto error_out_close;
+       }
+
+       bzero(address, sizeof(*address));
+       address->sin_family = AF_INET;
+       address->sin_addr.s_addr = INADDR_ANY;
+       address->sin_port = htons(REQUEST_SERVER_PORT);
+
+       if (bind(*sock, (struct sockaddr *)address, sizeof(*address)) < 0) {
+               _E("Failed to bind for TCP/IP socket");
+               goto error_out_close;
+       }
+
+       if (listen(*sock, PENDING_MAX) < 0) {
+               _E("Failed to begin listenning for TCP/IP socket");
+               goto error_out_close;
+       }
+
+       *addrlen = sizeof(*address);
+
+       return 0;
+
+error_out_close:
+       close(*sock);
+error_out:
+       return -EIO;
+}
+
+static int request_server_func(void *ctx, void **result)
+{
+       struct sockaddr_un unix_address;
+       struct sockaddr_in ip_address;
+       struct timeval wait;
+       int server_unix_socket;
+       int server_ip_socket;
+       int unix_addrlen;
+       int ip_addrlen;
+       int ret;
+       fd_set fds;
+
+       if (!g_request_server_run)
+               return THREAD_RETURN_DONE;
+
+       init_resource_id();
+
+       /* 0. initialize server socket */
+       ret = init_unix_socket(&server_unix_socket, &unix_address, &unix_addrlen);
+       if (ret < 0)
+               goto error_out;
+
+       /* initialize TCP socket */
+       ret = init_ip_socket(&server_ip_socket, &ip_address, &ip_addrlen);
+       if (ret < 0)
+               goto error_out_close_server_unix_socket;
 
        while (g_request_server_run) {
                FD_ZERO(&fds);
-               FD_SET(server_socket, &fds);
+               FD_SET(server_unix_socket, &fds);
+               FD_SET(server_ip_socket, &fds);
 
                wait.tv_sec = 1;
                wait.tv_usec = 0;
@@ -1135,9 +1212,21 @@ static int request_server_func(void *ctx, void **result)
                        goto error_out_close;
                }
 
-               if (FD_ISSET(server_socket, &fds)) {
-                       int new_socket = accept(server_socket, (struct sockaddr *)&address,
-                                       (socklen_t *)&addrlen);
+               if (FD_ISSET(server_unix_socket, &fds)) {
+                       int new_socket = accept(server_unix_socket, (struct sockaddr *)&unix_address,
+                                       (socklen_t *)&unix_addrlen);
+
+                       if (new_socket < 0) {
+                               _E("Failed to accept");
+                               goto error_out_close;
+                       }
+
+                       create_request_client(new_socket);
+               }
+
+               if (FD_ISSET(server_ip_socket, &fds)) {
+                       int new_socket = accept(server_ip_socket, (struct sockaddr *)&ip_address,
+                                       (socklen_t *)&ip_addrlen);
 
                        if (new_socket < 0) {
                                _E("Failed to accept");
@@ -1148,12 +1237,15 @@ static int request_server_func(void *ctx, void **result)
                }
        }
 
-       close(server_socket);
+       close(server_ip_socket);
+       close(server_unix_socket);
 
        return THREAD_RETURN_DONE;
 
 error_out_close:
-       close(server_socket);
+       close(server_ip_socket);
+error_out_close_server_unix_socket:
+       close(server_unix_socket);
 error_out:
 
        return THREAD_RETURN_ERROR;
diff --git a/systemd/pass-resource-monitor.socket.in b/systemd/pass-resource-monitor.socket.in
new file mode 100644 (file)
index 0000000..406f96f
--- /dev/null
@@ -0,0 +1,10 @@
+[Unit]
+Description=Pass resource-monitor socket
+
+[Socket]
+SocketUser=system_fw
+SocketGroup=system_fw
+ListenStream=/run/.pass.socket
+SocketMode=0777
+SmackLabelIPIn=*
+SmackLabelIPOut=@