Sunny
Sunny

Reputation: 10075

Is there a system call to run systemctl in C program (not the system() function)?

I am on a Ubuntu 22.04 server. I want to run:

systemctl restart someService

but want to do so in a C program.

Intuitively I tried:

system("systemctl restart someService")

This did not work even if my program itself has setUid set to root as systemctl does not itself have setUid bit set to root.

I would like to write a program and set its uid to root so that anyone can execute it to restart a certain system service. This is only possible by using some direct function and not the system call as done above. Any suggestions?

Upvotes: 0

Views: 1630

Answers (1)

Ajay Brahmakshatriya
Ajay Brahmakshatriya

Reputation: 9203

I don't think there is a system-call that can do the job of systemctl in general. I think your approach of calling the systemctl command from your program is correct. But, I am not getting into the security considerations here. You should be really careful when writing set-uid programs.

Now, the main issue with your code is that system should not be used from set-uid binaries because it doesn't let you control the environment variables, which can be set maliciously before calling your program to change the behavior of the called process. Besides that, the system command calls /bin/sh to run your command which on some versions of Linux drop privilege as mentioned on the man-page linked above. The right approach would be to use execve family of functions that offer more control and do not spawn a shell. What you need to do can be done in the following way -

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);
}

Notice the empty (or pure) environment above. It is worth noting that the execve should not return unless there is an error. If you need to wait for the return value from the systemctl command, you might have to combine this with fork

Upvotes: 3

Related Questions