Linux kernel module reference counter is always zero - module

I am implementing a kernel module that exposes some data to userspase using mmap interface.
I create a file in /proc file system passing struct file_operations with pointers to needed functions:
static struct file_operations module_file_ops = {
.owner = THIS_MODULE,
.open = module_open,
.mmap = module_mmap
};
proc_create(THIS_MODULE->name, 0444, NULL, &module_file_ops);
Userspace application is able to open and read from the file (mmap contents) as expected.
When I do lsof I see the file is opened by the userspace app.
However, lsmod always gives zero as usage counter despite I set .owner to THIS_MODULE, so that I can easily remove the module with rmmod and lead the system to crash.
Please advise.
module.c
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
static struct proc_dir_entry *proc_file;
static const struct file_operations test_file_ops = {
.owner = THIS_MODULE
};
static int __init initialize(void) {
int error = 0;
proc_file = proc_create(THIS_MODULE->name, 0444, NULL, &test_file_ops);
if (!proc_file) {
error = -EIO;
}
return error;
}
static void __exit teardown(void) {
proc_remove(proc_file);
}
module_init(initialize);
module_exit(teardown);
Makefile
obj-m += test.o
test-objs := module.o
CC=gcc
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
EXTRA_CFLAGS=-I/usr/include -I/usr/include/x86_64-linux-gnu
all:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules

Related

GetProcAddress returning the correct address with Visual C++ and an incorrect address with g++

This is going to sound really strange. I am using Visual Studio 2017 C++ (native mode) and also, g++ 4.7.1-2 of the MingW toolchain. Target is Windows 64bit.
Using VS C++, I compile the following trivial program:
`
#include "stdafx.h"
#include <Windows.h>
#include <winternl.h>
typedef NTSTATUS (NTAPI* RTLINT64)(ULONGLONG, ULONG, PUNICODE_STRING);
RTLINT64 RtlInt64 = (RTLINT64) nullptr;
int main()
{
UNICODE_STRING unicodestring = { 0 };
WCHAR localbuffer[256] = { 0 }; // way more than enough
__int64 value = 0;
unicodestring.Length = 0;
unicodestring.MaximumLength = sizeof(localbuffer);
unicodestring.Buffer = (PWCH) &localbuffer;
// get ntdll's module handle
HMODULE NtDllModule = LoadLibrary(L"ntdll.dll");
if (NtDllModule)
{
RtlInt64 = (RTLINT64) GetProcAddress(NtDllModule,
"RtlInt64ToUnicodeString");
value = 0xFFFFFFFFF;
RtlInt64 (value, 10, &unicodestring);
wprintf(L"%s\n", unicodestring.Buffer);
}
return 0;
}
`
As expected, GetProcAddress returns the address of RtlInt64ToUnicodeString (no surprise there!)
The code below is, with exception of the includes, pretty much a carbon copy of the above. Yet, somehow, in that version compiled with G++, GetProcAddress returns the address of RtlInterlockedSetBitRun instead of the address of RtlInt64ToUnicodeString (that IS a surprise!). Here is the code:
// GCC and MingW version
#include <Windows.h>
#include <winbase.h>
#include <strsafe.h>
#include <winuser.h>
#include <winternl.h>
// --------------------------------------------------------------------------
typedef NTSTATUS(NTAPI* RTLINT64)(ULONGLONG, ULONG, PUNICODE_STRING);
RTLINT64 RtlInt64 = (RTLINT64) nullptr;
// --------------------------------------------------------------------------
int main(int argc, char *argv[])
{
WCHAR localbuffer[256] = {0}; // way more than enough
UNICODE_STRING unicodestring = {0};
__int64 value = 0;
unicodestring.Length = 0;
unicodestring.MaximumLength = sizeof(localbuffer);
unicodestring.Buffer = (PWCH) &localbuffer;
// get ntdll's module handle
HMODULE NtDllModule = LoadLibraryW(L"ntdll.dll");
if (NtDllModule)
{
RtlInt64 = (RTLINT64) GetProcAddress(NtDllModule,
"RtlInt64ToUnicodeString");
// the above call to GetProcAddress returned the address of
// RtlInterlockedSetBitRun instead of the address of the requested function
// as a result, the statements below don't work.
value = 0xFFFFFFFFF;
RtlInt64(value, 10, &unicodestring);
wprintf(L"%s\n", unicodestring.Buffer);
}
return 0;
}
my question is: is there something in the above code that justifies the discrepancy ?
Also note that, I am using G++ with a tool called VisualGDB which integrates the compiler and the debugger into Visual Studio. Normally things of that kind can cause strange "side effects" but, in this case, it seems rather unlikely for something that has nothing to do with ntdll to be the culprit.
Thank you for your help.

./speaks: error while loading shared libraries: libespeak-ng.so.1: cannot open shared object file: No such file or directory

I have downloaded the last version of espeak-ng from github, and did ./autogen.sh ./configure make make install.
so I wrote a test program as you can see below:
#include <string.h>
#include <vector>
#include </usr/local/include/espeak-ng/speak_lib.h>
int samplerate; // determined by espeak, will be in Hertz (Hz)
const int buflength = 200; // passed to espeak, in milliseconds (ms)
std::vector<short> sounddata;
int SynthCallback(short *wav, int numsamples, espeak_EVENT *events) {
if (wav == NULL)
return 1; // NULL means done.
/* process your samples here, let's just gather them */
sounddata.insert(sounddata.end(), wav, wav + numsamples);
return 0; // 0 continues synthesis, 1 aborts
}
int main(int argc, char* argv[] ) {
char text[] = {"my name is espeak"};
samplerate = espeak_Initialize(AUDIO_OUTPUT_RETRIEVAL, buflength, NULL, 0);
espeak_SetSynthCallback(&SynthCallback);
espeak_SetVoiceByName("en");
unsigned int flags=espeakCHARS_AUTO | espeakENDPAUSE;
size_t size = strlen(text);
espeak_Synth(text, size + 1, 0, POS_CHARACTER, 0, flags, NULL, NULL);
espeak_Synchronize();
/* in theory sounddata holds your samples now... */
return 0;
}
And compiled it by this command without any errors:
g++ -W -o speaks espeak.cpp -lespeak-ng
But when I try to run the executable by ./speaks , I get this error message:
./speaks: error while loading shared libraries: libespeak-ng.so.1: cannot open shared object file: No such file or directory
What's the problem?
I know libespeak-ng.so.1 is here: /usr/local/lib/libespeak-ng.so.1
I solved the problem by adding these two lines to my `/etc/environment' file:
LD_LIBRARY_PATH=/usr/local/lib
PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
On Ubuntu 18.04 this is caused by setting the wrong path for the library.
You can fix it by:
sudo ln -s /usr/local/lib/libespeak-ng.so.1 /usr/lib/libespeak-ng.so.1

Simplest way to auto-restart a JVM on StackOverflowError

It does not seem that there is a -XX option to restart a JVM on StackOverflowError. What is the simplest way to auto-restart a JVM when it gets a StackOverflowError?
HotSpot JVM has built-in -XX:AbortVMOnException=java.lang.StackOverflowError option, but unfortunately this flag is available only in debug builds of JVM.
The working solution is to use JVM TI agent that will intercept all exceptions and abort the process whenever the exception belongs to the specified class. Here is an example of such agent.
#include <jvmti.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
static const char* fatal_error_class;
void JNICALL ExceptionCallback(jvmtiEnv* jvmti, JNIEnv* env, jthread thread,
jmethodID method, jlocation location, jobject exception,
jmethodID catch_method, jlocation catch_location) {
char* class_name;
jclass exception_class = env->GetObjectClass(exception);
jvmti->GetClassSignature(exception_class, &class_name, NULL);
class_name[strlen(class_name) - 1] = 0;
if (strcmp(class_name + 1, fatal_error_class) == 0) {
printf("Abort on fatal error\n");
exit(1);
}
jvmti->Deallocate((unsigned char*)class_name);
}
extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* unused) {
if (options == NULL || options[0] == 0) {
printf("Usage: -agentpath:/path/to/libabort.so=java/lang/StackOverflowError\n");
return 1;
}
fatal_error_class = strdup(options);
jvmtiEnv* jvmti;
vm->GetEnv((void**)&jvmti, JVMTI_VERSION_1_0);
jvmtiCapabilities capabilities = {0};
capabilities.can_generate_exception_events = 1;
jvmti->AddCapabilities(&capabilities);
jvmtiEventCallbacks callbacks = {0};
callbacks.Exception = ExceptionCallback;
jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks));
jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_EXCEPTION, NULL);
return 0;
}
How to compile it:
g++ -I $JAVA_HOME/include -I $JAVA_HOME/include/linux -fPIC -shared -olibabort.so abort.cpp
How to run:
java -agentpath:/path/to/libabort.so=java/lang/StackOverflowError ...

Googlemock - multiple actions in WillOnce cause build error

I am already using gtest for some time but recently wanted to try out gmock. I am trying to mock class with method that returns value but also returns something in output parameter through reference. Here is my small code.
#include <vector>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
using namespace ::testing;
class AReal
{
public:
virtual bool foo(std::vector<int>& v) const = 0;
};
class AMock : public AReal
{
public:
MOCK_CONST_METHOD1(foo, bool(std::vector<int>&));
};
class B
{
public:
B(AReal* _a) : a(_a) {}
bool foo(std::vector<int>& v) const { return a->foo(v); }
private:
AReal* a;
};
class FooTest : public Test {};
TEST_F(FooTest,
DummyTestVector) {
AMock a;
B b(&a);
std::vector<int> exp = { 1, 2, 3 };
EXPECT_CALL(a, foo(_))
.Times(1)
.WillOnce(AllOf(SetArgReferee<0>(exp), Return(true)));
std::vector<int> load;
EXPECT_TRUE(a.foo(load));
EXPECT_EQ(exp, load);
}
int main(int argc, char** argv) {
::testing::InitGoogleMock(&argc, argv);
return RUN_ALL_TESTS();
}
However, this code gives me this error.
$ g++ -Wall -Wextra -std=c++14 -I. -o test test.cpp gmock-gtest-all.cc -lpthread
test.cpp: In member function ‘virtual void FooTest_DummyTestVector_Test::TestBody()’:
test.cpp:40:61: error: no matching function for call to ‘testing::internal::TypedExpectation<bool(std::vector<int>&)>::WillOnce(testing::internal::AllOfResult2<testing::SetArgRefereeActionP<0, std::vector<int> >, testing::internal::ReturnAction<bool> >::type)’
.WillOnce(AllOf(SetArgReferee<0>(exp), Return(true)));
^
In file included from test.cpp:2:0:
gmock/gmock.h:10172:21: note: candidate: testing::internal::TypedExpectation<F>& testing::internal::TypedExpectation<F>::WillOnce(const testing::Action<F>&) [with F = bool(std::vector<int>&)]
TypedExpectation& WillOnce(const Action<F>& action) {
^
gmock/gmock.h:10172:21: note: no known conversion for argument 1 from ‘testing::internal::AllOfResult2<testing::SetArgRefereeActionP<0, std::vector<int> >, testing::internal::ReturnAction<bool> >::type {aka testing::internal::BothOfMatcher<testing::SetArgRefereeActionP<0, std::vector<int> >, testing::internal::ReturnAction<bool> >}’ to ‘const testing::Action<bool(std::vector<int>&)>&’
If I don't use AllOf but rather specify just one action, either SetArgReferee or Return, everything works just fine. The use of AllOf causes this kind of error. I have found about AllOf here gmock multiple in-out parameters SetArgReferee and basically my code is same as the answer.
After one whole afternoon of trying everything I found out it was just my stupidity. All the time I somehow thought that AllOf == DoAll. Realized it just now.

Use dlsym on a static binary

Is there any hope of running dlopen(NULL, ...) and getting symbols for a statically compiled binary?
For example, with the following code I can get symbols if the program is compiled dynamically and I use -rdynamic.
$ gcc -o foo foo.c -ldl -rdynamic
$ ./foo bar
In bar!
But with -static I get a cryptic error message:
$ gcc -static -o foo foo.c -ldl -rdynamic
/tmp/cc5LSrI5.o: In function `main':
foo.c:(.text+0x3a): warning: Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
$ ./foo bar
/lib/x86_64-linux-gnu/: cannot read file data: Is a directory
The source for foo.c follows:
#include <dlfcn.h>
#include <stdio.h>
int foo() { printf("In foo!\n"); }
int bar() { printf("In bar!\n"); }
int main(int argc, char**argv)
{
void *handle;
handle = dlopen(NULL, RTLD_NOW|RTLD_GLOBAL);
if (handle == NULL) {
fprintf(stderr, "%s\n", dlerror());
return 1;
}
typedef void (*function)();
function f = (function) dlsym(handle, argv[1]);
if (f == NULL) {
fprintf(stderr, "%s\n", dlerror());
return 2;
}
f();
return 0;
}
Is there any hope of running dlopen(NULL, ...) and getting symbols for a statically compiled binary?
No.
On most UNIXes you can't even link with -static and -ldl at the same time. Using glibc you can, but the utility of doing so is very limited. Basically, this ability is present only to support /etc/nsswitch.conf, and nothing else.
There is also no point in doing the dynamic lookup you did.
If you are trying to allow one of foo, bar or baz be called depending on command line arguments, just put a table in, e.g.
struct { const char *fname, void (*fn)(void) } table[] =
{ {"foo", &foo}, {"bar", &bar}, ...};
for (int i = 0; i < ...; ++i)
if (strcmp(argv[1], table[i].fname) == 0)
// found the entry, call it
(*table[i].fn)();
If you are trying to "maybe" call foo if it is linked in, and do nothing otherwise, then use weak references:
extern void foo(void) __attribute((weak));
if (&foo != 0) {
// foo was linked in, call it
foo();
}