Add a defense code for device_power_request/release_lock() APIs 38/181438/6 accepted/tizen/unified/20180614.150849 submit/tizen/20180614.063411
authorHyotaek Shim <hyotaek.shim@samsung.com>
Thu, 14 Jun 2018 03:11:02 +0000 (12:11 +0900)
committerHyotaek Shim <hyotaek.shim@samsung.com>
Thu, 14 Jun 2018 06:26:25 +0000 (15:26 +0900)
, which rejects API calls when the rate is over the threshold.

-- User-side solution --
Adding a delay(100ms) between calls.

-- Problem Definition --
Insensive async dbus calls like this can block dbus-daemon and others (deviced, etc.).

while (1) {
        ret = device_power_request_lock (POWER_LOCK_DISPLAY, 0);
}

Program terminated with signal SIGABRT, Aborted.
 #0  0xb68b6964 in poll () at ../sysdeps/unix/syscall-template.S:84
 84 ../sysdeps/unix/syscall-template.S: No such file or directory.
 [Current thread is 1 (Thread 0xb6f3f180 (LWP 367))]
 (gdb) bt
 #0  0xb68b6964 in poll () at ../sysdeps/unix/syscall-template.S:84
 #1  0xb6b74c18 in g_main_context_poll (priority=<optimized out>, n_fds=1, fds=0xb7574c80,
     timeout=<optimized out>, context=0xb756fb00) at gmain.c:4259
 #2  g_main_context_iterate (context=0xb756fb00, block=block@entry=1, dispatch=dispatch@entry=1,
     self=<optimized out>) at gmain.c:3955
 #3  0xb6b74fd8 in g_main_loop_run (loop=0xb7570c50) at gmain.c:4156
 #4  0xb6e345c0 in g_dbus_connection_send_message_with_reply_sync (
     connection=connection@entry=0xb752d868, message=message@entry=0xb51d2180,
     flags=G_DBUS_SEND_MESSAGE_FLAGS_NONE, timeout_msec=10000, timeout_msec@entry=-1226030992,
     out_serial=out_serial@entry=0x0, cancellable=0x0, error=0xbeeaeaf4, error@entry=0xbeeaeaec)
     at gdbusconnection.c:2844
 #5  0xb6e34b70 in g_dbus_connection_call_sync_internal (connection=connection@entry=0xb752d868,
     bus_name=<optimized out>, object_path=0xb6c91bb4 "/",
     interface_name=0xb6c91b9c "org.freedesktop.DBus", method_name=<optimized out>,
     method_name@entry=0x2710 <error: Cannot access memory at address 0x2710>, parameters=0xb515f960,
     parameters@entry=0xb6c91339 <dbus_connection_get_sender_pid+76>,
     reply_type=reply_type@entry=0xb6c91bb8, flags=flags@entry=G_DBUS_CALL_FLAGS_NONE,
     timeout_msec=timeout_msec@entry=10000, fd_list=fd_list@entry=0x0,
     out_fd_list=out_fd_list@entry=0x0, cancellable=cancellable@entry=0x0, error=0xbeeaeb78,
     error@entry=0x2710) at gdbusconnection.c:6901
 #6  0xb6e37294 in g_dbus_connection_call_sync (connection=connection@entry=0xb752d868,
     bus_name=<optimized out>, object_path=<optimized out>, interface_name=<optimized out>,
     method_name=0xb6c91bb8 "GetConnectionUnixProcessID", parameters=0xb515f960,
     reply_type=reply_type@entry=0x0, flags=flags@entry=G_DBUS_CALL_FLAGS_NONE,
     timeout_msec=timeout_msec@entry=10000, cancellable=cancellable@entry=0x0,
     error=error@entry=0xbeeaeb78) at gdbusconnection.c:7128
 #7  0xb6c91338 in dbus_connection_get_sender_pid (conn=conn@entry=0xb752d868,
     sender=sender@entry=0xb5169b58 ":1.103")
     at /usr/src/debug/libsyscommon-4.1/src/libgdbus/dbus-system.c:2412
 #8  0xb6f798a2 in dbus_lockstate (conn=0xb752d868, sender=0xb5169b58 ":1.103", path=<optimized out>,
     iface=<optimized out>, name=0xb5166cd8 "lockstate", param=0xb5159360, invocation=0xb50342c0,
     user_data=0xb6ca230c <g_dh>) at /usr/src/debug/deviced-5.0.0/src/display/display-dbus.c:128
 #9  0xb6c901d6 in _method_call_handler (conn=0xb752d868, sender=0xb5169b58 ":1.103",
     path=0xb504f000 "/Org/Tizen/System/DeviceD/Display",
     iface=0xb5157aa0 "org.tizen.system.deviced.display", name=0xb5166cd8 "lockstate",
     param=0xb5159360, invocation=0xb50342c0, user_data=0xb7532ee0)
     at /usr/src/debug/libsyscommon-4.1/src/libgdbus/dbus-system.c:1048
 #10 0xb6e32a60 in call_in_idle_cb (user_data=0xb50342c0) at gdbusconnection.c:5792
 #11 0xb6b748e8 in g_main_dispatch (context=0xb7528f28) at gmain.c:3234
 #12 g_main_context_dispatch (context=context@entry=0xb7528f28) at gmain.c:3887
 #13 0xb6b74c78 in g_main_context_iterate (context=0xb7528f28, block=block@entry=1,
     dispatch=dispatch@entry=1, self=<optimized out>) at gmain.c:3960
 #14 0xb6b74fd8 in g_main_loop_run (loop=0xb7529400) at gmain.c:4156
 #15 0xb6f5bb66 in deviced_main (argc=<optimized out>, argv=<optimized out>)
     at /usr/src/debug/deviced-5.0.0/src/core/main.c:116
 #16 0xb6f57ce8 in main (argc=1, argv=0xbeeaee64) at /usr/src/debug/deviced-5.0.0/src/core/main.c:126

Change-Id: Ide0b04f2af13c25a1e9347b9f3caf35736d61556
Signed-off-by: Hyotaek Shim <hyotaek.shim@samsung.com>
src/power.c

index e3207ef..4029d2a 100755 (executable)
@@ -22,6 +22,7 @@
 #include <glib.h>
 #include <limits.h>
 #include <tracker.h>
+#include <sys/time.h>
 
 #include "power.h"
 #include "display.h"
@@ -443,12 +444,65 @@ static int unlock_state(display_state_e state, unsigned int flag)
                        METHOD_UNLOCK_STATE, "ss", arr, unlock_cb, -1, NULL);
 }
 
+#define CHECK_RATE_THRESHOLD   100
+#define CHECK_RATE_PERIOD_LEN  5
+static int check_rate()
+{
+       static int status;
+       static long num_calls;
+       static struct timeval prev;
+       struct timeval cur;
+       int ret;
+
+       if (status < 0)
+               return status;
+
+       ret = gettimeofday(&cur, NULL);
+       if (ret < 0) {
+               _E("Failed to do gettimeofday() ret=%d", ret);
+               return 0;
+       }
+
+       if (num_calls > 0) {
+               long rate;
+               struct timeval diff;
+               timersub(&cur, &prev, &diff);
+
+               if (diff.tv_sec > 0) {
+                       rate = num_calls / diff.tv_sec;
+
+                       if (rate > CHECK_RATE_THRESHOLD) {
+                               status = -1;
+                               return status;
+                       }
+
+                       if (diff.tv_sec > CHECK_RATE_PERIOD_LEN) {
+                               /* Reset the check period */
+                               num_calls = 0;
+                               return 0;
+                       }
+               }
+       } else {
+               /* Start a new check period */
+               prev = cur;
+       }
+
+       num_calls++;
+       return 0;
+}
+
 int device_power_request_lock(power_lock_e type, int timeout_ms)
 {
        int ret;
 
        _I("power_lock_e = %d", type);
 
+       if (check_rate() < 0) {
+               _E("Rejected by too frequent calls; %d (calls per sec.) limit is over."
+                               , CHECK_RATE_THRESHOLD);
+               return DEVICE_ERROR_OPERATION_FAILED;
+       }
+
        if (timeout_ms < 0)
                return DEVICE_ERROR_INVALID_PARAMETER;
 
@@ -473,6 +527,12 @@ int device_power_release_lock(power_lock_e type)
 
        _I("power_lock_e = %d", type);
 
+       if (check_rate() < 0) {
+               _E("Rejected by too frequent calls; %d (calls per sec.) limit is over."
+                               , CHECK_RATE_THRESHOLD);
+               return DEVICE_ERROR_OPERATION_FAILED;
+       }
+
        if (type == POWER_LOCK_CPU) {
                ret = unlock_state(DISPLAY_STATE_SCREEN_OFF, PM_SLEEP_MARGIN);
                if (ret == 0) {