From 497c615abad7ee81994dd592194535aea2aad617 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 30 Jul 2006 20:19:33 -0700 Subject: [IPV6]: Audit all ip6_dst_lookup/ip6_dst_store calls The current users of ip6_dst_lookup can be divided into two classes: 1) The caller holds no locks and is in user-context (UDP). 2) The caller does not want to lookup the dst cache at all. The second class covers everyone except UDP because most people do the cache lookup directly before calling ip6_dst_lookup. This patch adds ip6_sk_dst_lookup for the first class. Similarly ip6_dst_store users can be divded into those that need to take the socket dst lock and those that don't. This patch adds __ip6_dst_store for those (everyone except UDP/datagram) that don't need an extra lock. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/net/ip6_route.h | 12 +++++++++--- include/net/ipv6.h | 3 +++ 2 files changed, 12 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index ab29dafb1a6a..96b0e66406ec 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -139,16 +139,22 @@ extern rwlock_t rt6_lock; /* * Store a destination cache entry in a socket */ -static inline void ip6_dst_store(struct sock *sk, struct dst_entry *dst, - struct in6_addr *daddr) +static inline void __ip6_dst_store(struct sock *sk, struct dst_entry *dst, + struct in6_addr *daddr) { struct ipv6_pinfo *np = inet6_sk(sk); struct rt6_info *rt = (struct rt6_info *) dst; - write_lock(&sk->sk_dst_lock); sk_setup_caps(sk, dst); np->daddr_cache = daddr; np->dst_cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0; +} + +static inline void ip6_dst_store(struct sock *sk, struct dst_entry *dst, + struct in6_addr *daddr) +{ + write_lock(&sk->sk_dst_lock); + __ip6_dst_store(sk, dst, daddr); write_unlock(&sk->sk_dst_lock); } diff --git a/include/net/ipv6.h b/include/net/ipv6.h index a8fdf7970b37..ece7e8a84ffd 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -468,6 +468,9 @@ extern void ip6_flush_pending_frames(struct sock *sk); extern int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl); +extern int ip6_sk_dst_lookup(struct sock *sk, + struct dst_entry **dst, + struct flowi *fl); /* * skb processing functions -- cgit v1.2.3 From 9cd3ecd674cf3194e07435b5b9559c4d432026d5 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Sun, 30 Jul 2006 20:20:07 -0700 Subject: [NETFILTER]: include/linux/netfilter_bridge.h: header cleanup Header doesn't use anything from atomic.h. It fixes headers_check warning: include/linux/netfilter_bridge.h requires asm/atomic.h, which does not exist Compile tested on alpha arm i386-up sparc sparc64-up x86_64 alpha-up i386 sparc64 sparc-up x86_64-up Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller --- include/linux/netfilter_bridge.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include') diff --git a/include/linux/netfilter_bridge.h b/include/linux/netfilter_bridge.h index 31f02ba036ce..10c13dc4665b 100644 --- a/include/linux/netfilter_bridge.h +++ b/include/linux/netfilter_bridge.h @@ -6,7 +6,6 @@ #include #if defined(__KERNEL__) && defined(CONFIG_BRIDGE_NETFILTER) -#include #include #endif -- cgit v1.2.3 From 3687b1dc6fe83a500ba4d3235704594f6a111a2d Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sun, 30 Jul 2006 20:35:54 -0700 Subject: [TCP]: SNMPv2 tcpAttemptFails counter error Refer to RFC2012, tcpAttemptFails is defined as following: tcpAttemptFails OBJECT-TYPE SYNTAX Counter32 MAX-ACCESS read-only STATUS current DESCRIPTION "The number of times TCP connections have made a direct transition to the CLOSED state from either the SYN-SENT state or the SYN-RCVD state, plus the number of times TCP connections have made a direct transition to the LISTEN state from the SYN-RCVD state." ::= { tcp 7 } When I lookup into RFC793, I found that the state change should occured under following condition: 1. SYN-SENT -> CLOSED a) Received ACK,RST segment when SYN-SENT state. 2. SYN-RCVD -> CLOSED b) Received SYN segment when SYN-RCVD state(came from LISTEN). c) Received RST segment when SYN-RCVD state(came from SYN-SENT). d) Received SYN segment when SYN-RCVD state(came from SYN-SENT). 3. SYN-RCVD -> LISTEN e) Received RST segment when SYN-RCVD state(came from LISTEN). In my test, those direct state transition can not be counted to tcpAttemptFails. Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- include/net/tcp.h | 3 +++ net/ipv4/tcp_ipv4.c | 2 -- net/ipv4/tcp_minisocks.c | 4 +++- net/ipv6/tcp_ipv6.c | 2 -- 4 files changed, 6 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/net/tcp.h b/include/net/tcp.h index 0720bddff1e9..7a093d0aa0fe 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -914,6 +914,9 @@ static inline void tcp_set_state(struct sock *sk, int state) static inline void tcp_done(struct sock *sk) { + if(sk->sk_state == TCP_SYN_SENT || sk->sk_state == TCP_SYN_RECV) + TCP_INC_STATS_BH(TCP_MIB_ATTEMPTFAILS); + tcp_set_state(sk, TCP_CLOSE); tcp_clear_xmit_timers(sk); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index f6f39e814291..4b04c3edd4a9 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -438,7 +438,6 @@ void tcp_v4_err(struct sk_buff *skb, u32 info) It can f.e. if SYNs crossed. */ if (!sock_owned_by_user(sk)) { - TCP_INC_STATS_BH(TCP_MIB_ATTEMPTFAILS); sk->sk_err = err; sk->sk_error_report(sk); @@ -874,7 +873,6 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) drop_and_free: reqsk_free(req); drop: - TCP_INC_STATS_BH(TCP_MIB_ATTEMPTFAILS); return 0; } diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 0ccb7cb22b15..624e2b2c7f53 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -589,8 +589,10 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb, /* RFC793: "second check the RST bit" and * "fourth, check the SYN bit" */ - if (flg & (TCP_FLAG_RST|TCP_FLAG_SYN)) + if (flg & (TCP_FLAG_RST|TCP_FLAG_SYN)) { + TCP_INC_STATS_BH(TCP_MIB_ATTEMPTFAILS); goto embryonic_reset; + } /* ACK sequence verified above, just make sure ACK is * set. If ACK not set, just silently drop the packet. diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index b76fd7fba5f5..b843a650be71 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -427,7 +427,6 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, case TCP_SYN_RECV: /* Cannot happen. It can, it SYNs are crossed. --ANK */ if (!sock_owned_by_user(sk)) { - TCP_INC_STATS_BH(TCP_MIB_ATTEMPTFAILS); sk->sk_err = err; sk->sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */ @@ -831,7 +830,6 @@ drop: if (req) reqsk_free(req); - TCP_INC_STATS_BH(TCP_MIB_ATTEMPTFAILS); return 0; /* don't send reset */ } -- cgit v1.2.3 From 792d1932e319ff8ba01361e7d151b1794c55c31f Mon Sep 17 00:00:00 2001 From: Tom Tucker Date: Sun, 30 Jul 2006 20:43:26 -0700 Subject: [NET]: Network Event Notifier Mechanism. This patch uses notifier blocks to implement a network event notifier mechanism. Clients register their callback function by calling register_netevent_notifier() like this: static struct notifier_block nb = { .notifier_call = my_callback_func }; ... register_netevent_notifier(&nb); Signed-off-by: Tom Tucker Signed-off-by: Steve Wise Signed-off-by: David S. Miller --- include/net/netevent.h | 33 ++++++++++++++++++++++++ net/core/netevent.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 include/net/netevent.h create mode 100644 net/core/netevent.c (limited to 'include') diff --git a/include/net/netevent.h b/include/net/netevent.h new file mode 100644 index 000000000000..e5d216241423 --- /dev/null +++ b/include/net/netevent.h @@ -0,0 +1,33 @@ +#ifndef _NET_EVENT_H +#define _NET_EVENT_H + +/* + * Generic netevent notifiers + * + * Authors: + * Tom Tucker + * Steve Wise + * + * Changes: + */ +#ifdef __KERNEL__ + +#include + +struct netevent_redirect { + struct dst_entry *old; + struct dst_entry *new; +}; + +enum netevent_notif_type { + NETEVENT_NEIGH_UPDATE = 1, /* arg is struct neighbour ptr */ + NETEVENT_PMTU_UPDATE, /* arg is struct dst_entry ptr */ + NETEVENT_REDIRECT, /* arg is struct netevent_redirect ptr */ +}; + +extern int register_netevent_notifier(struct notifier_block *nb); +extern int unregister_netevent_notifier(struct notifier_block *nb); +extern int call_netevent_notifiers(unsigned long val, void *v); + +#endif +#endif diff --git a/net/core/netevent.c b/net/core/netevent.c new file mode 100644 index 000000000000..35d02c38554e --- /dev/null +++ b/net/core/netevent.c @@ -0,0 +1,69 @@ +/* + * Network event notifiers + * + * Authors: + * Tom Tucker + * Steve Wise + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Fixes: + */ + +#include +#include + +static ATOMIC_NOTIFIER_HEAD(netevent_notif_chain); + +/** + * register_netevent_notifier - register a netevent notifier block + * @nb: notifier + * + * Register a notifier to be called when a netevent occurs. + * The notifier passed is linked into the kernel structures and must + * not be reused until it has been unregistered. A negative errno code + * is returned on a failure. + */ +int register_netevent_notifier(struct notifier_block *nb) +{ + int err; + + err = atomic_notifier_chain_register(&netevent_notif_chain, nb); + return err; +} + +/** + * netevent_unregister_notifier - unregister a netevent notifier block + * @nb: notifier + * + * Unregister a notifier previously registered by + * register_neigh_notifier(). The notifier is unlinked into the + * kernel structures and may then be reused. A negative errno code + * is returned on a failure. + */ + +int unregister_netevent_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(&netevent_notif_chain, nb); +} + +/** + * call_netevent_notifiers - call all netevent notifier blocks + * @val: value passed unmodified to notifier function + * @v: pointer passed unmodified to notifier function + * + * Call all neighbour notifier blocks. Parameters and return value + * are as for notifier_call_chain(). + */ + +int call_netevent_notifiers(unsigned long val, void *v) +{ + return atomic_notifier_call_chain(&netevent_notif_chain, val, v); +} + +EXPORT_SYMBOL_GPL(register_netevent_notifier); +EXPORT_SYMBOL_GPL(unregister_netevent_notifier); +EXPORT_SYMBOL_GPL(call_netevent_notifiers); -- cgit v1.2.3 From 8af2745645243b5e5b031504a643bf2158571dc7 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 31 Jul 2006 22:35:23 -0700 Subject: [NET]: Add netdev_alloc_skb(). Add a dev_alloc_skb variant that takes a struct net_device * paramater. For now that paramater is unused, but I'll use it to allocate the skb from node-local memory in a follow-up patch. Also there have been some other plans mentioned on the list that can use it. Signed-off-by: Christoph Hellwig Signed-off-by: David S. Miller --- include/linux/skbuff.h | 22 ++++++++++++++++++++++ net/core/skbuff.c | 24 ++++++++++++++++++++++++ 2 files changed, 46 insertions(+) (limited to 'include') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 4307e764ef0a..b91fbfb7d54c 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1104,6 +1104,28 @@ static inline struct sk_buff *dev_alloc_skb(unsigned int length) return __dev_alloc_skb(length, GFP_ATOMIC); } +extern struct sk_buff *__netdev_alloc_skb(struct net_device *dev, + unsigned int length, gfp_t gfp_mask); + +/** + * netdev_alloc_skb - allocate an skbuff for rx on a specific device + * @dev: network device to receive on + * @length: length to allocate + * + * Allocate a new &sk_buff and assign it a usage count of one. The + * buffer has unspecified headroom built in. Users should allocate + * the headroom they think they need without accounting for the + * built in space. The built in space is used for optimisations. + * + * %NULL is returned if there is no free memory. Although this function + * allocates memory it can be called from an interrupt. + */ +static inline struct sk_buff *netdev_alloc_skb(struct net_device *dev, + unsigned int length) +{ + return __netdev_alloc_skb(dev, length, GFP_ATOMIC); +} + /** * skb_cow - copy header of skb when it is required * @skb: buffer to cow diff --git a/net/core/skbuff.c b/net/core/skbuff.c index d236f02c6467..71487b915d67 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -256,6 +256,29 @@ nodata: goto out; } +/** + * __netdev_alloc_skb - allocate an skbuff for rx on a specific device + * @dev: network device to receive on + * @length: length to allocate + * @gfp_mask: get_free_pages mask, passed to alloc_skb + * + * Allocate a new &sk_buff and assign it a usage count of one. The + * buffer has unspecified headroom built in. Users should allocate + * the headroom they think they need without accounting for the + * built in space. The built in space is used for optimisations. + * + * %NULL is returned if there is no free memory. + */ +struct sk_buff *__netdev_alloc_skb(struct net_device *dev, + unsigned int length, gfp_t gfp_mask) +{ + struct sk_buff *skb; + + skb = alloc_skb(length + NET_SKB_PAD, gfp_mask); + if (likely(skb)) + skb_reserve(skb, NET_SKB_PAD); + return skb; +} static void skb_drop_list(struct sk_buff **listp) { @@ -2048,6 +2071,7 @@ EXPORT_SYMBOL(__kfree_skb); EXPORT_SYMBOL(kfree_skb); EXPORT_SYMBOL(__pskb_pull_tail); EXPORT_SYMBOL(__alloc_skb); +EXPORT_SYMBOL(__netdev_alloc_skb); EXPORT_SYMBOL(pskb_copy); EXPORT_SYMBOL(pskb_expand_head); EXPORT_SYMBOL(skb_checksum); -- cgit v1.2.3 From 76f10ad0e67cbc6ded2ee143e5188e0b7ff9fb15 Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Wed, 2 Aug 2006 14:06:55 -0700 Subject: [NET]: Remove lockdep_set_class() call from skb_queue_head_init(). The skb_queue_head_init() function is used both in drivers for private use and in the core networking code. The usage models are vastly set of functions that is only softirq safe; while the driver usage tends to be more limited to a few hardirq safe accessor functions. Rather than annotating all 133+ driver usages, for now just split this lock into a per queue class. This change is obviously safe and probably should make 2.6.18. Signed-off-by: Arjan van de Ven Signed-off-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- include/linux/skbuff.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index b91fbfb7d54c..b22d4a6083bd 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -606,10 +606,17 @@ static inline __u32 skb_queue_len(const struct sk_buff_head *list_) extern struct lock_class_key skb_queue_lock_key; +/* + * This function creates a split out lock class for each invocation; + * this is needed for now since a whole lot of users of the skb-queue + * infrastructure in drivers have different locking usage (in hardirq) + * than the networking core (in softirq only). In the long run either the + * network layer or drivers should need annotation to consolidate the + * main types of usage into 3 classes. + */ static inline void skb_queue_head_init(struct sk_buff_head *list) { spin_lock_init(&list->lock); - lockdep_set_class(&list->lock, &skb_queue_lock_key); list->prev = list->next = (struct sk_buff *)list; list->qlen = 0; } -- cgit v1.2.3 From 2b7e24b66d31d677d76b49918e711eb360c978b6 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 2 Aug 2006 14:07:58 -0700 Subject: [NET]: skb_queue_lock_key() is no longer used. Signed-off-by: Adrian Bunk Acked-by: Arjan van de Ven Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- include/linux/skbuff.h | 2 -- net/core/skbuff.c | 7 ------- 2 files changed, 9 deletions(-) (limited to 'include') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index b22d4a6083bd..19c96d498e20 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -604,8 +604,6 @@ static inline __u32 skb_queue_len(const struct sk_buff_head *list_) return list_->qlen; } -extern struct lock_class_key skb_queue_lock_key; - /* * This function creates a split out lock class for each invocation; * this is needed for now since a whole lot of users of the skb-queue diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 71487b915d67..022d8894c11d 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -70,13 +70,6 @@ static kmem_cache_t *skbuff_head_cache __read_mostly; static kmem_cache_t *skbuff_fclone_cache __read_mostly; -/* - * lockdep: lock class key used by skb_queue_head_init(): - */ -struct lock_class_key skb_queue_lock_key; - -EXPORT_SYMBOL(skb_queue_lock_key); - /* * Keep out-of-line to prevent kernel bloat. * __builtin_return_address is not used because it is not always -- cgit v1.2.3 From dc49c1f94e3469d94b952e8f5160dd4ccd791d79 Mon Sep 17 00:00:00 2001 From: Catherine Zhang Date: Wed, 2 Aug 2006 14:12:06 -0700 Subject: [AF_UNIX]: Kernel memory leak fix for af_unix datagram getpeersec patch From: Catherine Zhang This patch implements a cleaner fix for the memory leak problem of the original unix datagram getpeersec patch. Instead of creating a security context each time a unix datagram is sent, we only create the security context when the receiver requests it. This new design requires modification of the current unix_getsecpeer_dgram LSM hook and addition of two new hooks, namely, secid_to_secctx and release_secctx. The former retrieves the security context and the latter releases it. A hook is required for releasing the security context because it is up to the security module to decide how that's done. In the case of Selinux, it's a simple kfree operation. Acked-by: Stephen Smalley Signed-off-by: David S. Miller --- include/linux/security.h | 41 +++++++++++++++++++++++++++++++++++------ include/net/af_unix.h | 6 ++---- include/net/scm.h | 29 +++++++++++++++++++++++++---- net/ipv4/ip_sockglue.c | 9 +++++++-- net/unix/af_unix.c | 17 +++++------------ security/dummy.c | 14 ++++++++++++-- security/selinux/hooks.c | 38 ++++++++++++++++++++++++-------------- 7 files changed, 110 insertions(+), 44 deletions(-) (limited to 'include') diff --git a/include/linux/security.h b/include/linux/security.h index f75303831d09..aa5b8043dc38 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -1109,6 +1109,16 @@ struct swap_info_struct; * @name contains the name of the security module being unstacked. * @ops contains a pointer to the struct security_operations of the module to unstack. * + * @secid_to_secctx: + * Convert secid to security context. + * @secid contains the security ID. + * @secdata contains the pointer that stores the converted security context. + * + * @release_secctx: + * Release the security context. + * @secdata contains the security context. + * @seclen contains the length of the security context. + * * This is the main security structure. */ struct security_operations { @@ -1289,6 +1299,8 @@ struct security_operations { int (*getprocattr)(struct task_struct *p, char *name, void *value, size_t size); int (*setprocattr)(struct task_struct *p, char *name, void *value, size_t size); + int (*secid_to_secctx)(u32 secid, char **secdata, u32 *seclen); + void (*release_secctx)(char *secdata, u32 seclen); #ifdef CONFIG_SECURITY_NETWORK int (*unix_stream_connect) (struct socket * sock, @@ -1317,7 +1329,7 @@ struct security_operations { int (*socket_shutdown) (struct socket * sock, int how); int (*socket_sock_rcv_skb) (struct sock * sk, struct sk_buff * skb); int (*socket_getpeersec_stream) (struct socket *sock, char __user *optval, int __user *optlen, unsigned len); - int (*socket_getpeersec_dgram) (struct sk_buff *skb, char **secdata, u32 *seclen); + int (*socket_getpeersec_dgram) (struct socket *sock, struct sk_buff *skb, u32 *secid); int (*sk_alloc_security) (struct sock *sk, int family, gfp_t priority); void (*sk_free_security) (struct sock *sk); unsigned int (*sk_getsid) (struct sock *sk, struct flowi *fl, u8 dir); @@ -2059,6 +2071,16 @@ static inline int security_netlink_recv(struct sk_buff * skb, int cap) return security_ops->netlink_recv(skb, cap); } +static inline int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) +{ + return security_ops->secid_to_secctx(secid, secdata, seclen); +} + +static inline void security_release_secctx(char *secdata, u32 seclen) +{ + return security_ops->release_secctx(secdata, seclen); +} + /* prototypes */ extern int security_init (void); extern int register_security (struct security_operations *ops); @@ -2725,6 +2747,15 @@ static inline void securityfs_remove(struct dentry *dentry) { } +static inline int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) +{ + return -EOPNOTSUPP; +} + +static inline void security_release_secctx(char *secdata, u32 seclen) +{ + return -EOPNOTSUPP; +} #endif /* CONFIG_SECURITY */ #ifdef CONFIG_SECURITY_NETWORK @@ -2840,10 +2871,9 @@ static inline int security_socket_getpeersec_stream(struct socket *sock, char __ return security_ops->socket_getpeersec_stream(sock, optval, optlen, len); } -static inline int security_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata, - u32 *seclen) +static inline int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid) { - return security_ops->socket_getpeersec_dgram(skb, secdata, seclen); + return security_ops->socket_getpeersec_dgram(sock, skb, secid); } static inline int security_sk_alloc(struct sock *sk, int family, gfp_t priority) @@ -2968,8 +2998,7 @@ static inline int security_socket_getpeersec_stream(struct socket *sock, char __ return -ENOPROTOOPT; } -static inline int security_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata, - u32 *seclen) +static inline int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid) { return -ENOPROTOOPT; } diff --git a/include/net/af_unix.h b/include/net/af_unix.h index 2fec827c8801..c0398f5a8cb9 100644 --- a/include/net/af_unix.h +++ b/include/net/af_unix.h @@ -54,15 +54,13 @@ struct unix_skb_parms { struct ucred creds; /* Skb credentials */ struct scm_fp_list *fp; /* Passed files */ #ifdef CONFIG_SECURITY_NETWORK - char *secdata; /* Security context */ - u32 seclen; /* Security length */ + u32 secid; /* Security ID */ #endif }; #define UNIXCB(skb) (*(struct unix_skb_parms*)&((skb)->cb)) #define UNIXCREDS(skb) (&UNIXCB((skb)).creds) -#define UNIXSECDATA(skb) (&UNIXCB((skb)).secdata) -#define UNIXSECLEN(skb) (&UNIXCB((skb)).seclen) +#define UNIXSID(skb) (&UNIXCB((skb)).secid) #define unix_state_rlock(s) spin_lock(&unix_sk(s)->lock) #define unix_state_runlock(s) spin_unlock(&unix_sk(s)->lock) diff --git a/include/net/scm.h b/include/net/scm.h index 02daa097cdcd..5637d5e22d5f 100644 --- a/include/net/scm.h +++ b/include/net/scm.h @@ -3,6 +3,7 @@ #include #include +#include /* Well, we should have at least one descriptor open * to accept passed FDs 8) @@ -20,8 +21,7 @@ struct scm_cookie struct ucred creds; /* Skb credentials */ struct scm_fp_list *fp; /* Passed files */ #ifdef CONFIG_SECURITY_NETWORK - char *secdata; /* Security context */ - u32 seclen; /* Security length */ + u32 secid; /* Passed security ID */ #endif unsigned long seq; /* Connection seqno */ }; @@ -32,6 +32,16 @@ extern int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie extern void __scm_destroy(struct scm_cookie *scm); extern struct scm_fp_list * scm_fp_dup(struct scm_fp_list *fpl); +#ifdef CONFIG_SECURITY_NETWORK +static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_cookie *scm) +{ + security_socket_getpeersec_dgram(sock, NULL, &scm->secid); +} +#else +static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_cookie *scm) +{ } +#endif /* CONFIG_SECURITY_NETWORK */ + static __inline__ void scm_destroy(struct scm_cookie *scm) { if (scm && scm->fp) @@ -47,6 +57,7 @@ static __inline__ int scm_send(struct socket *sock, struct msghdr *msg, scm->creds.pid = p->tgid; scm->fp = NULL; scm->seq = 0; + unix_get_peersec_dgram(sock, scm); if (msg->msg_controllen <= 0) return 0; return __scm_send(sock, msg, scm); @@ -55,8 +66,18 @@ static __inline__ int scm_send(struct socket *sock, struct msghdr *msg, #ifdef CONFIG_SECURITY_NETWORK static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm) { - if (test_bit(SOCK_PASSSEC, &sock->flags) && scm->secdata != NULL) - put_cmsg(msg, SOL_SOCKET, SCM_SECURITY, scm->seclen, scm->secdata); + char *secdata; + u32 seclen; + int err; + + if (test_bit(SOCK_PASSSEC, &sock->flags)) { + err = security_secid_to_secctx(scm->secid, &secdata, &seclen); + + if (!err) { + put_cmsg(msg, SOL_SOCKET, SCM_SECURITY, seclen, secdata); + security_release_secctx(secdata, seclen); + } + } } #else static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm) diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 84f43a3c9098..2d05c4133d3e 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -112,14 +112,19 @@ static void ip_cmsg_recv_retopts(struct msghdr *msg, struct sk_buff *skb) static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb) { char *secdata; - u32 seclen; + u32 seclen, secid; int err; - err = security_socket_getpeersec_dgram(skb, &secdata, &seclen); + err = security_socket_getpeersec_dgram(NULL, skb, &secid); + if (err) + return; + + err = security_secid_to_secctx(secid, &secdata, &seclen); if (err) return; put_cmsg(msg, SOL_IP, SCM_SECURITY, seclen, secdata); + security_release_secctx(secdata, seclen); } diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 6f2909279268..de6ec519272e 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -128,23 +128,17 @@ static atomic_t unix_nr_socks = ATOMIC_INIT(0); #define UNIX_ABSTRACT(sk) (unix_sk(sk)->addr->hash != UNIX_HASH_SIZE) #ifdef CONFIG_SECURITY_NETWORK -static void unix_get_peersec_dgram(struct sk_buff *skb) +static void unix_get_secdata(struct scm_cookie *scm, struct sk_buff *skb) { - int err; - - err = security_socket_getpeersec_dgram(skb, UNIXSECDATA(skb), - UNIXSECLEN(skb)); - if (err) - *(UNIXSECDATA(skb)) = NULL; + memcpy(UNIXSID(skb), &scm->secid, sizeof(u32)); } static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb) { - scm->secdata = *UNIXSECDATA(skb); - scm->seclen = *UNIXSECLEN(skb); + scm->secid = *UNIXSID(skb); } #else -static inline void unix_get_peersec_dgram(struct sk_buff *skb) +static inline void unix_get_secdata(struct scm_cookie *scm, struct sk_buff *skb) { } static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb) @@ -1322,8 +1316,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock, memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred)); if (siocb->scm->fp) unix_attach_fds(siocb->scm, skb); - - unix_get_peersec_dgram(skb); + unix_get_secdata(siocb->scm, skb); skb->h.raw = skb->data; err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len); diff --git a/security/dummy.c b/security/dummy.c index bbbfda70e131..58c6d399c844 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -791,8 +791,7 @@ static int dummy_socket_getpeersec_stream(struct socket *sock, char __user *optv return -ENOPROTOOPT; } -static int dummy_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata, - u32 *seclen) +static int dummy_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid) { return -ENOPROTOOPT; } @@ -876,6 +875,15 @@ static int dummy_setprocattr(struct task_struct *p, char *name, void *value, siz return -EINVAL; } +static int dummy_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) +{ + return -EOPNOTSUPP; +} + +static void dummy_release_secctx(char *secdata, u32 seclen) +{ +} + #ifdef CONFIG_KEYS static inline int dummy_key_alloc(struct key *key, struct task_struct *ctx, unsigned long flags) @@ -1028,6 +1036,8 @@ void security_fixup_ops (struct security_operations *ops) set_to_dummy_if_null(ops, d_instantiate); set_to_dummy_if_null(ops, getprocattr); set_to_dummy_if_null(ops, setprocattr); + set_to_dummy_if_null(ops, secid_to_secctx); + set_to_dummy_if_null(ops, release_secctx); #ifdef CONFIG_SECURITY_NETWORK set_to_dummy_if_null(ops, unix_stream_connect); set_to_dummy_if_null(ops, unix_may_send); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index a91c961ba38b..5d1b8c733199 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3524,25 +3524,21 @@ out: return err; } -static int selinux_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata, u32 *seclen) +static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid) { + u32 peer_secid = SECSID_NULL; int err = 0; - u32 peer_sid; - if (skb->sk->sk_family == PF_UNIX) - selinux_get_inode_sid(SOCK_INODE(skb->sk->sk_socket), - &peer_sid); - else - peer_sid = selinux_socket_getpeer_dgram(skb); - - if (peer_sid == SECSID_NULL) - return -EINVAL; + if (sock && (sock->sk->sk_family == PF_UNIX)) + selinux_get_inode_sid(SOCK_INODE(sock), &peer_secid); + else if (skb) + peer_secid = selinux_socket_getpeer_dgram(skb); - err = security_sid_to_context(peer_sid, secdata, seclen); - if (err) - return err; + if (peer_secid == SECSID_NULL) + err = -EINVAL; + *secid = peer_secid; - return 0; + return err; } static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority) @@ -4407,6 +4403,17 @@ static int selinux_setprocattr(struct task_struct *p, return size; } +static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) +{ + return security_sid_to_context(secid, secdata, seclen); +} + +static void selinux_release_secctx(char *secdata, u32 seclen) +{ + if (secdata) + kfree(secdata); +} + #ifdef CONFIG_KEYS static int selinux_key_alloc(struct key *k, struct task_struct *tsk, @@ -4587,6 +4594,9 @@ static struct security_operations selinux_ops = { .getprocattr = selinux_getprocattr, .setprocattr = selinux_setprocattr, + .secid_to_secctx = selinux_secid_to_secctx, + .release_secctx = selinux_release_secctx, + .unix_stream_connect = selinux_socket_unix_stream_connect, .unix_may_send = selinux_socket_unix_may_send, -- cgit v1.2.3 From 95ce568812822931991a24147987c5c75c0ac5b0 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 2 Aug 2006 14:37:06 -0700 Subject: [SECURITY]: Fix build with CONFIG_SECURITY disabled. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit include/linux/security.h: In function ‘security_release_secctx’: include/linux/security.h:2757: warning: ‘return’ with a value, in function returning void Signed-off-by: David S. Miller --- include/linux/security.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include') diff --git a/include/linux/security.h b/include/linux/security.h index aa5b8043dc38..6bc2aad494ff 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -2754,7 +2754,6 @@ static inline int security_secid_to_secctx(u32 secid, char **secdata, u32 *secle static inline void security_release_secctx(char *secdata, u32 seclen) { - return -EOPNOTSUPP; } #endif /* CONFIG_SECURITY */ -- cgit v1.2.3 From 29bbd72d6ee1dbf2d9f00d022f8e999aa528fb3a Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Wed, 2 Aug 2006 15:02:31 -0700 Subject: [NET]: Fix more per-cpu typos Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- include/net/netdma.h | 2 +- net/core/dev.c | 4 ++-- net/ipv4/tcp.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/net/netdma.h b/include/net/netdma.h index ceae5ee85c04..7f53cd1d8b1e 100644 --- a/include/net/netdma.h +++ b/include/net/netdma.h @@ -29,7 +29,7 @@ static inline struct dma_chan *get_softnet_dma(void) { struct dma_chan *chan; rcu_read_lock(); - chan = rcu_dereference(__get_cpu_var(softnet_data.net_dma)); + chan = rcu_dereference(__get_cpu_var(softnet_data).net_dma); if (chan) dma_chan_get(chan); rcu_read_unlock(); diff --git a/net/core/dev.c b/net/core/dev.c index f25d7ecaf035..d95e2626d944 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3421,7 +3421,7 @@ static void net_dma_rebalance(void) if (net_dma_count == 0) { for_each_online_cpu(cpu) - rcu_assign_pointer(per_cpu(softnet_data.net_dma, cpu), NULL); + rcu_assign_pointer(per_cpu(softnet_data, cpu).net_dma, NULL); return; } @@ -3434,7 +3434,7 @@ static void net_dma_rebalance(void) + (i < (num_online_cpus() % net_dma_count) ? 1 : 0)); while(n) { - per_cpu(softnet_data.net_dma, cpu) = chan; + per_cpu(softnet_data, cpu).net_dma = chan; cpu = next_cpu(cpu, cpu_online_map); n--; } diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 7b621e44b124..934396bb1376 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1132,7 +1132,7 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, tp->ucopy.dma_chan = NULL; preempt_disable(); if ((len > sysctl_tcp_dma_copybreak) && !(flags & MSG_PEEK) && - !sysctl_tcp_low_latency && __get_cpu_var(softnet_data.net_dma)) { + !sysctl_tcp_low_latency && __get_cpu_var(softnet_data).net_dma) { preempt_enable_no_resched(); tp->ucopy.pinned_list = dma_pin_iovec_pages(msg->msg_iov, len); } else -- cgit v1.2.3