Problem stopping a child loop using sigaction and intercepting Ctrl*C - fork

I'm trying to write a program that intercepts Ctrl^C using sigaction, and then terminates the child of a fork.
Code:
static void usrHandler(int sig, siginfo_t * si, void * ignore) {
printf("Interrupt Worked");
}
int main(int argc, char * argv[]) {
struct sigaction sa;
sa.sa_flags = SA_SIGINFO;
sigemptyset( & sa.sa_mask);
sa.sa_sigaction = usrHandler;
sigaction(SIGINT, & sa, NULL);
int currentFile = 1;
int fd;
int forkChild;
forkChild = fork();
if (forkChild == 0) {
sleep(100);
} else if (forkChild > 0) {
sa.sa_sigaction = SIG_IGN;
sigaction(SIGUSR1, & sa, NULL);
}
}
I tried to remove all non necessary code for my example. For some reason I can not get the interrupt to work when I press Ctrl^C. Eventually I would like to be able to close the child and continue in the parent. Am I doing something wrong here?

For some reason I can not get the interrupt to work when I press Ctrl^C.
Because your data in IO buffer, so change printf("Interrupt Worked"); to printf("Interrupt Worked\n"); (add \n), you will get data.
For IO buffer, see https://stackoverflow.com/a/53083985/7671328

Related

how to alloc user space memory in kernel space?

I hook a syscall(open) on Linux, and want to print this opened filename.
then I call syscall(getcwd) to get the absolute path.
this is source code:
void *memndup_from_user(const void __user *src, long len)
{
void *kbuf = NULL;
if(src == NULL) {
return kbuf;
}
kbuf = kmalloc(len + 1, GFP_KERNEL);
if(kbuf != NULL) {
if (copy_from_user(kbuf, src, len)) {
printk(KERN_ALERT "%s\n", "copy_from_user failed.");
kfree(kbuf);
kbuf = NULL;
}
else {
((char *)kbuf)[len] = '\0';
}
} else {
printk(KERN_ALERT "%s\n", "kmalloc failed.");
}
return kbuf;
}
void *memdup_from_user(const void __user *src)
{
long len = 0;
if(src == NULL) {
return NULL;
}
len = strlen_user(src);
return memndup_from_user(src, len);
}
asmlinkage long fake_getcwd(char __user *buf, unsigned long size)
{
return real_getcwd(buf, size);
}
asmlinkage long
fake_open(const char __user *filename, int flags, umode_t mode)
{
if(flags & O_CREAT) {
char *k_filename = (char *)memdup_from_user(filename);
char *u_path = (char *)kmalloc(PAGE_SIZE, GFP_USER);
if(k_filename != NULL) {
printk(KERN_ALERT "ano_fake_open pid:%ld create : %s\n", ano_fake_getpid(), k_filename);
kfree(k_filename);
}
if(u_path != NULL) {
long retv;
retv = fake_getcwd(u_path, PAGE_SIZE);
if(retv > 0) {
printk(KERN_ALERT "getcwd ret val: %ld, path: %s\n", retv, u_path);
} else {
printk(KERN_ALERT "getcwd ret val: %ld, error...\n", retv);
}
kfree(u_path);
}
}
return real_open(filename, flags, mode);
}
the sys_getcwd requires an user space memory, and I call kmalloc with GFP_USER.
but sys_getcwd always return -EFAULT(Bad Address)...
this is dmesg logs:
[344897.726061] fake_open pid:70393 create : sssssssssssssssss
[344897.726065] getcwd ret val: -14, error...
[344897.727431] fake_open pid:695 create : /var/lib/rsyslog/imjournal.state.tmp
[344897.727440] getcwd ret val: -14, error...
so I find the implement in sys_getcwd, he does
# define __user __attribute__((noderef, address_space(1)))
# define __kernel __attribute__((address_space(0)))
#define __getname() kmem_cache_alloc(names_cachep, GFP_KERNEL)
SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
{
char *page = __getname();
get_fs_root_and_pwd_rcu(current->fs, &root, &pwd);
...
// char *cwd = page + xxx; (xxx < PAGE_SIZE)
// len = PAGE_SIZE + page - cwd;
...
if (len <= size) {
error = len;
if (copy_to_user(buf, cwd, len))
error = -EFAULT;
}
}
obviously, getcwd alloc memory with flag GFP_KERNEL, then copy to my buffer( __user *buf ) from (GFP_KERNEL) !!!
isn't __user MACRO be GFP_USER ?
the flag GFP_USER brief is https://elixir.bootlin.com/linux/v4.4/source/include/linux/gfp.h#L208:
/* GFP_USER is for userspace allocations that also need to be directly
* accessibly by the kernel or hardware. It is typically used by hardware
* for buffers that are mapped to userspace (e.g. graphics) that hardware
* still must DMA to. cpuset limits are enforced for these allocations.
*/
what's wrong ?
This is wrong on at least two accounts:
syscall hijacking (let alone for something like open) is just a bad idea. the only sensible method to catch all possible open path is through using LSM hooks. it also happens to deal with the actual file being opened avoiding the race: you read the path in your routine, wrapped opens reads it again. but by that time malicious userspace could have changed it and you ended up looking at the wrong file.
it should be clear getcwd has to have a method of resolving a name in order to put it into the userspace buffer. you should dig in into the call and see what can be changed to put it in a kernel buffer.
Why are you doing this to begin with?

freedesktop XEmbed systray client code in C, Xlib

I've been trying to implement a systray icon using straight C and Xlib, going along with the freedesktop specification [0]. I can't seem to get my Window to embed into my desktop manager's systray[1], while other apps seem to be able to do it. I am not sure how to go forward debugging this, but I've provided minimal sample code below.
I haven't been able to find any sample code using straight Xlib and C, and all the suggestions I've seen have been with regard to some framework like Gtk/Qt/Mono/whatever, but I want to understand what is supposed to be happening here as per the spec, and what I'm doing wrong.
#include <X11/Xutil.h>
#include <string.h>
#define MIN(A, B) ((A) < (B) ? (A) : (B))
/* --------- XEMBED and systray stuff */
#define SYSTEM_TRAY_REQUEST_DOCK 0
#define SYSTEM_TRAY_BEGIN_MESSAGE 1
#define SYSTEM_TRAY_CANCEL_MESSAGE 2
static int trapped_error_code = 0;
static int (*old_error_handler) (Display *, XErrorEvent *);
static int
error_handler(Display *display, XErrorEvent *error) {
trapped_error_code = error->error_code;
return 0;
}
void
trap_errors(void) {
trapped_error_code = 0;
old_error_handler = XSetErrorHandler(error_handler);
}
int
untrap_errors(void) {
XSetErrorHandler(old_error_handler);
return trapped_error_code;
}
void
send_systray_message(Display* dpy, Window w, long message, long data1, long data2, long data3) {
XEvent ev;
memset(&ev, 0, sizeof(ev));
ev.xclient.type = ClientMessage;
ev.xclient.window = w;
ev.xclient.message_type = XInternAtom (dpy, "_NET_SYSTEM_TRAY_OPCODE", False );
ev.xclient.format = 32;
ev.xclient.data.l[0] = CurrentTime;
ev.xclient.data.l[1] = message;
ev.xclient.data.l[2] = data1;
ev.xclient.data.l[3] = data2;
ev.xclient.data.l[4] = data3;
trap_errors();
XSendEvent(dpy, w, False, NoEventMask, &ev);
XSync(dpy, False);
if (untrap_errors()) {
/* Handle errors */
}
}
/* ------------ Regular X stuff */
int
main(int argc, char **argv) {
int width, height;
XWindowAttributes wa;
XEvent ev;
Display *dpy;
int screen;
Window root, win;
/* init */
if (!(dpy=XOpenDisplay(NULL)))
return 1;
screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen);
if(!XGetWindowAttributes(dpy, root, &wa))
return 1;
width = height = MIN(wa.width, wa.height);
/* create window */
win = XCreateSimpleWindow(dpy, root, 0, 0, width, height, 0, 0, 0xFFFF9900);
send_systray_message(dpy, win, SYSTEM_TRAY_REQUEST_DOCK, win, 0, 0);
XMapWindow(dpy, win);
XSync(dpy, False);
/* run */
while(1) {
while(XPending(dpy)) {
XNextEvent(dpy, &ev); /* just waiting until we error because window closed */
}
}
}
Any help would be greatly appreciated. I think this problem is language-agnostic, and more to do with me misunderstanding the protocols, so answers in any language are acceptable, as long as they help me iron out this XEvent stuff.
[0] https://specifications.freedesktop.org/systemtray-spec/systemtray-spec-0.2.html
[1] I'm using dwm with the systray patch http://dwm.suckless.org/patches/systray
You are sending the message to a wrong window. The documentation isn't really helpful, it makes no sense whatsoever to send a tray embed message to your own window!. You need to send it to the tray window.
Here's a a fixed send_systray_message
void
send_systray_message(Display* dpy, long message, long data1, long data2, long data3) {
XEvent ev;
Atom selection_atom = XInternAtom (dpy,"_NET_SYSTEM_TRAY_S0",False);
Window tray = XGetSelectionOwner (dpy,selection_atom);
if ( tray != None)
XSelectInput (dpy,tray,StructureNotifyMask);
memset(&ev, 0, sizeof(ev));
ev.xclient.type = ClientMessage;
ev.xclient.window = tray;
ev.xclient.message_type = XInternAtom (dpy, "_NET_SYSTEM_TRAY_OPCODE", False );
ev.xclient.format = 32;
ev.xclient.data.l[0] = CurrentTime;
ev.xclient.data.l[1] = message;
ev.xclient.data.l[2] = data1; // <--- your window is only here
ev.xclient.data.l[3] = data2;
ev.xclient.data.l[4] = data3;
trap_errors();
XSendEvent(dpy, tray, False, NoEventMask, &ev);
XSync(dpy, False);
usleep(10000);
if (untrap_errors()) {
/* Handle errors */
}
}
and a call to it
send_systray_message(dpy, SYSTEM_TRAY_REQUEST_DOCK, win, 0, 0); // pass win only once
Credits: http://distro.ibiblio.org/vectorlinux/Uelsk8s/GAMBAS/gambas-svn/gambas2/gb.gtk/src/gtrayicon.cpp

Browse LDAP servers in the domain

I am following this guide.
I used the following code to display LDAP servers in the domain:
#include <dns_sd.h>
#include <stdio.h>
#include <pthread.h>
void ResolveCallBack(DNSServiceRef sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
DNSServiceErrorType errorCode,
const char *fullname,
const char *hosttarget,
uint16_t port, /* In network byte order */
uint16_t txtLen,
const unsigned char *txtRecord,
void *context) {
}
void BrowserCallBack(DNSServiceRef inServiceRef,
DNSServiceFlags inFlags,
uint32_t inIFI,
DNSServiceErrorType inError,
const char* inName,
const char* inType,
const char* inDomain,
void* inContext) {
DNSServiceErrorType err = DNSServiceResolve(&inServiceRef,
0, // Indicate it's a shared connection.
inIFI,
inName,
inType,
inDomain,
ResolveCallBack,
NULL);
printf("DNSServiceResolve err = %x, name = %s, type=%s, domain=%s\n",
err, inName, inType, inDomain);
}
int main() {
DNSServiceRef ServiceRef;
DNSServiceErrorType err = DNSServiceBrowse(&ServiceRef, // Receives reference to Bonjour browser object.
kDNSServiceFlagsDefault, // Indicate it's a shared connection.
kDNSServiceInterfaceIndexAny, // Browse on all network interfaces.
"_ldap._tcp", // Browse for service types.
NULL, // Browse on the default domain (e.g. local.).
BrowserCallBack, // Callback function when Bonjour events occur.
NULL); // Callback context.
printf("err = 0x%x\n", err);
int sockfd = DNSServiceRefSockFD(ServiceRef);
printf("sockfd = %d\n", sockfd);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
struct timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
fd_set descriptors;
FD_ZERO(&descriptors);
FD_SET(sockfd, &descriptors);
int r = select(sockfd + 1, &descriptors, NULL, NULL, &timeout);
printf("r = %d\n", r);
fflush(stdout);
if (r > 0) {
if (FD_ISSET(sockfd, &descriptors)) {
// This function will call the appropiate callback to process the
// event, in this case the BrowseReply static method.
err = DNSServiceProcessResult(ServiceRef);
if (err != kDNSServiceErr_NoError) {
printf("Error on process an event in event loop, e = 0x%x\n", err);
}
}
} else if (r == -1) {
printf("The select() call failed");
}
return 0;
}
However, this didn't give me any LDAP server.
Any Help on this?
Thanks in advance
N.B:
This command returns results:
$nslookup -type=any _ldap._tcp
So there is LDAP servers in the domain.
When I tried "_http._tcp" as the registration type this returns
results.
Operating system is Mac OS X 10.9.

interacting user space during system call

I'm trying to write block device driver that implements read/write operations.
The tricky thing is that the information is not in the hardware, but in a user space process. Therefore, during the read/write system call I would like to interact the user space (i.e. sendign signal to the user space).
However, my user space process catching the signal only after the read/write system call returned. adding wait in the system call implementation seems to be ignored somehow.
I used this code at the read system call:
ssize_t sleepy_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
struct siginfo info;
struct task_struct *t;
int ret;
#define SIG_TEST 44
memset(&info, 0, sizeof(struct siginfo));
info.si_signo = SIG_TEST;
info.si_code = SI_QUEUE;
info.si_int = 1234;
rcu_read_lock();
t = pid_task(find_pid_ns(current->pid, &init_pid_ns), PIDTYPE_PID);
if(t == NULL){
printk(KERN_ERR "no such pid\n");
rcu_read_unlock();
return -ENODEV;
}
rcu_read_unlock();
ret = send_sig_info(SIG_TEST, &info, t); //send the signal
if (ret < 0) {
printk("error sending signal\n");
return ret;
}
wait_event_interruptible(wq, flag != 0);
msleep(10000);
return (0);
}
and this code at user space:
#define SIG_TEST 44
int g_devFile = -1;
void receiveData(int n, siginfo_t *info, void *unused)
{
printf("received value %i\n", info->si_int);
}
int main(void)
{
struct sigaction sig;
sig.sa_sigaction = receiveData;
sig.sa_flags = SA_SIGINFO;
sigaction(SIG_TEST, &sig, NULL);
g_devFile = open(devname, O_RDWR);
if ( g_devFile < 0 ) {
fprintf(stderr,"Error opening device[%s] file err[%s]\n",devname,strerror(errno));
return -1;
} else {
fprintf (stderr, "device opened. ptr=%p\n", (void*)g_devFile);
}
i = read(g_devFile, &buff, 11);
}
Currently I'm catching my signal (in user space) only after the 10 seconds sleep expieres (the wait seems to be ignored).
Any idea will be appriceated. Thanks.

How to fix service control buttons are disabled for custom service

I have a service that I start & it works fine (I verify it's running by looking at the EventLog messages it posts). For some reason though, services.msc shows the stop button greyed out & I can't figure out why.
static SERVICE_STATUS_HANDLE gServiceStatusHandle = NULL;
static DWORD WINAPI DaemonServiceHandler(DWORD control, DWORD eventType, LPVOID eventData, LPVOID context)
{
HANDLE stopEvent = reinterpret_cast<HANDLE>(context);
switch (control) {
case SERVICE_CONTROL_STOP:
ReportServiceStatus(SERVICE_STOP_PENDING, 100, 3000);
// notify main loop to stop
return NO_ERROR;
case SERVICE_CONTROL_INTERROGATE:
return NO_ERROR;
}
return ERROR_CALL_NOT_IMPLEMENTED;
}
void WINAPI DaemonMain(DWORD argc, LPWSTR *argv)
{
gServiceStatusHandle = RegisterServiceCtrlHandlerEx(WIN_UTF16(gServiceName), DaemonServiceHandler, NULL);
if (gServiceStatusHandle == NULL) {
ReportService(SERVICE_STOPPED);
return;
}
ReportService(SERVICE_RUNNING);
// do main loop
ReportService(SERVICE_STOPPED);
}
int tmain(int argc, tchar **argv)
{
const SERVICE_TABLE_ENTRYW DispatchTable[] =
{
{(L"MyService", DaemonMain},
{NULL, NULL}
};
if (!StartServiceCtrlDispatcherW(DispatchTable)) {
return 1;
}
return 0;
}
Bug in my ReportServiceStatus call.
I was setting dwControlsAccepted of the SERVICE_STATUS_HANDLE to 0 always instead of enabling SERVICE_ACCEPT_STOP when the current state to report wasn't SERVICE_START_PENDING.

Resources