Running an external binary from the Linux Kernel - c

In our development team we are modifying a driver for our own needs. We need it to execute an external binary (user space application) in the linux filesystem.
Is it correct to do this? What would be the best way to call a binary from inside the linux kernel? system(), popen()?
Thanks for your answer.

Well, I found a very well explained solution to my question.
char *argv[] = { "/usr/bin/logger", "help!", NULL };
static char *envp[] = {
"HOME=/",
"TERM=linux",
"PATH=/sbin:/bin:/usr/sbin:/usr/bin", NULL };
return call_usermodehelper( argv[0], argv, envp, UMH_WAIT_PROC );
I need to use the call_usermodehelper system calls. The example is self-explanatory.
Source: http://www.ibm.com/developerworks/linux/library/l-user-space-apps/index.html

Related

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?
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

Username as a Unicode/wchar_t string in systemd service?

Consider this typical for Linux function (it returns the current process username):
char* currentUserName(void) {
struct passwd *p = getpwuid(getuid());
return (p? p->pw_name : NULL);
}
How to get it in Unicode (let's say wchar_t)? To be honest, I don't know what is the encoding of pw_name even (system? Which one - File System? Always UTF-8?).
Is there a way to get the username as wchar_t string? Maybe some function similar to Windows's GetUserNameW() (where W is for wide-chars) - to do it without to link with iconv library...
Maybe I can use mbstowcs() but which locale will be used? I plan to call this function from systemd service, so I have not idea what LC_CTYPE/LANG is there...

Running cat /proc/cpuinfo in glib

I've been trying to look for questions on how to use g_spawn_sync() and they said that it is good to use when you want to execute a command in the terminal besides using pipes.
The only thing I can't figure out now is why the command cat /proc/cpuinfo doesn't work. error->message returns (No such file or directory)but if I use commands like ls or cat alone, it works. I also tried running cd /proc && cat cpuinfo but it gives me the same error.
I'm not an expert of glib but I read in the manual that I can use G_SPAWN_SEARCH_PATH so that it will check my PATH for the commands I can use without including the absolute path for the command.
I have the following code:
gchar *argv[] = { "cat /proc/cpuinfo", NULL };
char *output = NULL; // will contain command output
GError *error = NULL;
int exit_status = 0;
if (!g_spawn_sync(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL,
&output, NULL, &exit_status, &error))
{
printf("[getHardwareInfo] DEBUG: Error on g_spawn_sync %s.\n", error->message);
}
tl;dr: Do not use g_spawn_command_line_sync() unless you really know what you are doing.
Firstly, the actual problem you are hitting: John Szakmeister’s comment was correct: g_spawn_sync() takes an array of arguments, the first one of which is the path to the program to execute (or to look for in $PATH, if you’ve specified G_SPAWN_SEARCH_PATH). By passing the array { "cat /proc/cpuinfo", NULL }, you are saying that you want to run the program cat /proc/cpuinfo with no arguments, not the program cat with the argument /proc/cpuinfo.
However, there are many other problems here, and I think it’s important to mention them before people start cargo-culting this code, because they have security implications:
As LegalProgrammer says, why are you spawning cat when you could just call g_file_get_contents()?
Failing that, use GSubprocess instead of g_spawn_*(). It’s a more modern API, which allows you to monitor the lifecycle of the spawned process more easily, as well as getting streaming I/O in and out of the subprocess.
Do not ignore the warnings in the manual about the security implications of using g_spawn_command_line_sync(). There are several:
It will run the first matching program found in your $PATH, so if an attacker has control of your $PATH, or write access to any directory in that $PATH (such as ~/.local/bin), you will end up running an attacker-controlled program.
It’s a synchronous function, so will block on the subprocess completing, which could take unbounded time. Your program will be unresponsive for that time.
It returns the output in a single allocation, rather than as a stream, so if the subprocess returns many megabytes of output, you may hit allocation failures and abort.
The obvious next step from “g_spawn_command_line_sync() seems to do what I want” is “let’s use g_strdup_printf() to put together a command to run with it”, and then you have shell injection vulnerabilities, where an attacker who controls any of the parameters to that printf() can twist the entire shell command to execute their arbitrary code.
I'm answering my question here. After reading the manual again, I decided to use another function, g_spawn_command_line_sync, which is simpler to use than g_spawn_sync.
A simple version of g_spawn_sync() with little-used parameters removed, taking a command line instead of an argument vector. See g_spawn_sync() for full details. command_line will be parsed by g_shell_parse_argv(). Unlike g_spawn_sync(), the G_SPAWN_SEARCH_PATH flag is enabled. Note that G_SPAWN_SEARCH_PATH can have security implications, so consider using g_spawn_sync() directly if appropriate. Possible errors are those from g_spawn_sync() and those from g_shell_parse_argv().
Here is my new code:
char *output = NULL; // will contain command output
GError *error = NULL;
gint exit_status = 0;
if (!g_spawn_command_line_sync("cat /proc/cpuinfo", &output, NULL, &exit_status, &error))
{
printf("[getHardwareInfo] DEBUG: Error on g_spawn_command_line_sync %s.\n", error->message);

How to make c programe as daemon in ubuntu?

Hi I am new to the linux environment. I am trying to create daemon process.
#include<stdio.h>
int main()
{
int a=10,b=10,c;
c=sum(a,b);
printf("%d",c);
return (0);
}
int sum(int a,int b)
{
return a+b;
}
I want to create daemon process of it. May i know how can do this? Any help would be appreciated. Thank you.
A daemon generally doesn't use its standard input and output streams, so it is unclear how your program could be run as a daemon. And a daemon program usually don't have any terminal, so it cannot use clrscr. Read also the tty demystified page, and also daemon(7).
I recommend reading some good introduction to Linux programming, like the old freely downloadable ALP (or something newer). We can't explain all of it here, and you need to read an entire book. See also intro(2) and syscalls(2).
I also recommend reading more about OSes, e.g. the freely available Operating Systems: Three Easy Pieces textbook.
You could use the daemon(3) function in your C program to run it as a daemon (but then, you are likely to not have any input and output). You may want to log messages using syslog(3).
You might consider job control facilities of your shell. You could run your program in the background (e.g. type myprog myarg & in your interactive shell). You could use the batch command. However neither background processes nor batch jobs are technically daemons.
Perhaps you want to code some ONC-RPC or JSONRPC or Web API server and client. You'll find libraries for that. See also pipe(7), socket(7)
(take several days or several weeks to read much more)
First find what are the properties of daemon process, as of my knowledge a daemon process have these properties:
Should not have any parent (it itself should be parent)
Process itself is a session leader.
Environment change to root.
File mode creating mask should be zero.
No controlling terminal.
All terminal should be removed
Should not be un-mounted .
Implement the code by considering above properties which is
int i=0;
int main()
{
int pid;
pid=fork();
if(pid!=0) {
/** you can add your task here , whatever you want to run in background **/
exit(0);
}
else
{
setsid();//setting sessions
chdir("/");//root.. should'nt beunmounted
umask(0);
close(0);//all terminal are removed
close(1);
close(2);
while(1)
{
printf("i = %d \n",i);
i++;
}
}
return 0;
}
or you can go through man page of daemon()
int daemon(int nochdir, int noclose);
I hope it helps.
Instead of writing the code to make the C program a daemon I would go with an already mature tool like supervisor:
http://supervisord.org/
I think this below will work
screen cmd arg1 arg2
You can also try
nohup cmd arg1

How to find out if the eth0 mode is static or dhcp?

I want to use a C program to get if the ip of the network interface is set manually or via dhcp.
I've tried to use the following code and it has worked in Debian, but it hasn't worked in OpenWrt. I want to know how to write a C program doing this in OpenWrt.
I have tried to use this:
#include <stdio.h>
int main(void)
{
FILE *fp;
char buffer[80];
fp=popen("cat /etc/network/interfaces |grep ^iface\\ br-lan | awk -F ' ' '{print $4}'","r");
fgets(buffer, sizeof(buffer), fp);
printf("%s", buffer);
pclose(fp);
}
This code is working in Debian, but it isn't working normally in OpenWrt, so I want to know how to write a program to get the same result.
for OpenWRT you can get a such information with the following command:
$uci get network.lan.proto
so I take the program you put in your question and I change only the command used to get information:
#include <stdio.h> <br>
int main(void)
{
FILE *fp;
char buffer[80];
fp=popen("uci get network.lan.proto","r");
fgets(buffer, sizeof(buffer), fp);
printf("%s", buffer);
pclose(fp);
}
to see all network interfaces available in your OpenWRT you can use the following command:
$uci show network
You can avoid using calling linux command in your c by using the libuci. The libuci contains C function to execute uci commands without passing via popen ( popen is used to execute external command from shell).
The libuci exist by default in the development environment of OpenWRT, not need to download it, no need to build it and no need to install it on your OpenWRT machine
You can use libuci in this way
#include <uci.h>
void main()
{
char path[]="network.lan.proto";
char buffer[80];
struct uci_ptr ptr;
struct uci_context *c = uci_alloc_context();
if(!c) return;
if ((uci_lookup_ptr(c, &ptr, path, true) != UCI_OK) ||
(ptr.o==NULL || ptr.o->v.string==NULL)) {
uci_free_context(c);
return;
}
if(ptr.flags & UCI_LOOKUP_COMPLETE)
strcpy(buffer, ptr.o->v.string);
uci_free_context(c);
printf("%s\n", buffer);
}
(Not tested)
and when you compile your program you have to add the -luci in the compilation command gcc
There's no required way for an OS to decide how an interface should be configured. The kernel (the Linux part of e.g. GNU/Linux) doesn't decide, it doesn't (and shouldn't) care, it just gets told which network addresses go with which interfaces by whatever configuration system the OS is using. OpenWRT's not GNU, it operates differently.
There is AFAIK no definitive way.
Reading the interfaces file would be a hint only: there is no guarantee that the current seup came from there.
You could look at 'asking' the DBUS interface if there is one.
You could check for a dhclient process running.
You could check other files in /etc that specify network setup on different distros.
I think the most reliable option would be a multi-layered thing: check a whole host of hints to come up with the answer.
Another option: send a DHCP check packet to the dhcp server to verify the address.. if you don't get an answer though it could be that the network is down but was up when the address was allocated.

Resources