I'm writing a LKM program to hook sys_read function for reuse 80 TCP port.
But I meet an problem is that I don't know how to access Port by inode struct.
There is a part of my program.
Linux.2.6.3.38
asmlinkage ssize_t new_read(unsigned int fd, void *buf, size_t count){
//printk("PID %d called sys_read !\n",current->pid);
char kbuf[MAX_BUF];
ssize_t ret;
struct file *file;
ret=orig_read(fd, buf, count);
memset(kbuf, 0,MAX_BUF);
memcpy(kbuf, buf, ret);
printk("kbuf:%s\n",kbuf);
if( memcmp(kbuf, passwd, strlen(passwd)) == 0 )
{
file = fget(fd);
if(file->f_dentry->d_inode->???? == PORT)
printk("get http message\n");
fput(file);
}
}
Thanks for answering.
You can obtain the socket structure pointer from the struct file with the exported function sock_from_file.
It is then cast into a tcp_sock, which contains an inet_connection_sock which contains an inet_sock which contains a sock (not to be confused with socket) which contains sock_common. The two port numbers are ultimately stored in inet_sock and sock_common (well, that's how it works in a recent kernel version anyway).
Making use of these facts in a reliable way would be difficult. The layout and organization of all this is closely dependent on kernel version, and of course that the file descriptor actually represents a connected TCP socket.
Related
I am using UNIX domain datagram sockets to send records from multiple clients to a single server in a multithreaded program. Everything is done within one process; I'm sending records from multiple threads to a single thread that acts as the server. All threads are assigned to separate cores using their affinity masks.
It works fine with a single client, but now I am using multiple clients. The server will read data from the socket using select() to return file descriptors that are ready ("set"), then use recvfrom to get the records.
But first I need to write the file descriptors to the fd_set struct so I can use it with select(). I created fd_set as a global struct at the top of the C file that contains the programs to open client and server sockets and pass messages between them:
fd_set fdset;
I create client sockets in this way:
int64_t * create_socket_client(struct sockaddr_un claddr, int64_t retvals[])
{
int sfd, j;
size_t msgLen;
ssize_t numBytes;
char resp[BUF_SIZE];
retvals[0] = 0;
retvals[1] = 0;
sfd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (sfd == -1)
return retvals;
memset(&claddr, 0, sizeof(struct sockaddr_un));
claddr.sun_family = AF_UNIX;
snprintf(claddr.sun_path, sizeof(claddr.sun_path), "/tmp/ud_ucase_cl.%ld", (long) getpid());
retvals[0] = sfd;
retvals[1] = (int64_t)&claddr;
return retvals;
}
The array retvals is passed in and returned with file descriptor and client address. But to be used with select() I need to insert the file descriptor in the fd_set when the socket is created (in the program above).
Normally that wouldn't be a problem if I knew the layout of fd_set. It's defined in sys/select.h:
/* fd_set for select and pselect. */
typedef struct
{
/* XPG4.2 requires this member name. Otherwise avoid the name
from the global namespace. */
#ifdef __USE_XOPEN
__fd_mask fds_bits[__FD_SETSIZE / __NFDBITS];
# define __FDS_BITS(set) ((set)->fds_bits)
#else
__fd_mask __fds_bits[__FD_SETSIZE / __NFDBITS];
# define __FDS_BITS(set) ((set)->__fds_bits)
#endif
} fd_set;
but from that definition I can't tell what the fields are or how to get a file descriptor or array of file descriptors into fd_set.
So my question is: how can I get the file descriptors into fd_set so it can be used with select()?
The way to manipulate an fd_set is with the following macros (from the man page for select()):
void FD_CLR(int fd, fd_set *set);
int FD_ISSET(int fd, fd_set *set);
void FD_SET(int fd, fd_set *set);
void FD_ZERO(fd_set *set);
A new fd_set must be cleared before it is used:
FD_ZERO(&my_fd_set);
To set a file descriptor in an fd_set, do:
FD_SET(my_fd, &my_fd_set);
Similarly, to remove an fd from an fd_set, do:
FD_CLR(my_fd, &my_fd_set);
To test if a file descriptor is set in an fd_set (i.e. to test which descriptors returned ready):
if (FD_ISSET(my_fd, &my_fd_set)) {
// Take action on my_fd
}
I'm currently working on an assignment in which I need to write a linux firewall extension.
A bit of context:
My kernel module will maintain a list of "rules". A rule is just a port number with a path to an executable file. A rule indicates that the program is allowed to make outgoing connections on the corresponding port.
A connection by program A on port X should only be terminated if there are rules for port X and program A is not one of them. So if a port has no rules set, anyone can communicate on the port.
I know how to analyze the TCP packet headers and extract the source port. My problem is, how can I tell which program created this packet?
Here is some example code my lecturer gave me, although I'm not sure how it helps. I've removed parts that aren't relevant for clarity.
int init_module(void)
{
struct path path;
pid_t mod_pid;
struct dentry *procDentry;
struct dentry *parent;
char cmdlineFile[BUFFERSIZE];
int res;
mod_pid = current->pid;
snprintf (cmdlineFile, BUFFERSIZE, "/proc/%d/exe", mod_pid);
res = kern_path (cmdlineFile, LOOKUP_FOLLOW, &path);
if (res) {
return -EFAULT;
}
procDentry = path.dentry;
parent = procDentry->d_parent;
printk (KERN_INFO "The name is %s\n", procDentry->d_name.name);
printk (KERN_INFO "The name of the parent is %s\n", parent->d_name.name);
path_put(&path);
return 0;
}
I have a Pseudo-terminal slave that's giving me a read/write error of Resource Temporarily Unavailable (11). I have been unable to solve this problem, but up until a week ago I didn't know anything pty's. So, I might be missing something obvious.
From what I have read, this can be caused by calling read() on a non-blocking pty. However, when I check the F_GETFL after I open() the slave pty, the value shows that it is a blocking file descriptor.
The output of F_GETFL shows that the O_NONBLOCK flag is disabled, and the O_RDWR flag is enabled:
printf("F_GETFL: %x\n", fcntl( slavefd, F_GETFL)); // outputs F_GETFL: 2
I have even tried treating slavefd as a non-blocking file by using select() to determine when it's ready. But, it just times out every time.
So, why does read() set errno to Resource Temporarily Unavailable if slavefd is set to blocking? Do the flags of F_GETFL look correct? What else can I try to narrow the cause of this problem?
Update: (more info)
I'm not sure yet, but I think the pty slave device node is being locked somehow by pppd. I have been told that you can echo into pty slave, which seems to be true except when pppd is using it.
Update 2: (code added)
if (argc!=2)
return;
printf("opening %s\n", argv[1]);
slavefd = open(argv[1], O_RDWR );
if (slavefd < 0)
return;
This update shows how I'm opening the slave device. Since I am using this application for debugging, I'm just directly using argv[1].
PROBLEM SOLVED:
The slave node that I was attempting to read/write to was being modified by pppd. When pppd takes control of a tty/pty device, it changes the line discipline from N_TTY to N_PPP. This means that when when you open() and then read() or write() to the slave node, the PPP intermediate driver is being used instead of the TTY driver. So, a read() and write() boils down to a totally different function. Looking at the N_PPP driver I found the following. This answers my question as to why EAGAIN was being returned.
/*
* Read does nothing - no data is ever available this way.
* Pppd reads and writes packets via /dev/ppp instead.
*/
static ssize_t
ppp_asynctty_read(struct tty_struct *tty, struct file *file,
unsigned char __user *buf, size_t count)
{
return -EAGAIN;
}
/*
* Write on the tty does nothing, the packets all come in
* from the ppp generic stuff.
*/
static ssize_t
ppp_asynctty_write(struct tty_struct *tty, struct file *file,
const unsigned char *buf, size_t count)
{
return -EAGAIN;
}
The slave node that I was attempting to read/write to was being modified by pppd. When pppd takes control of a tty/pty device, it changes the line discipline from N_TTY to N_PPP. This means that when when you open() and then read() or write() to the slave node, the PPP intermediate driver is being used instead of the TTY driver. So, a read() and write() boils down to a totally different function. Looking at the N_PPP driver I found the following. This answers my question as to why EAGAIN was being returned.
/*
* Read does nothing - no data is ever available this way.
* Pppd reads and writes packets via /dev/ppp instead.
*/
static ssize_t
ppp_asynctty_read(struct tty_struct *tty, struct file *file,
unsigned char __user *buf, size_t count)
{
return -EAGAIN;
}
/*
* Write on the tty does nothing, the packets all come in
* from the ppp generic stuff.
*/
static ssize_t
ppp_asynctty_write(struct tty_struct *tty, struct file *file,
const unsigned char *buf, size_t count)
{
return -EAGAIN;
}
Is there a way to get the sockfd from a struct sock or any other way that would allow me to uniquely identify the socket / connection I'm working with in kernel space?
I need this piece of information in the context of a device driver for a network adapter.
I thought it was impossible but actually there is a way, at least for simple cases where we have no duplicate file descriptors for a single socket. I'm answering my own question, hoping it'll help people out there.
int get_sockfd(struct sock *sk)
{
int sockfd;
unsigned int i;
struct files_struct *current_files;
struct fdtable *files;
struct socket *sock;
struct file *sock_filp;
sockfd = -1;
sock = sk->sk_socket;
sock_filp = sock->file;
current_files = current->files;
files = files_fdtable(current_files);
for (i = 0; files->fd[i] != NULL; i++) {
if (sock_filp == files->fd[i]) {
sockfd = i;
break;
}
}
return sockfd;
}
You would of course want to check for NULL pointers, starting with struct sock *sk passed in param.
So, basically, the idea is that the numerical value of a file descriptor (a sockfd is just a regular file descriptor, after all) corresponds to the index of its corresponding entry in a process open files table. All we have to do when given a struct sock *sk pointer is loop over the open files table of the current process until the addres pointed to by sk->sk_socket->file matches an entry in the table.
I'm trying to write a simple device driver, and use the Dev_Read() and Dev_Write() functions, which I have already defined.
My driver registers a character device tied to a
given major number this way
# mknod /dev/mydev c 250 0
And then, from my user program I open the device this way
int fd;
if ((fd = open("/dev/mydev", O_RDWR)) < 0)
{
perror("open /dev/mydev");
exit(EXIT_FAILURE);
}
after I invoke the Read() function
int read_bytes = read (fd, buffer, 1);
and successfully get kernel space information, that my Dev_Read function works.
My problem is that I don't understand how to implement my Dev_Write function.
How can I write someting to my file, to see that Dev_Write function works ?
THANK YOU for help.
It would help to know what you've tried which didn't work.
One thing to be aware of, and not necessarily intuitive, is that your driver's write function must copy the write buffer from the caller's space into kernel space. An example of that can be seen in the tutorial at http://www.freesoftwaremagazine.com/articles/drivers_linux -
ssize_t memory_write( struct file *filp, char *buf,
size_t count, loff_t *f_pos) {
char *tmp;
tmp=buf+count-1;
copy_from_user(memory_buffer,tmp,1);
return 1;
}
where memory_buffer is space you've allocated within your driver.