Commit ad370e28 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://kernel.bkbits.net/davem/net-2.5

into home.transmeta.com:/home/torvalds/v2.5/linux
parents d8a1413d fd7c713f
...@@ -614,11 +614,9 @@ L: linux-net@vger.kernel.org ...@@ -614,11 +614,9 @@ L: linux-net@vger.kernel.org
S: Maintained S: Maintained
ETHERNET BRIDGE ETHERNET BRIDGE
P: Lennert Buytenhek
M: buytenh@gnu.org
L: bridge@math.leidenuniv.nl L: bridge@math.leidenuniv.nl
W: http://bridge.sourceforge.net/ W: http://bridge.sourceforge.net/
S: Maintained S: Unmaintained
ETHERTEAM 16I DRIVER ETHERTEAM 16I DRIVER
P: Mika Kuoppala P: Mika Kuoppala
......
This diff is collapsed.
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/skbuff.h> /* struct sk_buff */ #include <linux/skbuff.h> /* struct sk_buff */
#include <linux/security.h>
#ifdef CONFIG_FILTER #ifdef CONFIG_FILTER
#include <linux/filter.h> #include <linux/filter.h>
...@@ -458,28 +459,45 @@ extern void sock_init_data(struct socket *sock, struct sock *sk); ...@@ -458,28 +459,45 @@ extern void sock_init_data(struct socket *sock, struct sock *sk);
#ifdef CONFIG_FILTER #ifdef CONFIG_FILTER
/** /**
* sk_filter - run a packet through a socket filter * __sk_filter - run a packet through a socket filter
* @sk: sock associated with &sk_buff
* @skb: buffer to filter * @skb: buffer to filter
* @filter: filter to apply * @needlock: set to 1 if the sock is not locked by caller.
* *
* Run the filter code and then cut skb->data to correct size returned by * Run the filter code and then cut skb->data to correct size returned by
* sk_run_filter. If pkt_len is 0 we toss packet. If skb->len is smaller * sk_run_filter. If pkt_len is 0 we toss packet. If skb->len is smaller
* than pkt_len we keep whole skb->data. This is the socket level * than pkt_len we keep whole skb->data. This is the socket level
* wrapper to sk_run_filter. It returns 0 if the packet should * wrapper to sk_run_filter. It returns 0 if the packet should
* be accepted or 1 if the packet should be tossed. * be accepted or -EPERM if the packet should be tossed.
*
* This function should not be called directly, use sk_filter instead
* to ensure that the LSM security check is also performed.
*/ */
static inline int sk_filter(struct sk_buff *skb, struct sk_filter *filter)
{
int pkt_len;
pkt_len = sk_run_filter(skb, filter->insns, filter->len); static inline int __sk_filter(struct sock *sk, struct sk_buff *skb, int needlock)
if(!pkt_len) {
return 1; /* Toss Packet */ int err = 0;
else
skb_trim(skb, pkt_len);
return 0; if (sk->filter) {
struct sk_filter *filter;
if (needlock)
bh_lock_sock(sk);
filter = sk->filter;
if (filter) {
int pkt_len = sk_run_filter(skb, filter->insns,
filter->len);
if (!pkt_len)
err = -EPERM;
else
skb_trim(skb, pkt_len);
}
if (needlock)
bh_unlock_sock(sk);
}
return err;
} }
/** /**
...@@ -506,8 +524,26 @@ static inline void sk_filter_charge(struct sock *sk, struct sk_filter *fp) ...@@ -506,8 +524,26 @@ static inline void sk_filter_charge(struct sock *sk, struct sk_filter *fp)
atomic_add(sk_filter_len(fp), &sk->omem_alloc); atomic_add(sk_filter_len(fp), &sk->omem_alloc);
} }
#else
static inline int __sk_filter(struct sock *sk, struct sk_buff *skb, int needlock)
{
return 0;
}
#endif /* CONFIG_FILTER */ #endif /* CONFIG_FILTER */
static inline int sk_filter(struct sock *sk, struct sk_buff *skb, int needlock)
{
int err;
err = security_sock_rcv_skb(sk, skb);
if (err)
return err;
return __sk_filter(sk, skb, needlock);
}
/* /*
* Socket reference counting postulates. * Socket reference counting postulates.
* *
...@@ -712,36 +748,31 @@ static inline void skb_set_owner_r(struct sk_buff *skb, struct sock *sk) ...@@ -712,36 +748,31 @@ static inline void skb_set_owner_r(struct sk_buff *skb, struct sock *sk)
static inline int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) static inline int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
{ {
int err = 0;
/* Cast skb->rcvbuf to unsigned... It's pointless, but reduces /* Cast skb->rcvbuf to unsigned... It's pointless, but reduces
number of warnings when compiling with -W --ANK number of warnings when compiling with -W --ANK
*/ */
if (atomic_read(&sk->rmem_alloc) + skb->truesize >= (unsigned)sk->rcvbuf) if (atomic_read(&sk->rmem_alloc) + skb->truesize >= (unsigned)sk->rcvbuf) {
return -ENOMEM; err = -ENOMEM;
goto out;
#ifdef CONFIG_FILTER
if (sk->filter) {
int err = 0;
struct sk_filter *filter;
/* It would be deadlock, if sock_queue_rcv_skb is used
with socket lock! We assume that users of this
function are lock free.
*/
bh_lock_sock(sk);
if ((filter = sk->filter) != NULL && sk_filter(skb, filter))
err = -EPERM;
bh_unlock_sock(sk);
if (err)
return err; /* Toss packet */
} }
#endif /* CONFIG_FILTER */
/* It would be deadlock, if sock_queue_rcv_skb is used
with socket lock! We assume that users of this
function are lock free.
*/
err = sk_filter(sk, skb, 1);
if (err)
goto out;
skb->dev = NULL; skb->dev = NULL;
skb_set_owner_r(skb, sk); skb_set_owner_r(skb, sk);
skb_queue_tail(&sk->receive_queue, skb); skb_queue_tail(&sk->receive_queue, skb);
if (!sk->dead) if (!sk->dead)
sk->data_ready(sk,skb->len); sk->data_ready(sk,skb->len);
return 0; out:
return err;
} }
static inline int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb) static inline int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb)
......
...@@ -33,12 +33,12 @@ int (*br_should_route_hook) (struct sk_buff **pskb) = NULL; ...@@ -33,12 +33,12 @@ int (*br_should_route_hook) (struct sk_buff **pskb) = NULL;
void br_dec_use_count() void br_dec_use_count()
{ {
MOD_DEC_USE_COUNT; module_put(THIS_MODULE);
} }
void br_inc_use_count() void br_inc_use_count()
{ {
MOD_INC_USE_COUNT; try_module_get(THIS_MODULE);
} }
static int __init br_init(void) static int __init br_init(void)
......
...@@ -155,8 +155,6 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, struct net_device ...@@ -155,8 +155,6 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, struct net_device
p->path_cost = br_initial_port_cost(dev); p->path_cost = br_initial_port_cost(dev);
p->priority = 0x80; p->priority = 0x80;
dev->br_port = p;
for (i=1;i<255;i++) for (i=1;i<255;i++)
if (br_get_port(br, i) == NULL) if (br_get_port(br, i) == NULL)
break; break;
...@@ -166,6 +164,8 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, struct net_device ...@@ -166,6 +164,8 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, struct net_device
return NULL; return NULL;
} }
dev->br_port = p;
p->port_no = i; p->port_no = i;
br_init_port(p); br_init_port(p);
p->state = BR_STATE_DISABLED; p->state = BR_STATE_DISABLED;
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <linux/capability.h> #include <linux/capability.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/security.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/system.h> #include <asm/system.h>
...@@ -363,7 +364,7 @@ rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) ...@@ -363,7 +364,7 @@ rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp)
sz_idx = type>>2; sz_idx = type>>2;
kind = type&3; kind = type&3;
if (kind != 2 && !cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN)) { if (kind != 2 && security_netlink_recv(skb)) {
*errp = -EPERM; *errp = -EPERM;
return -1; return -1;
} }
......
...@@ -566,26 +566,19 @@ static void dn_nsp_linkservice(struct sock *sk, struct sk_buff *skb) ...@@ -566,26 +566,19 @@ static void dn_nsp_linkservice(struct sock *sk, struct sk_buff *skb)
*/ */
static __inline__ int dn_queue_skb(struct sock *sk, struct sk_buff *skb, int sig, struct sk_buff_head *queue) static __inline__ int dn_queue_skb(struct sock *sk, struct sk_buff *skb, int sig, struct sk_buff_head *queue)
{ {
#ifdef CONFIG_FILTER int err;
struct sk_filter *filter;
#endif
/* Cast skb->rcvbuf to unsigned... It's pointless, but reduces /* Cast skb->rcvbuf to unsigned... It's pointless, but reduces
number of warnings when compiling with -W --ANK number of warnings when compiling with -W --ANK
*/ */
if (atomic_read(&sk->rmem_alloc) + skb->truesize >= (unsigned)sk->rcvbuf if (atomic_read(&sk->rmem_alloc) + skb->truesize >= (unsigned)sk->rcvbuf) {
) err = -ENOMEM;
return -ENOMEM; goto out;
#ifdef CONFIG_FILTER
if (sk->filter) {
int err = 0;
if ((filter = sk->filter) != NULL && sk_filter(skb, sk->filter))
err = -EPERM; /* Toss packet */
if (err)
return err;
} }
#endif /* CONFIG_FILTER */
err = sk_filter(sk, skb, 0);
if (err)
goto out;
skb_set_owner_r(skb, sk); skb_set_owner_r(skb, sk);
skb_queue_tail(queue, skb); skb_queue_tail(queue, skb);
...@@ -603,8 +596,8 @@ static __inline__ int dn_queue_skb(struct sock *sk, struct sk_buff *skb, int sig ...@@ -603,8 +596,8 @@ static __inline__ int dn_queue_skb(struct sock *sk, struct sk_buff *skb, int sig
(sig == SIGURG) ? POLL_PRI : POLL_IN); (sig == SIGURG) ? POLL_PRI : POLL_IN);
} }
read_unlock(&sk->callback_lock); read_unlock(&sk->callback_lock);
out:
return 0; return err;
} }
static void dn_nsp_otherdata(struct sock *sk, struct sk_buff *skb) static void dn_nsp_otherdata(struct sock *sk, struct sk_buff *skb)
......
...@@ -148,6 +148,14 @@ config IP_NF_MATCH_ECN ...@@ -148,6 +148,14 @@ config IP_NF_MATCH_ECN
config IP_NF_MATCH_DSCP config IP_NF_MATCH_DSCP
tristate "DSCP match support" tristate "DSCP match support"
depends on IP_NF_IPTABLES depends on IP_NF_IPTABLES
help
This option adds a `DSCP' match, which allows you to match against
the IPv4 header DSCP field (DSCP codepoint).
The DSCP codepoint can have any value between 0x0 and 0x4f.
If you want to compile it as a module, say M here and read
Documentation/modules.txt. If unsure, say `N'.
config IP_NF_MATCH_AH_ESP config IP_NF_MATCH_AH_ESP
tristate "AH/ESP match support" tristate "AH/ESP match support"
......
...@@ -84,7 +84,6 @@ ip_nat_resize_packet(struct sk_buff **skb, ...@@ -84,7 +84,6 @@ ip_nat_resize_packet(struct sk_buff **skb,
iph = (*skb)->nh.iph; iph = (*skb)->nh.iph;
if (iph->protocol == IPPROTO_TCP) { if (iph->protocol == IPPROTO_TCP) {
struct tcphdr *tcph = (void *)iph + iph->ihl*4; struct tcphdr *tcph = (void *)iph + iph->ihl*4;
void *data = (void *)tcph + tcph->doff*4;
DEBUGP("ip_nat_resize_packet: Seq_offset before: "); DEBUGP("ip_nat_resize_packet: Seq_offset before: ");
DUMP_OFFSET(this_way); DUMP_OFFSET(this_way);
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/brlock.h> #include <linux/brlock.h>
#include <linux/sysctl.h> #include <linux/sysctl.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/security.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/route.h> #include <net/route.h>
...@@ -496,7 +497,7 @@ ipq_rcv_skb(struct sk_buff *skb) ...@@ -496,7 +497,7 @@ ipq_rcv_skb(struct sk_buff *skb)
if (type <= IPQM_BASE) if (type <= IPQM_BASE)
return; return;
if(!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN)) if (security_netlink_recv(skb))
RCV_SKB_FAIL(-EPERM); RCV_SKB_FAIL(-EPERM);
write_lock_bh(&queue_lock); write_lock_bh(&queue_lock);
......
...@@ -2288,7 +2288,7 @@ int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) ...@@ -2288,7 +2288,7 @@ int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
struct net_device *dev = __dev_get_by_index(iif); struct net_device *dev = __dev_get_by_index(iif);
err = -ENODEV; err = -ENODEV;
if (!dev) if (!dev)
goto out; goto out_free;
skb->protocol = htons(ETH_P_IP); skb->protocol = htons(ETH_P_IP);
skb->dev = dev; skb->dev = dev;
local_bh_disable(); local_bh_disable();
...@@ -2307,10 +2307,8 @@ int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) ...@@ -2307,10 +2307,8 @@ int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
fl.oif = oif; fl.oif = oif;
err = ip_route_output_key(&rt, &fl); err = ip_route_output_key(&rt, &fl);
} }
if (err) { if (err)
kfree_skb(skb); goto out_free;
goto out;
}
skb->dst = &rt->u.dst; skb->dst = &rt->u.dst;
if (rtm->rtm_flags & RTM_F_NOTIFY) if (rtm->rtm_flags & RTM_F_NOTIFY)
...@@ -2321,16 +2319,20 @@ int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) ...@@ -2321,16 +2319,20 @@ int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
err = rt_fill_info(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, err = rt_fill_info(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq,
RTM_NEWROUTE, 0); RTM_NEWROUTE, 0);
if (!err) if (!err)
goto out; goto out_free;
if (err < 0) { if (err < 0) {
err = -EMSGSIZE; err = -EMSGSIZE;
goto out; goto out_free;
} }
err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
if (err > 0) if (err > 0)
err = 0; err = 0;
out: return err; out: return err;
out_free:
kfree_skb(skb);
goto out;
} }
int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb) int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb)
......
...@@ -1697,12 +1697,6 @@ static int tcp_v4_checksum_init(struct sk_buff *skb) ...@@ -1697,12 +1697,6 @@ static int tcp_v4_checksum_init(struct sk_buff *skb)
*/ */
int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
{ {
#ifdef CONFIG_FILTER
struct sk_filter *filter = sk->filter;
if (filter && sk_filter(skb, filter))
goto discard;
#endif /* CONFIG_FILTER */
if (sk->state == TCP_ESTABLISHED) { /* Fast path */ if (sk->state == TCP_ESTABLISHED) { /* Fast path */
TCP_CHECK_TIMER(sk); TCP_CHECK_TIMER(sk);
if (tcp_rcv_established(sk, skb, skb->h.th, skb->len)) if (tcp_rcv_established(sk, skb, skb->h.th, skb->len))
...@@ -1805,6 +1799,9 @@ int tcp_v4_rcv(struct sk_buff *skb) ...@@ -1805,6 +1799,9 @@ int tcp_v4_rcv(struct sk_buff *skb)
if (!xfrm_policy_check(sk, XFRM_POLICY_IN, skb)) if (!xfrm_policy_check(sk, XFRM_POLICY_IN, skb))
goto discard_and_relse; goto discard_and_relse;
if (sk_filter(sk, skb, 0))
goto discard_and_relse;
skb->dev = NULL; skb->dev = NULL;
bh_lock_sock(sk); bh_lock_sock(sk);
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/pfkeyv2.h> #include <linux/pfkeyv2.h>
#include <linux/ipsec.h> #include <linux/ipsec.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/security.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/xfrm.h> #include <net/xfrm.h>
...@@ -774,7 +775,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *err ...@@ -774,7 +775,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *err
link = &xfrm_dispatch[type]; link = &xfrm_dispatch[type];
/* All operations require privileges, even GET */ /* All operations require privileges, even GET */
if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN)) { if (security_netlink_recv(skb)) {
*errp = -EPERM; *errp = -EPERM;
return -1; return -1;
} }
......
...@@ -538,10 +538,10 @@ ipq_rcv_skb(struct sk_buff *skb) ...@@ -538,10 +538,10 @@ ipq_rcv_skb(struct sk_buff *skb)
if (type <= IPQM_BASE) if (type <= IPQM_BASE)
return; return;
if(!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
RCV_SKB_FAIL(-EPERM);
if (security_netlink_recv(skb))
RCV_SKB_FAIL(-EPERM);
write_lock_bh(&queue_lock); write_lock_bh(&queue_lock);
if (peer_pid) { if (peer_pid) {
......
...@@ -1548,14 +1548,14 @@ int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) ...@@ -1548,14 +1548,14 @@ int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
{ {
struct rtattr **rta = arg; struct rtattr **rta = arg;
int iif = 0; int iif = 0;
int err; int err = -ENOBUFS;
struct sk_buff *skb; struct sk_buff *skb;
struct flowi fl; struct flowi fl;
struct rt6_info *rt; struct rt6_info *rt;
skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
if (skb == NULL) if (skb == NULL)
return -ENOBUFS; goto out;
/* Reserve room for dummy headers, this skb can pass /* Reserve room for dummy headers, this skb can pass
through good chunk of routing engine. through good chunk of routing engine.
...@@ -1579,8 +1579,10 @@ int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) ...@@ -1579,8 +1579,10 @@ int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
if (iif) { if (iif) {
struct net_device *dev; struct net_device *dev;
dev = __dev_get_by_index(iif); dev = __dev_get_by_index(iif);
if (!dev) if (!dev) {
return -ENODEV; err = -ENODEV;
goto out_free;
}
} }
fl.oif = 0; fl.oif = 0;
...@@ -1597,13 +1599,19 @@ int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) ...@@ -1597,13 +1599,19 @@ int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
fl.nl_u.ip6_u.saddr, fl.nl_u.ip6_u.saddr,
iif, iif,
RTM_NEWROUTE, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq); RTM_NEWROUTE, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq);
if (err < 0) if (err < 0) {
return -EMSGSIZE; err = -EMSGSIZE;
goto out_free;
}
err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
if (err < 0) if (err > 0)
return err; err = 0;
return 0; out:
return err;
out_free:
kfree_skb(skb);
goto out;
} }
void inet6_rt_notify(int event, struct rt6_info *rt) void inet6_rt_notify(int event, struct rt6_info *rt)
......
...@@ -1470,9 +1470,6 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) ...@@ -1470,9 +1470,6 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
{ {
struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk);
struct tcp_opt *tp; struct tcp_opt *tp;
#ifdef CONFIG_FILTER
struct sk_filter *filter;
#endif
struct sk_buff *opt_skb = NULL; struct sk_buff *opt_skb = NULL;
/* Imagine: socket is IPv6. IPv4 packet arrives, /* Imagine: socket is IPv6. IPv4 packet arrives,
...@@ -1486,11 +1483,8 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) ...@@ -1486,11 +1483,8 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
if (skb->protocol == htons(ETH_P_IP)) if (skb->protocol == htons(ETH_P_IP))
return tcp_v4_do_rcv(sk, skb); return tcp_v4_do_rcv(sk, skb);
#ifdef CONFIG_FILTER if (sk_filter(sk, skb, 0))
filter = sk->filter;
if (filter && sk_filter(skb, filter))
goto discard; goto discard;
#endif /* CONFIG_FILTER */
/* /*
* socket locking is here for SMP purposes as backlog rcv * socket locking is here for SMP purposes as backlog rcv
...@@ -1641,6 +1635,9 @@ static int tcp_v6_rcv(struct sk_buff *skb) ...@@ -1641,6 +1635,9 @@ static int tcp_v6_rcv(struct sk_buff *skb)
if(sk->state == TCP_TIME_WAIT) if(sk->state == TCP_TIME_WAIT)
goto do_time_wait; goto do_time_wait;
if (sk_filter(sk, skb, 0))
goto discard_and_relse;
skb->dev = NULL; skb->dev = NULL;
bh_lock_sock(sk); bh_lock_sock(sk);
...@@ -1672,6 +1669,10 @@ static int tcp_v6_rcv(struct sk_buff *skb) ...@@ -1672,6 +1669,10 @@ static int tcp_v6_rcv(struct sk_buff *skb)
kfree_skb(skb); kfree_skb(skb);
return 0; return 0;
discard_and_relse:
sock_put(sk);
goto discard_it;
do_time_wait: do_time_wait:
if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) { if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
TCP_INC_STATS_BH(TcpInErrs); TCP_INC_STATS_BH(TcpInErrs);
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/security.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/scm.h> #include <net/scm.h>
...@@ -636,7 +637,12 @@ static int netlink_sendmsg(struct kiocb *iocb, struct socket *sock, ...@@ -636,7 +637,12 @@ static int netlink_sendmsg(struct kiocb *iocb, struct socket *sock,
check them, when this message will be delivered check them, when this message will be delivered
to corresponding kernel module. --ANK (980802) to corresponding kernel module. --ANK (980802)
*/ */
NETLINK_CB(skb).eff_cap = current->cap_effective;
err = security_netlink_send(skb);
if (err) {
kfree_skb(skb);
goto out;
}
err = -EFAULT; err = -EFAULT;
if (memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len)) { if (memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len)) {
......
...@@ -159,6 +159,10 @@ int sctp_rcv(struct sk_buff *skb) ...@@ -159,6 +159,10 @@ int sctp_rcv(struct sk_buff *skb)
if (!xfrm_policy_check(sk, XFRM_POLICY_IN, skb)) if (!xfrm_policy_check(sk, XFRM_POLICY_IN, skb))
goto discard_release; goto discard_release;
ret = sk_filter(sk, skb, 1);
if (ret)
goto discard_release;
/* Create an SCTP packet structure. */ /* Create an SCTP packet structure. */
chunk = sctp_chunkify(skb, asoc, sk); chunk = sctp_chunkify(skb, asoc, sk);
if (!chunk) { if (!chunk) {
......
...@@ -77,6 +77,7 @@ ...@@ -77,6 +77,7 @@
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/divert.h> #include <linux/divert.h>
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/security.h>
#if defined(CONFIG_KMOD) && defined(CONFIG_NET) #if defined(CONFIG_KMOD) && defined(CONFIG_NET)
#include <linux/kmod.h> #include <linux/kmod.h>
...@@ -527,6 +528,10 @@ static int __sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr ...@@ -527,6 +528,10 @@ static int __sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr
si->msg = msg; si->msg = msg;
si->size = size; si->size = size;
err = security_socket_sendmsg(sock, msg, size);
if (err)
return err;
err = scm_send(sock, msg, si->scm); err = scm_send(sock, msg, si->scm);
if (err >= 0) { if (err >= 0) {
err = sock->ops->sendmsg(iocb, sock, msg, size, si->scm); err = sock->ops->sendmsg(iocb, sock, msg, size, si->scm);
...@@ -551,6 +556,7 @@ int sock_sendmsg(struct socket *sock, struct msghdr *msg, int size) ...@@ -551,6 +556,7 @@ int sock_sendmsg(struct socket *sock, struct msghdr *msg, int size)
int __sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, int size, int flags) int __sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, int size, int flags)
{ {
int err;
struct sock_iocb *si = kiocb_to_siocb(iocb); struct sock_iocb *si = kiocb_to_siocb(iocb);
si->sock = sock; si->sock = sock;
...@@ -560,6 +566,10 @@ int __sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, ...@@ -560,6 +566,10 @@ int __sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
si->size = size; si->size = size;
si->flags = flags; si->flags = flags;
err = security_socket_recvmsg(sock, msg, size, flags);
if (err)
return err;
memset(si->scm, 0, sizeof(*si->scm)); memset(si->scm, 0, sizeof(*si->scm));
size = sock->ops->recvmsg(iocb, sock, msg, size, flags, si->scm); size = sock->ops->recvmsg(iocb, sock, msg, size, flags, si->scm);
...@@ -963,6 +973,7 @@ int sock_wake_async(struct socket *sock, int how, int band) ...@@ -963,6 +973,7 @@ int sock_wake_async(struct socket *sock, int how, int band)
int sock_create(int family, int type, int protocol, struct socket **res) int sock_create(int family, int type, int protocol, struct socket **res)
{ {
int i; int i;
int err;
struct socket *sock; struct socket *sock;
/* /*
...@@ -986,6 +997,10 @@ int sock_create(int family, int type, int protocol, struct socket **res) ...@@ -986,6 +997,10 @@ int sock_create(int family, int type, int protocol, struct socket **res)
} }
family = PF_PACKET; family = PF_PACKET;
} }
err = security_socket_create(family, type, protocol);
if (err)
return err;
#if defined(CONFIG_KMOD) && defined(CONFIG_NET) #if defined(CONFIG_KMOD) && defined(CONFIG_NET)
/* Attempt to load a protocol module if the find failed. /* Attempt to load a protocol module if the find failed.
...@@ -1031,6 +1046,7 @@ int sock_create(int family, int type, int protocol, struct socket **res) ...@@ -1031,6 +1046,7 @@ int sock_create(int family, int type, int protocol, struct socket **res)
} }
*res = sock; *res = sock;
security_socket_post_create(sock, family, type, protocol);
out: out:
net_family_read_unlock(); net_family_read_unlock();
...@@ -1141,8 +1157,14 @@ asmlinkage long sys_bind(int fd, struct sockaddr *umyaddr, int addrlen) ...@@ -1141,8 +1157,14 @@ asmlinkage long sys_bind(int fd, struct sockaddr *umyaddr, int addrlen)
if((sock = sockfd_lookup(fd,&err))!=NULL) if((sock = sockfd_lookup(fd,&err))!=NULL)
{ {
if((err=move_addr_to_kernel(umyaddr,addrlen,address))>=0) if((err=move_addr_to_kernel(umyaddr,addrlen,address))>=0) {
err = security_socket_bind(sock, (struct sockaddr *)address, addrlen);
if (err) {
sockfd_put(sock);
return err;
}
err = sock->ops->bind(sock, (struct sockaddr *)address, addrlen); err = sock->ops->bind(sock, (struct sockaddr *)address, addrlen);
}
sockfd_put(sock); sockfd_put(sock);
} }
return err; return err;
...@@ -1163,6 +1185,13 @@ asmlinkage long sys_listen(int fd, int backlog) ...@@ -1163,6 +1185,13 @@ asmlinkage long sys_listen(int fd, int backlog)
if ((sock = sockfd_lookup(fd, &err)) != NULL) { if ((sock = sockfd_lookup(fd, &err)) != NULL) {
if ((unsigned) backlog > SOMAXCONN) if ((unsigned) backlog > SOMAXCONN)
backlog = SOMAXCONN; backlog = SOMAXCONN;
err = security_socket_listen(sock, backlog);
if (err) {
sockfd_put(sock);
return err;
}
err=sock->ops->listen(sock, backlog); err=sock->ops->listen(sock, backlog);
sockfd_put(sock); sockfd_put(sock);
} }
...@@ -1199,6 +1228,10 @@ asmlinkage long sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_a ...@@ -1199,6 +1228,10 @@ asmlinkage long sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_a
newsock->type = sock->type; newsock->type = sock->type;
newsock->ops = sock->ops; newsock->ops = sock->ops;
err = security_socket_accept(sock, newsock);
if (err)
goto out_release;
err = sock->ops->accept(sock, newsock, sock->file->f_flags); err = sock->ops->accept(sock, newsock, sock->file->f_flags);
if (err < 0) if (err < 0)
goto out_release; goto out_release;
...@@ -1218,6 +1251,8 @@ asmlinkage long sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_a ...@@ -1218,6 +1251,8 @@ asmlinkage long sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_a
if ((err = sock_map_fd(newsock)) < 0) if ((err = sock_map_fd(newsock)) < 0)
goto out_release; goto out_release;
security_socket_post_accept(sock, newsock);
out_put: out_put:
sockfd_put(sock); sockfd_put(sock);
out: out:
...@@ -1253,6 +1288,11 @@ asmlinkage long sys_connect(int fd, struct sockaddr *uservaddr, int addrlen) ...@@ -1253,6 +1288,11 @@ asmlinkage long sys_connect(int fd, struct sockaddr *uservaddr, int addrlen)
err = move_addr_to_kernel(uservaddr, addrlen, address); err = move_addr_to_kernel(uservaddr, addrlen, address);
if (err < 0) if (err < 0)
goto out_put; goto out_put;
err = security_socket_connect(sock, (struct sockaddr *)address, addrlen);
if (err)
goto out_put;
err = sock->ops->connect(sock, (struct sockaddr *) address, addrlen, err = sock->ops->connect(sock, (struct sockaddr *) address, addrlen,
sock->file->f_flags); sock->file->f_flags);
out_put: out_put:
...@@ -1275,6 +1315,11 @@ asmlinkage long sys_getsockname(int fd, struct sockaddr *usockaddr, int *usockad ...@@ -1275,6 +1315,11 @@ asmlinkage long sys_getsockname(int fd, struct sockaddr *usockaddr, int *usockad
sock = sockfd_lookup(fd, &err); sock = sockfd_lookup(fd, &err);
if (!sock) if (!sock)
goto out; goto out;
err = security_socket_getsockname(sock);
if (err)
goto out_put;
err = sock->ops->getname(sock, (struct sockaddr *)address, &len, 0); err = sock->ops->getname(sock, (struct sockaddr *)address, &len, 0);
if (err) if (err)
goto out_put; goto out_put;
...@@ -1299,6 +1344,12 @@ asmlinkage long sys_getpeername(int fd, struct sockaddr *usockaddr, int *usockad ...@@ -1299,6 +1344,12 @@ asmlinkage long sys_getpeername(int fd, struct sockaddr *usockaddr, int *usockad
if ((sock = sockfd_lookup(fd, &err))!=NULL) if ((sock = sockfd_lookup(fd, &err))!=NULL)
{ {
err = security_socket_getpeername(sock);
if (err) {
sockfd_put(sock);
return err;
}
err = sock->ops->getname(sock, (struct sockaddr *)address, &len, 1); err = sock->ops->getname(sock, (struct sockaddr *)address, &len, 1);
if (!err) if (!err)
err=move_addr_to_user(address,len, usockaddr, usockaddr_len); err=move_addr_to_user(address,len, usockaddr, usockaddr_len);
...@@ -1427,6 +1478,12 @@ asmlinkage long sys_setsockopt(int fd, int level, int optname, char *optval, int ...@@ -1427,6 +1478,12 @@ asmlinkage long sys_setsockopt(int fd, int level, int optname, char *optval, int
if ((sock = sockfd_lookup(fd, &err))!=NULL) if ((sock = sockfd_lookup(fd, &err))!=NULL)
{ {
err = security_socket_setsockopt(sock,level,optname);
if (err) {
sockfd_put(sock);
return err;
}
if (level == SOL_SOCKET) if (level == SOL_SOCKET)
err=sock_setsockopt(sock,level,optname,optval,optlen); err=sock_setsockopt(sock,level,optname,optval,optlen);
else else
...@@ -1448,6 +1505,13 @@ asmlinkage long sys_getsockopt(int fd, int level, int optname, char *optval, int ...@@ -1448,6 +1505,13 @@ asmlinkage long sys_getsockopt(int fd, int level, int optname, char *optval, int
if ((sock = sockfd_lookup(fd, &err))!=NULL) if ((sock = sockfd_lookup(fd, &err))!=NULL)
{ {
err = security_socket_getsockopt(sock, level,
optname);
if (err) {
sockfd_put(sock);
return err;
}
if (level == SOL_SOCKET) if (level == SOL_SOCKET)
err=sock_getsockopt(sock,level,optname,optval,optlen); err=sock_getsockopt(sock,level,optname,optval,optlen);
else else
...@@ -1469,6 +1533,12 @@ asmlinkage long sys_shutdown(int fd, int how) ...@@ -1469,6 +1533,12 @@ asmlinkage long sys_shutdown(int fd, int how)
if ((sock = sockfd_lookup(fd, &err))!=NULL) if ((sock = sockfd_lookup(fd, &err))!=NULL)
{ {
err = security_socket_shutdown(sock, how);
if (err) {
sockfd_put(sock);
return err;
}
err=sock->ops->shutdown(sock, how); err=sock->ops->shutdown(sock, how);
sockfd_put(sock); sockfd_put(sock);
} }
......
...@@ -115,6 +115,7 @@ ...@@ -115,6 +115,7 @@
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <linux/mount.h> #include <linux/mount.h>
#include <net/checksum.h> #include <net/checksum.h>
#include <linux/security.h>
int sysctl_unix_max_dgram_qlen = 10; int sysctl_unix_max_dgram_qlen = 10;
...@@ -816,6 +817,11 @@ static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr, ...@@ -816,6 +817,11 @@ static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr,
err = -EPERM; err = -EPERM;
if (!unix_may_send(sk, other)) if (!unix_may_send(sk, other))
goto out_unlock; goto out_unlock;
err = security_unix_may_send(sk->socket, other->socket);
if (err)
goto out_unlock;
} else { } else {
/* /*
* 1003.1g breaking connected state with AF_UNSPEC * 1003.1g breaking connected state with AF_UNSPEC
...@@ -981,6 +987,12 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr, ...@@ -981,6 +987,12 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,
goto restart; goto restart;
} }
err = security_unix_stream_connect(sock, other->socket, newsk);
if (err) {
unix_state_wunlock(sk);
goto out_unlock;
}
/* The way is open! Fastly set all the necessary fields... */ /* The way is open! Fastly set all the necessary fields... */
sock_hold(sk); sock_hold(sk);
...@@ -1280,6 +1292,10 @@ static int unix_dgram_sendmsg(struct kiocb *iocb, struct socket *sock, ...@@ -1280,6 +1292,10 @@ static int unix_dgram_sendmsg(struct kiocb *iocb, struct socket *sock,
if (other->shutdown&RCV_SHUTDOWN) if (other->shutdown&RCV_SHUTDOWN)
goto out_unlock; goto out_unlock;
err = security_unix_may_send(sk->socket, other->socket);
if (err)
goto out_unlock;
if (unix_peer(other) != sk && if (unix_peer(other) != sk &&
skb_queue_len(&other->receive_queue) > other->max_ack_backlog) { skb_queue_len(&other->receive_queue) > other->max_ack_backlog) {
if (!timeo) { if (!timeo) {
......
...@@ -15,6 +15,15 @@ config SECURITY ...@@ -15,6 +15,15 @@ config SECURITY
If you are unsure how to answer this question, answer N. If you are unsure how to answer this question, answer N.
config SECURITY_NETWORK
bool "Socket and Networking Security Hooks"
depends on SECURITY
help
This enables the socket and networking security hooks.
If enabled, a security module can use these hooks to
implement socket and networking access controls.
If you are unsure how to answer this question, answer N.
config SECURITY_CAPABILITIES config SECURITY_CAPABILITIES
tristate "Default Linux Capabilities" tristate "Default Linux Capabilities"
depends on SECURITY!=n depends on SECURITY!=n
......
...@@ -282,6 +282,8 @@ static struct security_operations capability_ops = { ...@@ -282,6 +282,8 @@ static struct security_operations capability_ops = {
.capset_check = cap_capset_check, .capset_check = cap_capset_check,
.capset_set = cap_capset_set, .capset_set = cap_capset_set,
.capable = cap_capable, .capable = cap_capable,
.netlink_send = cap_netlink_send,
.netlink_recv = cap_netlink_recv,
.bprm_compute_creds = cap_bprm_compute_creds, .bprm_compute_creds = cap_bprm_compute_creds,
.bprm_set_security = cap_bprm_set_security, .bprm_set_security = cap_bprm_set_security,
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#include <linux/security.h> #include <linux/security.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/netlink.h> #include <linux/netlink.h>
#include <net/sock.h>
static int dummy_ptrace (struct task_struct *parent, struct task_struct *child) static int dummy_ptrace (struct task_struct *parent, struct task_struct *child)
{ {
...@@ -597,6 +597,118 @@ static int dummy_sem_semop (struct sem_array *sma, ...@@ -597,6 +597,118 @@ static int dummy_sem_semop (struct sem_array *sma,
return 0; return 0;
} }
static int dummy_netlink_send (struct sk_buff *skb)
{
if (current->euid == 0)
cap_raise (NETLINK_CB (skb).eff_cap, CAP_NET_ADMIN);
else
NETLINK_CB (skb).eff_cap = 0;
return 0;
}
static int dummy_netlink_recv (struct sk_buff *skb)
{
if (!cap_raised (NETLINK_CB (skb).eff_cap, CAP_NET_ADMIN))
return -EPERM;
return 0;
}
#ifdef CONFIG_SECURITY_NETWORK
static int dummy_unix_stream_connect (struct socket *sock,
struct socket *other,
struct sock *newsk)
{
return 0;
}
static int dummy_unix_may_send (struct socket *sock,
struct socket *other)
{
return 0;
}
static int dummy_socket_create (int family, int type, int protocol)
{
return 0;
}
static void dummy_socket_post_create (struct socket *sock, int family, int type,
int protocol)
{
return;
}
static int dummy_socket_bind (struct socket *sock, struct sockaddr *address,
int addrlen)
{
return 0;
}
static int dummy_socket_connect (struct socket *sock, struct sockaddr *address,
int addrlen)
{
return 0;
}
static int dummy_socket_listen (struct socket *sock, int backlog)
{
return 0;
}
static int dummy_socket_accept (struct socket *sock, struct socket *newsock)
{
return 0;
}
static void dummy_socket_post_accept (struct socket *sock,
struct socket *newsock)
{
return;
}
static int dummy_socket_sendmsg (struct socket *sock, struct msghdr *msg,
int size)
{
return 0;
}
static int dummy_socket_recvmsg (struct socket *sock, struct msghdr *msg,
int size, int flags)
{
return 0;
}
static int dummy_socket_getsockname (struct socket *sock)
{
return 0;
}
static int dummy_socket_getpeername (struct socket *sock)
{
return 0;
}
static int dummy_socket_setsockopt (struct socket *sock, int level, int optname)
{
return 0;
}
static int dummy_socket_getsockopt (struct socket *sock, int level, int optname)
{
return 0;
}
static int dummy_socket_shutdown (struct socket *sock, int how)
{
return 0;
}
static int dummy_socket_sock_rcv_skb (struct sock *sk, struct sk_buff *skb)
{
return 0;
}
#endif /* CONFIG_SECURITY_NETWORK */
static int dummy_register_security (const char *name, struct security_operations *ops) static int dummy_register_security (const char *name, struct security_operations *ops)
{ {
return -EINVAL; return -EINVAL;
...@@ -723,7 +835,28 @@ void security_fixup_ops (struct security_operations *ops) ...@@ -723,7 +835,28 @@ void security_fixup_ops (struct security_operations *ops)
set_to_dummy_if_null(ops, sem_associate); set_to_dummy_if_null(ops, sem_associate);
set_to_dummy_if_null(ops, sem_semctl); set_to_dummy_if_null(ops, sem_semctl);
set_to_dummy_if_null(ops, sem_semop); set_to_dummy_if_null(ops, sem_semop);
set_to_dummy_if_null(ops, netlink_send);
set_to_dummy_if_null(ops, netlink_recv);
set_to_dummy_if_null(ops, register_security); set_to_dummy_if_null(ops, register_security);
set_to_dummy_if_null(ops, unregister_security); set_to_dummy_if_null(ops, unregister_security);
#ifdef CONFIG_SECURITY_NETWORK
set_to_dummy_if_null(ops, unix_stream_connect);
set_to_dummy_if_null(ops, unix_may_send);
set_to_dummy_if_null(ops, socket_create);
set_to_dummy_if_null(ops, socket_post_create);
set_to_dummy_if_null(ops, socket_bind);
set_to_dummy_if_null(ops, socket_connect);
set_to_dummy_if_null(ops, socket_listen);
set_to_dummy_if_null(ops, socket_accept);
set_to_dummy_if_null(ops, socket_post_accept);
set_to_dummy_if_null(ops, socket_sendmsg);
set_to_dummy_if_null(ops, socket_recvmsg);
set_to_dummy_if_null(ops, socket_getsockname);
set_to_dummy_if_null(ops, socket_getpeername);
set_to_dummy_if_null(ops, socket_setsockopt);
set_to_dummy_if_null(ops, socket_getsockopt);
set_to_dummy_if_null(ops, socket_shutdown);
set_to_dummy_if_null(ops, socket_sock_rcv_skb);
#endif /* CONFIG_SECURITY_NETWORK */
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment