2014年6月3日 星期二

EPERM error of settimeofday() , using capset() & capget() modify CAP_SYS_TIME.

最近發現 settimeofday() 沒有辦法執行 , 回報錯誤為 -1 (EPERM), 看一下 man 說明,發現沒有打開 CAP_SYS_TIME, 所以在 euid >= 1000 的時候不會允許設定系統時間. 
下列是 man settimeofday() 的說明:


       EPERM  The calling process has insufficient privilege  to  call  settimeofday();  
                     under  Linux  the  CAP_SYS_TIME  capability  is   required.

好吧 , 打開一下後門 ,  google 了一下,發現可以使用 capget() & capset來設定.
大致說明一下 CAP 的設定, 首先要先了解三個CAP 的等級.
A. effective => 有效的, 這個有設定就可以允許 操作相對應的東西 , 
                        例如 CAP_SYS_TIME 有設定就可以設定系統時間.
B. permitted => 這是允許的內容 , 如果這個資料內的 CAP_SYS_TIME 沒有設定 , 
                         那設定 effective 也沒用.
C. inheritable => 是否可被繼承 ,如果有設定 , fork() + exec() 的 子 process 也可以繼續
                          被允許對應的設定.

           typedef struct __user_cap_data_struct {
              __u32 effective;
              __u32 permitted;
              __u32 inheritable;
           } *cap_user_data_t;
 

來個實際例子吧, 目前子程序的 P (permitted) 是全部被允許的 , 
不過E(effective)沒有打開 ,利用下列的範例將其打開 , 就可以使用 settimeofday() 設定系統時間了.

        if (geteuid() > 0 )
        {
        //---- Not Root ,need turn on CAP_SYS_TIME.
                header.version = _LINUX_CAPABILITY_VERSION_1;
                header.pid = getpid();
                retval = capget(&header, &cap);
                if(retval)
                        goto capget_fail;

//                      printf("\t[%s] PID:%d E:%x P:%x I:%x\n", __FUNCTION__,
//                                      header.pid, cap.effective, cap.permitted,cap.inheritable);

                header.version = _LINUX_CAPABILITY_VERSION_1;
                header.pid = 0;

                if ( enable )
                        cap.effective   |=  (1 << CAP_SYS_TIME);
                else
                        cap.effective   &=  ~(1 << CAP_SYS_TIME);

                retval = capset(&header, &cap);
                if(retval)
                        goto capset_fail;
        }





PS. 這段 function call 我想要打開 CAP_SYS_TIME 設定系統時間後就關閉(我提供一個特別的 SO API , 所以使用者還是不能 設定 系統時間,除非透過這個 API .
       所以先判別是否為 root (利用 EUID) , 如果不是就可以enable / disable . 如果是 root , 就不理會(root 本來就可以)





沒有留言:

張貼留言