static int sock_fn(struct sock *sk, int optval, void *user, unsigned int len) { if (!capable(CAP_NET_ADMIN)) return -EPERM; return -ip_fw_ctl(optval, user, len); }
static int sock_fn(struct sock *sk, int optval, void __user *user, unsigned int len) { /* MAX of: 2.2: sizeof(struct ip_fwtest) (~14x4 + 3x4 = 17x4) 2.2: sizeof(struct ip_fwnew) (~1x4 + 15x4 + 3x4 + 3x4 = 22x4) 2.0: sizeof(struct ip_fw) (~25x4) We can't include both 2.0 and 2.2 headers, they conflict. Hence, 200 is a good number. --RR */ char tmp_fw[200]; if (!capable(CAP_NET_ADMIN)) return -EPERM; if (len > sizeof(tmp_fw) || len < 1) return -EINVAL; if (copy_from_user(&tmp_fw, user, len)) return -EFAULT; return -ip_fw_ctl(optval, &tmp_fw, len); }
int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen) { int val,err; unsigned char ucval; #if defined(CONFIG_IP_FIREWALL) || defined(CONFIG_IP_ACCT) struct ip_fw tmp_fw; #endif if (optval == NULL) { val=0; ucval=0; } else { err=verify_area(VERIFY_READ, optval, sizeof(int)); if(err) return err; val = get_user((int *) optval); ucval=get_user((unsigned char *) optval); } if(level!=SOL_IP) return -EOPNOTSUPP; #ifdef CONFIG_IP_MROUTE if(optname>=MRT_BASE && optname <=MRT_BASE+10) { return ip_mroute_setsockopt(sk,optname,optval,optlen); } #endif switch(optname) { case IP_OPTIONS: { struct options * opt = NULL; struct options * old_opt; if (optlen > 40 || optlen < 0) return -EINVAL; err = verify_area(VERIFY_READ, optval, optlen); if (err) return err; opt = kmalloc(sizeof(struct options)+((optlen+3)&~3), GFP_KERNEL); if (!opt) return -ENOMEM; memset(opt, 0, sizeof(struct options)); if (optlen) memcpy_fromfs(opt->__data, optval, optlen); while (optlen & 3) opt->__data[optlen++] = IPOPT_END; opt->optlen = optlen; opt->is_data = 1; opt->is_setbyuser = 1; if (optlen && ip_options_compile(opt, NULL)) { kfree_s(opt, sizeof(struct options) + optlen); return -EINVAL; } /* * ANK: I'm afraid that receive handler may change * options from under us. */ cli(); old_opt = sk->opt; sk->opt = opt; sti(); if (old_opt) kfree_s(old_opt, sizeof(struct optlen) + old_opt->optlen); return 0; } case IP_TOS: /* This sets both TOS and Precedence */ if (val<0 || val>63) /* Reject setting of unused bits */ return -EINVAL; if ((val&7) > 4 && !suser()) /* Only root can set Prec>4 */ return -EPERM; sk->ip_tos=val; switch (val & 0x38) { case IPTOS_LOWDELAY: sk->priority=SOPRI_INTERACTIVE; break; case IPTOS_THROUGHPUT: sk->priority=SOPRI_BACKGROUND; break; default: sk->priority=SOPRI_NORMAL; break; } return 0; case IP_TTL: if(val<1||val>255) return -EINVAL; sk->ip_ttl=val; return 0; case IP_HDRINCL: if(sk->type!=SOCK_RAW) return -ENOPROTOOPT; sk->ip_hdrincl=val?1:0; return 0; #ifdef CONFIG_IP_MULTICAST case IP_MULTICAST_TTL: { sk->ip_mc_ttl=(int)ucval; return 0; } case IP_MULTICAST_LOOP: { if(ucval!=0 && ucval!=1) return -EINVAL; sk->ip_mc_loop=(int)ucval; return 0; } case IP_MULTICAST_IF: { struct in_addr addr; struct device *dev=NULL; /* * Check the arguments are allowable */ err=verify_area(VERIFY_READ, optval, sizeof(addr)); if(err) return err; memcpy_fromfs(&addr,optval,sizeof(addr)); /* * What address has been requested */ if(addr.s_addr==INADDR_ANY) /* Default */ { sk->ip_mc_name[0]=0; return 0; } /* * Find the device */ dev=ip_mc_find_devfor(addr.s_addr); /* * Did we find one */ if(dev) { strcpy(sk->ip_mc_name,dev->name); return 0; } return -EADDRNOTAVAIL; } case IP_ADD_MEMBERSHIP: { /* * FIXME: Add/Del membership should have a semaphore protecting them from re-entry */ struct ip_mreq mreq; __u32 route_src; struct rtable *rt; struct device *dev=NULL; /* * Check the arguments. */ err=verify_area(VERIFY_READ, optval, sizeof(mreq)); if(err) return err; memcpy_fromfs(&mreq,optval,sizeof(mreq)); /* * Get device for use later */ if(mreq.imr_interface.s_addr==INADDR_ANY) { /* * Not set so scan. */ if((rt=ip_rt_route(mreq.imr_multiaddr.s_addr,0))!=NULL) { dev=rt->rt_dev; route_src = rt->rt_src; atomic_dec(&rt->rt_use); ip_rt_put(rt); } } else { /* * Find a suitable device. */ dev=ip_mc_find_devfor(mreq.imr_interface.s_addr); } /* * No device, no cookies. */ if(!dev) return -ENODEV; /* * Join group. */ return ip_mc_join_group(sk,dev,mreq.imr_multiaddr.s_addr); } case IP_DROP_MEMBERSHIP: { struct ip_mreq mreq; struct rtable *rt; __u32 route_src; struct device *dev=NULL; /* * Check the arguments */ err=verify_area(VERIFY_READ, optval, sizeof(mreq)); if(err) return err; memcpy_fromfs(&mreq,optval,sizeof(mreq)); /* * Get device for use later */ if(mreq.imr_interface.s_addr==INADDR_ANY) { if((rt=ip_rt_route(mreq.imr_multiaddr.s_addr,0))!=NULL) { dev=rt->rt_dev; atomic_dec(&rt->rt_use); route_src = rt->rt_src; ip_rt_put(rt); } } else { dev=ip_mc_find_devfor(mreq.imr_interface.s_addr); } /* * Did we find a suitable device. */ if(!dev) return -ENODEV; /* * Leave group */ return ip_mc_leave_group(sk,dev,mreq.imr_multiaddr.s_addr); } #endif #ifdef CONFIG_IP_FIREWALL case IP_FW_INSERT_IN: case IP_FW_INSERT_OUT: case IP_FW_INSERT_FWD: case IP_FW_APPEND_IN: case IP_FW_APPEND_OUT: case IP_FW_APPEND_FWD: case IP_FW_DELETE_IN: case IP_FW_DELETE_OUT: case IP_FW_DELETE_FWD: case IP_FW_CHECK_IN: case IP_FW_CHECK_OUT: case IP_FW_CHECK_FWD: case IP_FW_FLUSH_IN: case IP_FW_FLUSH_OUT: case IP_FW_FLUSH_FWD: case IP_FW_ZERO_IN: case IP_FW_ZERO_OUT: case IP_FW_ZERO_FWD: case IP_FW_POLICY_IN: case IP_FW_POLICY_OUT: case IP_FW_POLICY_FWD: case IP_FW_MASQ_TIMEOUTS: if(!suser()) return -EPERM; if(optlen>sizeof(tmp_fw) || optlen<1) return -EINVAL; err=verify_area(VERIFY_READ,optval,optlen); if(err) return err; memcpy_fromfs(&tmp_fw,optval,optlen); err=ip_fw_ctl(optname, &tmp_fw,optlen); return -err; /* -0 is 0 after all */ #endif #ifdef CONFIG_IP_ACCT case IP_ACCT_INSERT: case IP_ACCT_APPEND: case IP_ACCT_DELETE: case IP_ACCT_FLUSH: case IP_ACCT_ZERO: if(!suser()) return -EPERM; if(optlen>sizeof(tmp_fw) || optlen<1) return -EINVAL; err=verify_area(VERIFY_READ,optval,optlen); if(err) return err; memcpy_fromfs(&tmp_fw, optval,optlen); err=ip_acct_ctl(optname, &tmp_fw,optlen); return -err; /* -0 is 0 after all */ #endif /* IP_OPTIONS and friends go here eventually */ default: return(-ENOPROTOOPT); } }