xorl %eax, %eax

GRKERNSEC_PROC_IPADDR /proc IP Address Support

leave a comment »

This is a feature of grsecurity that can be used for monitoring the IP addresses’ of the user(s) of each task through the /proc file system. It could be quite convenient for detecting attacks early just by looking for suspicious remote or local connections from suspicious tasks. Also, as you can read in the description:

config GRKERNSEC_PROC_IPADDR
	bool "/proc/<pid>/ipaddr support"
	help
	  If you say Y here, a new entry will be added to each /proc/<pid>
	  directory that contains the IP address of the person using the task.
	  The IP is carried across local TCP and AF_UNIX stream sockets.
	  This information can be useful for IDS/IPSes to perform remote response
	  to a local attack.  The entry is readable by only the owner of the
	  process (and root if he has CAP_DAC_OVERRIDE, which can be removed via
	  the RBAC system), and thus does not create privacy concerns.

This could be utilized in IDS or IPS software to provide immediate, automated response to such incidents. The patch is fairly simple and you can find it under fs/proc/array.c.

#ifdef CONFIG_GRKERNSEC_PROC_IPADDR
int proc_pid_ipaddr(struct task_struct *task, char *buffer)
{
	return sprintf(buffer, "%pI4\n", &task->signal->curr_ip);
}
#endif

This function takes two arguments, the task to check and the buffer to write and simply prints the current IP address of the specified task to the provided buffer. For those of you who wonder what the hell is the ‘curr_ip’ member, it’s a grsecurity addition to the ‘signal_struct’ structure along with a few more…

#ifdef CONFIG_GRKERNSEC
	u32 curr_ip;
	u32 gr_saddr;
	u32 gr_daddr;
	u16 gr_sport;
	u16 gr_dport;
	u8 used_accept:1;
#endif

This is initialized in accept(2) (located at net/socket.c) system call using a grsecurity routine named gr_attach_curr_ip() like this:

SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr,
                int __user *, upeer_addrlen, int, flags)
{
      ...
        fd_install(newfd, newfile);
        err = newfd;

	gr_attach_curr_ip(newsock->sk);

out_put:
        fput_light(sock->file, fput_needed);
      ...
        goto out_put;
}

This means that when a new connection succeeds through accept(2) system call in the kernel, gr_attach_curr_ip() will be invoked passing the new socket’s structure. This grsecurity’s function can be found at grsecurity/grsec_sock.c file.

void
gr_attach_curr_ip(const struct sock *sk)
{
#ifdef CONFIG_GRKERNSEC
	struct signal_struct *p, *set;
	const struct inet_sock *inet = inet_sk(sk);	

	if (unlikely(sk->sk_protocol != IPPROTO_TCP))
		return;

	set = current->signal;

	spin_lock_bh(&gr_conn_table_lock);
	p = gr_lookup_task_ip_table(inet->inet_daddr, inet->inet_rcv_saddr,
				    inet->inet_dport, inet->inet_sport);
	if (unlikely(p != NULL)) {
		set->curr_ip = p->curr_ip;
		set->used_accept = 1;
		gr_del_task_from_ip_table_nolock(p);
		spin_unlock_bh(&gr_conn_table_lock);
		return;
	}
	spin_unlock_bh(&gr_conn_table_lock);

	set->curr_ip = inet->inet_daddr;
	set->used_accept = 1;
#endif
	return;
}

Obviously, gr_attach_curr_ip() requires ‘CONFIG_GRKERNSEC’ (grsecurity Kernel Security) option to be enabled in order to work. What it does is initialize the ‘curr_ip’ value based on the socket’s information. So, gr_lookup_ip_table() takes the source and destination IP and ports pair and returns the the matching signal structure like this:

#ifdef CONFIG_GRKERNSEC
#define gr_conn_table_size 32749
struct conn_table_entry {
	struct conn_table_entry *next;
	struct signal_struct *sig;
};

struct conn_table_entry *gr_conn_table[gr_conn_table_size];
  ...
static struct signal_struct * gr_lookup_task_ip_table(__u32 saddr, __u32 daddr,
					     __u16 sport, __u16 dport)
{
	struct conn_table_entry *match;
	unsigned int index;

	index = conn_hash(saddr, daddr, sport, dport, gr_conn_table_size);

	match = gr_conn_table[index];
	while (match && !conn_match(match->sig, saddr, daddr, sport, dport))
		match = match->next;

	if (match)
		return match->sig;
	else
		return NULL;
}

Back to gr_attach_curr_ip() we can see that if the gr_lookup_task_ip_table() was able to obtain the matching signal structure it’ll use it to initialize ‘curr_ip’ member. Otherwise, it will directly use the destination IP address of the given socket.
Finally, the only thing left is the actual /proc entry which is placed in fs/proc/base.c file with ‘ipaddr’ name and proc_pid_ipaddr() that was discussed above as its file operation handler routine.

static const struct pid_entry tgid_base_stuff[] = {
    ...
#ifdef CONFIG_GRKERNSEC_PROC_IPADDR
	INF("ipaddr",	  S_IRUSR, proc_pid_ipaddr),
#endif
};

Written by xorl

November 9, 2010 at 04:10

Posted in grsecurity, linux, security

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s