bpf_probe_read_kernel() always failed in tc ebpf prog - linux-kernel

I write a tc ebpf prog and attach it to some nic's egress, but when I call bpf_probe_read_kernel() to get the process id, it always return 0 and the pid was setted to zero.
__u32 pid = 1;
struct task_struct *curr_task = (struct task_struct *) bpf_get_current_task();
long ret = bpf_probe_read_kernel(&pid, sizeof(__u32), &(curr_task->pid));
bpf_printk("ret = %d, pid = %d", ret, pid);
The code run correctly on ubuntu, but incorrectly on centos, the kernel version is 5.10.25.
expect to get the process id, but it's pid is always set to zero

Related

Why different pids from fork() and getpid()?

My homework asks this:
Using the program below, identify the values of pid at lines A, B, C, and D. (Assume that the actual pids of the parent and child are 10 and 20, respectively.) Explain for each line the reason for the pid value.
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
int main() {
pid_t pid, pid1;
/* fork a child process */
pid = fork();
if (pid < 0) { /* error occurred */
fprintf(stderr, "Fork Failed\n");
return 1;
}
else if (pid == 0) { /* child process */
pid1 = getpid();
printf("child: pid = %d\n",pid); /* A */
printf("child: pid1 = %d\n",pid1); /* B */
}
else { /* parent process */
pid1 = getpid();
printf("parent: pid = %d\n",pid); /* C */
printf("parent: pid1 = %d\n",pid1); /* D */
wait(NULL);
}
return 0;
}
When I run it I get (for example):
parent: pid = 1586
parent: pid1 = 1585
child: pid = 0
child: pid1 = 1586
Why does fork() and getpid() return different pids for what's supposedly the same process?
You should first understand the return values of both function:
fork returns 0 in the child process and a non-zero value in the parent process; this non-zero value is the child process' PID.
getpid returns the PID of the current process; current means whoever is calling the getpid function.
First, in your code, even though the line pid1 = getpid() is the same, the caller is different. In the else if block it was the child process, and in the else block it was the parent. Therefore the two pid1s are different in the output.
Second, in the parent process, pid (fork's return value) is the child process' PID, not itself's. The reason fork returns child process' PID is to allow the parent process to communicate with and control the child.

UDP broadcasting on OSX fails, but works on Linux

The following code does not work on OSX (it works fine on Linux); it (bind) fails with errno=49 Can't assign requested address.
int fd, val;
struct sockaddr_in sa;
fd = socket(AF_INET, SOCK_DGRAM, 0);
if(fd < 0)
return -1;
val = 1;
if(setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)) < 0)
goto exit;
memset(&sa, 0, sizeof(sa));
sa.sin_len = sizeof(sa);
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = htonl(INADDR_BROADCAST);
sa.sin_port = htons(50000);
if(bind(fd, (struct sockaddr *)&sa, sizeof(sa)))
goto exit;
This bit of code does work on OSX if you specify an actual address other than INADDR_BROADCAST (or, at least INADDR_ANY works fine). I found that Darwin has this sin_len field that Linux does not, but setting or leaving it cleared has no effect.
Any idea what could be the trouble? If it were related to MACF I feel as if it would return a security-related error.
There are few example sources for OSX in general, and I did not find any for UDP broadcast.
It seems even socat can't do this properly on OSX. Incidentally it failed in the same way with the same error.
$ echo "TEST" | socat - UDP-DATAGRAM:255.255.255.255:50000,broadcast
2022/06/13 22:39:16 socat[7349] E sendto(5, 0x14100c000, 17, 0, LEN=16 AF=2 255.255.255.255: 50000, 16): Can't assign requested address

Cannot get user name for a pid using rust winapi

I'm trying to get the user that is associated with a PID on windows.
I'm looking at the source for NTop https://github.com/gsass1/NTop as an example.
I can build and debug NTop source on Clion and the following code works correctly.
HANDLE ProcessTokenHandle;
if(OpenProcessToken(Process.Handle, TOKEN_READ, &ProcessTokenHandle)) {
DWORD ReturnLength;
GetTokenInformation(ProcessTokenHandle, TokenUser, 0, 0, &ReturnLength);
if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
PTOKEN_USER TokenUserStruct = xmalloc(ReturnLength);
if(GetTokenInformation(ProcessTokenHandle, TokenUser, TokenUserStruct, ReturnLength, &ReturnLength)) {
SID_NAME_USE NameUse;
DWORD NameLength = UNLEN;
TCHAR DomainName[MAX_PATH];
DWORD DomainLength = MAX_PATH;
LookupAccountSid(0, TokenUserStruct->User.Sid, Process.UserName, &NameLength, DomainName, &DomainLength, &NameUse);
// FIXME: we cut user name here for display purposes because something like %9.9s does not work with MS's vsprintf function?
Process.UserName[9] = 0;
}
free(TokenUserStruct);
}
CloseHandle(ProcessTokenHandle);
}
When trying the same thing using rust winapi I get ERROR_NOACCESS every time no matter what I do.
Here's some example code that returns 0 as response code from OpenProcessToken and GetLastError will be ERROR_NOACCESS. It doesn't matter whether or not I run the program as administrator or not.
let pid: u32 = 8664; // process that is owned by me but can be any process, it will never work
let process_handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, 0, pid);
let mut process_token_handle: PHANDLE = null_mut();
let s = OpenProcessToken(process_handle, TOKEN_READ, process_token_handle);
let last_error = GetLastError();
Anyone have any idea why this code would work in NTop using the C api and not work using rust winapi?

Prevent terminal prompt from printing on exec() call

SO,
There are many similar questions, however none that I have been able to use. My code snippet is as follows:
for(int j=0; j<N; j++) {
pid_t pid = fork();
if (pid == -1) {
exit(-1); //err
} else if (pid == 0) {//kid
stringstream ss;
ss<<j;
execlp("./sub","sub",ss.str().c_str(),NULL);
exit(0);
} else {
/* parent */
}
}
my executing code in sub(.cpp) is:
int main( int argc, char **argv )
{
cout<<argv[i]<<endl;
exit(0);
}
my output is as such:
[terminal prompt '$'] 4
2
3
etc.
Is there a way I could prevent the prompt from displaying on the exec call? and why is it ONLY displaying on the first exec call, and not on every one?
What you see is the normal prompt of your shell, because the parent process terminates very quickly. It is not the output of the exec call. The forked processes print their output after the parent process has terminated.
You can use waitpid() in the parent process to "wait" until all forked process have terminated.

Child process won't suicide if parent dies

I have a subprocess (running on MacOS) that I want to kill itself if the parent quits, exits, terminates, is killed or crashes. Having followed the advice from How to make child process die after parent exits? I can't get it to quietly kill itself if the parent program crashes. It will go to 100% CPU until I manually kill it.
Here are the key points of the code:
int main(int argc, char *argv[])
{
// Catch signals
signal(SIGINT, interruptHandler);
signal(SIGABRT, interruptHandler);
signal(SIGTERM, interruptHandler);
signal(SIGPIPE, interruptHandler);
// Create kqueue event filter
int kqueue_fd = kqueue();
struct kevent kev, recv_kev;
EV_SET(&kev, parent_pid, EVFILT_PROC, EV_ADD|EV_ENABLE, NOTE_EXIT, 0, NULL);
kevent(kqueue_fd, &kev, 1, NULL, 0, NULL);
struct pollfd kqpoll;
kqpoll.fd = kqueue_fd;
kqpoll.events = POLLIN;
// Start a run loop
while(processEvents())
{
if(kill(parent_pid, 0) == -1)
if(errno == ESRCH)
break;
if(poll(&kqpoll, 1, 0) == 1)
if(kevent(kqueue_fd, NULL, 0, &recv_kev, 1, NULL))
break;
parent_pid = getppid();
if(parent_pid == 1)
break;
sleep(a_short_time);
// (simple code here causes subprocess to sleep longer if it hasn't
// received any events recently)
}
}
Answering my own question here:
The reason for this problem was not down to detecting whether the parent process had died. In processEvents() I was polling the pipe from the parent process to see if there was any communication. When the parent died, poll() returned a value of 1 and the read loop thought there was infinite data waiting to be read.
The solution was to detect whether the pipe had been disconnected or not.

Resources