I'm writing a FUSE filesystem that does some mapping through sqlite, then passes the calls through to the underlying filesystem (somewhat of an expansion on bbfs). It started giving me trouble when I tried to start making files. When I call mknod, it returns with ERANGE. Here's the tail of an strace (filesystem is mounted on test/):
$ ./p4fs test/
$ strace touch test/kilo 2> logs
$ cat logs
...
fstat(3, {st_mode=S_IFREG|0644, st_size=56467024, ...}) = 0
mmap(NULL, 56467024, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fbf006bf000
close(3) = 0
close(0) = 0
open("test/kilo", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666) = -1 ERANGE (Numerical result out of range)
futimesat(AT_FDCWD, "test/kilo", NULL) = 0
close(1) = 0
exit_group(0) = ?
and here's the relevant section from my internal logging:
getattr: database opened
getattr: requesting attr for /kilo
db_getrowid: statement executed: finding rowid of /kilo
db_getrowid: mapped /kilo to rowid 0
getattr: does not exist: /kilo
mknod: database opened
mknod: statement executed: checking for existing path
mknod: calling db_mkdentry(db, /kilo, 100644, 0, 0)
db_mkdentry: parent is /
db_getrowid: statement executed: finding rowid of /
db_getrowid: mapped / to rowid 1
db_mkdentry: statement executed: creating dentry /kilo
db_getrowid: statement executed: finding rowid of /kilo
db_getrowid: mapped /kilo to rowid 3
p4fs: calling system mknod(3, 100644, 0)
p4fs: got errno 13
I'm looking for (1) the solution to this immediate problem and (2) a good way to debug FUSE in general. I have a sneaking suspicion that the ERANGE is coming from strtol(), but I don't know how to check. I wish I could make gdb pop up when it hits the callback...
Thanks!
EDIT: Oh, here's the source for my mknod() function:
static int p4_mknod(const char *path, mode_t mode, dev_t dev) {
sqlite3 *db;
sqlite3_stmt *statement;
char query[MAX_QUERY_LENGTH];
int rc;
int return_value;
int path_exists = -1;
OPEN_LOG("mknod")
OPEN_DB(db_path, db)
/* check for existing filename */
sprintf(query,
"SELECT COUNT(*) FROM dentry "
"WHERE name = '%s'",
path);
sqlite3_prepare(db,
query,
-1,
&statement,
NULL);
rc = sqlite3_step(statement);
SQLITE3_ERRCHK("checking for existing path")
path_exists = sqlite3_column_int(statement, 0);
sqlite3_finalize(statement);
if (path_exists <= 0) {
int physical_rowid;
char physical_name[MAX_QUERY_LENGTH];
/* path is not already in db */
syslog(LOG_DEBUG, "calling db_mkdentry(db, %s, %o, 0, 0)",
path, mode);
db_mkdentry(db, (char *) path, mode, 0, 0);
/* make the actual file */
physical_rowid = db_getrowid(db, (char *) path);
sprintf(physical_name, "%i", physical_rowid);
syslog(LOG_DEBUG, "calling system mknod(%s, %o, %li)",
physical_name, mode, dev);
return_value = mknod(physical_name, mode, dev);
} else {
syslog(LOG_INFO, "called on existing path");
return_value = -EEXIST;
}
syslog(LOG_DEBUG, "errno %i", errno);
return errno;
}
A few pieces of advice:
Do not use sprintf and friends to build SQL statements for sqlite3. It is recommended that you use hosted parameters in your statement and bind values to them using the sqlite3_bind functions.
Always prefer snprintf instead of sprintf and check its output. It will save you from lots of trouble.
Make sure you run your FUSE filesystem process in the foreground - it makes debugging easier.
Have you tried breakpoints in gdb? Or a bunch of perror() calls in your code to locate where the errno value that you mentioned comes from?
BTW there is no strtol() call in the code snippet you provided and there are a few macros without their definitions. Also IIRC 13 is the error code for EACCESS.
EDIT:
Something that you may have missed from the FUSE API:
A major exception is that instead of
returning an error in 'errno', the
operation should return the negated
error value (-errno) directly.
You seem to be returning errno as-is.
It's not really an answer, but I got around the issue by running as root. I suspect it has something to do with FUSE, because I had a similar issue when trying to get sshfs to run as a normal user a few months ago.
Related
I just started to learn injection techniques in Linux and want to write a simple program to inject a shared library into a running process. (the library will simply print a string.) However, after a couple of hours research, I couldn't find any complete example. Well, I did figure out I probably need to use ptrace() to pause the process and inject the contents, but not sure how to load the library into the memory space of target process and relocation stuff in C code. Does anyone know any good resources or working examples for shared library injection? (Of course, I know there might be some existing libraries like hotpatch I can use to make injection much easier but that's not what I want)
And if anyone can write some pseudo code or give me an example, I will appreciate it. Thanks.
PS: I am not asking about LD_PRELOAD trick.
The "LD_PRELOAD trick" André Puel mentioned in a comment to the original question, is no trick, really. It is the standard method of adding functionality -- or more commonly, interposing existing functionality -- in a dynamically-linked process. It is standard functionality provided by ld.so, the Linux dynamic linker.
The Linux dynamic linker is controlled by environment variables (and configuration files); LD_PRELOAD is simply an environment variable that provides a list of dynamic libraries that should be linked against each process. (You could also add the library to /etc/ld.so.preload, in which case it is automatically loaded for every binary, regardless of the LD_PRELOAD environment variable.)
Here's an example, example.c:
#include <unistd.h>
#include <errno.h>
static void init(void) __attribute__((constructor));
static void wrerr(const char *p)
{
const char *q;
int saved_errno;
if (!p)
return;
q = p;
while (*q)
q++;
if (q == p)
return;
saved_errno = errno;
while (p < q) {
ssize_t n = write(STDERR_FILENO, p, (size_t)(q - p));
if (n > 0)
p += n;
else
if (n != (ssize_t)-1 || errno != EINTR)
break;
}
errno = saved_errno;
}
static void init(void)
{
wrerr("I am loaded and running.\n");
}
Compile it to libexample.so using
gcc -Wall -O2 -fPIC -shared example.c -ldl -Wl,-soname,libexample.so -o libexample.so
If you then run any (dynamically linked) binary with the full path to libexample.so listed in LD_PREALOD environment variable, the binary will output "I am loaded and running" to standard output before its normal output. For example,
LD_PRELOAD=$PWD/libexample.so date
will output something like
I am loaded and running.
Mon Jun 23 21:30:00 UTC 2014
Note that the init() function in the example library is automatically executed, because it is marked __attribute__((constructor)); that attribute means the function will be executed prior to main().
My example library may seem funny to you -- no printf() et cetera, wrerr() messing with errno --, but there are very good reasons I wrote it like this.
First, errno is a thread-local variable. If you run some code, initially saving the original errno value, and restoring that value just before returning, the interrupted thread will not see any change in errno. (And because it is thread-local, nobody else will see any change either, unless you try something silly like &errno.) Code that is supposed to run without the rest of the process noticing random effects, better make sure it keeps errno unchanged in this manner!
The wrerr() function itself is a simple function that writes a string safely to standard error. It is async-signal-safe (meaning you can use it in signal handlers, unlike printf() et al.), and other than errno which is kept unchanged, it does not affect the state of the rest of the process in any way. Simply put, it is a safe way to output strings to standard error. It is also simple enough for everbody to understand.
Second, not all processes use standard C I/O. For example, programs compiled in Fortran do not. So, if you try to use standard C I/O, it might work, it might not, or it might even confuse the heck out of the target binary. Using the wrerr() function avoids all that: it will just write the string to standard error, without confusing the rest of the process, no matter what programming language it was written in -- well, as long as that language's runtime does not move or close the standard error file descriptor (STDERR_FILENO == 2).
To load that library dynamically in a running process, you'll need to first attach ptrace to it, then stop it before next entry to a syscall (PTRACE_SYSEMU), to make sure you're somewhere you can safely do the dlopen call.
Check /proc/PID/maps to verify you are within the process' own code, not in shared library code. You can do PTRACE_SYSCALL or PTRACE_SYSEMU to continue to next candidate stopping point. Also, remember to wait() for the child to actually stop after attaching to it, and that you attach to all threads.
While stopped, use PTRACE_GETREGS to get the register state, and PTRACE_PEEKTEXT to copy enough code, so you can replace it with PTRACE_POKETEXT to a position-independent sequence that calls dlopen("/path/to/libexample.so", RTLD_NOW), RTLD_NOW being an integer constant defined for your architecture in /usr/include/.../dlfcn.h, typically 2. Since the pathname is constant string, you can save it (temporarily) over the code; the function call takes a pointer to it, after all.
Have that position-independent sequence you used to rewrite some of the existing code end with a syscall, so that you can run the inserted using PTRACE_SYSCALL (in a loop, until it ends up at that inserted syscall) without having to single-step it. Then you use PTRACE_POKETEXT to revert the code to its original state, and finally PTRACE_SETREGS to revert the program state to what its initial state was.
Consider this trivial program, compiled as say target:
#include <stdio.h>
int main(void)
{
int c;
while (EOF != (c = getc(stdin)))
putc(c, stdout);
return 0;
}
Let's say we're already running that (pid $(ps -o pid= -C target)), and we wish to inject code that prints "Hello, world!" to standard error.
On x86-64, kernel syscalls are done using the syscall instruction (0F 05 in binary; it's a two-byte instruction). So, to execute any syscall you want on behalf of a target process, you need to replace two bytes. (On x86-64 PTRACE_POKETEXT actually transfers a 64-bit word, preferably aligned on a 64-bit boundary.)
Consider the following program, compiled to say agent:
#define _GNU_SOURCE
#include <sys/ptrace.h>
#include <sys/user.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/syscall.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
struct user_regs_struct oldregs, regs;
unsigned long pid, addr, save[2];
siginfo_t info;
char dummy;
if (argc != 3 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
fprintf(stderr, " %s PID ADDRESS\n", argv[0]);
fprintf(stderr, "\n");
return 1;
}
if (sscanf(argv[1], " %lu %c", &pid, &dummy) != 1 || pid < 1UL) {
fprintf(stderr, "%s: Invalid process ID.\n", argv[1]);
return 1;
}
if (sscanf(argv[2], " %lx %c", &addr, &dummy) != 1) {
fprintf(stderr, "%s: Invalid address.\n", argv[2]);
return 1;
}
if (addr & 7) {
fprintf(stderr, "%s: Address is not a multiple of 8.\n", argv[2]);
return 1;
}
/* Attach to the target process. */
if (ptrace(PTRACE_ATTACH, (pid_t)pid, NULL, NULL)) {
fprintf(stderr, "Cannot attach to process %lu: %s.\n", pid, strerror(errno));
return 1;
}
/* Wait for attaching to complete. */
waitid(P_PID, (pid_t)pid, &info, WSTOPPED);
/* Get target process (main thread) register state. */
if (ptrace(PTRACE_GETREGS, (pid_t)pid, NULL, &oldregs)) {
fprintf(stderr, "Cannot get register state from process %lu: %s.\n", pid, strerror(errno));
ptrace(PTRACE_DETACH, (pid_t)pid, NULL, NULL);
return 1;
}
/* Save the 16 bytes at the specified address in the target process. */
save[0] = ptrace(PTRACE_PEEKTEXT, (pid_t)pid, (void *)(addr + 0UL), NULL);
save[1] = ptrace(PTRACE_PEEKTEXT, (pid_t)pid, (void *)(addr + 8UL), NULL);
/* Replace the 16 bytes with 'syscall' (0F 05), followed by the message string. */
if (ptrace(PTRACE_POKETEXT, (pid_t)pid, (void *)(addr + 0UL), (void *)0x2c6f6c6c6548050fULL) ||
ptrace(PTRACE_POKETEXT, (pid_t)pid, (void *)(addr + 8UL), (void *)0x0a21646c726f7720ULL)) {
fprintf(stderr, "Cannot modify process %lu code: %s.\n", pid, strerror(errno));
ptrace(PTRACE_DETACH, (pid_t)pid, NULL, NULL);
return 1;
}
/* Modify process registers, to execute the just inserted code. */
regs = oldregs;
regs.rip = addr;
regs.rax = SYS_write;
regs.rdi = STDERR_FILENO;
regs.rsi = addr + 2UL;
regs.rdx = 14; /* 14 bytes of message, no '\0' at end needed. */
if (ptrace(PTRACE_SETREGS, (pid_t)pid, NULL, ®s)) {
fprintf(stderr, "Cannot set register state from process %lu: %s.\n", pid, strerror(errno));
ptrace(PTRACE_DETACH, (pid_t)pid, NULL, NULL);
return 1;
}
/* Do the syscall. */
if (ptrace(PTRACE_SINGLESTEP, (pid_t)pid, NULL, NULL)) {
fprintf(stderr, "Cannot execute injected code to process %lu: %s.\n", pid, strerror(errno));
ptrace(PTRACE_DETACH, (pid_t)pid, NULL, NULL);
return 1;
}
/* Wait for the client to execute the syscall, and stop. */
waitid(P_PID, (pid_t)pid, &info, WSTOPPED);
/* Revert the 16 bytes we modified. */
if (ptrace(PTRACE_POKETEXT, (pid_t)pid, (void *)(addr + 0UL), (void *)save[0]) ||
ptrace(PTRACE_POKETEXT, (pid_t)pid, (void *)(addr + 8UL), (void *)save[1])) {
fprintf(stderr, "Cannot revert process %lu code modifications: %s.\n", pid, strerror(errno));
ptrace(PTRACE_DETACH, (pid_t)pid, NULL, NULL);
return 1;
}
/* Revert the registers, too, to the old state. */
if (ptrace(PTRACE_SETREGS, (pid_t)pid, NULL, &oldregs)) {
fprintf(stderr, "Cannot reset register state from process %lu: %s.\n", pid, strerror(errno));
ptrace(PTRACE_DETACH, (pid_t)pid, NULL, NULL);
return 1;
}
/* Detach. */
if (ptrace(PTRACE_DETACH, (pid_t)pid, NULL, NULL)) {
fprintf(stderr, "Cannot detach from process %lu: %s.\n", pid, strerror(errno));
return 1;
}
fprintf(stderr, "Done.\n");
return 0;
}
It takes two parameters: the pid of the target process, and the address to use to replace with the injected executable code.
The two magic constants, 0x2c6f6c6c6548050fULL and 0x0a21646c726f7720ULL, are simply the native representation on x86-64 for the 16 bytes
0F 05 "Hello, world!\n"
with no string-terminating NUL byte. Note that the string is 14 characters long, and starts two bytes after the original address.
On my machine, running cat /proc/$(ps -o pid= -C target)/maps -- which shows the complete address mapping for the target -- shows that target's code is located at 0x400000 .. 0x401000. objdump -d ./target shows that there is no code after 0x4006ef or so. Therefore, addresses 0x400700 to 0x401000 are reserved for executable code, but do not contain any. The address 0x400700 -- on my machine; may very well differ on yours! -- is therefore a very good address for injecting code into target while it is running.
Running ./agent $(ps -o pid= -C target) 0x400700 injects the necessary syscall code and string to the target binary at 0x400700, executes the injected code, and replaces the injected code with original code. Essentially, it accomplishes the desired task: for target to output "Hello, world!" to standard error.
Note that Ubuntu and some other Linux distributions nowadays allow a process to ptrace only their child processes running as the same user. Since target is not a child of agent, you either need to have superuser privileges (run sudo ./agent $(ps -o pid= -C target) 0x400700), or modify target so that it explicitly allows the ptracing (for example, by adding prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY); near the start of the program). See man ptrace and man prctl for details.
Like I explained already above, for longer or more complicated code, use ptrace to cause the target to first execute mmap(NULL, page_aligned_length, PROT_READ | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0), which allocates executable memory for new code. So, on x86-64, you only need to locate one 64-bit word you can replace safely, and then you can PTRACE_POKETEXT the new code for the target to execute. While my example uses the write() syscall, it is a really small change to have it use mmap() or mmap2() syscall instead.
(On x86-64 in Linux, the syscall number is in rax, and parameters in rdi, rsi, rdx, r10, r8, and r9, reading from left to right, respectively; and return value is also in rax.)
Parsing /proc/PID/maps is very useful -- see /proc/PID/maps under man 5 proc. It provides all the pertinent information on the target process address space. To find out whether there are useful unused code areas, parse objdump -wh /proc/$(ps -o pid= -C target)/exe output; it examines the actual binary of the target process directly. (In fact, you could easily find how much unused code there is at the end of the code mapping, and use that automatically.)
Further questions?
I have a program which requires a DNS query and a sqlite3 DB connection.
I have determined that it hangs indefinitely at a getaddrinfo() call. So I created a test program (from busybox's nslookup.c) with only this call. When I do not link the libsqlite3 it works as expected. The code segment is as follows:
#include <arpa/inet.h>
#include <netdb.h>
#include <resolv.h>
#include <string.h>
#include <signal.h>
static int sockaddr_to_dotted(struct sockaddr *saddr, char *buf, int buflen)
{
if (buflen <= 0) return -1;
buf[0] = '\0';
if (saddr->sa_family == AF_INET)
{
inet_ntop(AF_INET, &((struct sockaddr_in*)saddr)->sin_addr, buf, buflen);
return 0;
}
if (saddr->sa_family == AF_INET6)
{
inet_ntop(AF_INET6, &((struct sockaddr_in6*)saddr)->sin6_addr, buf, buflen);
return 0;
}
return -1;
}
static int print_host(const char *hostname, const char *header)
{
char str[128]; /* IPv6 address will fit, hostnames hopefully too */
struct addrinfo *result = NULL;
int rc;
struct addrinfo hint;
memset(&hint, 0, sizeof(hint));
/* hint.ai_family = AF_UNSPEC; - zero anyway */
/* Needed. Or else we will get each address thrice (or more)
* for each possible socket type (tcp,udp,raw...): */
hint.ai_socktype = SOCK_STREAM;
// hint.ai_flags = AI_CANONNAME;
printf("BEFORE GETADDRINFO\n");
rc = getaddrinfo(hostname, NULL /*service*/, &hint, &result);
printf("AFTER GETADDRINFO\n");
if (!rc)
{
struct addrinfo *cur = result;
// printf("%s\n", cur->ai_canonname); ?
while (cur)
{
sockaddr_to_dotted(cur->ai_addr, str, sizeof(str));
printf("%s %s\nAddress: %s\n", header, hostname, str);
str[0] = ' ';
if (getnameinfo(cur->ai_addr, cur->ai_addrlen, str + 1,
sizeof(str) - 1, NULL, 0, NI_NAMEREQD))
str[0] = '\0';
puts(str);
cur = cur->ai_next;
}
}
else
{
printf("getaddrinfo('%s') failed: %s", hostname, gai_strerror(rc));
}
freeaddrinfo(result);
return (rc != 0);
}
int main(int argc, char **argv)
{
if (argc != 2)
return -1;
res_init();
return print_host(argv[1], "Name: ");
}
I can only see "BEFORE GETADDRINFO" on the output.
I also tried to strace the program. (My dns server is 192.168.11.11, and queried "www.google.com") This is where it suspends:
socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP) = 3
connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("192.168.11.11")}, 16) = 0
send(3, "\0\2\1\0\0\1\0\0\0\0\0\0\3www\6google\3com\0\0\1\0\1", 32, 0) = 32
pselect6(4, [3], NULL, NULL, {10, 0}, 0) = 1 (in [3], left {9, 988000000})
recv(3, "\0\2\201\200\0\1\0\5\0\0\0\0\3www\6google\3com\0\0\1\0"..., 512, 0) = 112
close(3) = 0
rt_sigprocmask(SIG_SETMASK, NULL, [RTMIN], 8) = 0
rt_sigsuspend([]
My compiler is bfin-linux-uclibc-gcc (gcc version 4.1.2)
I cross compiled sqlite3 for bfin-linux-uclibc (version 3.6.23)
I appreciate any comment, help, debug procedure suggestion.
output of strace -e trace=file mybinary:
stat("/etc/ld.so.cache", {st_mode=S_IFREG|0644, st_size=1073, ...}) = 0
open("/etc/ld.so.cache", O_RDONLY) = 3
open("/lib/libsqlite3.so.0", O_RDONLY) = 3
open("/lib/libstdc++.so.6", O_RDONLY) = 3
open("/lib/libm.so.0", O_RDONLY) = 3
open("/lib/libgcc_s.so.1", O_RDONLY) = 3
open("/lib/libc.so.0", O_RDONLY) = 3
open("/lib/libdl.so.0", O_RDONLY) = 3
open("/lib/libpthread.so.0", O_RDONLY) = 3
open("/lib/libgcc_s.so.1", O_RDONLY) = 3
open("/lib/libc.so.0", O_RDONLY) = 3
open("/lib/libm.so.0", O_RDONLY) = 3
open("/lib/libgcc_s.so.1", O_RDONLY) = 3
open("/lib/libc.so.0", O_RDONLY) = 3
open("/lib/libc.so.0", O_RDONLY) = 3
open("/lib/libc.so.0", O_RDONLY) = 3
open("/lib/libc.so.0", O_RDONLY) = 3
open("/lib/libc.so.0", O_RDONLY) = 3
stat("/lib/ld-uClibc.so.0", {st_mode=S_IFREG|0755, st_size=29824, ...}) = 0
open("/etc/resolv.conf", O_RDONLY) = 3
open("/etc/hosts", O_RDONLY) = 3
Output of bfin-linux-uclibc-nm -g mybinary
00004fc4 A ___bss_start
w ___deregister_frame_info##GCC_3.0
00004f10 D ___dso_handle
00004fc4 A __edata
00004fe0 A __end
00000d60 T __fini
U _freeaddrinfo
U _gai_strerror
U _getaddrinfo
U _getnameinfo
U _inet_ntop
00000534 T __init
w __Jv_RegisterClasses
00000aa4 T _main
U _printf
U _puts
w ___register_frame_info##GCC_3.0
U ___res_init
00000e18 R __ROFIXUP_END__
00000de0 R __ROFIXUP_LIST__
00000670 T ___self_reloc
00020000 A __stacksize
0000060c T __start
U ___uClibc_main
Updated information shows libpthread being loaded, so the scenario is likely SQLite was built with pthread support enabled (default on most platforms), and your binary was not.
The clue is the presence of libpthread and the hang at rt_sigsuspend(), this is an explicit wait for a signal, and is very likely one thread waiting for another thread to exit, which never happens of course.
The background to this is that since C and the standard library/libc pre-date contemporary threading, there are many cases where the standard library or API is either not re-entrant or not thread-safe, or both. Back when dragons roamed the land it was common for the programmer to have to explicitly call alternate versions of such functions (names suffixed with "_r") or use alternate libraries (again usually with an "_r" suffix) to ensure that code behaved correctly. pthreads changed the programming interface for the better, but since thread-safety comes at a cost (performance, sometime substantial, and code size) it's not enabled unless you ask for it.
When you use -pthread at least two things usually happen:
_REENTRANT is defined as a preprocessor macro, this may change compile time behaviour
libpthread is linked in (equivalent to -lpthread), this will change run-time behaviour
It would take some non-trivial debugging to be certain, but what probably happened is that your binary ended up mixing the stub pthread functions in uClibc with a handful of the real pthread functions. This is because libpthread was not loaded explicitly, only the pthread symbols referenced by libsqlite were imported.
uClibc contains (as does glibc) dummy pthread functions (run nm on libc.so to see), these are defined as "weak" symbols, when the real libpthread is loaded explicitly it takes over all entry points with its "strong" symbols. (These stubs exists so that thread-aware libraries can work with non-threaded programs without changes.)
Building your binary with an explicit -pthread eliminates this mismatch, and resolves the issue.
For debugging:
Run nm -g and ldd (the uClibc version) against your compiled binary, and check which symbols are in which library, and see if you can spot a mismatch. Setting LD_DEBUG=all when running your program should be useful too (you'll probably want to redirect stderr for that, there will be a lot of output).
The SQLite library has a .init section, but as far as I can tell it's a stub that doesn't call any internal functions, so simply linking shouldn't cause SQLite code to execute.
Since SQLite uses threads, make sure you built thread-safe, and are using the .so dynamic library.
When you link against your build of SQLite, make sure you use both -L (compile-time) and -R (run-time) library paths, usually something like this before compile & link will do the trick (amend the path as needed):
export CFLAGS=-L/usr/local/sqlite3/lib
export LDFLAGS=-R/usr/local/sqlite3/lib
Test program:
#include<stdio.h>
#include<sqlite3.h>
int main(int argc,char *argv[]) {
printf("SQLite version (compile): %s\n",SQLITE_VERSION);
printf("SQLite version (API): %s\n",sqlite3_libversion());
}
If you run this and get different versions, then something is definitely wrong with your build environment.
These guesses don't directly solve this problem, but I'll leave them here for the record:
Normally my first guess would usually be an NSS library run-time/compile-time library mismatch: as you're using the system getaddrinfo() NSS (name service switch) is involved. This will dlopen() various libraries to support various user/group/host databases, depending on /etc/nsswitch.conf, including local file, DNS, LDAP, Berkeley and quite possibly SQLite. Since uClibc doesn't support this (glibc style libnss_xxx.so), that's one thing ruled out...
There's another possibility: PAM does something similar, and may load an incompatible library (BerkeleyDB or possibly SQLite, as used by pam_userdb or pam-sqlite). Neither uClibc nor SQLite use PAM though, and it's improbable that it's being linked by accident.)
Since dlopen() is used you won't see such libraries (NSS or PAM) with ldd, running under strace -e trace=file should help to confirm what libraries are being used, without the usual volume of output.
This problem has been driving me nuts! :)
I am generating a couple of public/private key pairs, but when i go to load the private key i get an error. I am using C. Note i do use the password "password" on the keys, it is set as a #define but i have tried putting it in manually as a string with no difference. Here is how i'm generating the keys:
FILE *fp;
OpenSSL_add_all_algorithms();
RSA *rsa=NULL;
unsigned char seed[KEYSIZE];
int i;
//Seed PRNG
srand(time(NULL));
RAND_bytes(seed, KEYSIZE - 1);
//Generate a key
if ((rsa=RSA_generate_key(KEYSIZE,65537,NULL,NULL)) == NULL) ERR_get_error();
//Write the public key
fp = fopen(pubkey,"w");
if (!PEM_write_RSA_PUBKEY(fp, rsa)) {
printf("Error writing public key\n"); exit(1);
}
fclose(fp);
//Write the private key
fp = fopen(privkey,"w");
if (!PEM_write_RSAPrivateKey(fp, rsa, EVP_des_ede3_cbc(), NULL, 0, NULL, PASSWORD))
{
printf("Error writing private key\n"); exit(1);
}
fclose(fp);
This completes successfully and i end up with the files in the appropriate places, and they look good. I've also successfully encrypted/decrypted on the command line using these files, so i know they work!
Here is how i'm loading the private key:
static void decrypt(int locale) {
FILE *key;
RSA *rsa;
key = fopen(PRIVATEKEY, "r");
if (key == NULL) perror("Error reading private key");
rsa = PEM_read_RSAPrivateKey(key, NULL, NULL, PASSWORD); // THIS BREAKS!
if (rsa == NULL) perror("Private Key not valid"); // I always get this error :(
if (rsa != NULL) RSA_free(rsa);
fclose(key);}
Any suggestions? I went through the source file rsa.c and this is basically exactly how they do it in there, except they use BIOs instead of freads. I don't see why my way shouldn't work though!
Here is the relevant section of strace output:
open("/opt/evoting/keys/priv/mix1.priv", O_RDONLY) = 15
fstat64(15, {st_mode=S_IFREG|0644, st_size=1751, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb773c000
read(15, "-----BEGIN RSA PRIVATE KEY-----\n"..., 4096) = 1751
dup(2) = 16
fcntl64(16, F_GETFL) = 0x2 (flags O_RDWR)
fstat64(16, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb773b000
_llseek(16, 0, 0xbfba00d0, SEEK_CUR) = -1 ESPIPE (Illegal seek)
write(16, "Private Key not valid: Resource "..., 56Private Key not valid: Resource temporarily unavailable ) = 56
close(16) = 0
munmap(0xb773b000, 4096) = 0
close(15) = 0
munmap(0xb773c000, 4096) = 0
Also, perror produces the error "resource not available". I'm not sure what that's about, but i reset my hard and soft ulimits to be really high and it did nothing. I copied the function into its own file and compiled it and it doesn't produce the error there (it still fails to read the key, though).
Aha! Alright, i just learned a lot about troubleshooting this stuff, and hopefully it will help someone else along the line. Most of my info came from this thread: http://readlist.com/lists/openssl.org/openssl-users/2/10340.html
Basically i needed to not use perror and instead use ERR_print_errors_fp(stderr). This gave me an actual error message like so:
3077973640:error:0906B072:lib(9):func(107):reason(114):pem_lib.c:530:
I then used the command: openssl errstr 0906B072 and got:
error:0906B072:PEM routines:PEM_get_EVP_CIPHER_INFO:unsupported encryption
Which basically led me back to the creation of my key pair where i specified CBC: EVP_des_ede3_cbc() which is not supported for RSA. So there you go!
I found solution - you just call OpenSSL_add_all_ciphers() function before
OpenSSL_add_all_ciphers() adds all encryption algorithms to the table including password based encryption algorithms.
The cipher and digest lookup functions are used in many parts of the library. If the table is not initialized several functions will misbehave and complain they cannot find algorithms. This includes the PEM, PKCS#12, SSL and S/MIME libraries. This is a common query in the OpenSSL mailing lists.
Calling OpenSSL_add_all_algorithms() links in all algorithms: as a result a statically linked executable can be quite large. If this is important it is possible to just add the required ciphers and digests.
http://www.openssl.org/docs/crypto/x509.html#
I'm trying to implement a program to access memory on an embedded system. I need to access some control register so I think that ioctl is the best way to do it. I have added the ioctl to the fops:
struct file_operations aes_fops = {
read: aes_read,
write: aes_write,
unlocked_ioctl: aes_ioctl,
open: aes_open,
release: aes_release
};
And have set up the function:
int aes_ioctl(struct inode *inode,
struct file *file,
unsigned int ioctl_num,
unsigned long ioctl_param){
printk(KERN_INFO "in ioctl\n");
....
}
But I am not getting inside of this function. Here is my user space code. Please help me understand if I am doing this totally wrong.
int main(int argc, char* argv[]){
int fd = fopen("/dev/aes", "r+");
ioctl(fd, 0, 1);
fclose(fd);
}
Some of the code is apparently for older kernels, because I am compiling for an embedded system where an older version of Linux has been modified.
The problem with your code is the request number you are using - 0. The kernel has some request number reserved for internal use. The kernel regards the request number as a struct, separates it to fields and calls the right subsystem for it.
See Documentation/ioctl/ioctl-number.txt (from Linux 3.4.6):
Code Seq#(hex) Include File Comments
========================================================
0x00 00-1F linux/fs.h conflict!
0x00 00-1F scsi/scsi_ioctl.h conflict!
0x00 00-1F linux/fb.h conflict!
0x00 00-1F linux/wavefront.h conflict!
0x02 all linux/fd.h
0x03 all linux/hdreg.h
...
Depending on what you are during, you'd have to follow the kernel guidelines for adding new ioctls():
If you are adding new ioctl's to the kernel, you should use the _IO
macros defined in <linux/ioctl.h>:
_IO an ioctl with no parameters
_IOW an ioctl with write parameters (copy_from_user)
_IOR an ioctl with read parameters (copy_to_user)
_IOWR an ioctl with both write and read parameters.
See the kernel's own Documentation/ioctl/ioctl-decoding.txt document for further details on how those numbers are structured.
In practice, if you pick Code 1, which means starting from 0x100 up until 0x1ff, you'd be fine.
Is your setup of the aes_fops structure correct? I've never seen it done that way. All the code I have is:
.unlocked_ioctl = aes_ioctl,
rather than:
unlocked_ioctl: aes_ioctl,
Colons within a structure (as you have in your setup) fields are used for bit fields as far as I'm aware (and during definition), not initialising the individual fields.
In other words, try:
struct file_operations aes_fops = {
.read = aes_read,
.write = aes_write,
.unlocked_ioctl = aes_ioctl,
.open = aes_open,
.release = aes_release
};
Note: It appears that gcc once did allow that variant of structure field initialisation but it's been obsolete since gcc 2.5 (see here, straight from the GCC documentation). You really should be using the proper method (ie, the one blessed by the ISO standard) to do this.
Without knowing the error returned, it's hard to say... My first though is your permissions on your file descriptor. I've seen similar issues before. First, you can get some more information about the failure if you take a look at the return of the ioctl:
#include <errno.h>
int main(int argc, char* argv[])
{
long ret;
int fd = fopen("/dev/aes", "r+");
ret = ioctl(fd, 0, 1);
if (ret < 0)
printf("ioctl failed. Return code: %d, meaning: %s\n", ret, strerror(errno));
fclose(fd);
}
Check the return values and this should help give you something to search on. Why check? See the bottom of the post...
Next in order to check if it is permissions issue, run the command:
ls -l /dev/aes
if you see something like:
crw------- 1 root root 10, 57 Aug 21 10:24 /dev/aes
Then just issue a:
sudo chmod 777 /dev/aes
And give it a try again. I bet it will work for you. (Note I ran that with root permissions since root is the owner of my version of your mod)
If the permissions are already OK, then I have a few more suggestions:
1) To me, the use of fopen/fclose is strange. You really only need to do:
int fd = open("/dev/aes");
close(fd);
My system doesn't even let your code compile as is.
2) Your IOCTL parameter list is old, I don't know what kernel version your compiling on, but recent kernels use this format:
long aes_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param){
Note the removal of the inode and the change of the return type. When I ran your code on my system, I made these changes.
Best of luck!
Note: Why should we check the return when we're "not getting into the ioctl"? Let me give you an example:
//Kernel Code:
//assume include files, other fops, exit, miscdev struct, etc. are present
long hello_ioctl(struct file *file, unsigned long ioctl_num, unsigned long ioctl_param) {
long ret = 0;
printk("in ioctl");
return ret;
}
static const struct file_operations hello_fops = {
owner: THIS_MODULE,
read: hello_read,
unlocked_ioctl: hello_ioctl,
};
static int __init hello_init(void) {
int ret;
printk("hello!\n");
ret = misc_register(&hello_dev); //assume it worked...
return ret;
}
User space code:
//assume includes
void main() {
int fd;
long ret;
fd = open("/dev/hello");
if(fd) {
c = ioctl(fd, 0, 1);
if (c < 0)
printf("error: %d, errno: %d, meaning: %s\n", c, errno, strerror(errno));
close(fd);
}
return;
}
So what's the output? Lets assume bad file permissions on /dev/hello (meaning our user space program can't access /dev/hello).
The dmesg | tail shows:
[ 2388.051660] Hello!
So it looks like we didn't "get in to" the ioctl. What's the output from the program?
error: -1, errno: 9, meaning: Bad file descriptor
Lots of useful output. Clearly the ioctl call did something, just not what we wanted. Now changing the permissions and re-running we can see the new dmesg:
[ 2388.051660] Hello!
[ 2625.025339] in ioctl
The following is code I've used to create a memory mapped file:
fid = open(filename, O_CREAT | O_RDWR, 0660);
if ( 0 > fid )
{
throw error;
}
/* mapped offset pointer to data file */
offset_table_p = (ubyte_2 *) shmat(fid, 0, SHM_MAP);
/* Initialize table */
memset(offset_table_p, 0x00, (table_size + 1) * 2);
say table_size is around 2XXXXXXXX bytes.
During debug, I've noticed it fails while attempt to initializing the 'offset table pointer',
Can anyone provide me some inputs on why it's failing during intilalization?
is there any possibilities that my memory map file was not created with required table size?
As far as I can tell from reading documentation, you are doing it completely wrong.
Either use open() and mmap() or use shmget() and shmat().
If you use open() you will need to make the file long enough first. Use ftruncate() for that.
First things first:
Examine the file both before and after the open() call. If on Linux, you can use the code:
char paxbuff[1000]; // at start of function
sprintf (paxbuff,"ls -al %s",filename);
system (paxbuff);
fid = open(filename, O_CREAT | O_RDWR, 0660); // this line already exists.
system (paxbuff);
Then, after you call shmat(), check the return values and size thus:
offset_table_p = (ubyte_2 *) shmat(fid, 0, SHM_MAP); // already exists.
printf ("ret = %p, errno = %d\n",offset_table_p,errno);
printf ("sz = %d\n",table_size);
That should be enough to work out the problem.