What would perror() be in the kernel? I can't tell what the error codes are from the error values ,i.e -22 alone.
The Linux kernel just uses negated errno codes as a convention. So look in asm-generic/errno-base.h or asm-generic/errno.h and find...
#define EINVAL 22 /* Invalid argument */
This can happen if you pass NULL to a function that doesn't accept NULL, for example. It depends on the function.
I know the question is old but I came across it and I found a workaround which is a little more satisfying than the accepted answer.
It's true there's no actual perror but errors can be printed in a nicer way (https://www.kernel.org/doc/html/latest/core-api/printk-formats.html#error-pointers). All we need to do is to supply the error pointer or convert it with the ERR_PTR function if we have a numeric value (basically just a cast) and we are settled.
One could then print the error directly or create their own perror as in the example:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#define MYPERROR(str, err) printk(str ": %pe\n", ERR_PTR(error))
static int __init mymodule_init(void) {
int error = -22;
printk("The error is %pe\n", ERR_PTR(error));
MYPERROR("Failure", error);
return 0;
}
static void __exit mymodule_exit(void) {
}
module_init(mymodule_init);
module_exit(mymodule_exit);
MODULE_LICENSE("GPL");
Related
I would like to write some code (for example as a small kernel module) to instrument local interrupts on Linux running on the x86-64 architecture, i.e. I would like to write some kind of handler that is called by the kernel every time a local interrupt is triggered by the APIC.
The handler would then check whether a certain process is currently running and inspect said process' memory.
I realize that what I am trying to do may not be good engineering practice, but my aim is to create a hacky one-off solution for exploration/research purposes.
In the ideal case, there would be some kind of function similar to request_irq [1] (which as far as I can tell is used for handling interrupts from devices like keyboards, network cards, ...) allowing me to tell the kernel to run my code every time a local timer interrupt occurs.
Does anybody have any pointers on how to accomplish this?
Does the kernel provide an API for registering a handler for local interrupts?
If not, I could directly modify the kernel's source code for handling interrupts. Where in the kernel would I find this code?
Edit: Here is what my research so far has found.
TLDR:request_irq is not the way to hook local timer interrupts.
According to Understanding the Linux Kernel, Table 4.2 [2], the interrupt vector 0xef is allocated to Local APIC timer interrupts. The kernel source confirms this [3].
Since request_irq takes an interrupt vector as its first argument, let's try registering a handler for this vector inside a kernel module:
#include <linux/module.h>
#include <linux/kernel.h> // included for KERN_INFO
#include <linux/init.h> // included for __init and __exit macros
#include <linux/interrupt.h> // included for IRQF_ and request_irq
#include <linux/irqreturn.h> // included for IRQ_NONE
#include <asm/irq_vectors.h> // included for LOCAL_TIMER_VECTOR
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Instrument local timer interrupts");
static int DEVICE_COOKIE = 1;
static int count = 0;
static irqreturn_t handler(int irq, void *dev) {
count++;
return IRQ_NONE;
}
static int __init test_init(void) {
int status;
printk(KERN_INFO "Running request_irq\n");
status = request_irq(
LOCAL_TIMER_VECTOR,
&handler,
IRQF_TIMER,
"foobar",
&DEVICE_COOKIE);
if (status == 0) {
printk(KERN_INFO "Successfully installed handler\n");
return 0;
} else {
printk(
KERN_INFO "Failed to install handler. error code: %d\n",
status);
return -1;
}
}
static void __exit test_cleanup(void) {
free_irq(LOCAL_TIMER_VECTOR, &DEVICE_COOKIE);
printk(KERN_INFO "Goodbye kernel. I saw %d interrupts.\n", count);
}
module_init(test_init);
module_exit(test_cleanup);
When we try to insert the module with insmod, request_irq returns -EINVAL:
[74890.287173] Running request_irq
[74890.287174] Failed to install handler. error code: -22
So where does the -EINVAL come from?
Reading through the kernel source, we find that request_irq is just a wrapper around request_threaded_irq [4]. request_threaded_irq calls irq_to_desc and returns -EINVAL if the call fails. We can easily check whether this is the case with another small kernel module:
#include <linux/kernel.h> // included for KERN_INFO
#include <linux/init.h> // included for __init and __exit macros
#include <linux/interrupt.h> // included for IRQF_ and request_irq
#include <linux/irqreturn.h> // included for IRQ_NONE
#include <asm/irq_vectors.h> // included for LOCAL_TIMER_VECTOR
#include <linux/irqnr.h> // included for irq_to-desc
#include <linux/irqdesc.h> // included for irq_desc
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Call irq_to_desc(LOCAL_TIMER_VECTOR)");
static int __init test_init(void) {
struct irq_desc *desc;
desc = irq_to_desc(LOCAL_TIMER_VECTOR);
if (!desc) {
printk(KERN_INFO "irq_to_desc(LOCAL_TIMER_VECTOR) failed");
return -1;
}
return 0;
}
static void __exit test_cleanup(void) {
}
module_init(test_init);
module_exit(test_cleanup);
And indeed it fails:
[75787.142533] irq_to_desc(LOCAL_TIMER_VECTOR) failed
[1] www.makelinux.net/books/lkd2/ch06lev1sec3
[2] www.safaribooksonline.com/library/view/understanding-the-linux/0596005652/ch04s06.html
[3] lxr.free-electrons.com/source/arch/x86/include/asm/irq_vectors.h?v=4.8#L108
[4] lxr.free-electrons.com/source/kernel/irq/manage.c?v=4.8#L1634
For a homework assignment, I have to modify the linux kernel.
I am working on a virtual machine, and I added a system call to the kernel, which I called get_unique_id. Here is the code for get_unique_id.c :
#include <linux/linkage.h>
#include <asm/uaccess.h>
asmlinkage long sys_get_unique_id(int * uuid)
{
// static because we want its state to persist between calls
static int uid = 0;
++uid;
// assign new uid value to user-provided mem location
// returns non-zero if success or -EFAULT otherwise
int ret = put_user(uid, uuid);
return ret;
}
I also added this line to syscalls.h :
asmlinkage long sys_get_unique_id(int * uuid);
This line to syscall_32.tbl :
383 i386 get_unique_id sys_get_unique_id
And finally this line to syscall_64.tbl :
548 common get_unique_id sys_get_unique_id
After recompiling and reloading the kernel, I wrote a little C program to test my system call, here is the code for the C test file :
// get_unique_id_test.c
#include <stdio.h>
#include <limits.h>
#include "syscalls_test.h"
int main(void)
{
// initialize the ints we want
int id1;
int id2;
// check the id's are unique and that no error occured
for (int i = INT_MIN; i < INT_MAX - 1; i += 2) {
long ret1 = get_unique_id(&id1);
long ret2 = get_unique_id(&id2);
if (ret1 != 0)
printf("ERROR: get_unique_id returned: %ld\n", ret1);
if (ret2 != 0)
printf("ERROR: get_unique_id returned: %ld\n", ret2);
if (id2 != id1 + 1)
printf("ERROR: successive id's did not increment properly: id1 = %d, id2 = %d\n", id1, id2);
}
return 0;
}
And its header file :
// syscalls_test.h
#include <errno.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#define __NR_get_unique_id 383
inline long get_unique_id(int * uuid)
{
return syscall(__NR_get_unique_id, uuid) ? errno : 0;
}
Unfortunately, while trying to compile the C test file with the following command : gcc -std=c99 get_unique_id_test.c -o get_unique_id_test, I get the following error :
In file included from get_unique_id_test.c:4:0:
syscalls_test.h: In function ‘get_unique_id’:
syscalls_test.h:10:5: warning: implicit declaration of function ‘syscall’ [-Wimplicit-function-declaration]
return syscall(__NR_get_unique_id, uuid) ? errno : 0;
^
syscalls_test.h: In function ‘get_unique_id’:
syscalls_test.h:10:5: warning: implicit declaration of function ‘syscall’ [-Wimplicit-function-declaration]
return syscall(__NR_get_unique_id, uuid) ? errno : 0;
^
/tmp/cc1euZ3r.o: In function `main':
get_unique_id_test.c:(.text+0x22): undefined reference to `get_unique_id'
get_unique_id_test.c:(.text+0x34): undefined reference to `get_unique_id'
collect2: error: ld returned 1 exit status
It appears gcc cannot find the function get_unique_id(int * uuid), which is declared in syscalls_test.h, and the syscall function, which should be declared, I believe, in syscall.h, right ?
I don't understand why this happens. Does anybody have an idea ?
EDIT : my problems were solved using a3f's solution (see below) PLUS moving the #include "syscalls_test.h" at the very top of the file, as he said in the comments. Thank you very much.
#define _GNU_SOURCE before including unistd.h or any other header as syscall(2) is not POSIX.
Use static inline instead of plain inline. Plain inline supplies an inline definition, but the compiler is free to ignore it and use the external definition instead, which you aren't providing.
Try the following one:
#include <unistd.h>
I am learning C.
In this program
I use sleep function to slowdown a count down.
My text book doesn't specify a library I should include to use the sleep function.
So I use it without including any special library for it and it works.
But it gives me this warning message in codeblocks.
I tried to include <windows.h> but still the same warning message appears.
warning D:\Project\C language\trial8\trial8.c|19|warning: implicit
declaration of function `sleep'|
And here is my code.
#include <stdio.h>
int main()
{
int start;
do
{
printf("Please enter the number to start\n");
printf("the countdown (1 to 100):");
scanf("%d",&start);
}
while(start<1 || start>100);
do
{
printf("T-minus %d\n",start);
start--;
sleep(3000);
}
while(start>0);
printf("Zero!\n Go!\n");
return(0);
}
I want to know what does the warning message mean? How important is it? Is there anything that I should do about it? Note that the program works anyway.
The issue is in the libraries (header files):
on Windows:
#include <windows.h> and Sleep(1000); => 1000 milliseconds
on Linux:
#include <unistd.h> and sleep(1); => 1 second
The function sleep is not part of C programming language. So, C compiler needs a declaration/prototype of it so that it can get to know about about number of arguments and their data types and return data type of the function. When it doesn't find it, it creates an Implicit Declaration of that function.
In Linux, sleep has a prototype in <unistd.h> and in windows, there is another function Sleep which has a prototype in <windows.h> or <synchapi.h>.
You can always get away with including header, if you explicitly supply the prototype of the function before using it. It is useful when you need only few functions from a header file.
The prototype of Sleep function in C on windows is:
VOID WINAPI Sleep(_In_ DWORD dwMilliseconds);
Remember, it is always a good practice to supply the prototype of the function being used either by including the appropriate header file or by explicitly writing it. Even, if you don't supply it, compiler will just throw a warning most of the time and it will make an assumption which in most cases will be something that you don't want. It is better to include the header file as API might change in future versions of the Library.
Windows doesn't have the sleep function. Instead, it has Sleep, which takes the number of milliseconds to sleep:
VOID WINAPI Sleep(
_In_ DWORD dwMilliseconds
);
You'll need to either #include <windows.h> or #include <synchapi.h>, depending on the version of Windows you're running. See MSDN for more details.
Update in 2022:
As it is stated on the Linux man page here we need to include unistd.h and should do fine for all OS.
#include <stdio.h>
#include <unistd.h>
int main()
{
sleep(1); /* sleep for 1 second*/
printf("END\n");
return 0;
}
To make it more cross-platform, try this:
#ifdef _WIN32
#include <Windows.h>
#else
#include <unistd.h>
#endif
I am working out of the 2nd edition of Jon Erickson's "Hacking: The Art of Exploitation" using a VM (virutalbox) to run the LiveCD it came with (Ubuntu 7.04). In section 0x281 "File Access", the author explains accessing files through file descriptors, as well as the open() close() read() and write() functions, using an example on pages 82-84.
The code for the simplenote.c is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
void usage(char *prog_name,char *filename){
printf("Usage: %s < data to add to %s>\n",prog_name,filename);
exit(0);
}
void fatal(char *);
void *ec_malloc(unsigned int );
int main(int argc,char *argv[]){
int fd; //file descriptor
char *buffer,*datafile;
buffer = (char *)ec_malloc(100);
datafile = (char *)ec_malloc(20);
strcpy(datafile,"/tmp/notes");
if(argc < 2)
usage(argv[0],datafile);
strcpy(buffer,argv[1]);
printf("[DEBUG] buffer # %p:\'%s'\n",buffer,buffer);
printf("[DEBUG] datafile # %p:\'%s'\n",datafile,datafile);
strncat(buffer,"\n",1);//Add a newline on the end.
fd = open(datafile,O_WRONLY|O_CREAT|O_APPEND,S_IRUSR|S_IWUSR);
if(fd == -1)
fatal("in main() while opening file");
printf("[DEBUG] file descriptor is %d\n",fd);
//Writing data
if(write(fd,buffer,strlen(buffer)) == -1)
fatal("in main() while writing buffer to file");
//Closing file
if(close(fd) == -1)
fatal("in main() while closing file");
printf("Note has been saved.\n");
free(buffer);
free(datafile);
}
//A function to display an error message and then exit
void fatal(char *message){
char error_message[100];
strcpy(error_message,"[!!]Fatal Error");
strncat(error_message,message,83);
perror(error_message);
exit(-1);
}
//An error-checked malloc() wrapper function
void *ec_malloc(unsigned int size){
void *ptr;
ptr = malloc(size);
if(ptr == NULL)
fatal("in ec_malloc() on memory allocation");
return ptr;
}
However, when I type the following instructions stated in the book into my terminal window, it returns the following error message:
reader#hacking:~/booksrc $ gcc -o simplenote simplenote.c
In file included from /usr/include/sys/stat.h:105, from simplenote.c:6:
/usr/include/bits/stat.h:70: error: field 'st_atim' has incomplete type
/usr/include/bits/stat.h:71: error: field 'st_mtim' has incomplete type
/usr/include/bits/stat.h:72: error: field 'st_ctim' has incomplete type
simplenote.c: In function 'main':
simplenote.c:35: error: 'O-WRONLY' undeclared (first use in this function)
simplenote.c:35: error: (Each undeclared identifier is reported only once
simplenote.c:35: error: for each function it appears in.)
simplenote.c:35: error: 'O_CREAT' undeclared (first use in this function)
simplenote.c:35: error: 'O_APPEND' undeclared (first use in this function)
Here is sys/stat.h line 105:
#include <bits/stat.h>
And here is bits/stat.h lines 63-83:
#ifdef __USE_MISC
/* Nanosecond resolution timestamps are stored in a format
equivalent to 'struct timespec'. This is the type used
whenever possible but the Unix namespace rules do not allow the
identifier 'timespec' to appear in the <sys/stat.h> header.
Therefore we have to handle the use of this header in strictly
standard-compliant sources special. */
struct timespec st_atim; /* Time of last access. */
struct timespec st_mtim; /* Time of last modification. */
struct timespec st_ctim; /* Time of last status change. */
# define st_atime st_atim.tv_sec /* Backward compatibility */
# define st_mtime st_mtim.tv_sec
# define st_ctime st_ctim.tv_sec
#else
__time_t st_atime; /* Time of last access. */
unsigned long int st_atimensec; /* Nscecs of last access. */
__time_t st_mtime; /* Time of last modification. */
unsigned long int st_mtimensec; /* Nsecs of last modification. */
__time_t st_ctime; /* Time of last status change. */
unsigned long int st_ctimensec; /* Nsecs of last status change. */
#endif
I suppose this might be of some use for the first set of issues:
C++ system file bits/stat.h suddenly breaks with "error: field ‘st_atim’ has incomplete type"
/usr/include/time.h
cat time.h
doesn't do anything in my terminal window.
And here is the simplenote.c main function lines 1-6, 34-35:
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
// Opening the file
fd = open(datafile, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR);
I'm guessing the open function problems stem from fcntl.h ?
I seem to keep running into issues because of faulty code the author provided. I don't want to constantly depend on the stackoverflow community for help, so what suggestions do you have for a novice about examining and fixing these problems in the future?
Thanks.
Transferring a selection of comments into a semi-coherent answer.
You should probably explicitly enable POSIX definitions. Add -D_XOPEN_SOURCE=700 to the command line, or #define _XOPEN_SOURCE 700 before the first #include and see if that solves anything. You should not be running into the problem though; the header should be self-contained.
Oh, but Ubuntu 7.04 is archaic…you may need to use 600 instead of 700. When was it released (when was the book published)? If it was 2009 or before, you probably need the older version (600). It's still surprising that you're seeing the error. The command line you specify doesn't contain the options that normally cause trouble (-ansi -pedantic, for example, or -std=c99 -pedantic). You could try using -std=gnu99 too; it might work better.
You had a similar problem recently (gcc -o stdlib.h syntax error c Hacking the Art of Exploitation). Did you get that resolved? It sounds as if the compilation system on the Live CD is not self-coherent, or the way you're able to use it means that it is not behaving self-coherently. Are you sure the compilation system works? It appears to be semi-defunct. Is it using the wrong headers, somehow?
I was able to resolve the previous problem by inserting #include <stdint.h> before #include <stdlib.h>
I will try the -D_XOPEN_SOURCE=600 and get back to you. Something must be wrong with the compilation system.
Well, you might need to include <time.h> (or possibly <sys/time.h>) before <sys/stat.h>, but the <sys/stat.h> header is broken if that works. And the <stdlib.h> header is broken if you have to include <stdint.h> before including it. I suppose Ubuntu 7.04 could be so old that you're supposed to #include <sys/types.h> before many of these headers, but that's still not an excuse for <stdlib.h>; that should be self-contained. POSIX 1997 required #include <sys/types.h> before <sys/stat.h>; POSIX 2004 did not. And I don't think Ubuntu 7.04 is quite that old.
Note, though, that the st_atim member is new; it was added to POSIX 2008 (and hence is in POSIX 2013). It was just st_atime before (and st_atime is now a macro for st_atim.tv_sec).
Including the -D_XOPEN_SOURCE=600 dealt with the bits stat issue. Ubuntu 7.04 was released in 2007 and the 2nd edition of the book that I am using came out in 2008. Also, not sure if this is of use, but in another previous example that included both <stdio.h> and <string.h> (as opposed to only <stdio.h>), the code would run fine without any intervention.
Interesting…it is going to make life interesting for you, in a way that life should not need to be interesting. (Chinese curses like "May you live in interesting times" spring to mind.) Use the -DXOPEN_SOURCE=600 option in all your compilations and keep your fingers crossed; that may well resolve most of your problems. Consider using -std=gnu99 as well, or instead. With luck, either or both of those should get you around most problems.
In case someone else is having the same issue with this book, I downloaded the iso file from hacking-live-1.0.iso.
Created a bootable usb and all works just fine without corrupted headers or anything.
I am writing a simple kernel module, which could register an interrupt and handle it.
However, when I try to register interrupt by calling the request_irq function,
it returns error code -22 :
ERROR: Cannot request IRQ 30 - code -22 , EIO 5 , EINVAL 22
I believe, this error code is equal to EINVAL (invalid argument)
Please tell me, what I am doing wrong. Here is a module:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/irqdomain.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <asm/exception.h>
#include <asm/mach/irq.h>
void int068_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
printk("Interrupt should be handled there\n");
}
static int __init
clcdint_init(void)
{
unsigned int irq;
unsigned int irqflags;
int ret;
irq=68;
irqflags=IRQF_SHARED | IRQF_NO_SUSPEND;
ret = request_irq(irq, int068_interrupt,
irqflags, "clcdint-int068", NULL);
if (ret!=0) {
printk("ERROR: Cannot request IRQ %d", irq);
printk(" - code %d , EIO %d , EINVAL %d\n", ret, EIO, EINVAL);
}
printk("CLCDINT_INIT\n");
return 0;
}
module_init(clcdint_init);
static void __exit
clcdint_exit(void)
{
unsigned int irq;
irq=68;
free_irq(irq, NULL);
printk("CLCDINT_EXIT\n");
}
module_exit(clcdint_exit);
You can't pass a NULL context (last parameters of the request_irq() call) when dealing with a shared interrupt line (IRQF_SHARED flag is on).
To understand why consider the following scenario: you have two identical network cards sharing the same IRQ. The same driver will pass the same interrupt handler function, the same irq number and the same description. There is no way to distinguish the two instances of the registration except via the context parameter.
Therefore, as a precaution, you can't pass a NULL context parameter if you pass the IRQF_SHARED flag.
irqflags has a type of unsigned int, but originally it had type long.
Try the following statement, it will definitely work:
request_irq(irq, int068_interrupt,IRQF_SHARED | IRQF_NO_SUSPEND, "clcdint-int068", NULL);