#c #file-read #linux-namespaces
#c #файл-прочитан #linux-пространства имен
Вопрос:
Мне нужно присоединить процесс к новому пространству имен, поэтому я извлекаю fd пространства имен процесса, чтобы он мог вызывать setns для этих fd.
Но проблема в том, что все возвращаемые fd являются -1s.
Я сделал это:
cout<<mnt<<"n"; // prints /proc/4563/ns/mnt
int mnt_fd = open(mnt, O_RDONLY | O_CLOEXEC);
cout<<mnt_fd<<" n"; // prints -1
cout<<net<<"n"; // prints /proc/4563/ns/net
int net_fd = open(net, O_RDONLY | O_CLOEXEC);
cout<<net_fd<<" n"; //prints -1
cout<<pid<<"n"; // prints /proc/4563/ns/pid
int pid_fd = open(pid, O_RDONLY | O_CLOEXEC);
cout<<pid_fd<<" n"; // prints -1
pid
, mnt
, net
являются объявленными путями.
Как я могу это решить?
EDIT1: при печати stderror говорится, что он печатает permission denied
при выполнении sudo chmod 755
во всей файловой системе proc operation not permitted
ПРАВКА2: я допустил ошибку, не скомпилировав и не запустив исполняемый файл с помощью sudo. На этот раз он может открыть fds, и все возвращенные fds положительные. Аналогично вышеописанному, я также открыл другие fd пространства имен, такие как usr_fd, чтобы присоединиться к пользовательскому пространству имен, ipc_fd для присоединения к пространству имен ipc и uts_fd для присоединения к пространству имен uts целевого процесса, но при выполнении setns
on userfd
выдается ошибка Invalid argument
. Ниже приведен код, который я написал для объединения пространств имен.
pid_t cpid = fork();
if(cpid == 0){
if (setns(pid_fd, 0) == -1) /* Join pid namespace */
cout<<"joining pid "<<strerror(errno);
if (setns(uts_fd, 0) == -1) /* Join uts namespace */
cout<<"joining uts "<<strerror(errno);
if (setns(ipc_fd, 0) == -1) /* Join pic namespace */
cout<<"joining ipc "<<strerror(errno);
if (setns(usr_fd, 0) == -1) /* Join usr namespace */
cout<<"joining usr "<<strerror(errno);
if (setns(net_fd, 0) == -1) /* Join net namespace */
cout<<"joining net "<<strerror(errno);
if (setns(mnt_fd, 0) == -1) /* Join mnt namespace */
cout<<"joining mnt "<<strerror(errno);
char *argv[] = { "sudo ./mycode",NULL };
execve(argv[0], argv, NULL);
}
Я хотел, чтобы дочерний процесс выполнил программу getcode в этом пространстве имен, но он этого не делает? Если это неправильный способ сделать это, то как дочерний элемент может запустить программу в этом пространстве имен?
mycode.cpp
int main() {
printf("I am child process %d of parent %dn", getpid(), getppid());
while (true) {
}
return 0;
}
ПРАВКА3: однако замена строки ниже:
char *argv[] = { "sudo ./mycode",NULL };
execve(argv[0], argv, NULL);
с помощью этого
char *argv[] = {"ps", NULL};
execvp(argv[0], amp;argv[0]);
работает.
Комментарии:
1. У вас есть необходимые разрешения для открытия путей? Что произойдет, если вы сделаете это
ls /proc/4563/ns/mnt
в командной строке?2. что говорит errno?
3. @G.M. Написано, что в разрешении отказано
4. @user253751 да, ошибка также указывает, что в разрешении отказано, что я могу теперь сделать?
5. изменение разрешения также не помогает. при выполнении sudo chmod 755 во всей файловой системе proc сообщается, что операция не разрешена
Ответ №1:
Короче говоря, вам нужна CAP_SYS_PTRACE
возможность доступа к ссылкам на пространства имен (и нескольким другим вещам) внутри файловой системы /proc
процесса, включая связанные с пространством имен подразделы, поступающие из файловой системы пространства имен nsfs внутри procfs. ………. Здесь CAP_DAC_READ_SEARCH
и CAP_DAC_OVERRIDE
являются только частью игры. В зависимости от вашего конкретного развертывания они могут потребоваться при запуске не как UID0 с ограниченными возможностями.
Запуск от имени root обычно предоставляет вам все возможности, включая CAP_SYS_PTRACE
. Процессу, отличному от UID0, можно предоставить доступ, предоставив ему ограниченные, разрешенные и не в последнюю очередь эффективные CAP_SYS_PTRACE
возможности.
Один из способов сделать это — установить возможности файла («POSIX») с помощью setcap
CLI tool. Как обычно, с большой мощностью приходит большая ответственность, поэтому убедитесь, что ваш двоичный файл должным образом укреплен, чтобы его нельзя было использовать в качестве трамплина для получения запрещенного доступа к системе.