%20%D0%B2%20C%2FC%2B%2B.png)
В настоящее время я пытаюсь понять возможности Linux, читаяhttp://man7.org/linux/man-pages/man7/capabilities.7.html
Я создал небольшое приложение на C++ с возможностьюCAP_DAC_READ_SEARCH+eip
Возможность работает отлично для приложения. Но у меня есть system()
вызов внутри
system("cat /dev/mtdX > targetFile");
Как я могу унаследовать возможность этого вызова?
Редактировать:
Я знаю, что это system()
управляется fork()
+ execl()
. В документации упоминается, что с fork()
дочерним процессом получаются те же возможности, что и у родительского процесса. Но почему возможность чтения не наследуется?
решение1
Прежде всего, вам следует убраться system(3)
с дороги; в отличие от того, что вы предлагаете, system(3)
это не просто fork+exec
, а что-то довольно сложное, включающее изменение расположения сигналов, ожидание дочернего объекта и использование /bin/sh
в качестве оболочки (которая может уменьшать или увеличивать возможности в зависимости от прихотей и предположений ее сопровождающего, возиться с переменными окружения, исходными скриптами инициализации и другими забавными вещами). Использование просто execv*(2)
вместо system(3)
уберет все эти ложные осложнения с пути.
Во-вторых, вам следует глубоко изучить execve()
часть «Трансформация возможностей во время»capabilities(7)
manpage. Я не буду копировать-вставлять это сюда, но в целом это сводится к следующему:Возможности НЕ наследуются через execve(), если только они не добавлены вокружающийнаборпотока (процесса), и они не могут быть добавлены туда, если они уже не находятся в наследуемом наборенить. («Наследуемые» возможности метаданных файла — это всего лишьмаска, ограничивая таковые в потоке).
Итак, для того, чтобы унаследовать способности, execve()
вам следуета)скопируйте их изразрешенныйкнаследственныйнабор (который вы могли бы сделать с помощьюcapset(2)
системный вызов [1]) иб)добавьте их вокружающийнабор (который вы могли бы сделать сprctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE)
).
Собираем все вместе:
$ cat capexec.c
#include <sys/prctl.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <linux/capability.h>
#include <err.h>
int main(int ac, char **av){
static char *dav[] = { "/bin/bash", 0 };
struct __user_cap_header_struct hs;
struct __user_cap_data_struct ds[2];
hs.version = 0x20080522; /*_LINUX_CAPABILITY_VERSION_3;*/
hs.pid = getpid();
if(syscall(SYS_capget, &hs, ds)) err(1, "capget");
ds[0].inheritable = ds[0].permitted;
if(syscall(SYS_capset, &hs, ds)) err(1, "capset");
if(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_DAC_READ_SEARCH, 0, 0)) err(1, "prctl(pr_cap_ambient_raise)");
av = ac < 2 ? dav : av + 1;
execvp(*av, av);
err(1, "execvp %s", *av);
}
$ cc -Wall capexec.c -o capexec
# as root
# setcap cap_dac_read_search+ip /tmp/capexec
$ ./capexec dd if=/dev/sda of=/dev/null count=1
1+0 records in
1+0 records out
512 bytes copied, 0.000299173 s, 1.7 MB/s
[1] В документации рекомендуется использовать библиотеку libcap; части этого примера были взяты из хака, который я написал для старой версии Android, где не было libcap и отсутствовали многие определения заголовков. Преобразование его для использования оболочек libcap остается в качестве упражнения для читателя.
решение2
Спасибо @mosvy. Я реализовал его решение с помощью libcap, и, похоже, оно работает так, как и ожидалось.
void inheritCapabilities()
{
cap_t caps;
caps = cap_get_proc();
if (caps == NULL)
throw "Failed to load capabilities";
printf("DEBUG: Loaded Capabilities: %s\n", cap_to_text(caps, NULL));
cap_value_t cap_list[1];
cap_list[0] = CAP_DAC_READ_SEARCH;
if (cap_set_flag(caps, CAP_INHERITABLE, 1, cap_list, CAP_SET) == -1)
throw "Failed to set inheritable";
printf("DEBUG: Loaded Capabilities: %s\n", cap_to_text(caps, NULL));
if (cap_set_proc(caps) == -1)
throw "Failed to set proc";
printf("DEBUG: Loaded Capabilities: %s\n", cap_to_text(caps, NULL));
caps = cap_get_proc();
if (caps == NULL)
throw "Failed to load capabilities";
printf("DEBUG: Loaded Capabilities: %s\n", cap_to_text(caps, NULL));
if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_DAC_READ_SEARCH, 0, 0) == -1)
throw "Failed to pr_cap_ambient_raise! Error: " + errno;
}
main() {
inheritCapabilities();
char *catargv[5];
catargv[0] = (char *)"cmd";
catargv[1] = (char *)"arg1";
catargv[2] = (char *)"arg2";
catargv[3] = (char *)"arg3";
catargv[4] = NULL;
if (execvp(catargv[0], catargv) == -1)
throw "Failed! command";
}