Why doesn't this keyboard intercepting kernel extension work? - c++

my fellow developers! I hope very much that at least some of you will not get frightened by the amount of text this question contains (I simply did my best to be as descriptive as humanely possible). :)
To those who think I've asked this question to write malware or something. I want to write an application that will allow users to select applications to be launched after the OS will finish launching. The whole idea is to allow user to select these apps BEFORE the OS finished launching by pressing hotkeys previously binded to the apps. For example user turns on his Mac, types SMTV and goes away, when the system finishes launching my app recovers the input and launches Safari, Mail, Tweetie and Vuze. I'm new to SO but I do my best to help others by answering their questions - I think I can expect the same in return. Check my profile and my activity and after that start screaming about malware.
This question is a follow-up to the question Is it possible to recover keyboard input that was done while Mac OS was starting up?.
Guided by Pekka's advice, I've stumbled upon an article Intercepting Keyboard Events by Christian Starkjohann that describes how he and the Objective Development team succeeded in reassigning iBook's CDROM eject key from F12 to Shift+F12. The main part is that they actually intercepted keyboard events, which is what I need. In the end Christian has written this article exactly for developers like me to use the idea of iJect as a prototype for similar functionality.
To start with, I decided to create a simple kernel extension to simply log the user's keyboard input to /var/log/kernel.log. I've started a new Generic Kernel Extension project in XCode, followed the instructions of the Hello Kernel: Creating a Kernel Extension With Xcode tutorial found in Mac Dev Center's Kernel Extension Concepts to create a Hello World project and then stuffed it with code taken from iJect sources. Here are the results:
TestKEXT.c
#include <sys/systm.h>
#include <mach/mach_types.h>
extern int HidHackLoad(void);
extern int HidHackUnload(void);
kern_return_t MacOSSCKEXT_start (kmod_info_t * ki, void * d) {
return HidHackLoad() == 0 ? KERN_SUCCESS : KERN_FAILURE;
}
kern_return_t MacOSSCKEXT_stop (kmod_info_t * ki, void * d) {
return HidHackUnload() == 0 ? KERN_SUCCESS : KERN_FAILURE;
}
HIDHack.h
#ifdef __cplusplus
extern "C" {
#endif
#include <mach/mach_types.h>
#include <sys/systm.h>
extern int HidHackLoad(void);
extern int HidHackUnload(void);
#ifdef __cplusplus
}
#endif
#include <IOKit/system.h>
#include <IOKit/assert.h>
#include <IOKit/hidsystem/IOHIDSystem.h>
class HIDHack : public IOHIDSystem {
public:
virtual void keyboardEvent(unsigned eventType,
/* flags */ unsigned flags,
/* keyCode */ unsigned key,
/* charCode */ unsigned charCode,
/* charSet */ unsigned charSet,
/* originalCharCode */ unsigned origCharCode,
/* originalCharSet */ unsigned origCharSet,
/* keyboardType */ unsigned keyboardType,
/* repeat */ bool repeat,
/* atTime */ AbsoluteTime ts);
virtual void keyboardSpecialEvent(unsigned eventType,
/* flags */ unsigned flags,
/* keyCode */ unsigned key,
/* specialty */ unsigned flavor,
/* guid */ UInt64 guid,
/* repeat */ bool repeat,
/* atTime */ AbsoluteTime ts);
};
HIDHack.cpp
#include "HIDHack.h"
static void *oldVtable = NULL;
static void *myVtable = NULL;
int HidHackLoad(void) {
IOHIDSystem *p;
HIDHack *sub;
if (oldVtable != NULL) {
printf("###0 KEXT is already loaded\n");
return 1;
}
if (myVtable == NULL) {
sub = new HIDHack();
myVtable = *(void **)sub;
sub->free();
}
p = IOHIDSystem::instance();
oldVtable = *(void **)p;
*(void **)p = myVtable;
printf("###1 KEXT has been successfully loaded\n");
return 0;
}
int HidHackUnload(void) {
IOHIDSystem *p;
if (oldVtable != NULL) {
p = IOHIDSystem::instance();
if (*(void **)p != myVtable) {
printf("###2 KEXT is not loaded\n");
return 1;
}
*(void **)p = oldVtable;
oldVtable = NULL;
}
printf("###3 KEXT has been successfully unloaded\n");
return 0;
}
void HIDHack::keyboardEvent(unsigned eventType, unsigned flags, unsigned key, unsigned charCode, unsigned charSet, unsigned origCharCode, unsigned origCharSet, unsigned keyboardType, bool repeat,
AbsoluteTime ts) {
printf("###4 hid event type %d flags 0x%x key %d kbdType %d\n", eventType, flags, key, keyboardType);
IOHIDSystem::keyboardEvent(eventType, flags, key, charCode, charSet, origCharCode, origCharSet, keyboardType, repeat, ts);
}
void HIDHack::keyboardSpecialEvent( unsigned eventType,
/* flags */ unsigned flags,
/* keyCode */ unsigned key,
/* specialty */ unsigned flavor,
/* guid */ UInt64 guid,
/* repeat */ bool repeat,
/* atTime */ AbsoluteTime ts) {
printf("###5 special event type %d flags 0x%x key %d flavor %d\n", eventType, flags, key, flavor);
IOHIDSystem::keyboardSpecialEvent(eventType, flags, key, flavor, guid, repeat, ts);
}
The resulting kernel extension gets successfully loaded/unloaded by kextload/kextunload programs, but doesn't actually intercept any of the keyboard events. I've tried doing lots of things to get it working, but without any errors or other problems with it in the way I can't google anything useful and ask your help.

The problem is not with how you are overriding the existing IOHIDSystem instance. That works just fine.
The problem is that when IOHIKeyboard is opened, it is passed a callback function to the IOHIDSystem for processing events. The callback is a static private function of IOHIDSystem, called _keyboardEvent:
success = ((IOHIKeyboard*)source)->open(this, kIOServiceSeize,0,
(KeyboardEventCallback) _keyboardEvent,
(KeyboardSpecialEventCallback) _keyboardSpecialEvent,
(UpdateEventFlagsCallback) _updateEventFlags);
The callback then calls keyboardEvent function in the IOHIDSystem instance:
self->keyboardEvent(eventType, flags, key, charCode, charSet,
origCharCode, origCharSet, keyboardType, repeat, ts, sender);
It does not call the ten parameter one, which is virtual (and which you are overriding). Instead, what is being called is the 11 parameter non-virtual one. So even if you tried to override the 11 parameter one, it would not work as the call never goes through the vtable.

Related

C++ variable changed during interrupt resets after interrupt

I'm trying to use a flag to see if an event has finished.
Via the debugger, I have seen that the interrupt triggers correctly and does set the value of transmitCompleteI2c to 1. When I return to the if statement which checks whether or not the flag has been set to 1, it has been reset to 0.
The only 2 locations where i alter the value of transmitCompleteI2c are after the if statement and in the interrupt routine.
I'm running the following bits of code. The declaration of transmitCompleteI2c is done in the header file of the class. fireEvent() is a member function of the class I2c.
volatile uint8_t transmitCompleteI2c;
void I2c::foo() {
if (transmitCompleteI2c) {
transmitCompleteI2c = 0;
// trigger event which sets transmitComplete back to 0 when done
fireEvent();
}
}
void I2c::sendHandler(XIic *InstancePtr) {
transmitCompleteI2c = 1;
}
After some extensive digging, it turned out that the address the interrupt routine writes a transmitCompleteI2c to is not the same as the variable in the class. Even after renaming the variable, it is still happening. Below are the header file and source code of my class.
Header file:
#define SLAVE_ADDRESS 0xA0/2
#define SEND_COUNT 16
#define RECEIVE_COUNT 16
#define IIC_INTR_ID XPAR_FABRIC_AXI_IIC_0_IIC2INTC_IRPT_INTR
#define IIC_DEVICE_ID XPAR_AXI_IIC_0_DEVICE_ID
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
class I2c{
private:
void sendHandler(void* InstancePtr, int);
void receiveHandler(XIic* InstancePtr, int);
void statusHandler(XIic* InstancePtr, int);
XIic_Config* configPtr;
const XScuGic& intcInterrupt;
XIic iicDevice;
int status;
uint8_t writeBuffer[SEND_COUNT];
uint8_t readBuffer[RECEIVE_COUNT];
volatile uint8_t transmitCompleteI2c, receiveComplete;
volatile bool test;
public:
I2c() : intcInterrupt{IntcInstance} {};
uint8_t initialize();
int writeData(u16 ByteCount);
int readData(u8 *BufferPtr, u16 ByteCount);
};
Implementation:
Initialization function:
uint8_t I2c::initialize() {
// init driver
configPtr = XIic_LookupConfig(IIC_DEVICE_ID);
XIic_CfgInitialize(&iicDevice, configPtr, configPtr->BaseAddress);
//init interrupt system
XScuGic_SetPriorityTriggerType((XScuGic*) &intcInterrupt, IIC_INTR_ID, 0xA0, 0x3);
status = XScuGic_Connect((XScuGic*) &intcInterrupt, IIC_INTR_ID, (Xil_ExceptionHandler) XIic_InterruptHandler, &iicDevice);
XScuGic_Enable((XScuGic*) &intcInterrupt, IIC_INTR_ID);
Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT, (Xil_ExceptionHandler) XScuGic_InterruptHandler, &IntcInstance);
Xil_ExceptionEnable();
// set transmit flag
transmitCompleteI2c = true;
xil_printf("%08x\n", &transmitCompleteI2c);
// attach interrupts to i2c device
XIic_SetSendHandler(&iicDevice, &iicDevice, (XIic_Handler) (&I2c::sendHandler));
XIic_SetRecvHandler(&iicDevice, &iicDevice, (XIic_Handler) &I2c::receiveHandler);
XIic_SetStatusHandler(&iicDevice, &iicDevice, (XIic_StatusHandler) &I2c::statusHandler);
// set slave address
status = XIic_SetAddress(&iicDevice, XII_ADDR_TO_SEND_TYPE, SLAVE_ADDRESS);
// start device
status = XIic_Start(&iicDevice);
if (status != XST_SUCCESS) {
return XST_FAILURE;
}
return 0;
}
Write data function:
int I2c::writeData(u16 ByteCount) {
xil_printf("%08x\n", &transmitCompleteI2c);
/*
* Set flag
*/
transmitCompleteI2c = false;
/*
* Send the data
*/
status = XIic_MasterSend(&iicDevice, &writeBuffer[0], 6);
if (status != XST_SUCCESS) {
xil_printf("%d\n", status);
return XST_FAILURE;
}
return XST_SUCCESS;
}
Interrupt routine:
void I2c::sendHandler(void *InstancePtr, int byteCount) {
transmitCompleteI2c = true;
xil_printf("%08x\n", &transmitCompleteI2c);
}
"...it should all be in the same class"
but transmitCompleteI2c isn't a static member, so it has to be the same object, not just the same class. Every instance of I2c gets its own copy of each non-static data member.
You can just make it static if you know only one copy is required (this effectively makes it a global, although still only accessible by I2c) - but don't forget it needs a single non-inline definition.
Alternatively, you need to figure out what I2c objects exist, and where they're created. You can implement all constructor and assignment operator overloads with logging (or to set breakpoints) if you're having trouble figuring out where they get created.

QT: Not getting XIDeviceEvent data in X11EventFilter

I have a Qt Application that works fine on Ubuntu 14.04 and Ubuntu 12.04.I need to redirect Touch and button press XEvents to my application.
The piece of code that does this is as follows-
XIEventMask eventmask;
eventmask.deviceid = XIAllMasterDevices;
eventmask.mask_len = XIMaskLen(XI_LASTEVENT);
eventmask.mask = (unsigned char*) calloc(eventmask.mask_len, sizeof(char));
XISetMask(eventmask.mask, XI_TouchBegin);
XISetMask(eventmask.mask, XI_TouchUpdate);
XISetMask(eventmask.mask, XI_TouchEnd);
XISetMask(eventmask.mask, XI_ButtonPress);
XISetMask(eventmask.mask, XI_ButtonRelease);
XISetMask(eventmask.mask, XI_Motion);
printf("Return value from XISelectevents: %d\n",XISelectEvents(QX11Info::display(), viewer->winId(), &eventmask, 1));
The XISelectEvents() function returns 0 which I assume is the return value for success. Then I have a oveeride function bool MainApplication::x11EventFilter(XEvent *event) to process the events.
XEvent ev = *event;
if (ev.xcookie.type == GenericEvent)
{
//printf("event: %d\n", ev.xcookie.evtype);
XIDeviceEvent* evData = (XIDeviceEvent*)(ev.xcookie.data);
int id = 0;
if(evData != 0)
id = evData->detail;
else{
printf("Device Event data not coming\n");
// return false;
}
...
The above code works fine on Ubuntu but on Debian 8 the value of (XIDeviceEvent*)(ev.xcookie.data) is 0. Is there any reason why this shouldn't work on Debian 8?
I needed to call XGetEventData(QX11Info::display(),ev.xcookie) in order to get the event data.
This is what I found out after doing some digging. The cookie is simply a unique ID for every event. The XGenericEventCookie data structure is as follows-
typedef struct
{
int type; /* of event. Always GenericEvent */
unsigned long serial; /* # of last request processed */
Bool send_event; /* true if from SendEvent request */
Display *display; /* Display the event was read from */
int extension; /* major opcode of extension that caused the event */
int evtype; /* actual event type. */
unsigned int cookie; /* unique event cookie */
void *data; /* actual event data */
} XGenericEventCookie;
Turns out simply retrieving the event retrieves the event cookie with the data pointer NULL. XGetEventData has to be called in order to actually claim the cookie.

Multi-threading through lots of files

Good evening to everyone.
First, sorry for my English, I'm trying to know better this language.
I've three files:
Main.cpp -> Contain the graphics interface, and the two worker
thread.
Lettore.cpp -> Contain the functions to reconize the type of
the file and use the correct library for play the audio, also contain
the function for stop, play,pause,skip a song.
The two audio code library -> That decode the track and send it to ao for playing.
Now, i'm trying to divide the audio process from the main code. But i don't know how to realize that.
I see C++ 11 reference, i study the condition variable of the pthreded module, but how i can implement this ?
For example, a implement like this in one of the libraries audio files, is correct?
//mpg123.c
int playmp3(char* filename,int action)
{
static mpg123_handle *mh;
static unsigned char *buffer;
/*...Many Static Dichiaration.../*
static long rate;
char* canzone=filename;
if (action==0)
{
/* Inizialize */
/*...*/
/* open the file and get the decoding format */
mpg123_open(mh,canzone);
mpg123_getformat(mh, &rate, &channels, &encoding);
/* set the output format and open the output device */
format.bits = mpg123_encsize(encoding) * BITS;
/*...*/
dev = ao_open_live(driver, &format, NULL);
}
if(action==1)
{
/* decode and play */
while (action==1&&mpg123_read(mh, buffer, buffer_size, &done) == MPG123_OK)
if((ao_play(dev, (char*)buffer, done)==0)&&action==1)
}
if(action==2)
{
/* clean up */
free(buffer);
ao_close(dev);
mpg123_close(mh);
/*...*/
}
}
Like you can see i need extern the code in other files because "playmp3" is write in C and "playother" is write in C++.
In "Lettore.cpp" how i can control the audio flow ? I can include directly a function of Lettore.cpp in a thread of the main.cpp?
Thank you for your time
Ps: if this question isn't congruent with the rules i modify this question instantly!
EDIT: For clarity I attach also my attempt on Lettore.cpp
//Lettore.cpp
#include <iostream>
#include "playother.h"
#include "Lettore.h"
extern "C" {
#include "mpg123.h"
}
bool Audio::isMp3(char * nome)
{
//Reconize if the file is an mp3.
}
void Audio::inizialize(char * filename)
{
Audio::currentrack=filename;
Audio::isOpen=true;
if (isMp3(Audio::tracciacorrente)){
playmp3(Audio::currentrack,0);
}else{
playmusic(Audio::currentrack,0);
}
}
void Audio::play()
{
if (isMp3(Audio::currentrack)){
playmp3(Audio::currentrack,1);
}else{
playmusic(Audio::currentrack,1);
}
}
void Audio::close()
{
if (isMp3(Audio::currentrack)){
playmp3(Audio::currentrack,2);
}else{
playmusic(Audio::currentrack,2);
}
Audio::currentrack=NULL;
Audio::isOpen=false;
}
void Audio::pause()
{
if (isMp3(Audio::currentrack)){
playmp3(Audio::currentrack,4);
}else{
playmusic(Audio::currentrack,4);
}
}
bool Audio::get_openstatus()
{
return Audio::isOpen;
}
Now the question is the same: If this is the correct implementation of the two files, what should I write about main.cpp order to use these files?

spidermonkey 1.8.5 crashes in debug mode

I am using Spidermonkey 1.8.5 in my application.
My application crashes when I use the debug JS library. I am building the library with the following options:
--enable-debug --disable-optimize --enable-threadsafe
crash is pointing here:
Assertion failure: (cx)->thread->data.requestDepth || (cx)->thread == (cx)->runtime->gcThread, at ../../src/jsapi.cpp
Here is the sample program
/* Include the JSAPI header file to get access to SpiderMonkey. */
#include "jsapi.h"
/* The class of the global object. */
static JSClass global_class = {
"global", JSCLASS_GLOBAL_FLAGS,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
JSCLASS_NO_OPTIONAL_MEMBERS
};
/* The error reporter callback. */
void reportError(JSContext *cx, const char *message, JSErrorReport *report)
{
fprintf(stderr, "%s:%u:%s\n",
report->filename ? report->filename : "<no filename=\"filename\">",
(unsigned int) report->lineno,
message);
}
int main(int argc, const char *argv[])
{
/* JSAPI variables. */
JSRuntime *rt;
JSContext *cx;
JSObject *global;
printf("Started\n");
/* Create a JS runtime. You always need at least one runtime per process. */
rt = JS_NewRuntime(8 * 1024 * 1024);
if (rt == NULL)
return 1;
/*
* Create a context. You always need a context per thread.
* Note that this program is not multi-threaded.
*/
cx = JS_NewContext(rt, 8192);
if (cx == NULL)
return 1;
JS_SetErrorReporter(cx, reportError);
/*
* Create the global object in a new compartment.
* You always need a global object per context.
*/
global = JS_NewCompartmentAndGlobalObject(cx, &global_class, NULL);
if (global == NULL)
return 1;
/*
* Populate the global object with the standard JavaScript
* function and object classes, such as Object, Array, Date.
*/
if (!JS_InitStandardClasses(cx, global))
return 1;
/* Your application code here. This may include JSAPI calls
* to create your own custom JavaScript objects and to run scripts.
*
* The following example code creates a literal JavaScript script,
* evaluates it, and prints the result to stdout.
*
* Errors are conventionally saved in a JSBool variable named ok.
*/
char *script = "'Hello ' + 'World!'";
jsval rval;
JSString *str;
JSBool ok;
const char *filename = "noname";
uintN lineno = 0;
ok = JS_EvaluateScript(cx, global, script, strlen(script),
filename, lineno, &rval);
if (rval == NULL | rval == JS_FALSE)
return 1;
str = JS_ValueToString(cx, rval);
printf("%s\n", JS_EncodeString(cx, str));
/* End of your application code */
/* Clean things up and shut down SpiderMonkey. */
JS_DestroyContext(cx);
JS_DestroyRuntime(rt);
JS_ShutDown();
return 0;
}
If I am building in release mode the program works fine. this problem is only with the debug mode. What am I missing here?
Insert JS_BeginRequest(cx); just before the JS_NewCompartmentAndGlobalObject call.
Insert JS_EndRequest(cx); just before the call to JS_DestroyContext.
Most JSAPI functions require a request. (I'm not sure why. The original reason for threads had to do with multithreading, but each JSRuntime is single-threaded now.)
The debug build of SpiderMonkey includes assertions that check API usage in ways that release mode can't. So you will likely see debug-only assertions again. I strongly recommend developing against a debug build, because those assertions almost always indicate real problems.
The next SpiderMonkey release is coming soon: https://bugzilla.mozilla.org/show_bug.cgi?id=735599#c54

siginfo anonymous unions

I am trying to get the address of a system call that generates a sigsys signal! But I am getting the following error from gcc :
gcc emulator.c -fms-extensions
error: ‘siginfo_t’ has no member named ‘si_call_addr’
the code I am using is :
static void emulator(int nr, siginfo_t *siginfo, void *void_context)
{
ucontext_t *ctx = (ucontext_t *)(void_context);
int syscall;
char *buf;
ssize_t bytes;
size_t len;
if (siginfo->si_code != SYS_SECCOMP)
return;
if (!ctx)
return;
syscall = ctx->uc_mcontext.gregs[REG_SYSCALL];
printf("System call %d ADDR %X\n", syscall, siginfo->si_call_addr);
setcontext(ctx);
return;
}
the si_call_addr is defined as an anonymous structure in siginfo_t.
There's no si_call_addr in siginfo_t. You might be looking for the si_addr member.
Here's the siginfo_t provided by linux:
siginfo_t {
int si_signo; /* Signal number */
int si_errno; /* An errno value */
int si_code; /* Signal code */
int si_trapno; /* Trap number that caused
hardware-generated signal
(unused on most architectures) */
pid_t si_pid; /* Sending process ID */
uid_t si_uid; /* Real user ID of sending process */
int si_status; /* Exit value or signal */
clock_t si_utime; /* User time consumed */
clock_t si_stime; /* System time consumed */
sigval_t si_value; /* Signal value */
int si_int; /* POSIX.1b signal */
void *si_ptr; /* POSIX.1b signal */
int si_overrun; /* Timer overrun count; POSIX.1b timers */
int si_timerid; /* Timer ID; POSIX.1b timers */
void *si_addr; /* Memory location which caused fault */
long si_band; /* Band event (was int in
glibc 2.3.2 and earlier) */
int si_fd; /* File descriptor */
short si_addr_lsb; /* Least significant bit of address
(since kernel 2.6.32) */
}