我的自定義程序以非root權限執行,其用戶標識爲:uid: 1000 euid: 0
,其中fork()後,在子進程中調用execv()以運行SSH客戶端服務。由於我在非特權用戶下啓動程序,因此當試圖將套接字綁定到設備時,Linux內核會執行所有權限檢查,導致子例程sock_setbindtodevice()
中的一個故障,同時檢查CAP_NET_RAW
功能,如下所示。更改用戶ID以分配附加功能
我在想的解決方案是首先在子進程中獲取root權限,執行特權操作,例如設置所需的功能,然後退回到非root用戶。
這裏的一個問題是,下拉到非根需要什麼,因爲執行ssh命令時,我希望生成的DSA/RSA
鍵存儲在$HOME/.ssh/known_hosts
而不是root/.ssh/known_hosts
中。
請找到下面的代碼片段:
void
global_exec_func (const char *proc_name, const char *proc_path, char **arg_list)
{
pid_t pid;
int status, euid;
struct __user_cap_header_struct cap_header_data;
cap_user_header_t cap_header = &cap_header_data;
struct __user_cap_data_struct cap_data_data;
cap_user_data_t cap_data = &cap_data_data;
pid = fork();
if (pid < 0) {
printf("%% can't fork process %s", proc_name);
return;
}
/*
* Child process.
*/
if (pid == 0) {
euid = geteuid(); /* Storing euid */
/*Gaining root privileges */
if (setuid(0) < 0) {
printf("setuid(0) failed");
}
printf("After setting: getuid: %d geteuid: %d\n", getuid(),
geteuid());
cap_header->pid = 0;
cap_header->version = _LINUX_CAPABILITY_VERSION;
/* Get the capabilities */
if(capget(cap_header, cap_data) < 0) {
printf("failed capget error:%s", strerror(errno));
}
cap_data->effective = (1 << CAP_NET_RAW); /* Set bit 13 */
cap_data->inheritable = 0;
/* Set the capabilities */
if (capset(cap_header, cap_data) < 0) {
printf("failed capset error:%s", strerror(errno));
}
/* Drop back privileges */
if (seteuid(euid) < 0) {
printf("seteuid(euid) failed");
}
printf("After drop: getuid: %d geteuid: %d\n", getuid(), geteuid());
prctl(PR_SET_KEEPCAPS, 1);
execv(proc_path, arg_list);
exit(1);
}
/*
* Parent Process code follows
*/
Result:
[local]linux#ssh 101.1.1.101
After setting: getuid: 0 geteuid: 0
After drop: getuid: 0 geteuid: 0
The authenticity of host '101.1.1.101 (101.1.1.101)' can't be established.
DSA key fingerprint is 0c:61:df:01:93:74:1f:5f:49:34:f4:4e:06:e8:d7:5f.
Are you sure you want to continue connecting (yes/no)? ^C
[local]linux#
結果表明,SSH是成功的,但該方案在這一點上,這是不正確運行爲root
。我如何返回到UID爲uid: 1000 euid: 0
,以便ssh密鑰存儲在正確的目錄中。
請在我的解決方案上提出意見和建議,它真的能解決問題嗎?
感謝明確的解釋。但是,通過啓用'cap_net_raw'功能,相同的實現無法解決。甲調試打印'的printf( 「%S \ n」 個,cap_to_text(cap_get_proc(),NULL));'之前和之後'cap_set_proc()'顯示爲'組PROC之前= EP組PROC後= EP CAP_NET_RAW + i',這是否告訴我們能力已經確定? –
'= ep cap_net_raw'表示'CAP_NET_RAW'能力是有效的並且被允許的,這意味着當前進程確實具有這種能力。 '= EP CAP_NET_RAW + i'意味着'CAP_NET_RAW'能力是有效的,允許的,和繼承,這意味着當前的進程確實有這樣的能力,並且所有子進程它產生就會有這樣的能力了。你確實意識到許多應用程序像'ssh'做了他們自己的內部健康檢查?例如,即使你給'在/ usr/bin中/ ssh'了'CAP_NET_BIND_SERVICE'能力,在默認情況下它仍然拒絕綁定端口<1024 –
@SunEric:我覺得我並沒有強調效果*文件系統能力*確實超過了'exec()'。我更新了我的答案以反映這些(請參閱「編輯添加:」分數)。 –