Not sure if anyone has any ideas here, I haven't seen this before. I'm writing a stub to test out my kernel module, when I check the value of the command in userspace I get a different value vs. when I take a look at the in kernel space.
Part of the stub:
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "ain.h"
#include "ain_ioctl.h"
#define AI_DEVICE "/dev/ain"
void main()
{
int fd, error, ioctl_par = 0;
char* dev;
long ret;
dev = AI_DEVICE;
printf("Starting driver test\n");
fd = open(dev, O_RDWR);
if (fd < 0) {
/* Failed to open -> Print error-message and exit */
printf("%s failed to open, error: %s\n", dev, strerror(errno));
}
printf("Doing the IOCTL now... cmd: %d\n", AIN_IOC_GET_AN0_CONF);
fflush(stdout);
ret = ioctl(fd, AIN_IOC_GET_AN0_CONF, &ioctl_par);
The ain_ioctl.h file:
#define AIN_IOC_MAGIC 'e'
#define AIN_IOC_GET_AN0_CONF _IOR(AIN_IOC_MAGIC, 46, int)
The ioctl routine in the kernel:
int ain_ioctl (struct inode * inodep, struct file * filp, unsigned int cmd, unsigned long arg)
{
printk("In the ain_ioctl function, cmd: %d. type: %d, dir: %d, nr: %d, size: %d\n",
cmd, _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd));
printk("Testing against command: %d. type: %d, dir: %d, nr: %d, size: %d\n",
AIN_IOC_GET_AN0_CONF, _IOC_TYPE(AIN_IOC_GET_AN0_CONF), _IOC_DIR(AIN_IOC_GET_AN0_CONF),
_IOC_NR(AIN_IOC_GET_AN0_CONF), _IOC_SIZE(AIN_IOC_GET_AN0_CONF));
Now I would have expected identical output in the user space print as in the kernel. And in the first set of prints in the kernel to the second. However that's not what I'm seeing...
Output:
mike#linux-4puc:~> ./a.out
Starting driver test
Doing the IOCTL now... cmd: -2147195602
mike#linux-4puc:~> dmesg | tail
[75253.205136] In the ain_ioctl function, cmd: -1078168112. type: 117, dir: 2, nr: 208, size: 16316
[75253.205140] Testing against cmd: -2147195602. type: 101, dir: 2, nr: 46, size: 4
Anyone have any ideas on why my command is acting differently when I pass it to the kernel via the ioctl command vs when I just check the values by hard coding them (as I am doing in my prints)?
The only warnings I'm seeing when I build seem nothing to do with the ioctl calls:
makedepend: warning: ignoring option -Wall
makedepend: warning: ignoring option -Wall
makedepend: warning: ain.c (reading /usr/src/linux/include/linux/compiler-gcc.h), line 94: incomplete include == "#include gcc_header(__GNUC__)"
makedepend: warning: ain.c (reading /usr/src/linux/include/linux/string.h, line 13): cannot find include file "stdarg.h"
Thanks.
The -1078168112 (why aren't you printing these in hex?) looks like a stack pointer. Possibly &ioctl_par. This suggests that your ioctl method is receiving different parameters than you expected.
In the current kernel source I see ioctl methods taking 3 parameters, not 4. The 4-argument ioctl seems to be an older interface.
Do you get any warnings during the module compilation? Pay attention to them!
Alan Curry's answer was not the complete "correct" answer, but it lead me to the solution. The hex value of the command was way off so I took a look at other ioctl calls in the kernel.
The system I have is based off an older 2.4X kernel, and I'm updating it for 3.1. The issue here is the parameter list for the ioctl call. Having the inode pointer in the parameter list was causing the problem as it was taking the file pointer to be the command.
Proper solution:
long ain_ioctl (struct file * filp, unsigned int cmd, unsigned long arg) {
...
Related
F
I'm using Graphviz to render .dot file as graphs, and typically I would write in my terminal :
dot -Tpng yourFile.dot -o yourOutput.png to produce a .png image representing my graph. (I'm using a Unix environment btw)
Now let's say I have the following C function:
#include <stdlib.h>
#include <string.h>
#define MAXSIZE 255
typedef struct placeholder mystruct;
struct placeholder {
...
}
void outputGraph(mystruct str, char* outputName) {
char command[MAXSIZE];
char* tmpFile = "temp.dot";
char imageFile[MAXSIZE];
snprintf(imageFile, MAXSIZE, "%s.png", outputName);
FILE* file = fopen(tmpFile, "w");
writeStructToFile(str, file);
snprintf(command, MAXSIZE, "dot -Tpng %s -o %s", tmpFile, imageFile);
system(command);
snprintf(command, MAXSIZE, "rm %s", tmpFile);
system(command);
}
(my function WriteStructToFile is another one that I made and is working properly so the problem is somewhere else)
From what I understood about the system() function, it should produce the image output just the same as when I execute the same command myself.
Well, it does execute without any errors, but there is no image in the directory where I'm working.
At first, I thought, it's easy, system() doesn't start a new shell in the same working directory, so I tried to see the output of system(pwd); and it was my current working directory. So back to the starting point.
I also tried to check the value system(command) by doing int status = system(command); and then printf("status : %d\n", status); and, well, it printed 0.
Now I'm kinda clueless, I really don't see why it doesn't produce the image output.
I'd be very interested in any ideas or even solutions you have.
This is not the most elegant code, but it works & may help you debug your problem. It calls dot in three different ways. All three work as expected.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main () {
char command[50];
int rc;
strcpy(command, "dot -Tdot this.gv" );
rc=system(command);
printf("\n\n+++ call #1 returned %d\n", rc);
strcpy(command, "dot -Tdot this.gv -oout1.dot" );
rc=system(command);
printf("\n\n+++ call #2 returned %d\n", rc);
strcpy(command, "dot -Tdot this.gv -o out2.dot" );
rc=system(command);
printf("\n\n+++ call #3 returned %d\n", rc);
return(0);
}
snprintf(command, MAXSIZE, "touch %s", tmpFile);
system(command);
Why do you code that?
You certainly don't need to use system(3) then touch(1). You could use appropriate syscalls(2) (open(2) and close(2) here) or at least fopen(3) followed by fclose(3).
You might in some cases consider using popen(3) with pclose(3)
Of course, after
snprintf(command, MAXSIZE, "dot -Tpng %s -o %s", tmpFile, imageFile);
int bad = system(command);
You need to first check that bad is 0 and you probably want to use stat(2) or access(2) to check that imageFile exists.
There could be many reasons why system with a dot command fails. For example, a bad $PATH variable. I suggest using popen(3) with pclose(3) and probably /usr/bin/dot in the command.
Compile your C code using GCC as gcc -Wall -Wextra -g and use GDB to debug your executable. Both strace(1) and ltrace(1) could help you understand the behavior of your program.
Consider reading Advanced Linux Programming and studying for inspiration the source code of some simple open source Linux shells, such as sash or (more complex) GNU bash.
Be aware that Graphviz could be used as a library.
I wasn't closing the temp.dot file in which I was writing. My mistake.
I shall now remember to always close files that I open!
A big thank you to everyone who helped on here.
(Whether it was for the problem or on how to use properly SO)
Consider the following program (vul.c) with buffer overflow vulnerability.
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
char buf[10];
strcpy(buf, argv[1]);
printf("%s\n", buf);
return 0;
}
Above program compiled using gcc -o vul vul.c and executed on arch linux - linux 4.4.16-1-lts x86-64 gave following output when executed in terminal with ./vul $(perl -e 'print "A"x100') command:
AAAAAAAAAAA...A
Segmentation fault (core dumped)
Then checking the program status using echo $? command gave 139 output.
Following program (exp.c) (for crashing the above program)
#include <stdlib.h>
int main(void)
{
printf("%d\n", system("./vul $(perl -e 'print \"A\"x100')"));
return 0;
}
compiled using gcc -o exp exp.c when executed with ./exp command on same system gave following output:
AAAAAAAAAAAA...A
139
I have two questions:
Why no error message was generated by 2nd program? and,
I need to compile the program with -fstack-protector flag to enable the *** stack smashing detected *** error messages in arch linux but not in Ubuntu. In Ubuntu, it might be that this flag is include by default in gcc or is there any other reason?
As I pointed out in my comment,system returns an int with the programs's return value, which is normally it's error code (0 if successful).
If you want to print the error as a nice looking message, you can probably use strerror.
According to #rht's comment (see my next edit) and the answers to the question referenced in that comment, the returned value will be 0 on success and on error it will be error | 0x80. To get the original error code, use 128 - err_code.
try this:
#include <stdlib.h>
#include <errno.h>
int main(void)
{
int tmp = system("./vul $(perl -e 'print \"A\"x100)");
if(tmp < 0)
error("Couldn't run system command");
else if(tmp >0)
printf(stderr, "System command returned error: %s", strerror(128 - tmp));
else
; // nothing
return 0;
}
The fact that vul.c does (or does not) print an error message should be irrelevant for your exp.c program, since it depends on vul.c's compile flags values and any default compiler flags - things exp.c can't control.
EDIT(2) - in answer to the comment.
It could be that the error message returned isn't an errno value, but a signal trap value.
These are sometimes hard to differentiate and I have no good advice about how you can tell which one it is without using memcmp against the answer.
In this case you know vul.c will never return it's errno value, which leaves you only with signal trap errors, so you can use strsignal to print the error message.
As pointed out in #rht's comment, which references this question:
Passing tmp to strsignal generates the same error message: "unknown signal 139". The reason is that there is no signal with this signal number. /usr/include/bits/signum.h contains all the signals with their signal numbers. Passing tmp-128 to strsignal works.
i.e.
#include <stdlib.h>
#include <string>
int main(void)
{
int tmp = system("./vul $(perl -e 'print \"A\"x100)");
if(tmp < 0)
error("Couldn't run system command");
else if(tmp >0)
printf(stderr, "System command returned error: %s", strsignal(tmp - 128));
else
; // nothing
return 0;
}
EDIT
The question was edited because it's code was mis-copied. I altered the answer to reflect that change.
From my comment to #Myst 's answer for "passing tmp-128 to strsignal()" function, after experimenting a little I found that it does not work in situations where the program exited normally but returned status other than 0.
Following are the contents of my /usr/include/bits/waitstatus.h:
/* If WIFEXITED(STATUS), the low-order 8 bits of the status. */
#define __WEXITSTATUS(status) (((status) & 0xff00) >> 8)
/* If WIFSIGNALED(STATUS), the terminating signal. */
#define __WTERMSIG(status) ((status) & 0x7f)
/* Nonzero if STATUS indicates normal termination. */
#define __WIFEXITED(status) (__WTERMSIG(status) == 0)
/* Nonzero if STATUS indicates termination by a signal. */
#define __WIFSIGNALED(status) \
(((signed char) (((status) & 0x7f) + 1) >> 1) > 0)
Above code show that, exit status of a program is a 16bit number, the high order 8 bits of which are the status that the program returned and some/all of the remaining bits are set if the program exited because of a signal, 7 bits of which denote the signal that caused the program to exit. That's why subtracting 128 from the exit status returned by system() will not work in the situation as described above.
System()'s source code
Since system() function too uses fork() to create a new process and waits for the termination of the process, the same method of checking a child process's status in parent process can also be applied here. Following program demonstrates this:
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>
int main(void)
{
int status = system("prg_name");
if (WIFEXITED(status))
printf("Exited Normally, status = %d\n", WEXITSTATUS(status));
else if (WIFSIGNALED(status))
printf("Killed by Signal %d which was %s\n", WTERMSIG(status), strsignal(WTERMSIG(status)));
return 0;
}
Answering my own 2nd question.
gcc -Q -v vul.c command displayed the options passed to the gcc. The options in Ubuntu included -fstack-protector-strong flag but not in arch-linux. So in Ubuntu, the flag is passed by default to gcc.
There exists two problems in your vul.c and exp.c.
In vul.c,
char buf[10];
10 is not sufficient in this case, since the argv[1], i.e., $(perl -e 'print "A"x100', is larger than the buffer to be allocated. Enlarge the buf size should fix the segmentation fault.
In exp.c, you're missing one single quote, and should be modified as followed:
printf("%d\n", system("./vul $(perl -e 'print \"A\"x100')"));
I’m trying to make a C program which is prompting the user to type a message from the console and then show that message the user has typed, as in the following example:
C:>promptTest
type your message >>>> test
typed : test
C:>
This is my code:
#include <stdio.h>
#include <string.h>
int main(){
char msg[32];
printf("type your message >>>>\t");
fgets(msg,sizeof(msg),stdin);
msg[strlen(msg) - 1] = '\0';
printf("typed : %s\n",msg);
return 0;
}
It can be built on both Windows7 and CentOS and it can be run normally on Windows like above.
However, it can’t be run on CentOS. I mean nothing accepts any message from the prompt like below:
$ ./promptTest
type your message >>>> test
typed :
$
How can I fix this?
Here is information about my machine.
$ cat /etc/redhat-release
CentOS release 6.4 (Final)
$
$ arch
x86_64
$
strlen() returns size_t not int.
Printing size_t on a 64bit IXish system using %d might fail, as the former most likly is 64bit while the latter expects 32bit.
So at least on a 64bit IXish system instead of
printf("### buf(%d) = %s\n",strlen(buf),buf);
printf("### message(%d) = %s\n",strlen(message),message);
do
printf("### buf(%zu) = %s\n",strlen(buf),buf);
printf("### message(%zu) = %s\n",strlen(message),message);
As a (ugly) workaround you could also cast strlen() down to int.
printf("### buf(%d) = %s\n", (int) strlen(buf),buf);
printf("### message(%d) = %s\n", (int) strlen(message),message);
This workaround however assumes no string being longer then INT_MAX.
I found the solution.
CL+LF coused this matter.
see Controlling prompt for command line
I have a very simple question, but I have not managed to find any answers to it all weekend. I am using the sendto() function and it is returning error code 14: EFAULT. The man pages describe it as:
"An invalid user space address was specified for an argument."
I was convinced that this was talking about the IP address I was specifying, but now I suspect it may be the memory address of the message buffer that it is referring to - I can't find any clarification on this anywhere, can anyone clear this up?
EFAULT It happen if the memory address of some argument passed to sendto (or more generally to any system call) is invalid. Think of it as a sort of SIGSEGV in kernel land regarding your syscall. For instance, if you pass a null or invalid buffer pointer (for reading, writing, sending, recieving...), you get that
See errno(3), sendto(2) etc... man pages.
EFAULT is not related to IP addresses at all.
Minimal runnable example with getcpu
Just to make things more concrete, we can have a look at the getcpu system call, which is very simple to understand, and shows the same EFAULT behaviour.
From man getcpu we see that the signature is:
int getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache);
and the memory pointed to by the cpu will contain the ID of the current CPU the process is running on after the syscall, the only possible error being:
ERRORS
EFAULT Arguments point outside the calling process's address space.
So we can test it out with:
main.c
#define _GNU_SOURCE
#include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
int main(void) {
int err, ret;
unsigned cpu;
/* Correct operation. */
assert(syscall(SYS_getcpu, &cpu, NULL, NULL) == 0);
printf("%u\n", cpu);
/* Bad trash address == 1. */
ret = syscall(SYS_getcpu, 1, NULL, NULL);
err = errno;
assert(ret == -1);
printf("%d\n", err);
perror("getcpu");
return EXIT_SUCCESS;
}
compile and run:
gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
./main.out
Sample output:
cpu 3
errno 14
getcpu: Bad address
so we see that the bad call with a trash address of 1 returned 14, which is EFAULT as seen from kernel code: https://stackoverflow.com/a/53958705/895245
Remember that the syscall itself returns -14, and then the syscall C wrapper detects that it is an error due to being negative, returns -1, and sets errno to the actual precise error code.
And since the syscall is so simple, we can confirm this from the kernel 5.4 implementation as well at kernel/sys.c:
SYSCALL_DEFINE3(getcpu, unsigned __user *, cpup, unsigned __user *, nodep,
struct getcpu_cache __user *, unused)
{
int err = 0;
int cpu = raw_smp_processor_id();
if (cpup)
err |= put_user(cpu, cpup);
if (nodep)
err |= put_user(cpu_to_node(cpu), nodep);
return err ? -EFAULT : 0;
}
so clearly we see that -EFAULT is returned if there is a problem with put_user.
It is worth mentioning that my glibc does have a getcpu wrapper as well in sched.h, but that implementation segfaults in case of bad addresses, which is a bit confusing: How do I include Linux header files like linux/getcpu.h? But it is not what the actual syscall does to the process, just whatever glibc is doing with that address.
Tested on Ubuntu 20.04, Linux 5.4.
EFAULT is a macro defined in a file "include/uapi/asm-generic/errno-base.h"
#define EFAULT 14 /* Bad address */
I have to write a program in C which returns file size in blocks just like ls -s command.
Please help.
I tried using stat() function (st_blksize)...And I am unable to implement it.
My code looks like this
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
void main(int argc, char **argv)
{
DIR *dp;
struct dirent *dirp;
struct stat buf;
if(argc < 2)
{
dp = opendir(".");
}
if(dp == NULL)
{
perror("Cannot open directory ");
exit(2);
}
while ((dirp = readdir(dp)) != NULL)
{
printf("%s\n", dirp->d_name);
if (stat(".", &buf))
printf("%d ", buf.st_blksize);
}
closedir(dp);
exit(0);
}
It is giving error buf size is not declared. Don't know what is the problem.
Addition
Thanks for the correction. I included the <sys/stat.h> header file. Now it is giving a warning:
warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘__blksize_t’
I am new to C so can't make out what should be the possible solution.
You need to include the correct header:
#incude <sys/stat.h>
That declares the structure and associated functions.
Note that stat() returns zero on success, so your test needs changing (and, as #jsmchmier pointed out in a comment, the call to stat should probably use dirp->d_name rather than the string literal "."). Also, st_blksize is the size of the disk blocks, not the size of the file - that is st_size (measured in bytes).
POSIX says:
off_t st_size For regular files, the file size in bytes.
For symbolic links, the length in bytes of the
pathname contained in the symbolic link.
blksize_t st_blksize A file system-specific preferred I/O block size
for this object. In some file system types, this
may vary from file to file.
blkcnt_t st_blocks Number of blocks allocated for this object.
Note that old (very old) versions of Unix did not support st_blksize or st_blocks. I expect most current versions do.
Now it is giving a warning..warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘__blksize_t’
The chances are that __blksize_t is an unisgned integer type similar to size_t. I'd probably use a simple cast:
printf("Block size = %d\n", (int)buf.st_blksize);
Alternatively, if you have C99 available, you could use the facilities from <inttypes.h> to use a bigger size:
printf("Block size = %" PRIu64 "\n", (uint64_t)buf.st_blksize);
In practice, this is overkill; the block size is unlikely to exceed 2 GB this decade, so int is likely to be sufficient for the foreseeable future.
From man 2 stat on my Mac OS X box:
NAME
fstat, fstat64, lstat, lstat64, stat, stat64 -- get file status
SYNOPSIS
#include <sys/stat.h>
int
fstat(int fildes, struct stat *buf);
Note the #include <sys/stat.h> which you have not done. No doubt the actual layout of struct stat is defined in there, which is what your compiler is complaining about.
This is one aspect of the man pages which is not always discussed with beginners but is very useful indeed: the whole unix API is documented in them. Oh, it is not always the easiest place to find a function when you know what it should do but don't know what it is called, but all the answers are there.
Open the file, and stat/fstat it. The struct field st_blocks should contain the information you want. If you're dealing with a directory, use opendir, readdir, closedir (posix)... Just pointers to start your work.
EDIT
Add unistd.h and sys/stat.h. Then remember that stat return 0 on success, so
if (stat(dirp->d_name, &buf) == 0)
and I've changed "." to the name of the "element", which is what you wanted, I suppose. Another change is to use st_blocks and not st_blksize, which says how big is each block (e.g. 1024 or 4096 or...), and -s returns the size in number of blocks, not the size of a block.
The fragment of code is of course incomplete: if you pass an argument, dp is not initialized and even dp == NULL can fail, you shoud have nullified it before:
DIR *dp = NULL;
struct dirent *dirp = NULL;
Careful, one bug in your code is that dp points to garbage and is only initialised if argc is less than 2, but you still try to use it in your while loop and you also try to closedir it. If you invoke your application with any arguments at all, it will probably crash.
To avoid the warning, change the %d to %ld in the line: printf("%d ", buf.st_blksize);