Kernel crash when dereferencing a null pointer - pointers

I have a simple module like this:
#define MODULE
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
int init_module(void) {
struct inode {
int i_ino;
};
struct dentry {
struct inode *d_inode;
};
struct dentry *f_dentry;
f_dentry = NULL;
struct inode * p = f_dentry->d_inode;
return 0;
}
void cleanup_module(void) {
printk("Goodbye world\n");
}
And my Makefile is like this:
obj-m += oops.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules$(shell uname -r)/build M=$(PWD) clean
I expect that the kernel will crash because struct inode * p = f_dentry->d_inode; has dereferenced a null pointer, right? But it does not. Anything wrong with my idea?
All right, now I'll have one more try. If my module is like this:
#define MODULE
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
int init_module(void) {
*(int *)0 = 0;
return 0;
}
void cleanup_module(void) {
printk("Goodbye world\n");
}
My computer really crashes. Or anything wrong with my former example? It doesn't dereference a null pointer?

If you look at the assembly code(via e.g. objdump -D oops.ko), all of your init_module() is optimized away, presumably because it doesn't do anything.
If you e.g. do p->i_ino = 1; , you'll likely see different results(Albeit this is undefined behavior, so it's not straight forward to reason about what the code is going to do - better check the assembly in this case too).

Related

How to read /proc/PID/maps of a child process just before the child process terminates

I'm trying to read memory usage(PSS, specifically) of a child process by reading its proc filesystem when the child process is about to be terminated.
Following this and this answers, I managed to hook SIGCHLD signal of child process and read some data from proc filesystem. I found it works well for most of the proc filesystem, but doesn't work for /proc/PID/maps and /proc/PID/smaps. It looks like both maps and smaps are already empty when SIGCHLD signal is emitted. If it is too late to read maps and smaps when SIGCHLD is emitted, what alternative approach could I have? Any hint would be appreciated. thanks.
The following is example code copied from the second answer I linked above.
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>
pthread_mutex_t mutex;
void sigchldhandler(int s) {
// signals to the main thread that child has exited
pthread_mutex_unlock(&mutex);
}
int main() {
// init and lock the mutex
pthread_mutex_init(&mutex, NULL);
pthread_mutex_lock(&mutex);
// install signal handler
signal(SIGCHLD, sigchldhandler);
pid_t child_pid = fork();
if (child_pid > 0) {
// parent
// wait for the signal
pthread_mutex_lock(&mutex);
char buffer[0x1000];
sprintf(buffer, "/proc/%d/io", child_pid);
FILE * fp = fopen(buffer, "r");
if (!fp) {
perror("fopen");
abort();
}
while (fgets(buffer, sizeof(buffer), fp)) {
printf("%s", buffer);
}
// clean up child
wait(0);
return 0;
} else if (child_pid < 0) {
perror("fork");
abort();
} else {
// child
char* args[] = { "cat", "test.txt" };
execv(args[0], args);
}
}

Add new system call at FreeBSD 10.1

I wanna add new system call at FreeBSD. My system call code is:
#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/mount.h>
#include <sys/sysproto.h>
int Sum(int a, int b);
int
Sum(a,b)
{
int c;
c = a + b;
return (0);
}
But when I rebuild the kernel, I have an error:
What's wrong? Can you help me?
Thanks a lot.
Here's how I did it with my example system call of setkey which takes two unsigned ints.
I added my system call to the end /kern/syscalls.master
546 AUE_NULL STD { int setkey(unsigned int k0, unsigned int k1);}
Then I did
cd /usr/src
sudo make -C /sys/kern/ sysent
Next, I added the file to /sys/conf/files
kern/sys_setkey.c standard
My sys_setkey.c is as follows
#include <sys/sysproto.h>
#include <sys/proc.h>
//required for printf
#include <sys/types.h>
#include <sys/systm.h>
#ifndef _SYS_SYSPROTO_H_
struct setkey_args {
unsigned int k0;
unsigned int k1;
};
#endif
/* ARGSUSED */
int sys_setkey(struct thread *td, struct setkey_args *args)
{
printf("Hello, Kernel!\n");
return 0;
}
Also, I added the system call to /kern/capabilities.conf
##
## Allow associating SHA1 key with user
##
setkey
Finally, while in /usr/src/ I ran the command
sudo make -j8 kernel
sudo reboot
This is a program which runs the system call
#include <sys/syscall.h>
#include <unistd.h>
#include <stdio.h>
int main(){
//syscall takes syscall.master offset,and the system call arguments
printf("out = %d\n",syscall(546,1,1));
return 0;
}
Please read this
I think, that you haven't included your file with sys_Sum function in kernel makefile ( notice, that in your code, that you have provided, function name is Sum and in error there is call to sys_Sum. I hope, that it's just a typo in your code and the name of function is sys_Sum ).

strcat dumping core in SunOS

I have a program which goes through the directory structure and concatenates the files present in the path to szFile . I have used dirent here to get the directory entries. It is dumping core in the strcat function inside the for loop only in SunOS . It goes through fine in HP and AIX machine .
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <limits.h>
#include <sys/types.h>
int main()
{
DIR *pDirHand;
char szFile[1024];
struct dirent pdirent ;
struct dirent *pResult = NULL;
char *sDir = "fullpath"; /* fullpath can be /make/users/path */
strncpy (szFile, sDir, sizeof(szFile)-1);
szFile[sizeof(szFile)-1] = '\0';
if (NULL == (pDirHand = opendir(szFile)))
{
return -1;
}
for(readdir_r(pDirHand, &pdirent, &pResult); pResult != 0;readdir_r(pDirHand, &pdirent, &pResult))
{
FILE *fp;
fp=fopen("debug.log","a+");
strcpy (szFile, sDir);
strcat (szFile, "/");
strcat (szFile, pdirent.d_name);
}
if (pDirHand) closedir (pDirHand);
return 0;
}
I dont have any files currently in the path that I assign to sDir. It has "." and ".." directory entries in it but I get a core dump in the line
strcat (szFile, pdirent.d_name);
I had used dbx to find out the value of szFile , during the second iteration the value is exceeding the memory allocated for it . The value comes as
"fullpath/../fullpath/../fullpath/../fullpath/../fullpath/..fullpath/..fullpath/../../../../../../fullpath/../fullpath/../fullpath/../fullpath/../fullpath/../fullpath/../fullpath/../fullpath/../fullpath/../fullpath/..fullpath/../fullpath/../fullpath/../fullpath/../fullpath/../fullpath/../fullpath/../fullpath/../fullpath/../fullpath/.." ...
I have tried using strlcat , but the concatinated value of szFile is not coming properly.
Anybody faced this problem in SunOS or can help ?

UNIX IPC C program only parent process can write to file, child not working

I need to use Signal to write UNIX Interprocess communication program in C. I want a parent process and child process to write to a same file.
The result only show parent written text. I can use either BSD or System V. Please help
#include <stdio.h> /* basic I/O routines. */
#include <unistd.h> /* define fork(), etc. */
#include <sys/types.h> /* define pid_t, etc. */
#include <sys/wait.h> /* define wait(), etc. */
#include <signal.h>
int myFlag = 0;
void myHandler(int);
int child_pid;
int main()
{
//oldmask = sigblock(sigmask(SIGUSR1));
sighold(SIGUSR1);
sighold(SIGINT);
/* critical region */
signal (SIGUSR1, myHandler);
sigrelse(SIGUSR1);
sigrelse(SIGINT);
child_pid = fork();
if (child_pid==0) {
for ( ; ; ) {
while(myFlag == 0)
sigpause(0);
sigblock (sigmask(SIGUSR1));
myFlag = 0;
FILE *fp=fopen("test","w");
fwrite("child",1,6,fp);
fclose(fp);
kill(getppid(),SIGUSR1);
}
}
if (child_pid>0){
FILE *fp;
fp=fopen("test","w");
fwrite("parent",1,6,fp);
fclose(fp);
for ( ; ; ) {
while(myFlag == 0)
sigpause(0);
sigblock (sigmask(SIGUSR1));
myFlag = 0;
fp=fopen("test","w");
fwrite("parent",1,6,fp);
fclose(fp);
}
kill(child_pid, SIGUSR1);
//kill ()-child_pid ;
}
exit(0);
}
void myHandler(int sigNo) {
myFlag = 1;
//signal (SIGUSR1, myHandler);
}
You should start by opening the file in append mode rather than write mode:
fp = fopen("test", "a");
That will position the write position of fp at the end of file rather than the beginning. When you open with "w", you truncate the file and start writing from position 0:
w or wb
Truncate to zero length or create file for writing.
Then you might want to think about file locking to keep the two processes from writing to the file at the same time.
Also, your child process writes out the nul terminator:
fwrite("child", 1, 6, fp);
but your parent process doesn't:
fwrite("parent", 1, 6, fp);
That may or may not be your intention but it does look odd.
Your logic is flawed. The parent process does not signal the child process before it waits for the child process to signal it. The child process waits for the parent process to signal it before writing the file and signaling the parent process.
This means after you write the file in the parent both the parent and child are stuck in busy loops waiting for the other one to do something.
Also, while I don't think this is a problem in your code since the call to sigpause(0); should cause the compiler to believe that global variables may have changed and need to be reloaded, in other situations you might want to declare myFlag as volatile int myFlag;. This forces the compiler to read or write its value from memory every time you reference it.
Lastly, of course, your programs will simply re-write over the same bytes repeatedly because you open the files in "w" (write) mode instead of "a" (append) mode.
Here's a program that accomplishes what you want using POSIX standard calls and techniques instead of the old deprecated obsolete calls you were using:
#include <stdio.h> /* basic I/O routines. */
#include <unistd.h> /* define fork(), etc. */
#include <sys/types.h> /* define pid_t, etc. */
#include <sys/wait.h> /* define wait(), etc. */
#include <signal.h>
#include <stdlib.h>
volatile sig_atomic_t myFlag = 0;
void myHandler(int);
int child_pid;
int main()
{
signal (SIGUSR1, myHandler);
child_pid = fork();
if (child_pid==0) {
for ( ; ; ) {
while(myFlag == 0)
;
{
sigset_t oldmask;
sigset_t usr1;
sigemptyset(&oldmask);
sigemptyset(&usr1);
sigaddset(&usr1, SIGUSR1);
sigprocmask(SIG_BLOCK, &usr1, &oldmask);
myFlag = 0;
sigprocmask(SIG_SETMASK, &oldmask, NULL);
}
FILE *fp=fopen("test","a");
fwrite("child\n",1,6,fp);
fclose(fp);
kill(getppid(),SIGUSR1);
}
}
if (child_pid>0){
FILE *fp;
fp=fopen("test","a");
fwrite("parent\n",1,7,fp);
fclose(fp);
for ( ; ; ) {
kill(child_pid, SIGUSR1);
//kill ()-child_pid ;
while(myFlag == 0)
;
{
sigset_t oldmask;
sigset_t usr1;
sigemptyset(&oldmask);
sigemptyset(&usr1);
sigaddset(&usr1, SIGUSR1);
sigprocmask(SIG_BLOCK, &usr1, &oldmask);
myFlag = 0;
sigprocmask(SIG_SETMASK, &oldmask, NULL);
}
fp=fopen("test","a");
fwrite("parent\n",1,7,fp);
fclose(fp);
}
}
exit(0);
}
void myHandler(int sigNo) {
myFlag = 1;
//signal (SIGUSR1, myHandler);
}

How to use a QFile with std::iostream?

Is it possible to use a QFile like a std::iostream? I'm quite sure there must be a wrapper out there. The question is where?
I have another libs, which requires a std::istream as input parameter, but in my program i only have a QFile at this point.
I came up with my own solution using the following code:
#include <ios>
#include <QIODevice>
class QStdStreamBuf : public std::streambuf
{
public:
QStdStreamBuf(QIODevice *dev) : std::streambuf(), m_dev(dev)
{
// Initialize get pointer. This should be zero so that underflow is called upon first read.
this->setg(0, 0, 0);
}
protected:
virtual std::streamsize xsgetn(std::streambuf::char_type *str, std::streamsize n)
{
return m_dev->read(str, n);
}
virtual std::streamsize xsputn(const std::streambuf::char_type *str, std::streamsize n)
{
return m_dev->write(str, n);
}
virtual std::streambuf::pos_type seekoff(std::streambuf::off_type off, std::ios_base::seekdir dir, std::ios_base::openmode /*__mode*/)
{
switch(dir)
{
case std::ios_base::beg:
break;
case std::ios_base::end:
off = m_dev->size() - off;
break;
case std::ios_base::cur:
off = m_dev->pos() + off;
break;
}
if(m_dev->seek(off))
return m_dev->pos();
else
return std::streambuf::pos_type(std::streambuf::off_type(-1));
}
virtual std::streambuf::pos_type seekpos(std::streambuf::pos_type off, std::ios_base::openmode /*__mode*/)
{
if(m_dev->seek(off))
return m_dev->pos();
else
return std::streambuf::pos_type(std::streambuf::off_type(-1));
}
virtual std::streambuf::int_type underflow()
{
// Read enough bytes to fill the buffer.
std::streamsize len = sgetn(m_inbuf, sizeof(m_inbuf)/sizeof(m_inbuf[0]));
// Since the input buffer content is now valid (or is new)
// the get pointer should be initialized (or reset).
setg(m_inbuf, m_inbuf, m_inbuf + len);
// If nothing was read, then the end is here.
if(len == 0)
return traits_type::eof();
// Return the first character.
return traits_type::not_eof(m_inbuf[0]);
}
private:
static const std::streamsize BUFFER_SIZE = 1024;
std::streambuf::char_type m_inbuf[BUFFER_SIZE];
QIODevice *m_dev;
};
class QStdIStream : public std::istream
{
public:
QStdIStream(QIODevice *dev) : std::istream(m_buf = new QStdStreamBuf(dev)) {}
virtual ~QStdIStream()
{
rdbuf(0);
delete m_buf;
}
private:
QStdStreamBuf * m_buf;
};
I works fine for reading local files. I haven't tested it for writing files. This code is surely not perfect but it works.
I came up with my own solution (which uses the same idea Stephen Chu suggested)
#include <iostream>
#include <fstream>
#include <cstdio>
#include <QtCore>
using namespace std;
void externalLibFunction(istream & input_stream) {
copy(istream_iterator<string>(input_stream),
istream_iterator<string>(),
ostream_iterator<string>(cout, " "));
}
ifstream QFileToifstream(QFile & file) {
Q_ASSERT(file.isReadable());
return ifstream(::_fdopen(file.handle(), "r"));
}
int main(int argc, char ** argv)
{
QFile file("a file");
file.open(QIODevice::WriteOnly);
file.write(QString("some string").toLatin1());
file.close();
file.open(QIODevice::ReadOnly);
std::ifstream ifs(QFileToifstream(file));
externalLibFunction(ifs);
}
Output:
some string
This code uses std::ifstream move constructor (C++x0 feature) specified in 27.9.1.7 basic_ifstream constructors section of Working Draft, Standard for Programming Language C++:
basic_ifstream(basic_ifstream&& rhs);
Effects: Move constructs from the
rvalue rhs. This is accomplished by
move constructing the base class, and
the contained basic_filebuf. Next
basic_istream::set_rdbuf(&sb) is called to install the contained
basic_filebuf.
See How to return an fstream (C++0x) for discussion on this subject.
If the QFile object you get is not open for read already, you can get filename from it and open an ifstream object.
If it's already open, you can get file handle/descriptor with handle() and go from there. There's no portable way of getting a fstream from platform handle. You will have to find a workaround for your platforms.
Here's a good guide for subclassing std::streambuf to provide a non-seekable read-only std::istream: https://stackoverflow.com/a/14086442/316578
Here is a simple class based on that approach which adapts a QFile into an std::streambuf which can then be wrapped in an std::istream.
#include <iostream>
#include <QFile>
constexpr qint64 ERROR = -1;
constexpr qint64 BUFFER_SIZE = 1024;
class QFileInputStreamBuffer final : public std::streambuf {
private:
QFile &m_file;
QByteArray m_buffer;
public:
explicit QFileInputStreamBuffer(QFile &file)
: m_file(file),
m_buffer(BUFFER_SIZE, Qt::Uninitialized) {
}
virtual int underflow() override {
if (atEndOfBuffer()) {
// try to get more data
const qint64 bytesReadIntoBuffer = m_file.read(m_buffer.data(), BUFFER_SIZE);
if (bytesReadIntoBuffer != ERROR) {
setg(m_buffer.data(), m_buffer.data(), m_buffer.data() + bytesReadIntoBuffer);
}
}
if (atEndOfBuffer()) {
// no more data available
return std::char_traits<char>::eof();
}
else {
return std::char_traits<char>::to_int_type(*gptr());
}
}
private:
bool atEndOfBuffer() const {
return gptr() == egptr();
}
};
If you want to be able to more things like seek, write, etc., then you'd need one of the other more complex solutions here which override more streambuf functions.
If you don't care much for performance you can always read everything from the file and dump it into an std::stringstream and then pass that to your library. (or the otherway, buffer everything to a stringstream and then write to a QFile)
Other than that, it doesn't look like the two can inter-operate. At any rate, Qt to STL inter operations are often a cause for obscure bugs and subtle inconsistencies if the version of STL that Qt was compiled with is different in any way from the version of STL you are using. This can happen for instance if you change the version of Visual Studio.

Resources