File access control in linux - c

I`m writing a module to control file access. I'm now trying to implement the prohibition of file opening. I've already tried are kernel module system open overload: http://pastebin.com/JWKbpFYT
I've also tried system read overload: http://pastebin.com/psK8vX41
The problem in the first one is that I could restrict access to target file only in console (it didn't work in graphical interface, e.g. gedit).
The second one didn't work as the system stopped responding on running gedit with target file.
How can I prohibit file opening without using SELinux?
asmlinkage int custom_open(const char __user *file_name, int flags, mode_t mod)
{
printk("hook: open(\"%s\")", file_name);
if (!strcmp(file_name, "test"))
return -1;
return original_open(file_name, flags, mod);
}
struct file *fget(unsigned int fd)
{
struct file *file;
struct files_struct *files = current->files;
rcu_read_lock();
file = fcheck_files(files, fd);
if (file) {
/* File object ref couldn't be taken */
if (file->f_mode & FMODE_PATH ||
!atomic_long_inc_not_zero(&file->f_count))
file = NULL;
}
rcu_read_unlock();
return file;
}
asmlinkage int custom_read(int fd, void *buf, size_t noct)
{
struct file *filp = fget(fd);
unsigned char f_name[DNAME_INLINE_LEN];
strcpy(f_name,filp->f_path.dentry->d_name.name);
if (!strcmp(f_name, "_ttt.c")){
printk("hook1: read fd=(%d: -> %s)\n",fd,f_name);
return -1;
}
return original_read(fd, buf, noct);
}

Related

How to send and receive an image over RPC

I am using Sun XDR RPC in ubuntu 14. I need to send and receive an image over RPC for compression. Here is my .x file
onst MAXPARAMNAME = 9024;
typedef string prog<MAXPARAMNAME>;
struct prognames
{
prog program1;
int index;
};
program RPC_PROG {
version RPC_VERS {
string RUN_PROGS(prognames) = 1; /* procedure numer=1 */
} = 1; /* version number = 1 */
} = 0x12345678; /* program number = 0x12345678 */
Following is client file
FILE *imageN=fopen("index.jpg", "r");
char b[9024];
int i=0;
while(!feof(imageN))
{
fread(b, 1,1024,imageN );
i+=1024;
fseek( imageN,i, SEEK_SET );
}
prognames args;
args.program1 =&b;
/*remote procedure run_progs */
resultStringFromServerExecutePrograms = run_progs_1(&args, cl);
I am only mentioning that code where image is being sent.
Finally server code:
char** run_progs_1_svc(prognames *argparams, struct svc_req *arg2)
{
FILE* fpipe;
char* program1AndProgram2;
char* prog1 = argparams->program1;
static char* readPipeInto1;
readPipeInto1 = (char*)malloc((READ_MAX_SIZE + 1)*sizeof(char));
static char* readPipeInto;
readPipeInto = (char*)malloc((READ_MAX_SIZE + 1)*sizeof(char));
memset(readPipeInto, 0, READ_MAX_SIZE + 1);
program1AndProgram2=(char*)malloc((strlen(prog1))*sizeof(char));
strcpy(program1AndProgram2, argparams->program1);
//execute commands
if ( !(fpipe= (FILE*)fopen("tst.jpg","w")) )
{
perror("Cant open pipe!");
exit(1);
}
fwrite(program1AndProgram2,0,8024,fpipe);
long length;
//calculating size of file
//fread((char *)readPipeInto1, length, 1, fpipe);
fclose(fpipe);
//compression code
After running code, server side says that the file is empty. While on the client side after a while following error is generated.
localhost: RPC: Unable to receive; errno = Connection refused
Basic logic behind my code is that client reads from file stores it in the structure and then sends this structure to server (RPC). Server writes data in structure to a file and then opens that file and compresses.
But I'm not sure whether my logic is correct or not.

Retrieve a file's inode number by the filename on MINIX

I want to create a new system call in VFS server which will be given a filename as a parameter and will print this certain file's inode number in MINIX3.2.1.
I examined the code of the do_stat() function(inside /usr/src/servers/vfs/stadir.c) and i found out that i have to assign to a vnode struct variable the faction eat_path() in order to access v_inode_nr which is the inode number.In order to do that how am i able to assign the file i am looking for,where to put the user input filename(m_in.m1_p1)?
Here is the do_stat() function inside stadir.c
int do_stat() {
/* Perform the stat(name, buf) system call. */
int r;
struct vnode *vp;
struct vmnt *vmp;
char fullpath[PATH_MAX];
struct lookup resolve;
int old_stat = 0;
vir_bytes vname1, statbuf;
size_t vname1_length;
vname1 = (vir_bytes)job_m_in.name1;
vname1_length = (size_t)job_m_in.name1_length;
statbuf = (vir_bytes)job_m_in.m1_p2;
lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp);
resolve.l_vmnt_lock = VMNT_READ;
resolve.l_vnode_lock = VNODE_READ;
if (job_call_nr == PREV_STAT)
old_stat = 1;
if (fetch_name(vname1, vname1_length, fullpath) != OK)
return (err_code);
if ((vp = eat_path(&resolve, fp)) == NULL)
return (err_code);
r = req_stat(vp->v_fs_e, vp->v_inode_nr, who_e, statbuf, old_stat);
unlock_vnode(vp);
unlock_vmnt(vmp);
put_vnode(vp);
return r;
}
I've found a solution to my problem, i was not able to understand the way fetch_name() parameters work(vname1,vname1_length and fullpath).
So in order to do that I looked into /usr/src/vfs/params.h
#define name m3_p1
#define flength m2_l1
#define name1 m1_p1
#define name2 m1_p2
#define name_length m3_i1
#define name1_length m1_i1
#define name2_length m1_i2
#define nbytes m1_i2
Υou can see name1 stands for m1_p1 and name1_length stands for m1_i1 message variables.
As for fetch_name function,i looked /usr/src/vfs/utility.c
int fetch_name(vir_bytes path, size_t len, char *dest)
{
/* Go get path and put it in 'dest'. */
int r;
So fetch_name actually gets the path (filename from the user) and converts it to fullpath of the file.
The question now is what's actually size_t len variable is...I looked it up online and i found out that it's the strlen of the path variable!
It's the strlen(name) + 1 as stored in m.m1_i1
You can add the user input as an argument to the sys_call. If i understand correctly it is a school assignment, so you might just:
int do_stat(char * filename) {
...
}

Returning multiple file pointers in C

I'm new to C and would like some help with an issue I have. I'm reading and writing to pipes as follows:
f = fdopen(fdH2P[WRITE], "w"); // writing to pipe, returns a file pointer
and
r = fdopen(fdP2H[READ], "r"); // reading from pipe
I want to return both these file pointers from my function. What's the best way to do that?
You can either put the two file pointers into a structure and return that, or you can pass pointers to the function, like this
void GetPipes( FILE **wptr, FILE **rptr )
{
*wptr = fdopen(fdH2P[WRITE], "w");
*rptr = fdopen(fdP2H[READ], "r");
}
void SomeOtherFunction( void )
{
FILE *wptr, *rptr;
GetPipes( &wptr, &rptr );
...
}
You can return a struct:
Define struct, with typedef for convenience
typedef struct dual_fp {
FILE *read_fp;
FILE *write_fp;
} dual_fp;
Add function to open two files
dual_fp dual_fdopen(int write_fd, int read_fd) {
dual_fp ret;
// review error handling and reporting,
// such as add error code fields to struct dual_fp,
// and possibly do not open 2nd / close 1st file if the other fails
ret.write_fp = fdopen(write_fd, "w");
if (!ret.write_fp) perror("dual_fdopen for write");
ret.read_fp = fdopen(read_fd, "r");
if (!ret.read_fp) perror("dual_fdopen for read");
return ret;
}
Call it
dual_fp fps = dual_fdopen(fdH2P[WRITE], fdopen(fdP2H[READ]);
// use fps.read_fp and fps.write_fp after checking they are not NULL
Create a struct and return an instance of the struct.
typedef struct
{
FILE* write;
FILE* read;
} FilePointers;
FilePointers foo()
{
// Assuming you have access to the data...
FILE* w = fdopen(fdH2P[WRITE], "w");
FILE* r = fdopen(fdP2H[READ], "r");
FilePointers fp = {w, r};
return fp;
}

Share variable between libraries and program

I have 2 shared libraries(let them be 1.so,2.so) and program(a.out).
2.so is linked to 1.so and a.out - it has some functions that is used in 1 and a.
The code of 2.so is
FILE *in;
char filename[128];
int func_printer(int a)
{
if(strlen(filename)==0)
{
sprintf(filename,"%ld",time(NULL);
}
if((in=fopen(filename,"a"))==NULL)return;
fprintf(in,"%i",a);
fclose(in);
}
a.out has next
extern int func_printer(int);
extern void some_action();
int main()
{
some_action();
func_printer(2);
return 0;
}
And finally 1.so has method some_action
extern int func_printer(int);
void some_action()
{
func_printer(1);
printf("hello world");
return;
}
So when a.out starts, it call's 1.so(some_action()) and it call's 2.so(func_printer). It create file with name of timestamp(t1), write in it some info. After that 1.so calls 2.so(func_printer) and it creates another file's with timestamp.
Is it possible in this situation that some_action write always to t1, but when program starts again it should write to another file. All in all simply when program starts all libraries should know the filename where to write(without hard predifining the file name like char *filename="somefile.txt";)?
It seems like the only thing that writes to a file is 2.so. Just expose a setter:
char filename[128];
void set_filename(char * path) {
strncpy(filename, sizeof(filename), path);
filename[sizeof(filename) - 1] = '\0';
}
int func_printer(int a)
{
FILE *in;
if(strlen(filename)==0) {
sprintf(filename,"%ld",time(NULL);
}
if((in=fopen(filename,"a"))==NULL)return;
fprintf(in,"%i",a);
fclose(in);
}

Kernel module's parameters in sysfs - quick reaction for changes

Is it possible to notify the module when one of it's sys files was changed? My task is to do a file which controls size of buffer inside the module, I want to resize the buffer when the value in the file is changed.
My other idea (if I can't notify the module) was to check the previous value each time the module is used and then resize the buffer.
Isn't this the purpose of Sysfs?
When you create a kobject and give it a representation in Sysfs (which is a directory), you then create attributes for that object which will become files in that directory. You provide a store and a show callback to the kobject, which are basically equivalents of resp. write and read.
store is what you want here. It looks like this:
ssize_t (*store)(struct kobject *kobj, struct attribute *attr,
const char *buffer, size_t size);
You receive size bytes within buffer as soon as the virtual file is written in user land.
Have a look at this module which does it (taken from here):
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/slab.h>
struct my_attr {
struct attribute attr;
int value;
};
static struct my_attr my_first = {
.attr.name="first",
.attr.mode = 0644,
.value = 1,
};
static struct my_attr my_second = {
.attr.name="second",
.attr.mode = 0644,
.value = 2,
};
static struct attribute * myattr[] = {
&my_first.attr,
&my_second.attr,
NULL
};
static ssize_t default_show(struct kobject *kobj, struct attribute *attr,
char *buf)
{
struct my_attr *a = container_of(attr, struct my_attr, attr);
return scnprintf(buf, PAGE_SIZE, "%d\n", a->value);
}
static ssize_t default_store(struct kobject *kobj, struct attribute *attr,
const char *buf, size_t len)
{
struct my_attr *a = container_of(attr, struct my_attr, attr);
sscanf(buf, "%d", &a->value);
return sizeof(int);
}
static struct sysfs_ops myops = {
.show = default_show,
.store = default_store,
};
static struct kobj_type mytype = {
.sysfs_ops = &myops,
.default_attrs = myattr,
};
struct kobject *mykobj;
static int __init sysfsexample_module_init(void)
{
int err = -1;
mykobj = kzalloc(sizeof(*mykobj), GFP_KERNEL);
if (mykobj) {
kobject_init(mykobj, &mytype);
if (kobject_add(mykobj, NULL, "%s", "sysfs_sample")) {
err = -1;
printk("Sysfs creation failed\n");
kobject_put(mykobj);
mykobj = NULL;
}
err = 0;
}
return err;
}
static void __exit sysfsexample_module_exit(void)
{
if (mykobj) {
kobject_put(mykobj);
kfree(mykobj);
}
}
module_init(sysfsexample_module_init);
module_exit(sysfsexample_module_exit);
MODULE_LICENSE("GPL");
Also: you might want to output the buffer size to the user when the entry is read. This is usually the way of doing it. Also make sure the information (read and written) is in a human-readable format to keep up with the Unix philosophy.
Update: see this recent interesting article about Sysfs file creation written by Greg Kroah-Hartman, one of the top kernel developers.

Resources