Я работаю над небольшим кластером Raspberry PI, моя хост-программа создает фрагменты IP-пакетов и отправляет их нескольким программам-ретрансляторам. Ретрансляторы получают эти фрагменты пакетов и пересылают их к месту назначения, используя необработанные сокеты. Из-за необработанных сокетов мои программы-ретрансляторы должны запускаться с разрешением sudo. Моя установка включает RPi 3 B v2 и RPi 2 B v1. SSH уже настроен, узлы могут подключаться по SSH без пароля, хотя я должен запустить ssh-agent и ssh-add свои ключи на каждом узле. Мне удалось запустить программу, отправляющую ранг с одного узла на другой (2 разных RPis). Я запускаю программы MPI в формате MPMD, поскольку у меня есть только 2 RP, я запускаю хост и ретрансляцию на узле №1 и ретрансляцию на узле №2. Хост-программа принимает путь к файлу для отправки в качестве аргумента командной строки.
Если я бегу:
mpirun --oversubscribe -n 1 --host localhost /home/pi/Desktop/host /some.jpeg : -n 2 --host localhost,rpi2 /home/pi/Desktop/relay
он работает, но, очевидно, программа дает сбой, потому что реле не могут открывать сырые сокеты без разрешения sudo.
Если я бегу:
mpirun --oversubscribe -n 1 --host localhost /home/pi/Desktop/host /some.jpeg : -n 2 --host localhost,rpi2 sudo /home/pi/Desktop/relay
ретрансляторы сообщают о размере мира: 1, и хост-программа зависает.
Если я бегу:
mpirun --oversubscribe -n 1 --host localhost sudo /home/pi/Desktop/host /some.jpeg : -n 2 --host localhost,rpi2 sudo /home/pi/Desktop/relay
все ретрансляторы и хост-отчеты мирового размера 1.
Я нашел аналогичную проблему здесь: OpenMPI/mpirun или mpiexec с разрешением sudo
После короткого ответа я бегу:
mpirun --oversubscribe -n 1 --host localhost /home/pi/Desktop/host /some.jpeg : -n 2 --host localhost,rpi2 sudo -E /home/pi/Desktop/relay
что приводит к:
[raspberrypi:00979] OPAL ERROR: Unreachable in file ext2x_client.c at line 109
[raspberrypi:00980] OPAL ERROR: Unreachable in file ext2x_client.c at line 109
*** An error occurred in MPI_Init
*** An error occurred in MPI_Init
*** on a NULL communicator
*** MPI_ERRORS_ARE_FATAL (processes in this communicator will now abort,
*** and potentially your MPI job)
[raspberrypi:00979] Local abort before MPI_INIT completed completed successfully, but am not able to aggregate error messages, and not able to guarantee that all other processes were killed!
*** on a NULL communicator
*** MPI_ERRORS_ARE_FATAL (processes in this communicator will now abort,
*** and potentially your MPI job)
[raspberrypi:00980] Local abort before MPI_INIT completed completed successfully, but am not able to aggregate error messages, and not able to guarantee that all other processes were killed!
--------------------------------------------------------------------------
Primary job terminated normally, but 1 process returned
a non-zero exit code. Per user-direction, the job has been aborted.
--------------------------------------------------------------------------
--------------------------------------------------------------------------
mpirun detected that one or more processes exited with non-zero status, thus causing
the job to be terminated. The first process to do so was:
Process name: [[32582,1],1]
Exit code: 1
--------------------------------------------------------------------------
Я запустил sudo visudo, и мой файл на обоих узлах выглядит так:
# User privilege specification
root ALL=(ALL:ALL) ALL
pi ALL = NOPASSWD:SETENV: /etc/alternatives/mpirun
pi ALL=NOPASSWD:SETENV: /usr/bin/orterun
pi ALL=NOPASSWD:SETENV: /usr/bin/mpirun
Когда я запускаю все на одном узле, он просто работает:
sudo mpirun --alow-run-as-root --oversubscribe -n 1 --host localhost /home/pi/Desktop/host /some.jpeg : -n 2 --host localhost,localhost /home/pi/Desktop/relay
//хозяин
int main(int argc, char *argv[]) {
MPI_Init(&argc, &argv);
int world_size = []() {
int size;
MPI_Comm_size(MPI_COMM_WORLD, &size);
return size;
}();
int id = []() {
int id;
MPI_Comm_rank(MPI_COMM_WORLD, &id);
return id;
}();
if (argc != 2) {
std::cerr << "Filepath not passed\n";
MPI_Finalize();
return 0;
}
const std::filesystem::path filepath(argv[1]);
if (not std::filesystem::exists(filepath)) {
std::cerr << "File doesn't exist\n";
MPI_Finalize();
return 0;
}
std::cout << "World size: " << world_size << '\n';
MPI_Finalize();
return 0;
}
//relay
int main(int argc, char *argv[]) {
MPI_Init(&argc, &argv);
int world_size = []() {
int size;
MPI_Comm_size(MPI_COMM_WORLD, &size);
return size;
}();
int id = []() {
int id;
MPI_Comm_rank(MPI_COMM_WORLD, &id);
return id;
}();
std::cout << "World size: " << world_size << '\n';
MPI_Finalize();
return 0;
}
Как настроить узлы, чтобы они могли запускать программы MPI с помощью sudo?
Если запустить sudo mpirun --alow-run-as-root все зависает. Я пытался установить suids релейных программ, sudo -i, chmod u+s relay_program и запустить их на одном узле, но он все равно не открывается. Я не могу разобраться с настройкой беспарольного доступа ssh к root. Что вы имеете в виду под помощником?
Запускайте все из своей учетной записи пользователя, и до MPI_Init() вы можете fork&exec sudo helper. Целью помощника является создание необработанных сокетов, а затем передача их в программу MPI через передачу fd. Другой вариант — сделать ваше приложение MPI setuid а также владельцем root, создать необработанные сокеты и setuid для пользователя перед MPI_Init(), а затем запустить mpi из вашей учетной записи пользователя.
Я сделал небольшую программу, которая создает необработанный сокет, а затем инициализирует MPI pastebin.com/RRTX9kzr. Затем sudo -i и скомпилировал программу с помощью mpic++, изменил suid на chmod u+s a.out, что сделало ее корневой и с разрешением sudo при выполнении -rwsr-xr-x 1 root root 36316 lip 9 23:28 a.out. Когда я просто запускаю ее как обычную программу ./a.out, она работает, но потом, когда я запускаю ее с помощью mpirun -n 1 /home/pi/Desktop/a.out, она вылетает с ошибкой pastebin.com/x2Q8iGvH. Если я запускаю его с --allow-run-as-root, он зависает, где я что-то пропустил?
Хорошо, я пропустил момент, когда uid возвращался пользователю, в основном я скомпилировал программу с помощью mpic++, sudo -i, затем сменил владельца на root с помощью chown 0:0 a.out и установил suid на root с помощью chmod u+s a.out. Повторил это на обоих узлах и запустил программу MPI от имени пользователя с mpirun -n 2 --host localhost, rpi1 /home/pi/Desktop/a.out и все работает. В коде я изменил uid непосредственно перед MPI_Init, используя setreuid(geteuid(), getuid());. Это хорошее решение, и я рад, что могу дальше разрабатывать и тестировать свое приложение! Хотя мне придется решить проблему должным образом, прежде чем он будет готов к коммерческому использованию.
обратите внимание, что вы можете использовать возможности вместо бита setuid (ping раньше был suid root, но теперь использует возможности, которые более безопасны: $ getcap /usr/bin/ping /usr/bin/ping = cap_net_admin,cap_net_raw+p
Я проверил решение с помощью возможностей, в основном я устанавливаю возможности с помощью setcap program cap_net_raw,cap_net_admin+eip. Все работает просто отлично, и мне не нужно устанавливать suid для пользователя перед MPI_Init. Я думаю, что это действительно элегантное решение, спасибо.





Самый простой способ решить проблему - установить возможности файла, это все еще создает проблему безопасности, но это не так серьезно, как установка suid программы для root. Чтобы установить возможности программы, позволяющие открывать необработанный сокет: setcap program cap_net_raw,cap_net_admin+eip.
что, если вы
sudo mpirun --alow-run-as-rootс несколькими хостами? обратите внимание, что вы должны иметь возможность использовать ssh без пароля от имени пользователя root (например,sudo ssh remotehost hostnameдолжен работать). вы также можете подумать о том, чтобы установить битsuidв свой двоичный файл и запустить его безsudo(помните о последствиях для безопасности) или даже использовать помощника, который создает необработанные сокеты для вас.