I wrote a basic module that implements IOCTL handling. I'm trying to cross compile this module to arm64, against 4.19.114 kernel source. Here is my Makefile:
ARCH=arm64
CROSS_COMPILE=aarch64-linux-gnu-
obj-m := chardev.o
KDIR := linux-4.19.114
PWD := $(shell pwd)
default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) clean
Here is my module source:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/ioctl.h>
#include <linux/uaccess.h>
#define NAME "chardev_roi"
#define MAGIC 'a'
#define READPARAM 'b'
#define WRITEPARAM 'c'
#define IOCTL_READ_ROI _IOR(MAGIC, READPARAM, int64_t*)
#define IOCTL_WRITE_ROI _IOW(MAGIC, WRITEPARAM, int64_t*)
static ssize_t ext_read(struct file *filp, char __user *buf, size_t len, loff_t *off)
{
printk("Reading from driver\n");
return 0;
}
static ssize_t ext_write(struct file *filp, const char __user *buf, size_t len, loff_t *off)
{
printk("Writing to driver...\n");
return 0;
}
static long ext_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
char* _from_user_buffer = NULL;
switch (cmd)
{
case IOCTL_WRITE_ROI:
printk("IOCTL_WRITE_ROI just has benn called\n");
_from_user_buffer = kmalloc(32, GFP_KERNEL);
copy_from_user(_from_user_buffer, (char*) arg, sizeof(_from_user_buffer));
break;
case IOCTL_READ_ROI:
printk("IOCTL_READ_ROI just has been called\n");
copy_to_user((char*) arg, "Hello, World!\n", 14);
break;
}
}
static int init(void)
{
int major_number;
static struct file_operations _fops =
{
.owner = THIS_MODULE,
.read = ext_read,
.write = ext_write,
.unlocked_ioctl = ext_ioctl
};
major_number = register_chrdev(0, NAME, &_fops);
return 0;
}
Running this command: sudo ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make -d -C linux-4.19.114 M=$(pwd) modules
Throws this error:
./include/uapi/linux/types.h:5:10: fatal error: asm/types.h: No such file or directory
The kernel configuration is defconfig without any changes. Tried to run make clean && make mrproper but it didn't help.
The problem was that I didn't generate the modules.
Run:
make <args> modules
Will probably solve the problem.
Related
I'm seeking to implement a custom nss module for the getent hosts lookup. Based on glibc's resolv/nss-dns/dns-host.c and gnunet's src/gns/nss/nss_gns.c I wrote the following minimal implementation that I hoped at least should write something to syslog - which it sadly doesn't.
#include <netdb.h>
#include <nss.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <syslog.h>
#define _nss_lash_gethostbyname2_r _nss_lash_gethostbyname_r
#define _nss_lash_gethostbyname3_r _nss_lash_gethostbyname_r
#define _nss_lash_gethostbyname4_r _nss_lash_gethostbyname_r
#define _nss_lash_getcanonname_r _nss_lash_gethostbyaddr_r
#define _nss_lash_gethostbyaddr2_r _nss_lash_gethostbyaddr_r
#define _nss_lash_getnetbyname_r _nss_lash_gethostbyaddr_r
#define _nss_lash_getnetbyaddr_r _nss_lash_gethostbyaddr_r
typedef char addr[1];
const addr default_addrs[2] = {0x01, 0x00};
enum nss_status
_nss_lash_gethostbyname_r (const char *name, struct hostent *result,
char *buffer, size_t buflen, int *errnop,
int *h_errnop)
{
syslog(LOG_WARNING, name);
if (!strcmp(name, "lash")) {
return NSS_STATUS_UNAVAIL;
}
*(result->h_aliases) = 0x0;
result->h_addrtype = AF_INET;
result->h_length = 1;
*(result->h_addr_list) = (char *)default_addrs;
*errnop = 0;
*h_errnop = NETDB_SUCCESS;
return NSS_STATUS_SUCCESS;
}
enum nss_status
_nss_lash_gethostbyaddr_r (const char *name, struct hostent *result,
char *buffer, size_t buflen, int *errnop,
int *h_errnop)
{
syslog(LOG_ERR, name);
if (!strcmp(name, "lash")) {
return NSS_STATUS_UNAVAIL;
}
*(result->h_aliases) = 0x0;
result->h_addrtype = AF_INET;
result->h_length = 1;
*(result->h_addr_list) = (char *)default_addrs;
*errnop = 0;
*h_errnop = NETDB_SUCCESS;
return NSS_STATUS_SUCCESS;
}
I've added lash to /etc/nsswitch.conf. strace shows that the /lib/libnss_lash.so.2 file is being successfully opened. However the return value from the nss lookup is NSS_UNAVAIL / ENOENT. If I add [unavail=return] to /etc/nsswitch.conf after the lash entry, I get the same result.
Anyone have any clues to what I'm missing?
(the #define lines attempt to catch all symbols found in objdump -T /lib/libnss_dns.so, which seems to be the simpler implementation)
Using:
glibc 2.30
gnunet 0.11.6-ish
nss 3.49.2
How to use Golang Generated libgolang.a from C code to build C executable: test.exe:
these commands makes executable binary 'test' in Ubuntu x86-64 and works fine (but not in Windows x86-64):
go build -buildmode c-archive -o libgolang.a
gcc -o test _main.c libgolang.a -lpthread
with:
this is main.go file:
package main
import "C"
import "fmt"
//export Add
func Add(a, b uint64) uint64 {
return a + b
}
func main() {
fmt.Println("Hi")
}
and this is _main.c file:
#include <stdio.h>
#include <stdint.h>
#include "libgolang.h"
int main()
{
uint64_t a=10;
uint64_t b=20;
uint64_t c=Add(a,b);
printf("%ld\n",c);
return 0;
}
in Windows this command:
go build -buildmode c-archive -o libgolang.a
works fine and generates libgolang.a and libgolang.h files. libgolang.h:
/* Created by "go tool cgo" - DO NOT EDIT. */
/* package github.com/ARamazani/go/DLL */
/* Start of preamble from import "C" comments. */
/* End of preamble from import "C" comments. */
/* Start of boilerplate cgo prologue. */
#ifndef GO_CGO_PROLOGUE_H
#define GO_CGO_PROLOGUE_H
typedef signed char GoInt8;
typedef unsigned char GoUint8;
typedef short GoInt16;
typedef unsigned short GoUint16;
typedef int GoInt32;
typedef unsigned int GoUint32;
typedef long long GoInt64;
typedef unsigned long long GoUint64;
typedef GoInt64 GoInt;
typedef GoUint64 GoUint;
typedef __SIZE_TYPE__ GoUintptr;
typedef float GoFloat32;
typedef double GoFloat64;
typedef float _Complex GoComplex64;
typedef double _Complex GoComplex128;
/*
static assertion to make sure the file is being used on architecture
at least with matching size of GoInt.
*/
typedef char _check_for_64_bit_pointer_matching_GoInt[sizeof(void*)==64/8 ? 1:-1];
typedef struct { const char *p; GoInt n; } GoString;
typedef void *GoMap;
typedef void *GoChan;
typedef struct { void *t; void *v; } GoInterface;
typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;
#endif
/* End of boilerplate cgo prologue. */
#ifdef __cplusplus
extern "C" {
#endif
extern GoUint64 Add(GoUint64 p0, GoUint64 p1);
#ifdef __cplusplus
}
#endif
but this command:
gcc -o test _main.c libgolang.a -lpthread
output:
libgolang.a(go.o):(.data+0x2150): undefined reference to `NtWaitForSingleObject'
libgolang.a(go.o):(.data+0x21b8): undefined reference to `WSAGetOverlappedResult'
libgolang.a(go.o):(.data+0x21d8): undefined reference to `timeBeginPeriod'
collect2.exe: error: ld returned 1 exit status
go version go1.7rc3 windows/amd64
I want to use this libgolang.a from C code to build C executable: test.exe
any workaround?
some useful links:
http://blog.ralch.com/tutorial/golang-sharing-libraries/
Using Go code in an existing C project
Using Go on existing C project
Finally found at least one way:
using this file main.go:
package main
import "C"
import "fmt"
//export Add
func Add(a, b uint64) uint64 {
return a + b
}
func main() {
fmt.Println("Hi")
}
run this command:
go build -buildmode c-archive -o libgolang.a
to generate libgolang.a and libgolang.h
then using _main.c:
#include <stdio.h>
#include <stdint.h>
#include "libgolang.h"
int main()
{
uint64_t a=10;
uint64_t b=20;
uint64_t c=Add(a,b);
printf("%ld\n",c);
return 0;
}
this is the answer (this works for me):
gcc -o test _main.c libgolang.a -lWinMM -lntdll -lWS2_32
that test.exe created.
run:
test.exe
output:
30
The Microsoft Windows always trick us!
But for production code my suggestion is use the optimization compile commands below:
go build -ldflags "-s -w" -buildmode c-archive -o libgolang.a
The parameter -ldflags "-s -w", will reduze the final file size.
The "libgolang.a" shrink from 4.295.562 to 1.994.554.
And the "test.exe" shrink from 3.430.485 to 1.715.561.
I guess this is a desired behavior!
I'm a noob to linux kernel programming and thought I'd be able to find the answer for this (since it seems really simple) but haven't had any luck yet. I need to make a linux kernel module that prints the version number of the kernel. The assignment requires that implement a module which displays this kind of message when loaded:
"Hello Master. You are currently using Linux (version)", where (version) is the kernel version no.
How can I do this? I tried using uname (http://man7.org/linux/man-pages/man2/uname.2.html) but when I include sys/utsname.h, I get a fatal error upon compiling with my makefile
"Cannot open include file: 'sys/utsname.h': No such file or directory".
Here is my module
#undef __KERNEL__
#define __KERNEL__
#undef __MODULE__
#define __MODULE__
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <sys/utsname.h>
struct utsname unameData;
static int __init config_init(void)
{
uname(&unameData);
printk(KERN_INFO "Version number is %s\n", unameData.version);
return 0;
}
static void __exit config_exit(void)
{
printk(KERN_INFO "config_exit executed with success\n");
return;
}
module_init(config_init);
module_exit(config_exit);
MODULE_LICENSE("GPL");
Makefile
obj-m := config.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean
Firstly, you need to use the correct headers and also the correct function utsname(). Following code work well for me.
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/utsname.h>
static int __init my_init(void)
{
printk(KERN_INFO "Kernel version %s\n", utsname()->version);
printk(KERN_INFO "Kernel release %s\n", utsname()->release);
return 0;
}
static void __exit my_exit(void)
{
printk(KERN_INFO "exit module");
return;
}
module_init(my_init);
module_exit(my_exit);
MODULE_LICENSE("GPL");
dmesg output should looks something like this:
[ 1117.358451] Kernel version #64-Ubuntu SMP Mon Sep 22 21:28:38 UTC 2014
[ 1117.358457] Kernel release 3.13.0-37-generic
all:
I have 2 files, module1.c and module2.c which contains functions needed by the third file, big_module.c. My Makefile complained of not finding functions defined in module1.c and module2.c. These functions are needed by big_module.c Could you please help me defining my Makefile so it would work?
module1.c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/version.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <asm/uaccess.h>
int module1 (struct file *filp, struct vm_area_struct *vma)
{ return 0; }
int __init init_module1 (void)
{ return 0; }
void __exit cleanup_module1 (void)
{ }
module2.c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/version.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
#include <asm/io.h>
unsigned long virt_addr;
int module2(struct file * filp, struct vm_area_struct * vma)
{ return 0; }
int __init init_module2 (void)
{ return 0; }
void __exit cleanup_module2 (void) { }
big_module.c
#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/vt_kern.h>
#include <linux/fs.h>
MODULE_DESCRIPTION("Example");
MODULE_AUTHOR("Your Name Here");
MODULE_LICENSE("GPL");
static int __init hello_init(void)
{
init_module1();
init_module2();
return 0;
}
static void __exit hello_cleanup(void)
{
cleanup_module1();
cleanup_module2();
}
module_init(hello_init);
module_exit(hello_cleanup);
Makefile:
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
obj-m += big_module.o
obj-m += module1.o
obj-m += module2.o
modules:
$(MAKE) -C $(KDIR) M=$(PWD) modules
Errors:
> uu#uu-VirtualBox:~/UCSC-Ext/LDDII/Assignment3/ASK$ sudo make
> make -C /lib/modules/3.10.0uu/build M=/home/uu/UCSC-Ext/LDDII/Assignment3/ASK modules
> make[1]: Entering directory `/usr/src/linux-3.10'
> CC [M] /home/uu/UCSC-Ext/LDDII/Assignment3/ASK/big_module.o
> /home/uu/UCSC-Ext/LDDII/Assignment3/ASK/big_module.c: In function ‘hello_init’:
> /home/uu/UCSC-Ext/LDDII/Assignment3/ASK/big_module.c:14:2: error: implicit declaration of function ‘init_module1’
> [-Werror=implicit-function-declaration]
> /home/uu/UCSC-Ext/LDDII/Assignment3/ASK/big_module.c:15:2: error: implicit declaration of function ‘init_module2’
> [-Werror=implicit-function-declaration]
> /home/uu/UCSC-Ext/LDDII/Assignment3/ASK/big_module.c: In function ‘hello_cleanup’:
> /home/uu/UCSC-Ext/LDDII/Assignment3/ASK/big_module.c:21:2: error: implicit declaration of function ‘cleanup_module1’
> [-Werror=implicit-function-declaration]
> /home/uu/UCSC-Ext/LDDII/Assignment3/ASK/big_module.c:22:2: error: implicit declaration of function ‘cleanup_module2’
> [-Werror=implicit-function-declaration]
> cc1: some warnings being treated as errors
> make[2]: *** [/home/uu/UCSC-Ext/LDDII/Assignment3/ASK/big_module.o] Error 1
> make[1]: *** [_module_/home/uu/UCSC-Ext/LDDII/Assignment3/ASK] Error 2
> make[1]: Leaving directory `/usr/src/linux-3.10'
> make: *** [modules] Error 2
all:
I found the solution to my question. It's in the Makefile which should look
like the following:
Makefile
=======================
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
obj-m := big_module.o
big_module-objs := module1.o module2.o
modules:
$(MAKE) -C $(KDIR) M=$(PWD) modules
=======================
I'm trying to intercept the openat() system call on Linux using a custom shared library that I can load via LD_PRELOAD. An example intercept-openat.c has this content:
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <dlfcn.h>
int (*_original_openat)(int dirfd, const char *pathname, int flags, mode_t mode);
void init(void) __attribute__((constructor));
int openat(int dirfd, const char *pathname, int flags, mode_t mode);
void init(void)
{
_original_openat = (int (*)(int, const char *, int, mode_t))
dlsym(RTLD_NEXT, "openat");
}
int openat(int dirfd, const char *pathname, int flags, mode_t mode)
{
fprintf(stderr, "intercepting openat()...\n");
return _original_openat(dirfd, pathname, flags, mode);
}
I compile it via gcc -fPIC -Wall -shared -o intercept-openat.so intercept-openat.c -ldl. Then, when I run this small example program:
int main(int argc, char *argv[])
{
int fd;
fd = openat(AT_FDCWD, "/home/feh/.vimrc", O_RDONLY);
if(fd == -1)
return -1;
close(fd);
return 0;
}
The openat() call is re-written via the library:
$ LD_PRELOAD=./intercept-openat.so ./openat
intercepting openat()...
However, the same does not happen with GNU tar, even though it uses the same system call:
$ strace -e openat tar cf /tmp/t.tgz .vimrc
openat(AT_FDCWD, ".vimrc", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW|O_CLOEXEC) = 4
$ LD_PRELOAD=./intercept-openat.so tar cf /tmp/t.tgz .vimrc
So the custom openat() from intercept-openat.so is not being called. Why is that?
It uses the same system call, but apparently it does not call that via the same C function. Alternatively, it could be that it does, but it's statically linked.
Either way, I think you've proved that it never dynamically links a function names "openat". If you still want to pursue this option, you might like to see if it links against a specific version of that function, but that's a long shot.
You can still intercept the system call by writing your program to use ptrace. This is the same interface used by strace and gdb. It will have a higher performance penalty though.
http://linux.die.net/man/2/ptrace