I have an interest in modifying Linux for my own purposes through hijacking system calls. I have managed to successfully hijack open(), ioctl(), and the system calls used for manipulating extended attributes. I am trying to hijack execve() with:
asmlinkage int (*real_execve)(const char __user *,
const char __user *const __user *,
const char __user *const __user *);
asmlinkage int hijacked_execve(const char __user *filename,
const char __user *const __user *argv,
const char __user *const __user *envp) {
return real_execve(filename, argv, envp);
}
by modifying the system call table. Upon inserting the kernel module, the terminal just hangs. If I type in a command and press enter, the terminal just acts like a text editor that won't accept backspaces or react to Ctrl+X or Ctrl+C, looking like:
main#vm:~/hijack_execve$ sudo insmod hijack_execve.ko
[sudo] password for main:
main#vm:~/hijack_execve$ <any command>
^C^X
Strangely, I can hijack mmap() so long as it maintains the same form as above, only passing the parameters on to the real mmap(). Anyone have any idea as to what could be going wrong here? I'm wondering if the process of hijacking execve() makes it unavailable during the time the system call table is being modified, and that during this time execve() is needed to complete the operation.
Related
The question may seem naive, but I'm new to kernel/driver programming. I created a device mapper over a block device, which is working fine. It's constructor/destructor and map methods are called.
Now, I'm trying to write an ioctl for this mapper. When ioctl is written for a device, it has the following signature:
int ioctl(int d, /* other args */);
A file structure/descriptor is expected in ioctl. This can be easily used by application process as it has access to file.
But the ioctl for device mapper has the following signature ( in struct target_type):
typedef int (*dm_ioctl_fn) (struct dm_target *ti, unsigned int cmd,
unsigned long arg);
How can user application get access to device mapper with ioctl without having knowledge of struct dm_target ?
-Ioctl which stand for Input Output control is a system call used in linux to implement system calls which are not be available in the
kernel by default.
-The major use of this is in case of handling some specific operations of a device for which the kernel does not have a system call by default. For eg: Ejecting the media from a "CD" drive. An ioctl command is implemented to give the eject system call to the cd drive.
-ioctl(fd, cmd , INPARAM or OUTPARAM);
|
3rd argument is INPARAM or OUTPARAM i.e we don't have to read a device, then how how to interact with device ? use ioctl.
-open ioctl.h and check you will get more information
#define "ioctl name" __IOX("magic number","command number","argument type")
static long char_dev_ioctl( struct file *filp, unsigned int cmd, unsigned long arg)
{
/* verify argument using access_ok() */
/* impliment support of ioctl commands */
}
I'm attempting to learn how to write a sysfs module, and am confused at the basic initialization. In this document looking at the kobject.h file, there are several different functions related to creating a sysfs entry.
From the looks of it, the function "kobject_init_and_add" seems like the right thing to use, which takes the following:
90 int kobject_init_and_add(struct kobject *kobj,
91 struct kobj_type *ktype, struct kobject *parent,
92 const char *fmt, ...);
struct kobject and struct kobj_type are straightforward enough, but I don't understand what the *parent kobject and *fmt cstring are supposed to be.
Further, after initializing these objects, I would need to remove them at the exit_module function, but there are two options that seem possible: kobject_del and kobject_puts. What are the differences between these?
Part of my confusion comes from the fact that while googling for the answer, I see tutorials which says to use functions like kobject_register instead, but that function doesn't actually exist.
Yes there are lot of example on mainline kernel which you can refers for your implementatin. For Your doubts I am adding the some example code"
Module Probe/init function
static struct kobject *module_kobject;
module_kobject=kobject_create_and_add("module_status",NULL);
sysfs_create_group(module_kobject,&module_attr);
Module Remove/exit function
sysfs_remove_group(module_kobject,&module_attr);
kobject_put(module_kobject);
If you want to expose more than one attribute on the user space; than you need to define the group as well
static struct attribute_group module_attr={
.attrs = module_attribute,
};
There is some more implementation and function you may need like:
static ssize_t module_show_status(struct kobject *kobj,struct kobj_attribute *attr,char *buf);
static ssize_t module_store__status(struct kobject *kobj,struct kobj_attribute *attr,const char *buf,size_t len);
I think you can start your sysfs module implementation based on the above code and Feel free for any help.
There are many kernel modules that create sysfs entries. For example,
http://lxr.free-electrons.com/source/net/bridge/br_sysfs_br.c
This module uses kobject_create_and_add(), which gets as a parameter a kobject instance, created by sysfs_create_group(). I believe that looking into such module, and trying to code step by step, following the patterns in that module, can help. Also look in
http://lxr.free-electrons.com/source/Documentation/kobject.txt
Rami Rosen
I'm working with some existing software that I cannot change, and it loads its config data from a bunch of config files, all following the same naming scheme - let's say, file_param1.conf, file_param2.conf, file_param3.conf etc. The difference between the content of the files is just param1 vs param2 vs param3, so a typical config file will look like
foo=bar
x=param1
or
foo=bar
x=param2
Is there any examples anywhere on creating a virtual fs in Linux that would let me on access of file_param1.conf generate the file dynamically with the appropriate param variable? I know about scriptfs but not about any tutorials on using it.
(Posting as an answer because this is too long for a comment.)
You might find it easier to use an LD_PRELOAD library and interpose on the open()/fopen()/open64() or whatever exact library call(s) your existing software uses to access your configuration file and replacing the application-supplied file name with one that points to the file you want to use.
This code is off the top of my head and I haven't tried compiling it:
#include <dlfcn.h>
// don't want to #include anything else or we're likely to get
// the vararg prototype for open()
int strcmp( const char *s1, const char *s2 );
// typedef a function pointer
typedef int ( *open_func_ptr_t )( const char *, int, mode_t );
static open_func_ptr_t real_open = NULL;
int open( const char *pathname, int flags, mode_t mode )
{
// find the real open() call
if ( real_open == NULL )
{
real_open = ( open_func_ptr_t ) dlsym( RTLD_NEXT, "open" );
}
if ( 0 == strcmp( pathname, "/path/to/config/file" );
{
pathname = "/path/to/replacement/config/file";
}
return( real_open( pathname, flags, mode ) );
}
That code relies on the fact that although open() is declared as a varargs function because of the restrictions placed on current C code, originally C didn't have prototypes so all functions were de facto vararg functions. The open() call only accesses the mode argument when needed, so open() doesn't always need to be passed a mode argument. With current C, the only way to do that is with a vararg function. That makes #include files problematic with this code as any declaration of open() will be the vararg one and that will cause the code to not compile. You might need to replace mode_t with int (or whatever it's typedef'd to) in order to compile.
Compile that with cc [-m64|-m32] -shared source.c -ldl -o mylib.so. You need the -ldl to link in dlsym(), and you need the proper -m64 or -m32 option to get a 64- or 32-bit library to match your application.
Then set LD_PRELOAD to your .so file:
LD_PRELOAD=/path/to/mylib.so
export LD_PRELOAD
Then run your application with the LD_PRELOAD set. You also need to be real careful that any child processes spawned by your application are all the same 32- or 64-bit as the shared object LD_PRELOAD is set to. If you nave mixed 32- and 64-bit processes to deal with, read the man page for ld.so and pay particular attention the the $PLATFORM section.
Note also that the code is not reentrant because of the race condition modifying real_open and might have problems with multithreaded access to open().
I have to declare multiple devices inside the open call. Now is there a way I could fix the minor nos to 0,1,2,3 so that I can just extract that from filp->f_dentry->inode and put that in the array of struct scull_dev[] everytime I make an open read write or close call and then life becomes easy :P. Or is their a way to make life easier ?
If I understand what you need, you shouldn't have ever to access your devices directly except for initialization and cleanup. Take a look at:
http://www.cs.uni.edu/~diesburg/courses/dd/code/scull/pipe.c
In open function, you can get the current device you need to open via:
struct scull_pipe *dev;
dev = container_of(inode->i_cdev, struct scull_pipe, cdev);
You can see in other functions how the device is accessed via arguments that kernel is passing to these functions. For example:
static ssize_t scull_p_write(struct file *filp, const char __user *buf, size_t count,
loff_t *f_pos)
{
struct scull_pipe *dev = filp->private_data;
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
The community reviewed whether to reopen this question 11 months ago and left it closed:
Original close reason(s) were not resolved
Improve this question
Can anyone tell me about this...
I want to create a pam module similar to the login module in /etc/pam.d
If you are looking for pam based face authentication during login, you need to write a module which does that for you and plug that in login configuration file at /etc/pam.d/login.
Before directly get into this, I would suggest you to write some simple module to understand the flow, working of PAM and configuration file like start playing with sshd pam configuration file and try to plug some sample pam module available. I found these article quite helpful :
http://aplawrence.com/Basics/understandingpam.html
https://www.packtpub.com/article/development-with-pluggable-authentication-modules-pam
FYI : Rohan Anil developed pam-face-authentication during GSOC08 under opensuse which is hosted at code.google.com/p/pam-face-authentication/
Since the answer is really to long to be written here, I can link you my PAM tutorials:
Write a Linux PAM module and
Linux PAM Configuration tutorial
Before starting writing the module I advise you to read the configuration tutorial first, in which you can learn what does the module do.
To sum up, a module is a shared object loaded by PAM when the application wants to authenticate. Every time the application triggers a "stage" (auth, account, session, password) the correspondent function is called in the module. Therefore, your module should provide the following functions:
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *handle, int flags, int argc, const char **argv){
/* In this function we will ask the username and the password with pam_get_user()
* and pam_get_authtok(). We will then decide if the user is authenticated */
}
PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) {
/* In this function we check that the user is allowed in the system. We already know
* that he's authenticated, but we could apply restrictions based on time of the day,
* resources in the system etc. */
}
PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) {
/* We could have many more information of the user other then password and username.
* These are the credentials. For example, a kerberos ticket. Here we establish those
* and make them visible to the application */
}
PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv) {
/* When the application wants to open a session, this function is called. Here we should
* build the user environment (setting environment variables, mounting directories etc) */
}
PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv) {
/* Here we destroy the environment we have created above */
}
PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv){
/* This function is called to change the authentication token. Here we should,
* for example, change the user password with the new password */
}
In this functions you will use PAM functions to retrieve the username and the password from the application. This happens through a conversation function that must be defined in the application (see this tutorial). At the end of every function, you must return a PAM return code that determines the result (for PAM error codes see this and the module writer documentation in general).
One of the best resources for authoring pam modules is the documentation
itself:
http://www.linux-pam.org/Linux-PAM-html/Linux-PAM_MWG.html
However I agree with #GG in making sure you understand how PAM works first.