Есть ли системный вызов для запуска systemctl в программе C (а не функция system())?

Я на сервере Ubuntu 22.04. Я хочу запустить:

systemctl restart someService

но хотите сделать это в программе C.

Интуитивно я попробовал:

system("systemctl restart someService")

Это не сработало, даже если в самой моей программе для setUid установлено значение root, поскольку в самой systemctl бит setUid не установлен на root.

Я хотел бы написать программу и установить для ее uid значение root, чтобы любой мог выполнить ее для перезапуска определенной системной службы. Это возможно только при использовании некоторой прямой функции, а не системного вызова, как это было сделано выше. Какие-либо предложения?

Попробуйте указать полный путь к systemctl и посмотрите, будет ли это иметь значение.

konsolebox 07.02.2023 04:38

Man-страница system специально рекомендует не вызывать ее из set-uid как корневой двоичный файл.

Ajay Brahmakshatriya 07.02.2023 04:44

@AjayBrahmakshatriya Я все равно не хочу использовать вызов system(), поэтому я согласен с вашим предложением. Я не думал об execve и друзьях, но все же мне понадобится вызов system(). В любом случае я ищу вызов функции (кроме system()), чтобы выполнить ее как собственную функцию.

Sunny 07.02.2023 04:57

@AjayBrahmakshatriya Например, как выполнить systemctl restart sshd из программы на C?

Sunny 07.02.2023 05:04

@konsolebox Я не пытался указать полный путь к systemctl, но я пробовал другие исполняемые файлы (с полным путем), у которых для setuid не было установлено значение root, но для вызывающей программы setUid было установлено значение root. В любом случае, почему установка полного пути имеет значение, если в PATH нет другого systemctl?

Sunny 07.02.2023 05:07

Возможно, PATH сбрасывается. Это просто удаление ненужных возможностей.

konsolebox 07.02.2023 05:55

@konsolebox с помощью system вызывает команду через /bin/sh, которая в некоторых дистрибутивах сбрасывает пользователя.

Ajay Brahmakshatriya 07.02.2023 05:58

Похоже, вы решаете не ту задачу. Если вы заставите свою программу создать фиктивный файл, скажем, /tmp/dummy, будет ли он принадлежать пользователю root?

n. m. 07.02.2023 06:04

@AjayBrahmakshatriya Верно. Интуитивно следующее, что нужно сделать, это вызвать двоичный файл напрямую с некоторыми функциями exec. Продолжайте сужать его.

konsolebox 07.02.2023 06:35
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
10
72
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я не думаю, что существует системный вызов, который может выполнять работу systemctl в целом. Я думаю, что ваш подход к вызову команды systemctl из вашей программы правильный. Но я не вдаюсь в соображения безопасности здесь. Вы должны быть очень осторожны при написании программ set-uid.

Теперь основная проблема с вашим кодом заключается в том, что system не следует использовать из двоичных файлов set-uid, потому что это не позволяет вам управлять переменными среды, которые могут быть установлены злонамеренно перед вызовом вашей программы для изменения поведения называется процессом. Кроме того, команда system вызывает /bin/sh для запуска вашей команды, которая в некоторых версиях Linux сбрасывает привилегии, как указано на справочной странице, указанной выше. Правильным подходом будет использование семейства функций execve, которые предлагают больше контроля и не создают оболочку. То, что вам нужно сделать, можно сделать следующим образом -

int main(int argc, char* argv[]) {
    setuid(0);
    setgid(0);
    char *newargv[] = {"/usr/bin/systemctl", "restart", "someService", NULL};
    char *newenviron[] = { NULL };
    execve(newargv[0], newargv, newenviron);
    perror("execve");   /* execve() returns only on error */
    exit(EXIT_FAILURE);
}

Обратите внимание на пустую (или чистую) среду выше. Стоит отметить, что execve не должен возвращаться, если нет ошибки. Если вам нужно дождаться возвращаемого значения от команды systemctl, возможно, вам придется объединить это с fork

Работало отлично, но я установил uid для исполняемого файла после смены владельца на root, а не с помощью setuid(), setgid().

Sunny 07.02.2023 10:24

@Sunny есть разница между эффективным идентификатором пользователя (идентификатор, установленный при использовании setuid) и идентификатором пользователя, под которым работает программа. Вы можете вызывать setuid(0) только в том случае, если у вас есть соответствующие привилегии, одна из которых — установить эффективный uid равным 0.

Ajay Brahmakshatriya 07.02.2023 18:29

Но для выполнения setuid(0) вам также нужно, чтобы uid запущенной программы был от root. Поэтому мне не хватает преимущества использования setuid()

Sunny 09.02.2023 04:59

@Sunny не совсем, вы можете setuid(0) если только ваш эффективный uid равен 0 (который отличается от uid и устанавливается, когда ваш двоичный файл имеет флаг +s)

Ajay Brahmakshatriya 09.02.2023 19:18

Мой предыдущий комментарий должен был быть таким: «Но для выполнения setuid(0) вам понадобится эффективный uid программы…» Мой аргумент по-прежнему таков: если эффективный uid установлен на 0, зачем нужно использовать setuid(0) снова в программе?"

Sunny 10.02.2023 08:08

@Санни, верно! Намерение состояло в том, чтобы также «настоящий» UID и «настоящий» GID равным 0 (который в противном случае был бы установлен на ваш идентификатор пользователя). В основном это не имеет значения, за исключением доступа к файлам. Я не уверен, что systemctl обращается к файлам, но это обычная практика, когда вы хотите, чтобы программа работала точно так же, как root. Подробнее о setuid

Ajay Brahmakshatriya 11.02.2023 00:04

Другие вопросы по теме