Converting a C struct to FFI::Struct - ruby

I am having difficulty setting up a struct from the pcap library in FFI.
Struct:
struct pcap_if {
struct pcap_if *next;
char *name;
char *description;
struct pcap_addr *addresses;
bpf_u_int32 flags;
};
The relevant Ruby code
module Pcap
extend FFI::Library
ffi_lib 'pcap'
attach_function :pcap_findalldevs,[:pointer,:string],:int
class Pcap_if < FFI::Struct
layout :next,:pointer,
:name,:string,
:description,:string,
:pcap_addr,:pointer,
:flags,:int
end
end
Above attached function definition
int pcap_findalldevs(pcap_if_t **, char *)
The test code(run as root)
tmp=''
ptr = FFI::MemoryPointer.new :pointer
res = Pcap.pcap_findalldevs ptr,tmp
devs = Pcap::Pcap_if.new ptr
puts res
puts devs.offsets
puts devs[:name]
The output is
0 #pcap_findalldevs return success
next
0
name
4
description
8
pcap_addr
12
flags
16
pcap.rb:29:in `[]': Memory access offset=4 size=4 is out of bounds (IndexError)
The offsets look right to me but my C is very rusty. I was expecting 2 devices: lo and eth0 as names.

Slow post:
Code should go like this:
ptr = FFI::MemoryPointer.new Pcap::Pcap_if.size
res = Pcap.pcap_findalldevs ptr,tmp
devs = Pcap::Pcap_if.new ptr

I found the solution. FFI can't deal with pcap_if_t **. I wrote a C function to return just an array of structs.
pcap_if_t* find_devs()
{
pcap_if_t *devs;
char errbuf[PCAP_ERRBUF_SIZE];
int res;
res=pcap_findalldevs(&devs, errbuf);
return devs;
}
I still need to handle error cases, but this does work.

Related

Smart pointer operator[] "no match" when type is array with known length

Given the below code:
typedef std::unique_ptr<uint8_t[SHA256::DIGEST_SIZE]> sha256hash;
std::ostream& operator<<(std::ostream& os, const sha256hash &hash) {
// Save old formatting
std::ios oldFormat(nullptr);
oldFormat.copyfmt(os);
// Set up formatting
os << std::setfill('0') << std::setw(2) << std::hex;
// Do our printing
for (int i = 0;i < SHA256::DIGEST_SIZE; i++)
os << hash[i];
// Restore formatting
os.copyfmt(oldFormat);
}
I get the following error:
In function ‘std::ostream& operator<<(std::ostream&, const sha256hash&)’:
error: no match for ‘operator[]’ (operand types are ‘const sha256hash {aka const std::unique_ptr<unsigned char [32]>}’ and ‘int’)
os << hash[i];
I thought that the typedef would give me a smart pointer containing a pointer to an array of uint8_t and so operator[] should be indexing into that array. My best guesses at what's happening is that I'm instead saying that I want a unique_ptr to a pointer to an array of uint8_t. I think I see a couple of ways out of this but I'm not sure which is best
typedef std::unique_ptr<uint8_t[]> sha256hash;
compiles, but I'm not entirely sure that my overloaded operator won't try to print any unique_ptr to an array of ints.
I make a container struct for the int array, and put a unique_ptr around that.
Due to #PeterT's input I ended up going with my second option. A custom deleter seemed too far out of my way, and this was fairly easy to integrate into my already existing code. Here are my changes:
//! Light wrapper around SHA256 digest
class SHA256Hash {
//! The actual digest bits.
uint8_t buff[SHA256::DIGEST_SIZE];
public:
//! Pointer to a hash.
typedef std::unique_ptr<SHA256Hash> ptr;
//! Default constructor
SHA256Hash() : buff() { }
//! Operator to offer convenient buffer access
uint8_t &operator[](const uint8_t i) { return buff[i]; }
//! Operator to offer convenient buffer access
const uint8_t &operator[](const uint8_t i) const { return buff[i]; }
//! Offers access to the underlying digest
uint8_t *get() { return (uint8_t *) &buff; }
};
// Delegate to the version that prints references
std::ostream &operator<<(std::ostream &os, const SHA256Hash::ptr &hashp) {
os << *hashp;
return os;
}
std::ostream &operator<<(std::ostream &os, const SHA256Hash &hash) {
// Save old formatting
std::ios oldFormat(nullptr);
oldFormat.copyfmt(os);
// Set up formatting
os << std::setfill('0') << std::setw(2) << std::hex;
// Do our printing
for (int i = 0;i < SHA256::DIGEST_SIZE; i++)
os << (int) hash[i];
// Restore formatting
os.copyfmt(oldFormat);
return os;
}

How to dump/list all kernel symbols with addresses from Linux kernel module?

In a kernel module, how to list all the kernel symbols with their addresses?
The kernel should not be re-compiled.
I know "cat /proc/kallsyms" in an interface, but how to get them directly from kernel data structures, using functions like kallsyms_lookup_name.
Example
Working module code:
#include <linux/module.h>
#include <linux/kallsyms.h>
static int prsyms_print_symbol(void *data, const char *namebuf,
struct module *module, unsigned long address)
{
pr_info("### %lx\t%s\n", address, namebuf);
return 0;
}
static int __init prsyms_init(void)
{
kallsyms_on_each_symbol(prsyms_print_symbol, NULL);
return 0;
}
static void __exit prsyms_exit(void)
{
}
module_init(prsyms_init);
module_exit(prsyms_exit);
MODULE_AUTHOR("Sam Protsenko");
MODULE_DESCRIPTION("Module for printing all kernel symbols");
MODULE_LICENSE("GPL");
Explanation
kernel/kallsyms.c implements /proc/kallsyms. Some of its functions are available for external usage. They are exported via EXPORT_SYMBOL_GPL() macro. Yes, your module should have GPL license to use it. Those functions are:
kallsyms_lookup_name()
kallsyms_on_each_symbol()
sprint_symbol()
sprint_symbol_no_offset()
To use those functions, include <linux/kallsyms.h> in your module. It should be mentioned that CONFIG_KALLSYMS must be enabled (=y) in your kernel configuration.
To print all the symbols you obviously have to use kallsyms_on_each_symbol() function. The documentation says next about it:
/* Call a function on each kallsyms symbol in the core kernel */
int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *,
unsigned long), void *data);
where fn is your callback function that should be called for each symbol found, and data is a pointer to some private data of yours (will be passed as first parameter to your callback function).
Callback function must have next signature:
int fn(void *data, const char *namebuf, struct module *module,
unsigned long address);
This function will be called for each kernel symbol with next parameters:
data: will contain pointer to your private data you passed as last argument to kallsyms_on_each_symbol()
namebuf: will contain name of current kernel symbol
module: will always be NULL, just ignore that
address: will contain address of current kernel symbol
Return value should always be 0 (on non-zero return value the iteration through symbols will be interrupted).
Supplemental
Answering the questions in your comment.
Also, is there a way to output the size of each function?
Yes, you can use sprint_symbol() function I mentioned above to do that. It will print symbol information in next format:
symbol_name+offset/size [module_name]
Example:
psmouse_poll+0x0/0x30 [psmouse]
Module name part can be omitted if symbol is built-in.
I tried the module and see the result with "dmesg". But a lot of symbols are missing such as "futex_requeue". The output symbol number is about 10K, while it is 100K when I use "nm vmlinux".
This is most likely because your printk buffer size is insufficient to store all the output of module above.
Let's improve above module a bit, so it provides symbols information via miscdevice. Also let's add function size to the output, as requested. The code as follows:
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/kallsyms.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/sizes.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
#define DEVICE_NAME "prsyms2"
/* 16 MiB is sufficient to store information about approx. 200K symbols */
#define SYMBOLS_BUF_SIZE SZ_16M
struct symbols {
char *buf;
size_t pos;
};
static struct symbols symbols;
/* ---- misc char device definitions ---- */
static ssize_t prsyms2_read(struct file *file, char __user *buf, size_t count,
loff_t *pos)
{
return simple_read_from_buffer(buf, count, pos, symbols.buf,
symbols.pos);
}
static const struct file_operations prsyms2_fops = {
.owner = THIS_MODULE,
.read = prsyms2_read,
};
static struct miscdevice prsyms2_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &prsyms2_fops,
};
/* ---- module init/exit definitions ---- */
static int prsyms2_store_symbol(void *data, const char *namebuf,
struct module *module, unsigned long address)
{
struct symbols *s = data;
int count;
/* Append address of current symbol */
count = sprintf(s->buf + s->pos, "%lx\t", address);
s->pos += count;
/* Append name, offset, size and module name of current symbol */
count = sprint_symbol(s->buf + s->pos, address);
s->pos += count;
s->buf[s->pos++] = '\n';
if (s->pos >= SYMBOLS_BUF_SIZE)
return -ENOMEM;
return 0;
}
static int __init prsyms2_init(void)
{
int ret;
ret = misc_register(&prsyms2_misc);
if (ret)
return ret;
symbols.pos = 0;
symbols.buf = vmalloc(SYMBOLS_BUF_SIZE);
if (symbols.buf == NULL) {
ret = -ENOMEM;
goto err1;
}
dev_info(prsyms2_misc.this_device, "Populating symbols buffer...\n");
ret = kallsyms_on_each_symbol(prsyms2_store_symbol, &symbols);
if (ret != 0) {
ret = -EINVAL;
goto err2;
}
symbols.buf[symbols.pos] = '\0';
dev_info(prsyms2_misc.this_device, "Symbols buffer is ready!\n");
return 0;
err2:
vfree(symbols.buf);
err1:
misc_deregister(&prsyms2_misc);
return ret;
}
static void __exit prsyms2_exit(void)
{
vfree(symbols.buf);
misc_deregister(&prsyms2_misc);
}
module_init(prsyms2_init);
module_exit(prsyms2_exit);
MODULE_AUTHOR("Sam Protsenko");
MODULE_DESCRIPTION("Module for printing all kernel symbols");
MODULE_LICENSE("GPL");
And here is how to use it:
$ sudo insmod prsyms2.ko
$ sudo cat /dev/prsyms2 >symbols.txt
$ wc -l symbols.txt
$ sudo rmmod prsyms2
File symbols.txt will contain all kernel symbols (both built-in and from loaded modules) in next format:
ffffffffc01dc0d0 psmouse_poll+0x0/0x30 [psmouse]
It seems that I can use kallsyms_lookup_name() to find the address of the function, can then use a function pointer to call the function?
Yes, you can. If I recall correctly, it's called reflection. Below is an example how to do so:
typedef int (*custom_print)(const char *fmt, ...);
custom_print my_print;
my_print = (custom_print)kallsyms_lookup_name("printk");
if (my_print == 0) {
pr_err("Unable to find printk\n");
return -EINVAL;
}
my_print(KERN_INFO "### printk found!\n");

copy_from_user is fetching unexpected data

I want to use the write sycall for copying a struct
from userspace to kernel.
In both user and kernel space, the struct is defined as
struct packet{
unsigned char packet[256];
int length;
}__attribute__ ((packed));
User space uses a local variable of type struct packet and passes it to the write syscall.
struct packet p;
/* ... (fill in data) */
printf("packet.length: %d\n",packet.length); /* looks correct */
result = write(uartFD, &p, sizeof(struct packet));
The kernel side looks like this, checking for correct length is done, just removed from example.
/* write syscall */
ssize_t packet_write(
struct file *file_ptr,
const char __user *user_buffer,
size_t count, loff_t *position)
{
struct packet p;
int retval;
if (copy_from_user((void*)&p, user_buffer, sizeof(struct packet))){
retval = -EACCES;
goto err;
}
/* looks wrong - different numbers like 96373062 or 96373958 */
printk("packet length: %d\n",p.length);
The opposite direction using read sycall is working as expected:
/* read syscall */
struct packet p;
/* ... (fill in data) */
copy_to_user(user_buffer, (void*)&p, sizeof(struct packet));
/* userspace */
read(uartFD, (void*)&packet, sizeof(struct packet));
What am I doing wrong with write syscall?
(Posted on behalf of the OP).
This is solved - it was my own silly. Both copying an integer and an unsigned char buffer separately was working, so it had to be something about the struct.
One site was packed, the other was not... reusing old code...

Some warnings being treated as errors while making a modified ver of ext2 kernel module under ubuntu

I have succeeded in making a modified version of ext2 (so called myext2.ko) and tested it for mount and umount, and something else; the problem occurs when I add the following code into my fs/myext2/file.c and tried to implement a simple "encryption" func, that is, negating the last bit of the read-in string :
ssize_t my_new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
{
struct iovec iov; //changed
struct kiocb kiocb;
struct iov_iter iter;
ssize_t ret;
//inserted by adward - begin
size_t i;
char buff[len];
for (i=0;i<len;i++){
buff[i] = buf[i] ^ 1;
}
iov.iov_base = (void __user *)buff;
iov.iov_len = len;
printk("Inside my_new_sync_write");
//inserted by adward - end
init_sync_kiocb(&ki_nbytesocb, filp);
kiocb.ki_pos = *ppos;
kiocb.ki_nbytes = len;
iov_iter_init(&iter, WRITE, &iov, 1, len);
ret = filp->f_op->write_iter(&kiocb, &iter);
if (-EIOCBQUEUED == ret)
ret = wait_on_sync_kiocb(&kiocb);
*ppos = kiocb.ki_pos;
return ret;
}
ssize_t my_new_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
{
struct iovec iov = { .iov_base = buf, .iov_len = len };
struct kiocb kiocb;
struct iov_iter iter;
ssize_t ret;
//inserted by adward - begin
size_t i;
//inserted by adward - end
init_sync_kiocb(&kiocb, filp);
kiocb.ki_pos = *ppos;
kiocb.ki_nbytes = len;
iov_iter_init(&iter, READ, &iov, 1, len);
ret = filp->f_op->read_iter(&kiocb, &iter);
if (-EIOCBQUEUED == ret)
ret = wait_on_sync_kiocb(&kiocb);
*ppos = kiocb.ki_pos;
//inserted by adward - begin
for (i=0;i<len;i++){
buf[i] ^= 1;
}
printk("inside my_new_sync_read");
//inserted by adward - end
return ret;
}
The prototype of the above two functions are actually in fs/read_write.c , using by almost all file system types in the kernel code ver 3.17.6; I just copied them into fs/myext2/file.c and make some minor change as commented, so that I can do some test without having to change any Makefile.
But the moment I paste them into my file.c, "sudo make" gives the error message as following:
/home/adward/linux-3.17.6/fs/myext2/file.c:64:15: error: storage size of ‘kiocb’ isn’t known
struct kiocb kiocb;
^
/home/adward/linux-3.17.6/fs/myext2/file.c:65:18: error: storage size of ‘iter’ isn’t known
struct iov_iter iter;
^
and cc1: some warnings being treated as errors
even if I haven't refered to them by changing the func pointers in file_operations in the same source code file, or say, I haven't used them!
P.S.
My file_operation struct now looks like:
const struct file_operations myext2_file_operations = {
.llseek = generic_file_llseek,
.read = new_sync_read, //want to replace with my_new_sync_read
.write = new_sync_write, //want to replace with my_new_sync_write
...
}
Has anyone who have done something similar and crashed into some problems like this one? Please notify me if I have done something remarkable wrong, thanks.
Met the same error before. U should add <linux/aio.h> as ext2 uses asynchronous IO for reading/writing files.
Hope that helps :)

Is it possible to call Rust's struct fields directly from Ruby code without implementing extern "C" getter to the corresponding fields

I am thinking about writing a Ruby gem with Rust. Lets assume I want to create some structs in Rust which are returned to the Ruby code similar to the example here. While getting the Point struct to my Ruby code, I would like to call its attributes directly. Currently I would have to do something like that:
point.rb:
require "fiddle"
require "fiddle/import"
module RustPoint
extend Fiddle::Importer
dlload "./libmain.dylib"
extern "Point* make_point(int, int)"
extern "double get_distance(Point*, Point*)"
extern "int y(Point*)"
extern "int x(Point*)"
end
main.rs:
use std::num::pow;
pub struct Point { x: int, y: int }
#[no_mangle]
pub extern "C" fn make_point(x: int, y: int) -> Box<Point> {
box Point { x: x, y: y }
}
#[no_mangle]
pub extern "C" fn x(p: &Point) -> int {
p.x
}
#[no_mangle]
pub extern "C" fn y(p: &Point) -> int {
p.y
}
and use this in Ruby:
point = RustPoint::make_point(0, 42)
# To get x:
x = RustPoint::x(point)
to get an x value. I would prefer something like:
point = RustPoint::make_point(0, 42)
# To get x:
x = point.x
Does anyone know a library or a way to get this implemented easier. I think it would be much nicer if i wouldn't see a different regarding the point object from ruby side. i should not make a difference weather this is a C extension, a Ruby object or written in Rust.
Edit: I want the Rust code to behave like a native extension. So the returned struct should be callable from Ruby side similar to a C struct using ruby objects as values. Of course a library would be nessessary to handle the ruby objects in rust code.
You could wrap the whole thing in a custom delegator:
class RustDelegator
attr_accessor :__delegate_class__, :__delegate__
def method_missing(method_name, *arguments, &block)
__delegate_class__.public_send(method_name, *__rust_arguments__(arguments), &block)
end
def respond_to_missing(name, include_private = false)
__delegate_class__.respond_to?(name, include_private)
end
private
def __rust_arguments__(arguments)
arguments.unshift(__delegate__)
end
end
class Point < RustDelegator
def initialize(x, y)
self.__delegate_class__ = RustPoint
self.__delegate__ = RustPoint::make_point(0, 42)
end
end
p = Point.new(0, 42)
#=> #<Point:0x007fb4a4b5b9d0 #__delegate__=[0, 42], #__delegate_class__=RustPoint>
p.x
#=> 0
p.y
#=> 42
Rust provides a native C interface for struct as well. If you define your struct like this:
#[repr(C)]
pub struct Point {
pub x: i32,
pub y: i32
}
It will behave like the C struct
struct Point
{
int32_t x;
int32_t y;
}
You may then use it in Ruby like any other C struct.
I recommend using the fixed size int types rather than plain int, because you have no real guaranty Rust's int are the same size as C's int. If you really need to use it, you should probably use libc::c_int.

Resources