warning "errno" undefined in kernel module [duplicate] - c

This question already has answers here:
Linux syscalls and errno
(4 answers)
Closed 2 years ago.
I'm writing a kernel module, and I need to use the errno variable.
I included <linux/errno.h> with no problems, and added extern int errno;,
to my code.
I use the variable in the following way: errno = ENOENT;.
When I compile the program I get the following warning, and I cannot load the module:
WARNING: "errno" [module path] undefined!
Why is that happening?
I am using a VM of Ubuntu 12.0.4
EDIT:
My hooked open syscall looks like this:
asmlinkage int hooked_open(char* path, int flags){
if(strstr(path, file_to_hide) != NULL){
return -ENOENT;
}
return original_open(path, flags);
}
When running strace cat file_to_hide when the module is loaded the return value is 4294967294, no error.
When running strace on a file that does not exist, return value is -1 and ENOENT is raised. I would like to be able to imitate that.

From man page of errno:
errno is defined by the ISO C standard to be a modifiable lvalue of type int, and must not be explicitly declared;
On some ancient systems, <errno.h> was not present or did not
declare errno, so that it was necessary to declare errno manually
(i.e., extern int errno). Do not do this. It long ago ceased to
be necessary, and it will cause problems with modern versions of
the C library.
There is no need to explicitly declare errno.

Related

Calling readline() makes errno 2 in C. Does anyone know about this?

While testing my code, I have found out readline makes errno 2. This is ENOENT which means No such file or directory.
Does anyone know why??
#include <readline/readline.h>
#include <stdio.h>
#include <errno.h>
int main()
{
char *a = readline("shell$");
printf("%d\n", errno);
while (a)
{
printf("%s\n", a);
readline("shell$");
}
}
Do I have to set errno to 2 after readline? or Is it an error?
its in Macos
compiled with this comm -> gcc -lreadline main.c
Since I am using the Mac which is provided from a kind of institution, I don't have super privileges. Maybe could it cause the error? permission thing?
If a function does not return error value (or otherwise indicate there was an error), then, generally speaking, valuenof errno is not set or reset by it.
So probably some operation done by readline had an error, but it was recoverable and readline succeeded and did not touch errno itself.
So, before checking errno, you have to check if the function failed (or otherwise is documented to set errno in some specific way), usually by checking the return value.

How do the err/warn functions get the program name?

From the err/warn manpage:
The err() and warn() family of functions display a formatted error
message on the standard error output. In all cases, the last component
of the program name, a colon character, and a space are output. If the
fmt argument is not NULL, the printf(3)-like formatted error message is
output.
If I make this call: warn("message"); it will output something like this:
a.out: message: (output of strerror here)
How do the warn/err functions find the name of the program (in this case, a.out) without seemingly having any access to argv at all? Does it have anything to do with the fact that they are BSD extensions?
The err/warn functions prepend the basename of the program name. According to the answers to this SO post, there are a few ways to get the program name without access to argv.
One way is to call readlink on /proc/self/exe, then call basename on that. A simple program that demonstrates this:
#include <libgen.h>
#include <linux/limits.h>
#include <stdio.h>
#include <unistd.h>
char *
progname(void)
{
char path[PATH_MAX];
if (readlink("/proc/self/exe", path, PATH_MAX) == -1)
return NULL;
/* not sure if a basename-returned string should be
* modified, maybe don't use this in production */
return basename(path);
}
int
main(void)
{
printf("%s: this is my fancy warn message!\n", progname());
return 0;
}
You can also use the nonstandard variables __progname, which may not work depending on your compiler, and program_invocation_short_name, which is a GNU extension defined in errno.h.
In pure standard C, there's no way to get the program name passed as argv[0] without getting it, directly or indirectly, from main. You can pass it as an argument to functions, or save it in a global variable.
But system functions also have the option of using system-specific methods. On open-source operating system, you can download the source code and see how it's done. For Unix-like systems, that's libc.
For example, on FreeBSD:
The warn and err functions call the internal system function _getprogname().
_getprogname() reads the global variable __progname.
__progname is set in handle_argv which is called from _start(). This code is not in libc, but in CSU, which is a separate library containing program startup code.
_start() is the program's entry point. It's defined in the architecture-specific crt1*.c. It's also the function that calls main, and it passes the same argv to both handle_argv() and main().
_start is the first C function called in the program. It's called from assembly code that reads the argv pointer from the stack.
The program arguments are copied into the program's address space by the kernel as part of the implementation of the execve system call.
Note that there are several concepts of “program name” and they aren't always equivalent. See Finding current executable's path without /proc/self/exe for a discussion of the topic.
How do the warn/err functions find the name of the program (in this case, a.out) without seemingly having any access to argv at all? Does it have anything to do with the fact that they are BSD extensions?
Such things can easily be figured out using the strace utility, which records all system calls.
I wrote the highly complex program test.c:
#include <err.h>
int main() { warn("foo"); }
and gcc -o test -static test.c; strace ./test yields (the -static to avoid the noise from trying to load a lot of libraries):
execve("./test", ["./test"], 0x7fffcbb7fd60 /* 101 vars */) = 0
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffd388d6540) = -1 EINVAL (Invalid argument)
brk(NULL) = 0x201e000
brk(0x201edc0) = 0x201edc0
arch_prctl(ARCH_SET_FS, 0x201e3c0) = 0
set_tid_address(0x201e690) = 55889
set_robust_list(0x201e6a0, 24) = 0
uname({sysname="Linux", nodename="workhorse", ...}) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
readlink("/proc/self/exe", "/tmp/test", 4096) = 9
getrandom("\x43\xff\x90\x4b\xa8\x82\x38\xdd", 8, GRND_NONBLOCK) = 8
brk(0x203fdc0) = 0x203fdc0
brk(0x2040000) = 0x2040000
mprotect(0x4b6000, 16384, PROT_READ) = 0
write(2, "test: ", 6) = 6
write(2, "foo", 3) = 3
write(2, ": Success\n", 10) = 10
exit_group(0) = ?
+++ exited with 0 +++
And there you have it: you can just readlink /proc/self/exe to know what you're called.

What is a deprecated warning?

I am writing a packet sniffer using c and libpcap functions. following is the source code.
#include <pcap.h>
#include <stdlib.h>
#include <stdio.h>
#include "YYY.h"
void pcap_fatal(const char *failed_in, const char *errbuf){
printf("Fata Error in %s: %s\n", failed_in, errbuf);
exit(1);
}
int main(){
struct pcap_pkthdr header;
const u_char *packet;
char errbuf[PCAP_ERRBUF_SIZE];
char *device;
pcap_t *pcap_handle;
int i;
device = pcap_lookupdev(errbuf);
if(device == NULL)
pcap_fatal("pcap_lookupdev", errbuf);
printf("Sniffing of device %s\n", device);
pcap_handle = pcap_open_live(device, 4096, 1, 0, errbuf);
for(i=0;i<3;i++){
packet = pcap_next(pcap_handle, &header);
printf("Got a %d bute packet\n", header.len);
dump(packet, header.len);
}
pcap_close(pcap_handle);
}
However when I tried to compile it with gcc it gives the following warning as follows.
libcap_sniff.c: In function ‘main’:
libcap_sniff.c:20:2: warning: ‘pcap_lookupdev’ is deprecated: use 'pcap_findalldevs' and use the first device [-Wdeprecated-declarations]
20 | device = pcap_lookupdev(errbuf);
| ^~~~~~
In file included from /usr/include/pcap.h:43,
from libcap_sniff.c:1:
/usr/include/pcap/pcap.h:394:16: note: declared here
394 | PCAP_API char *pcap_lookupdev(char *)
| ^~~~~~~~~~~~~~
can anyone help me with this. I don't yet know what a deprecated warnning is.
Use pcap_findalldevs instead of pcap_lookupdev.
Deprecating software means that it may be usable but is regarded as obsolete and that it should be avoided. Usually deprecated software has been replaced by an alternative.
GCC has features for marking functions has deprecated. When a program uses a function that is marked as deprecated, GCC warns you about it, so that you can modify the code to use more modern functions. Deprecated functions may be removed in future versions of the software they are part of.
This documentation indicates that you can use pcap_findalldevs to perform the function of the pcap_lookupdev routine.
gcc has a non-standard extension called function attributes which can be used for all manner of things, such as inlining or declaring functions in a certain memory section. They are used by writing __attribute__ (arg) after a function declaration (not after a function definition).
One of these attributes is called deprecated, which tells gcc to give the application programmer a warning about an obsolete function getting called. Optionally, deprecated can be given a message argument. Example:
#include <stdio.h>
void foo (void) __attribute__((deprecated("consider using bar instead")));
void foo (void)
{
puts("foo");
}
int main (void)
{
foo();
}
This gives:
warning: 'foo' is deprecated: consider using bar instead [-Wdeprecated-declarations]
foo();
This warning is enabled by default. To shut it up, one needs to explicitly use the compiler option -Wno-deprecated-declarations.
As for why your specific function is deprecated, you have to consult the (lacking) documentation for it. man doesn't mention why it is deprecated.
Beware: the beginning of the question is about the generic warning. The correct answer to the actual question is later in the post.
Although the standard only defines the #error directive, most common implementations accepts a non fatal #warning one. They can be used by libraries writer to raise errors or warnings when something can be detected at compilation time.
This just means that the guys from libpcap have deprecated usage of pcap_lookupdev and that it is likely to be removed in a later version. They just warn users of their library to stop using it in new code.
But here a different mechanism is involved. Gnu C compiler (but maybe others) have a specific attribute to indicate deprecation. It is intended to be used with the special option -Wdeprecated-declarations to switch deprecation warnings on, and -Wno-deprecated-declaration to switch them off.

How does an undefined system call return -1?

I have defined a 'helloworld' system call in my Linux kernel and recompiled it. The code for the system call is:
#include<linux/kernel.h>
#include<linux/init.h>
#include<linux/sched.h>
#include<linux/syscalls.h>
#include "processInfo.h"
asmlinkage long sys_listProcessInfo(void)
{
printk("Hello World. My new syscall..FOSS Lab!\n");
return 0;
}
But when I'm calling this system call from the same operating system with another kernel version, which does not include this system call, using the below code:
#include<stdio.h>
#include<linux/kernel.h>
#include<sys/syscall.h>
#include<unistd.h>
int main()
{
long int var = syscall(326);
printf("Returning: %ld\n",var);
return 0;
}
The variable var gets the value -1. I would like to know how var gets -1 instead of displaying an error.
Why do you expect an error? The syscall function exists, the linker can resolve it. So there won't be an error from the compiler or linker.
When you run the executable, the old kernel's syscall function detects that 326 is an invalid system call number and the functions returns -1, probably with errno set to ENOSYS = system call not implemented.

System call stat() converted to stat64() without any cpp option

I am running 32-bit SUSE Linux with kernel level 3.0.76.
I can see a stat() call in my code translate to stat64() in the strace output, without me specifying any CPP options like _LARGEFILE64_SOURCE or _FILE_OFFSET_BITS=64.
#include<stdio.h>
#include<sys/stat.h>
int main ( int argc, char * argv[] )
{
char * path = "nofile";
struct stat b;
if (stat(path, &b) != 0) {
}
}
I compiled this file with gcc with no compiler options/flags.
On running the program, relevant strace output is:
munmap(0xb770a000, 200704) = 0
stat64("nofile", 0xbfb17834) = -1 ENOENT (No such file or directory)
exit_group(-1)
Can anyone please tell me how the stat() was converted to stat64() ?
Thanks in advance!
The answer seems to be found in the stat man page
Over time, increases in the size of the stat structure have led to
three successive versions of stat(): sys_stat() (slot __NR_oldstat),
sys_newstat() (slot __NR_stat), and sys_stat64() (new in kernel 2.4;
slot __NR_stat64). The glibc stat() wrapper function hides these
details from applications, invoking the most recent version of the
system call provided by the kernel, and repacking the returned
information if required for old binaries. Similar remarks apply for
fstat() and lstat().
Basically, glibc always call stat64.
If you add a printf("%zu\n", sizeof b); , the struct stat sizes are likely different depending on whether you use _FILE_OFFSET_BITS=64 or not, and glibc converts the struct stat between the kernel and your code.
I can see a stat() call in my code translate to stat64() in the strace output
You need to analyze the way syscall stat is wrapped on your system http://sourceware.org/glibc/wiki/SyscallWrappers (one way that you can see this code is to use gdb: execute this command under gdb: catch syscall stat and when you program will stop on this breakpoint get backtrace and analyze the function that called stat).
From http://linux.die.net/man/2/stat64
Over time, increases in the size of the stat structure have led to
three successive versions of stat(): sys_stat() (slot __NR_oldstat),
sys_newstat() (slot __NR_stat), and sys_stat64() (new in kernel 2.4;
slot __NR_stat64). The glibc stat() wrapper function hides these
details from applications, invoking the most recent version of the
system call provided by the kernel, and repacking the returned
information if required for old binaries.
So it is glibc_wrapper that decides based on sizeof(struct stat) that it should call why stat64.

Resources