Я хотел бы сделать дубликат дескриптора файла, работающего в несвязанном процессе на Linux. Я знаю оотправить сообщение(2)и SCM_RIGHTS
(напримерhttps://stackoverflow.com/questions/4489433/отправка-файла-дескриптора-через-unix-domain-socket-and-select) , но это работает только если другой процесс сотрудничает. Мне нужно решение, которое не требует активного сотрудничества с другим процессом. Я также знаю, что я мог бы сначала создать дескриптор файла, сохранить копию, а затем создать другой процесс, но мне нужно решение, в котором другой процесс создает свой собственный дескриптор файла.
Я вижу дескриптор файла:
$ ls -l /proc/13115/fd/3
lrwx------ 1 pts pts 64 2013-05-04 13:15 /proc/13115/fd/3 -> socket:[19445454]
Однако open("/proc/13115/fd/3", O_RDWR)
выполнение в другом процессе возвращает ошибкуНет такого устройства или адреса. Есть ли что-то еще, что сработает? Вероятно, сptrace?
решение1
Это сделано намеренно: совместное использование файловых дескрипторов с другими процессами является явным. По умолчанию файловые дескрипторы являются такими же частными, как и собственная память процесса.
Как обычно, если у вас есть правоptraceпроцесс, вы можете делать все, что угодно, включая вызов sendmsg
. Традиционно вызов ptrace
требует запуска с тем же идентификатором пользователя; ограничения безопасности, такие как SELinux, возможности, тюрьмы и т. д., могут сделать ptrace
более строгими. Например, в конфигурации Ubuntu по умолчанию некорневой процесс может вызывать только ptrace
своих собственных потомков (через AppArmor).
Использовать ptrace
robustly немного сложно: нужно ввести правильные данные, убедиться, что ничего не перезаписали, и убрать за собой. Поэтому я рекомендую ввести код окольным путем и запустить этот код с помощью существующего инструмента.
Напишите небольшую общую библиотеку, содержащую sendmsg
код, и LD_PRELOAD
ее в другой процесс. Вот некоторыенепроверенныйскелетный код с отсутствующей проверкой ошибок.
int pts_gift_fd (char *path, int fd) {
int sock;
struct sockaddr_un addr = {0};
struct msghdr msg = {0};
struct iovec iov = {0};
addr.sun_family = AF_UNIX;
strlcpy(addr.sun_path, path, sizeof(addr.sun_path));
/* Populate msg, iov as in the code you've already found */
sock = socket(AF_UNIX, SOCK_STREAM, 0);
connect(sock, (struct sockaddr*)&addr, sizeof(addr));
sendmsg(sock, &msg, 0);
close(sock);
}
Затем, чтобы запустить код, запустите gdb -n -pid 13115 -batch -x /dev/stdin
его popen
и введите в него входные данные следующим образом (где %d
fd — это файл, который вы хотите получить, а %s
— это путь к сокету unix, который вы ранее создали и прослушиваете):
call pts_gift_fd("%s", %d)
detach
quit
решение2
Вы не можете сделать это по той же причине, по которой вы не можете получить доступ к памяти несвязанного процесса, поскольку дескриптор файлаявляетсячасть памяти другого процесса. Единственная причина, по которой там есть информация о таких вещах, /proc
заключается в том, что ядро предоставляет ее там, и она доступна только для чтения (поэтому есть средства для проверкикопияпамяти процесса).
Если это относится к файлу, вы, конечно, можете попытаться получить доступ к файлу. Если это сокет, вы можете шпионить за ним, используяlibpcapили что-то, производное от него.
Ситуация в основном такова: дескриптор файла (снова) является частью памяти процесса. Дескриптор имеет базовый буфер, который существует в пространстве ядра; когда процесс читает или пишет в/из дескриптора, он записывает в и из этого буфера. Для исходящих данных ядро соответствующим образом сбрасывает буфер (на оборудование); для входящих данных оно снова заполняет буфер (с оборудования), когда процесс его очищает. Эти буферы, насколько мне известно, недоступны другим процессам, хотя есть некоторые средства (например, libpcap)чтениеданные в той или иной форме определяются конкретным интерфейсом ядра, точно так же, как интерфейс proc может предоставлять некоторые данные из памяти пользовательского пространства процесса.