Allow setting an IP4root address per processes This is the same idea a from the vserver project except that the ip4root is set via /proc and once set, a process can bind to privileged ports on that IP address ----------- Diffstat output ------------ ./fs/proc/array.c | 1 ./fs/proc/base.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++ ./include/linux/sched.h | 1 ./include/net/route.h | 7 ++++++ ./net/ipv4/af_inet.c | 20 +++++++++++++---- ./net/ipv4/tcp_ipv4.c | 11 +++++++-- 6 files changed, 88 insertions(+), 7 deletions(-) --- ./fs/proc/array.c 2002/05/20 00:10:41 1.1 +++ ./fs/proc/array.c 2002/05/20 00:11:59 1.2 @@ -286,6 +286,7 @@ buffer = task_mem(mm, buffer); mmput(mm); } + buffer += sprintf(buffer, "ipv4root: 0x%x\n", ntohl(task->ipv4root)); buffer = task_sig(task, buffer); buffer = task_cap(task, buffer); #if defined(CONFIG_ARCH_S390) --- ./fs/proc/base.c 2002/05/20 00:10:41 1.1 +++ ./fs/proc/base.c 2002/05/20 00:11:59 1.2 @@ -328,6 +328,55 @@ read: proc_info_read, }; +static int proc_read_ipv4root(struct task_struct *task, char *buffer) +{ + unsigned long addr = ntohl(task->ipv4root); + int res = + sprintf(buffer, "%ld.%ld.%ld.%ld\n", + (addr>>24)&255, + (addr>>16)&255, + (addr>>8)&255, + addr&255); + return res; +} + +static ssize_t proc_ipv4root_write(struct file * file, const char *buf, + size_t count, loff_t *ppos) +{ + char str[31]; + int a,b,c,d; + struct task_struct *task = file->f_dentry->d_inode->u.proc_i.task; + if (task->ipv4root) + return -EIO; + if (count > 30) + count = 30; + if (copy_from_user(str, buf, count)) + return -EFAULT; + + str[30]=0; + switch(sscanf(str, "%d.%d.%d.%d", &a,&b,&c,&d)) { + case 4: + task->ipv4root = htonl((a<<24)|(b<<16)|(c<<8)|d); + break; + case 3: + task->ipv4root = htonl((a<<24)|(b<<16)|c); + break; + case 2: + task->ipv4root = htonl((a<<24)|b); + break; + case 1: + task->ipv4root = htonl(a); + break; + } + return count; +} + + +static struct file_operations proc_ipv4root_file_operations = { + read: proc_info_read, + write: proc_ipv4root_write, +}; + #define MAY_PTRACE(p) \ (p==current||(p->p_pptr==current&&(p->ptrace & PT_PTRACED)&&p->state==TASK_STOPPED)) @@ -540,6 +589,7 @@ PROC_PID_MAPS, PROC_PID_CPU, PROC_PID_MOUNTS, + PROC_PID_IPV4ROOT, PROC_PID_FD_DIR = 0x8000, /* 0x8000-0xffff */ }; @@ -560,6 +610,7 @@ E(PROC_PID_ROOT, "root", S_IFLNK|S_IRWXUGO), E(PROC_PID_EXE, "exe", S_IFLNK|S_IRWXUGO), E(PROC_PID_MOUNTS, "mounts", S_IFREG|S_IRUGO), + E(PROC_PID_IPV4ROOT, "ipv4root", S_IFREG|S_IRUGO), {0,0,NULL,0} }; #undef E @@ -924,6 +975,10 @@ case PROC_PID_MEM: inode->i_op = &proc_mem_inode_operations; inode->i_fop = &proc_mem_operations; + break; + case PROC_PID_IPV4ROOT: + inode->i_fop = &proc_ipv4root_file_operations; + inode->u.proc_i.op.proc_read = proc_read_ipv4root; break; case PROC_PID_MOUNTS: inode->i_fop = &proc_mounts_operations; --- ./include/linux/sched.h 2002/05/20 00:10:41 1.1 +++ ./include/linux/sched.h 2002/05/20 00:12:00 1.2 @@ -406,6 +406,7 @@ size_t sas_ss_size; int (*notifier)(void *priv); void *notifier_data; + unsigned long ipv4root; /* Process can only bind to this IP, but no ports are privileged */ sigset_t *notifier_mask; /* Thread group tracking */ --- ./include/net/route.h 2002/05/20 00:10:41 1.1 +++ ./include/net/route.h 2002/05/20 00:12:00 1.2 @@ -160,6 +160,13 @@ static inline int ip_route_connect(struct rtable **rp, u32 dst, u32 src, u32 tos, int oif) { int err; + if (current->ipv4root) { + if (src == 0) { + src = current->ipv4root; + } else if (current->ipv4root != src) { + return -EPERM; + } + } err = ip_route_output(rp, dst, src, tos, oif); if (err || (dst && src)) return err; --- ./net/ipv4/af_inet.c 2002/05/20 00:10:41 1.1 +++ ./net/ipv4/af_inet.c 2002/05/20 00:12:00 1.2 @@ -5,7 +5,7 @@ * * PF_INET protocol family socket handler. * - * Version: $Id: af_inet.c,v 1.136 2001/11/06 22:21:08 davem Exp $ + * Version: $Id: af_inet.c,v 1.1 2002/03/01 03:04:58 neilb Exp neilb $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -477,6 +477,7 @@ unsigned short snum; int chk_addr_ret; int err; + __u32 s_addr; /* If the socket has its own bind function then use it. (RAW) */ if(sk->prot->bind) @@ -485,7 +486,15 @@ if (addr_len < sizeof(struct sockaddr_in)) return -EINVAL; - chk_addr_ret = inet_addr_type(addr->sin_addr.s_addr); + s_addr = addr->sin_addr.s_addr; + if (current->ipv4root) { + if (s_addr == 0) { + s_addr = current->ipv4root; + } else if (s_addr != current->ipv4root) { + return -EADDRNOTAVAIL; + } + } + chk_addr_ret = inet_addr_type(s_addr); /* Not specified by any standard per-se, however it breaks too * many applications when removed. It is unfortunate since @@ -496,14 +505,15 @@ */ if (sysctl_ip_nonlocal_bind == 0 && sk->protinfo.af_inet.freebind == 0 && - addr->sin_addr.s_addr != INADDR_ANY && + s_addr != INADDR_ANY && chk_addr_ret != RTN_LOCAL && chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST) return -EADDRNOTAVAIL; snum = ntohs(addr->sin_port); - if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) + if (snum && snum < PROT_SOCK && + ! (capable(CAP_NET_BIND_SERVICE) || current->ipv4root)) return -EACCES; /* We keep a pair of addresses. rcv_saddr is the one @@ -521,7 +531,7 @@ (sk->num != 0)) goto out; - sk->rcv_saddr = sk->saddr = addr->sin_addr.s_addr; + sk->rcv_saddr = sk->saddr = s_addr; if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST) sk->saddr = 0; /* Use device */ --- ./net/ipv4/tcp_ipv4.c 2002/05/20 00:10:41 1.1 +++ ./net/ipv4/tcp_ipv4.c 2002/05/20 00:12:00 1.2 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_ipv4.c,v 1.237.2.1 2002/01/15 08:49:49 davem Exp $ + * Version: $Id: tcp_ipv4.c,v 1.1 2002/03/15 01:53:31 neilb Exp neilb $ * * IPv4 specific functions * @@ -188,8 +188,15 @@ sk2->state == TCP_LISTEN) { if (!sk2->rcv_saddr || !sk->rcv_saddr || - (sk2->rcv_saddr == sk->rcv_saddr)) + (sk2->rcv_saddr == sk->rcv_saddr)) { + + if (sk2->state == TCP_LISTEN && + sk2->rcv_saddr == 0 && + sk->rcv_saddr != 0 && + sk->rcv_saddr == current->ipv4root) + continue; break; + } } } }