Create a prank to cut the connection between the TCP connection and the process

Do you want to play another prank? ?

When many operations and maintenance find that there is an abnormal tcp connection in the system, they will use the netstat/ss command to find out the processing process corresponding to the tcp connection, and then go to the R&D debug process. such as:

[root@localhost ~]# netstat -ntp
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 192.168.56.110:22       192.168.56.1:50069      ESTABLISHED 1420/sshd: root@pts
tcp        0      0 192.168.56.110:22       192.168.56.1:50048      ESTABLISHED 1357/sshd: root@pts
tcp        0      0 192.168.56.110:22       192.168.56.1:50060      ESTABLISHED 1378/sshd: root@pts
tcp        0      0 192.168.56.110:22       192.168.56.1:50063      ESTABLISHED 1399/sshd: root@pts

What happens if I tear down the association between the tcp connection and the process? Juggling a craft to see their performance?

Or, more importantly, can I achieve the goal of blaming others by exchanging the tcp connections handled by process 1 and process 2? I want you to check, I want you to check a ball of yarn!

To accomplish this, you must first understand how the association between the tcp connection and the process is established in Linux.

OK, let's get started.

In the Linux system, a tcp connection is represented by a tcp_sock object at the bottom.

In the OO design of sock, there is the following inheritance relationship, we start from the base class sock_common:
sock_common <-- sock <-- inet_sock <-- inet_connection_sock <-- tcp_sock

however…

However, the process and tcp_sock do not point to each other, because a tcp connection is not the only one corresponding to a process. We know that tcp_sock exists as a file descriptor in the process context, and multiple processes can operate the same tcp connection.

Therefore, you can correspond to a tcp connection from the file descriptor of a process, but not vice versa. You cannot confirm the process it belongs to through a tcp_sock.
Insert picture description here

Based on the fact that there is no one-to-one correspondence between a TCP connection and a process, in terms of implementation, to associate a TCP connection with a process, it must be handled in two steps:

  • Linux exports all tcp_sock in /proc/net/tcp, where the inode field points to the i_ino field of the inode address of the socket_alloc structure object of the Berkeley socket layer.
  • Linux exports all processes in the /proc/$pid directory, and exports all file descriptors opened by the process in the /proc/$pid/fd subdirectory.

When you execute netstat -antp, the actions of netstat are as follows:

  1. Save the inode numbers of all tcp connections in /proc/net/tcp in a linked list.
  2. Traverse the links in the /proc/$pid/fd directory of all processes exported under /proc, and use the link inode number to match the inode number in the tcp inode linked list.
  3. Establish an association between the successfully matched tcp inode number and /proc/$pid/fd/$fd->inode.

If you replace netstat with ss, the process remains the same. The only difference is that the tcp inode list is no longer obtained through /proc/net/tcp, but through netlink.

You can observe all of this through strace netstat/ss without analyzing the source code of netstat/ss.

This process is very similar to the process of the driver/device mutual probe on the bus in the Linux kernel driver management mechanism!

In order to complete this prank, the conventional idea is to hook /proc/$pid/fd/x, so that the link that was originally a tcp socket will be displayed as pointing to other things such as /dev/null.

But with an understanding of the process of the association process to the tcp connection, it is easier to remove the association between them. There is no need to hook the file operation interface of procfs, as shown in the following figure:
Insert picture description here
this is obviously a kind of file than hook procfs. The operation interface is closer to the essential approach. Personally, I don’t like hook procfs. It is complicated and inelegant, and it doesn’t solve the problem fundamentally! The scheme described in the diagram above is the essential scheme.

The code to accomplish this is as follows:

#!/usr/bin/stap -g

function relieve(fd:long)
%{
    
    
	struct dentry *dentry = current->files->fdt->fd[STAP_ARG_fd]->f_path.dentry;
	struct inode *ino = current->files->fdt->fd[0]->f_path.dentry->d_inode;
	dentry->d_inode = ino;
%}

probe kernel.function("__schedule").return
{
    
    
	if (pid() == $1) {
    
    
		relieve($2);
		exit()
	}
}

function wakeup(pid:long)
%{
    
    
	struct task_struct *tsk;

	tsk = pid_task(find_vpid(STAP_ARG_pid), PIDTYPE_PID);
	if (tsk)
		wake_up_process(tsk);
%}

probe timer.ms(500)
{
    
    
	wakeup($1)
}

Super super super simple code.

Explain why you need to hook __schedule.return, because at this position you can ensure that the scheduled process does not hold a spin lock (holding a spin lock is forbidden to schedule), and other processes on the same CPU do not hold spin Lock (otherwise it will not be switched out)

Come and see the effect. Take the example at the beginning of this article as an experiment. My purpose is to eliminate the display of process pid and process name behind netstat -ntp:

[root@localhost test]# for pid in $(netstat -ntp|egrep -o [0-9]+\/|egrep -o [0-9]+); do ./relieve.stp $pid 3;done
[root@localhost test]# netstat -ntp
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 192.168.56.110:22       192.168.56.1:50069      ESTABLISHED -
tcp        0      0 192.168.56.110:22       192.168.56.1:50048      ESTABLISHED -
tcp        0      0 192.168.56.110:22       192.168.56.1:50060      ESTABLISHED -
tcp        0      0 192.168.56.110:22       192.168.56.1:50063      ESTABLISHED -
[root@localhost test]#
[root@localhost test]# netstat -ntp|egrep -o [0-9]+\/|egrep -o [0-9]+
[root@localhost test]# echo $?
1
[root@localhost test]#

Oh,yes!

A friend suggested that it is boring to get rid of it directly. It is better to confuse the relationship between the process and the tcp connection, which is more confusing. OK, this is really great. The simple code is as follows:

struct dentry *den1 = tsk1->files->fdt->fd[STAP_ARG_fd1]->f_path.dentry;
struct dentry *den2 = tsk2->files->fdt->fd[STAP_ARG_fd2]->f_path.dentry;
struct inode *tmp;

tmp = den1->d_inode;
den1->d_inode = den2->d_inode;
den2->d_inode = tmp;

Replace the code with the above, simply demonstrate an example.

First access two tcp connections, as shown below:
Insert picture description here

[root@localhost ~]# netstat -ntp
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 192.168.56.110:22       192.168.56.1:52105      ESTABLISHED 1046/sshd: root@pts
tcp        0      0 192.168.56.110:22       192.168.56.1:53346      ESTABLISHED 1523/sshd: root@pts

Then use the above code to exchange the f_path.dentry->d_inode of the two, which confuses the audiovisual, as shown below:
Insert picture description here

[root@localhost ~]# netstat -ntp
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 192.168.56.110:22       192.168.56.1:52105      ESTABLISHED 1523/sshd: root@pts
tcp        0      0 192.168.56.110:22       192.168.56.1:53346      ESTABLISHED 1046/sshd: root@pts

Look carefully, the relationship between the process and the connection has been exchanged. If the operation and maintenance finds an abnormality at this time, can you tease them, at least let them hold a meeting for this, haha!

what? May be down? To play in this business, enduring downtime is a must, and it must be polished slowly to produce quality products, haha.

As for how to crack this kind of trick, it's very simple. Instead of following the clue of procfs, we can just follow the clue of socket/sock:

  • The clue of socket/sock is endless!

Insert picture description here

I will use the crash plugin to demonstrate later, as for today's trick, I will stop here.


The leather shoes in Wenzhou, Zhejiang are wet, so they won’t get fat in the rain.

Guess you like

Origin blog.csdn.net/dog250/article/details/108113329