I would like to use an user-editable global variable in the linux kernel. Is that possible?
That's what I came up with using the example provided with the source code:
arch/x86/kernel/foo.c
#include <linux/kobject.h>
#include <linux/string.h>
#include <linux/sysfs.h>
#include <linux/module.h>
#include <linux/init.h>
int foo = 12;
static ssize_t foo_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
return sprintf(buf, "%d\n", foo);
}
static ssize_t foo_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t count)
{
sscanf(buf, "%du", &foo);
return count;
}
static struct kobj_attribute foo_attribute =
__ATTR(foo, 0666, foo_show, foo_store);
static struct attribute *attrs[] = {
&foo_attribute.attr,
NULL,
};
static struct attribute_group attr_group = {
.attrs = attrs,
};
static struct kobject *example_kobj;
static int __init example_init(void)
{
int retval;
example_kobj = kobject_create_and_add("kobject_example", kernel_kobj);
if (!example_kobj)
return -ENOMEM;
retval = sysfs_create_group(example_kobj, &attr_group);
if (retval)
kobject_put(example_kobj);
return retval;
}
static void __exit example_exit(void)
{
kobject_put(example_kobj);
}
module_init(example_init);
module_exit(example_exit);
include/linux/foo.h
#ifndef FOO_H
#define FOO_H
extern unsigned int foo;
#endif
arch/x86/randomfile.c
#include <linux/foo.h>
....
int foobar = ( 12 + foo );
....
I get this
error: initializer element is not constant
which makes me realize I must be doing something really wrong, but as much as I search I can't find anything and I can't figure out how to do it from looking at other implementations in the kernel...
Could someone point me to the right direction, possibly with a practical example?
C global variables must be initialized with values known at compile-time. foo isn't.
As a general rule, it's possible to initialize a global integer with enum values, numeric constants, and mathematical operations on either of them. For instance, this is valid:
enum foo_enum
{
foo = 12
};
int foobar = (12 + foo);
But, obviously, you just lost the ability to change foo at runtime.
If there is a function that is called when the kernel module is loaded (is that what the __init-marked function is?), you can do the initialization there.
Related
this a reproducible example and not the entire code the entire code is too large..
my problem was that i had a structure that i created using malloc and i needed to access it from another function in another file, but i keep getting segfault...
header file
main.h
#ifndef main_a
#define main_a
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct cmd_s
{
int n;
} cmd_t;
extern cmd_t *ptr;
void push(char *line);
#endif
the main.c file
main.c
#include "main.h"
cmd_t *ptr = NULL;
int main(void)
{
cmd_t *ptr = malloc(sizeof(cmd_t));
ptr->n = 5;
push("line");
return (0);
}
and where i need to access the struct from named opcode.c
opcode.c
#include "main.h"
void push(char *line)
{
int new = ptr->n;
}
note that this is not the actual code the actual code has useful values, this is an example that contains the challenge i am facing
i tried to use static instead but i got the same error.
i'm still a novice in c programming..
and i don't want to change the way i created the structure, which is through malloc because another function depends on it... i just need to make that malloced structure accessible to another file in the program.
thanks.
int main(void)
{
cmd_t *ptr = malloc(sizeof(cmd_t));
You create new ptr variable visible only in function main. Your push see the global pointer ptr but not the one you have malloced.
You need to
int main(void)
{
ptr = malloc(sizeof(*ptr));
/* .... */
Use obiects not types in sizeof (as in this example)
I wrote an example of system call hooking from our Linux Kernel module.
Updated open system call in system call table to use my entry point instead of the default.
#include <linux/module.h>
#include <linux/kallsyms.h>
MODULE_LICENSE("GPL");
char *sym_name = "sys_call_table";
typedef asmlinkage long (*sys_call_ptr_t)(const struct pt_regs *);
static sys_call_ptr_t *sys_call_table;
typedef asmlinkage long (*custom_open) (const char __user *filename, int flags, umode_t mode);
custom_open old_open;
static asmlinkage long my_open(const char __user *filename, int flags, umode_t mode)
{
char user_msg[256];
pr_info("%s\n",__func__);
memset(user_msg, 0, sizeof(user_msg));
long copied = strncpy_from_user(user_msg, filename, sizeof(user_msg));
pr_info("copied:%ld\n", copied);
pr_info("%s\n",user_msg);
return old_open(filename, flags, mode);
}
static int __init hello_init(void)
{
sys_call_table = (sys_call_ptr_t *)kallsyms_lookup_name(sym_name);
old_open = (custom_open)sys_call_table[__NR_open];
// Temporarily disable write protection
write_cr0(read_cr0() & (~0x10000));
sys_call_table[__NR_open] = (sys_call_ptr_t)my_open;
// Re-enable write protection
write_cr0(read_cr0() | 0x10000);
return 0;
}
static void __exit hello_exit(void)
{
// Temporarily disable write protection
write_cr0(read_cr0() & (~0x10000));
sys_call_table[__NR_open] = (sys_call_ptr_t)old_open;
// Re-enable write protection
write_cr0(read_cr0() | 0x10000);
}
module_init(hello_init);
module_exit(hello_exit);
I wrote a simple user program to verify.
#define _GNU_SOURCE
#include <sys/syscall.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
int fd = syscall(__NR_open, "hello.txt", O_RDWR|O_CREAT, 0777);
exit(EXIT_SUCCESS);
}
File gets created in my folder, but strncpy_user fails with bad address
[ 927.415905] my_open
[ 927.415906] copied:-14
What is the mistake in the above code?
OP is probably using a kernel/architecture that uses "syscall wrappers" where the system call table contains a wrapper function that calls the real syscall function (possibly as an inline function call). The x86_64 architecture has used syscall wrappers since kernel version 4.17.
For x86_64 on kernel 4.17 or later, sys_call_table[__NR_open] points to __x64_sys_open (with prototype asmlinkage long __x64_sys_open(const struct pt_regs *regs)), which calls static function __se_sys_open (with prototype static long __se_sys_open(const __user *filename, int flags, umode_t mode)), which calls inline function __do_sys_open (with prototype static inline long __do_sys_open(const __user *filename, int flags, umode_t mode). Those will all be defined by the SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode) macro call in "fs/open.c" and the function body that follows the macro call.
SYSCALL_DEFINE3 is defined in "include/linux/syscalls.h" and uses the SYSCALL_DEFINEx macro in the same file, which uses the __SYSCALL_DEFINEx macro. Since x86_64 defines CONFIG_ARCH_HAS_SYSCALL_WRAPPER, the __SYSCALL_DEFINEx macro is defined by #include <asm/syscall_wrapper.h>, which maps to "arch/x86/include/asm/syscall_wrapper.h".
For background on this change, see
LWN: use struct pt_regs based syscall calling for x86-64
LKML: [PATCH 000/109] remove in-kernel calls to syscalls https://lkml.org/lkml/2018/3/29/409
It seems the motivation is to only pass a pointer to pt_regs, instead of having a bunch of user-space values in registers down the call chain. (Perhaps to increase resistance to Spectre attacks by making gadgets less useful?)
Why open still worked, even though the wrapper didn't:
If OP is indeed using x86_64 kernel 4.17 or later, and replacing the sys_call_table[__NR_open] entry with a pointer to a function that uses a different prototype and calls the original function (pointed to by old_open) with the same parameters, that explains why the call to strncpy_from_user(user_msg, filename, sizeof(user_msg)) failed. Although declared as const char * __user filename, the filename pointer is actually pointing to the original struct pt_regs in kernel space.
In the subsequent call to old_open(filename, flags, mode), the first parameter filename is still pointing to the original struct pt_regs so the old function (which expects a single parameter of type struct pt_regs *) still works as expected.
i.e. the function passed on its first pointer arg unchanged, despite calling it a different type.
Update: Below is working code, Thanks everyone for providing inputs
#include <linux/module.h>
#include <linux/kallsyms.h>
MODULE_LICENSE("GPL");
char *sym_name = "sys_call_table";
typedef asmlinkage long (*sys_call_ptr_t)(const struct pt_regs *);
static sys_call_ptr_t *sys_call_table;
sys_call_ptr_t old_open;
static asmlinkage long my_open(const struct pt_regs *regs)
{
char __user *filename = (char *)regs->di;
char user_filename[256] = {0};
long copied = strncpy_from_user(user_filename, filename, sizeof(user_filename));
if (copied > 0)
pr_info("%s filename:%s\n",__func__, user_filename);
return old_open(regs);
}
static int __init hello_init(void)
{
sys_call_table = (sys_call_ptr_t *)kallsyms_lookup_name(sym_name);
old_open = sys_call_table[__NR_open];
// Temporarily disable write protection
write_cr0(read_cr0() & (~0x10000));
sys_call_table[__NR_open] = my_open;
// Re-enable write protection
write_cr0(read_cr0() | 0x10000);
return 0;
}
static void __exit hello_exit(void)
{
// Temporarily disable write protection
write_cr0(read_cr0() & (~0x10000));
sys_call_table[__NR_open] = old_open;
// Re-enable write protection
write_cr0(read_cr0() | 0x10000);
}
module_init(hello_init);
module_exit(hello_exit);
We have a system that relies heavily on loading modules using dlopen(). Our modules are self-describing, with a symbol that points to some metadata relevant to loading the module (description, load order, loading flags, etc.).
We first load the modules specifying the RTLD_LAZY flag to dlopen(), get what we need from the metadata, and then load the modules for real later (after we know what the load order should be, how they should be loaded, etc.).
This has worked pretty well for a while, but we've recently discovered that taking the address of a function requires that the function be resolved at load time. What are some ways we can work around this problem?
I've put together a fairly small example that demonstrates the problem.
/* foo.h */
void foo(void);
/* foo.c */
void foo(void) {}
/* bar.c */
#include "foo.h"
/* Calls foo normally */
void bar(void) { foo(); }
/* bam.c */
#include "foo.h"
static void (*f)(void);
/* Takes the address of foo */
void bam(void) { f = foo; }
/* rtld_lazy.c */
#include <dlfcn.h>
#include <stdio.h>
void check(const char *module) {
void *mod = dlopen(module, RTLD_LAZY);
if (mod) {
printf("%s successfully loaded\n", module);
dlclose(mod);
} else {
printf("%s failed to load: %s\n", module, dlerror());
}
}
int main() {
check("./bar.so");
check("./bam.so");
check("./foo.so");
}
With the following output:
./bar.so successfully loaded
./bam.so failed to load: ./bam.so: undefined symbol: foo
./foo.so successfully loaded
You should use dlsym() to obtain the address of a symbol. See POSIX :
http://pubs.opengroup.org/onlinepubs/009695399/functions/dlsym.html
We've come up with two methods for working around this problem, depending on the situation.
The first is in the caller's module, write a small static wrapper for the function. The static wrapper will dynamically bind to the function in question, and you can take the address of that function without any problems.
/* bam.c */
#include "foo.h"
static void (*f)(void);
static void foo_wrapper(void) { foo(); }
/* Takes the address of foo */
void bam(void) { f = foo_wrapper; }
If you find yourself writing lots of this tiny wrappers, you can instead put a function that returns the function pointer you need into the providing module.
/* foo.h */
void foo(void);
typedef void (*foo_ptr_type)(void);
foo_ptr_type foo_ptr(void);
/* foo.c */
void foo(void) {}
foo_ptr_type foo_ptr(void) { return foo; }
/* bam.c */
#include "foo.h"
static void (*f)(void);
/* Takes the address of foo */
void bam(void) { f = foo_ptr(); }
File api.h
#include <stdio.h>
#ifndef API
#define API
struct trytag;
typedef struct trytag try;
void trial (try *);
#endif
File core.h
#ifndef CORE
#define CORE
struct trytag
{
int a;
int b;
};
#endif
File func.c
#include "api.h"
#include "core.h"
void trial (try *tryvar)
{
tryvar->a = 1;
tryvar->b = 2;
}
File main.c
#include "api.h"
int main ()
{
try s_tryvar;
trial(&s_tryvar);
printf("a = %d\nb = %d\n", s_tryvar.a, s_tryvar.b);
}
When I compile, I get:
main.c:5: error: storage size of ‘s_tryvar’ isn’t known
If I include core.h in main.c this error doesn't come as try is defined in core.h. But I want the structure try to be hidden to main.c — it should not know the members of try structure. What am I missing?
I don't think what you're trying to do is possible. The compiler needs to know how big a try structure is to compile main.c. If you really want it to be opaque, make a generic pointer type, and instead of declaring the variable directly in main(), make alloc_try() and free_try() functions to handle the creation and deletion.
Something like this:
api.h:
#ifndef API
#define API
struct trytag;
typedef struct trytag try;
try *alloc_try(void);
void free_try(try *);
int try_a(try *);
int try_b(try *);
void trial (try *);
#endif
core.h:
#ifndef CORE
#define CORE
struct trytag
{
int a;
int b;
};
#endif
func.c:
#include "api.h"
#include "core.h"
#include <stdlib.h>
try *alloc_try(void)
{
return malloc(sizeof(struct trytag));
}
void free_try(try *t)
{
free(t);
}
int try_a(try *t)
{
return t->a;
}
int try_b(try *t)
{
return t->b;
}
void trial(try *t)
{
t->a = 1;
t->b = 2;
}
main.c:
#include <stdio.h>
#include "api.h"
int main()
{
try *s_tryvar = alloc_try();
trial(s_tryvar);
printf("a = %d\nb = %d\n", try_a(s_tryvar), try_b(s_tryvar));
free_try(s_tryvar);
}
Think how the opaque FILE structure works in C. You only work with pointers, and you need a function like fopen() to create an instance, and a function like fclose() to dispose of it.
The problem is in main.c, the compiler hasn't seen the definition of struct try. Because of that, the compiler is limited to using pointers to struct try.
What you want to do is add two new functions to your API:
try *create_try();
void *destroy_try(try *t);
These functions will call malloc and free respectively.
If you don't want to limit your structure to only being allowed on the heap, you are going to have to give up on making it opaque.
There is a way to do something that technically is not exactly what you are asking for, but should serve the same purpose of keeping your structure opaque while supporting non-heap allocation.
in api.h, you state an opaque structure as follows:
struct trytag_opaque
{
char data[sizeof(int)*2];
};
if you wanted to be more opaque than that, you could calculate the maximum size of the structure required across any supported platform, and use:
struct trytag_opaque
{
char data[MAX_TRYTAG_SIZE];
};
Then your api.h function declarations would look like:
int try_a(struct trytag_opaque *t)
and your function code would look like:
int try_a(struct trytag_opaque *t_opaque) {
trytag *t = (trytag *)t_opaque;
...
}
and your main.c would look like:
#include "api.h"
int main() {
struct trytag_opaque t;
...
try_a(&t);
...
}
I’m trying to figure out a way to use nested global structs as a sort of API namespacing for my C library.
Specifically, I want to expose a single Primary ‘namespacing struct,’ that contains other such structs (such as Primary.Secondary), that themselves contain function pointers (Primary.Secondary.a_function()).
I’ve abstracted out the following (relatively) simple example of what I want to do:
main.c:
#include "Primary.h"
int main () {
Primary.Secondary.a_function();
return 0;
}
Primary.h:
#if !defined(SECONDARY_H)
# include "Secondary.h"
#endif
struct Primary_struct {
struct Primary__Secondary_struct Secondary;
} extern Primary;
Primary.c:
#include "Primary.h"
struct Primary_struct Primary = {
.Secondary = Primary__Secondary
};
Secondary.h:
struct Primary__Secondary_struct {
void (*a_function) (void);
void (*another_function) (void);
} extern Primary__Secondary;
Secondary.c:
#include "Secondary.h"
#include <stdio.h>
void Primary__Secondary__a_function (void);
void Primary__Secondary__another_function (void);
struct Primary__Secondary_struct {
.a_function = Primary__Secondary__a_function,
.another_function = Primary__Secondary__another_function
} extern Primary__Secondary;
void Primary__Secondary__a_function(void) {
Primary.Secondary.another_function();
}
void Primary__Secondary__another_function(void) {
printf("run!\n");
}
When I attempt to compile this, I run into the following compiler error:
> C -O0 Primary.c Secondary.c main.c
Primary.c:3:33: error: initializer element is not a compile-time constant
struct Primary_struct Primary = {
^
1 diagnostic generated.
I should note, ideally, both the Primary and Primary__Secondary variables would be const. I was worried that the added complexity would exacerbate the problem… so for now, I’ve left that aspect out.
The problem seems to be that, for some reason, even when set as const, and containing only elements present at compile time, the Primary__Secondary struct is not a compile-time constant, and thus cannot be stored in another struct at compile-time. I can probably work around this by setting up all of the interfaces at runtime, but… that seems like a really hacky solution. I’m looking for any alternative solutions to this problem, that the more C-fu of you than I can come up with.
(Note: This is related to this question, but is substantially different, and quite a bit more specific.)
What you're trying can't be done; sorry. Here's a condensed example:
#include <stdio.h>
int a = 5;
int b = a;
int main(int argc, char *argv[])
{
printf("Hello, world!\n");
return 0;
}
Compiling this code gives the error:
main.c:4: error: initializer element is not constant
Because the compiler doesn't know how to make the assignment int b = a at compile time. It's just the way the language works!
You had some odd notations in your code - I've converted them to a more orthodox form. Also, as a general rule, avoid using double-underscore in names; in C++ this is absolutely necessary.
You also need to use a pointer to the embedded structure - then the code will run:
Primary.h
//Primary.h:
#ifndef PRIMARY_H
#define PRIMARY_H
#include "Secondary.h"
struct Primary_struct {
struct Primary_Secondary_struct *Secondary;
};
extern struct Primary_struct Primary;
#endif // PRIMARY_H
Secondary.h
//Secondary.h:
#ifndef SECONDARY_H
#define SECONDARY_H
struct Primary_Secondary_struct {
void (*a_function)(void);
void (*another_function)(void);
};
extern struct Primary_Secondary_struct Primary_Secondary;
#endif // SECONDARY_H
Primary.c
//Primary.c:
#include "Primary.h"
struct Primary_struct Primary = {
.Secondary = &Primary_Secondary
};
Secondary.c
//Secondary.c:
#include "Secondary.h"
#include "Primary.h"
#include <stdio.h>
void Primary_Secondary_a_function(void);
void Primary_Secondary_another_function(void);
struct Primary_Secondary_struct Primary_Secondary = {
.a_function = Primary_Secondary_a_function,
.another_function = Primary_Secondary_another_function
};
void Primary_Secondary_a_function(void) {
Primary_Secondary.another_function();
printf("hide!\n");
}
void Primary_Secondary_another_function(void) {
printf("run!\n");
}
main.c
//main.c:
#include "Primary.h"
int main () {
Primary.Secondary->a_function();
return 0;
}
This generates:
run!
hide!
I ended up going with a runtime approach, at least for now. I might try a pointers approach (suggested by Jonathan Leffler above) later on, and see if I end up with a less complex / more comprehensible codebase… but this works for now.
I use clang (and gcc)’s __attribute__((constructor)) extension to set up the structs’ relationships at runtime; the same could be achieved more portably (but less cleanly) with some code in main().
I’d offer a little more explanation, but it’s 4AM here… heh. I’ve spent all day on this >,<
main.c:
#include "Package.h"
int main () {
Package.One.a_function();
Package.One.another_function();
Package.Two.a_function();
Package.Two.another_function();
return 0;
}
Package.h:
#define PACKAGE_H
#if !defined(ONE_H)
# include "One.h"
#endif
#if !defined(TWO_H)
# include "Two.h"
#endif
// It seems this is broken, at least in `clang`
// #if __has_feature(attribute_constructor)
# define constructor __attribute__((constructor))
// #endif
struct Package_struct {
struct Package__One_struct One;
struct Package__Two_struct Two;
};
struct Package_struct extern Package;
Package.c:
#include "Package.h"
struct Package_struct Package = {};
One.h:
#define ONE_H
struct Package__One_struct {
void (*a_function) (void);
void (*another_function) (void);
};
struct Package__One_struct extern Package__One;
One.c:
#include "One.h"
#include "Package.h"
#include <stdio.h>
void Package__One__a_function (void);
void Package__One__another_function (void);
struct Package__One_struct Package__One = {
.a_function = Package__One__a_function,
.another_function = Package__One__another_function
};
void constructor Package__register_One(void) {
Package.One = Package__One; }
void Package__One__a_function(void) {
Package.One.another_function();
}
void Package__One__another_function(void) {
printf("one!\n");
}
Two.h:
#define TWO_H
struct Package__Two_struct {
void (*a_function) (void);
void (*another_function) (void);
};
struct Package__Two_struct extern Package__Two;
Two.c:
#include "Two.h"
#include "Package.h"
#include <stdio.h>
void Package__Two__a_function (void);
void Package__Two__another_function (void);
struct Package__Two_struct Package__Two = {
.a_function = Package__Two__a_function,
.another_function = Package__Two__another_function
};
void constructor Package__register_Two(void) {
Package.Two = Package__Two; }
void Package__Two__a_function(void) {
Package.Two.another_function();
}
void Package__Two__another_function(void) {
printf("two!\n");
}