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
......
...@@ -31,7 +31,8 @@ ...@@ -31,7 +31,8 @@
#include <linux/shm.h> #include <linux/shm.h>
#include <linux/msg.h> #include <linux/msg.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/skbuff.h>
#include <linux/netlink.h>
/* /*
* These functions are in security/capability.c and are used * These functions are in security/capability.c and are used
...@@ -48,6 +49,20 @@ extern int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid, ...@@ -48,6 +49,20 @@ extern int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid,
extern void cap_task_kmod_set_label (void); extern void cap_task_kmod_set_label (void);
extern void cap_task_reparent_to_init (struct task_struct *p); extern void cap_task_reparent_to_init (struct task_struct *p);
static inline int cap_netlink_send (struct sk_buff *skb)
{
NETLINK_CB (skb).eff_cap = current->cap_effective;
return 0;
}
static inline int cap_netlink_recv (struct sk_buff *skb)
{
if (!cap_raised (NETLINK_CB (skb).eff_cap, CAP_NET_ADMIN))
return -EPERM;
return 0;
}
/* /*
* Values used in the task_security_ops calls * Values used in the task_security_ops calls
*/ */
...@@ -63,16 +78,13 @@ extern void cap_task_reparent_to_init (struct task_struct *p); ...@@ -63,16 +78,13 @@ extern void cap_task_reparent_to_init (struct task_struct *p);
/* setfsuid or setfsgid, id0 == fsuid or fsgid */ /* setfsuid or setfsgid, id0 == fsuid or fsgid */
#define LSM_SETID_FS 8 #define LSM_SETID_FS 8
#ifdef CONFIG_SECURITY
/* forward declares to avoid warnings */ /* forward declares to avoid warnings */
struct sk_buff;
struct net_device;
struct nfsctl_arg; struct nfsctl_arg;
struct sched_param; struct sched_param;
struct swap_info_struct; struct swap_info_struct;
#ifdef CONFIG_SECURITY
/** /**
* struct security_operations - main security structure * struct security_operations - main security structure
* *
...@@ -586,6 +598,149 @@ struct swap_info_struct; ...@@ -586,6 +598,149 @@ struct swap_info_struct;
* is being reparented to the init task. * is being reparented to the init task.
* @p contains the task_struct for the kernel thread. * @p contains the task_struct for the kernel thread.
* *
* Security hooks for Netlink messaging.
*
* @netlink_send:
* Save security information for a netlink message so that permission
* checking can be performed when the message is processed. The security
* information can be saved using the eff_cap field of the
* netlink_skb_parms structure.
* @skb contains the sk_buff structure for the netlink message.
* Return 0 if the information was successfully saved.
* @netlink_recv:
* Check permission before processing the received netlink message in
* @skb.
* @skb contains the sk_buff structure for the netlink message.
* Return 0 if permission is granted.
*
* Security hooks for Unix domain networking.
*
* @unix_stream_connect:
* Check permissions before establishing a Unix domain stream connection
* between @sock and @other.
* @sock contains the socket structure.
* @other contains the peer socket structure.
* Return 0 if permission is granted.
* @unix_may_send:
* Check permissions before connecting or sending datagrams from @sock to
* @other.
* @sock contains the socket structure.
* @sock contains the peer socket structure.
* Return 0 if permission is granted.
*
* The @unix_stream_connect and @unix_may_send hooks were necessary because
* Linux provides an alternative to the conventional file name space for Unix
* domain sockets. Whereas binding and connecting to sockets in the file name
* space is mediated by the typical file permissions (and caught by the mknod
* and permission hooks in inode_security_ops), binding and connecting to
* sockets in the abstract name space is completely unmediated. Sufficient
* control of Unix domain sockets in the abstract name space isn't possible
* using only the socket layer hooks, since we need to know the actual target
* socket, which is not looked up until we are inside the af_unix code.
*
* Security hooks for socket operations.
*
* @socket_create:
* Check permissions prior to creating a new socket.
* @family contains the requested protocol family.
* @type contains the requested communications type.
* @protocol contains the requested protocol.
* Return 0 if permission is granted.
* @socket_post_create:
* This hook allows a module to update or allocate a per-socket security
* structure. Note that the security field was not added directly to the
* socket structure, but rather, the socket security information is stored
* in the associated inode. Typically, the inode alloc_security hook will
* allocate and and attach security information to
* sock->inode->i_security. This hook may be used to update the
* sock->inode->i_security field with additional information that wasn't
* available when the inode was allocated.
* @sock contains the newly created socket structure.
* @family contains the requested protocol family.
* @type contains the requested communications type.
* @protocol contains the requested protocol.
* @socket_bind:
* Check permission before socket protocol layer bind operation is
* performed and the socket @sock is bound to the address specified in the
* @address parameter.
* @sock contains the socket structure.
* @address contains the address to bind to.
* @addrlen contains the length of address.
* Return 0 if permission is granted.
* @socket_connect:
* Check permission before socket protocol layer connect operation
* attempts to connect socket @sock to a remote address, @address.
* @sock contains the socket structure.
* @address contains the address of remote endpoint.
* @addrlen contains the length of address.
* Return 0 if permission is granted.
* @socket_listen:
* Check permission before socket protocol layer listen operation.
* @sock contains the socket structure.
* @backlog contains the maximum length for the pending connection queue.
* Return 0 if permission is granted.
* @socket_accept:
* Check permission before accepting a new connection. Note that the new
* socket, @newsock, has been created and some information copied to it,
* but the accept operation has not actually been performed.
* @sock contains the listening socket structure.
* @newsock contains the newly created server socket for connection.
* Return 0 if permission is granted.
* @socket_post_accept:
* This hook allows a security module to copy security
* information into the newly created socket's inode.
* @sock contains the listening socket structure.
* @newsock contains the newly created server socket for connection.
* @socket_sendmsg:
* Check permission before transmitting a message to another socket.
* @sock contains the socket structure.
* @msg contains the message to be transmitted.
* @size contains the size of message.
* Return 0 if permission is granted.
* @socket_recvmsg:
* Check permission before receiving a message from a socket.
* @sock contains the socket structure.
* @msg contains the message structure.
* @size contains the size of message structure.
* @flags contains the operational flags.
* Return 0 if permission is granted.
* @socket_getsockname:
* Check permission before the local address (name) of the socket object
* @sock is retrieved.
* @sock contains the socket structure.
* Return 0 if permission is granted.
* @socket_getpeername:
* Check permission before the remote address (name) of a socket object
* @sock is retrieved.
* @sock contains the socket structure.
* Return 0 if permission is granted.
* @socket_getsockopt:
* Check permissions before retrieving the options associated with socket
* @sock.
* @sock contains the socket structure.
* @level contains the protocol level to retrieve option from.
* @optname contains the name of option to retrieve.
* Return 0 if permission is granted.
* @socket_setsockopt:
* Check permissions before setting the options associated with socket
* @sock.
* @sock contains the socket structure.
* @level contains the protocol level to set options for.
* @optname contains the name of the option to set.
* Return 0 if permission is granted.
* @socket_shutdown:
* Checks permission before all or part of a connection on the socket
* @sock is shut down.
* @sock contains the socket structure.
* @how contains the flag indicating how future sends and receives are handled.
* Return 0 if permission is granted.
* @socket_sock_rcv_skb:
* Check permissions on incoming network packets. This hook is distinct
* from Netfilter's IP input hooks since it is the first time that the
* incoming sk_buff @skb has been associated with a particular socket, @sk.
* @sk contains the sock (not socket) associated with the incoming sk_buff.
* @skb contains the incoming network data.
*
* Security hooks affecting all System V IPC operations. * Security hooks affecting all System V IPC operations.
* *
* @ipc_permission: * @ipc_permission:
...@@ -947,11 +1102,42 @@ struct security_operations { ...@@ -947,11 +1102,42 @@ struct security_operations {
int (*sem_semop) (struct sem_array * sma, int (*sem_semop) (struct sem_array * sma,
struct sembuf * sops, unsigned nsops, int alter); struct sembuf * sops, unsigned nsops, int alter);
int (*netlink_send) (struct sk_buff * skb);
int (*netlink_recv) (struct sk_buff * skb);
/* allow module stacking */ /* allow module stacking */
int (*register_security) (const char *name, int (*register_security) (const char *name,
struct security_operations *ops); struct security_operations *ops);
int (*unregister_security) (const char *name, int (*unregister_security) (const char *name,
struct security_operations *ops); struct security_operations *ops);
#ifdef CONFIG_SECURITY_NETWORK
int (*unix_stream_connect) (struct socket * sock,
struct socket * other, struct sock * newsk);
int (*unix_may_send) (struct socket * sock, struct socket * other);
int (*socket_create) (int family, int type, int protocol);
void (*socket_post_create) (struct socket * sock, int family,
int type, int protocol);
int (*socket_bind) (struct socket * sock,
struct sockaddr * address, int addrlen);
int (*socket_connect) (struct socket * sock,
struct sockaddr * address, int addrlen);
int (*socket_listen) (struct socket * sock, int backlog);
int (*socket_accept) (struct socket * sock, struct socket * newsock);
void (*socket_post_accept) (struct socket * sock,
struct socket * newsock);
int (*socket_sendmsg) (struct socket * sock,
struct msghdr * msg, int size);
int (*socket_recvmsg) (struct socket * sock,
struct msghdr * msg, int size, int flags);
int (*socket_getsockname) (struct socket * sock);
int (*socket_getpeername) (struct socket * sock);
int (*socket_getsockopt) (struct socket * sock, int level, int optname);
int (*socket_setsockopt) (struct socket * sock, int level, int optname);
int (*socket_shutdown) (struct socket * sock, int how);
int (*socket_sock_rcv_skb) (struct sock * sk, struct sk_buff * skb);
#endif /* CONFIG_SECURITY_NETWORK */
}; };
/* global variables */ /* global variables */
...@@ -1543,6 +1729,16 @@ static inline int security_sem_semop (struct sem_array * sma, ...@@ -1543,6 +1729,16 @@ static inline int security_sem_semop (struct sem_array * sma,
return security_ops->sem_semop(sma, sops, nsops, alter); return security_ops->sem_semop(sma, sops, nsops, alter);
} }
static inline int security_netlink_send(struct sk_buff * skb)
{
return security_ops->netlink_send(skb);
}
static inline int security_netlink_recv(struct sk_buff * skb)
{
return security_ops->netlink_recv(skb);
}
/* prototypes */ /* prototypes */
extern int security_scaffolding_startup (void); extern int security_scaffolding_startup (void);
extern int register_security (struct security_operations *ops); extern int register_security (struct security_operations *ops);
...@@ -2104,7 +2300,228 @@ static inline int security_sem_semop (struct sem_array * sma, ...@@ -2104,7 +2300,228 @@ static inline int security_sem_semop (struct sem_array * sma,
return 0; return 0;
} }
/*
* The netlink capability defaults need to be used inline by default
* (rather than hooking into the capability module) to reduce overhead
* in the networking code.
*/
static inline int security_netlink_send (struct sk_buff *skb)
{
return cap_netlink_send (skb);
}
static inline int security_netlink_recv (struct sk_buff *skb)
{
return cap_netlink_recv (skb);
}
#endif /* CONFIG_SECURITY */ #endif /* CONFIG_SECURITY */
#ifdef CONFIG_SECURITY_NETWORK
static inline int security_unix_stream_connect(struct socket * sock,
struct socket * other,
struct sock * newsk)
{
return security_ops->unix_stream_connect(sock, other, newsk);
}
static inline int security_unix_may_send(struct socket * sock,
struct socket * other)
{
return security_ops->unix_may_send(sock, other);
}
static inline int security_socket_create (int family, int type, int protocol)
{
return security_ops->socket_create(family, type, protocol);
}
static inline void security_socket_post_create(struct socket * sock,
int family,
int type,
int protocol)
{
security_ops->socket_post_create(sock, family, type, protocol);
}
static inline int security_socket_bind(struct socket * sock,
struct sockaddr * address,
int addrlen)
{
return security_ops->socket_bind(sock, address, addrlen);
}
static inline int security_socket_connect(struct socket * sock,
struct sockaddr * address,
int addrlen)
{
return security_ops->socket_connect(sock, address, addrlen);
}
static inline int security_socket_listen(struct socket * sock, int backlog)
{
return security_ops->socket_listen(sock, backlog);
}
static inline int security_socket_accept(struct socket * sock,
struct socket * newsock)
{
return security_ops->socket_accept(sock, newsock);
}
static inline void security_socket_post_accept(struct socket * sock,
struct socket * newsock)
{
security_ops->socket_post_accept(sock, newsock);
}
static inline int security_socket_sendmsg(struct socket * sock,
struct msghdr * msg, int size)
{
return security_ops->socket_sendmsg(sock, msg, size);
}
static inline int security_socket_recvmsg(struct socket * sock,
struct msghdr * msg, int size,
int flags)
{
return security_ops->socket_recvmsg(sock, msg, size, flags);
}
static inline int security_socket_getsockname(struct socket * sock)
{
return security_ops->socket_getsockname(sock);
}
static inline int security_socket_getpeername(struct socket * sock)
{
return security_ops->socket_getpeername(sock);
}
static inline int security_socket_getsockopt(struct socket * sock,
int level, int optname)
{
return security_ops->socket_getsockopt(sock, level, optname);
}
static inline int security_socket_setsockopt(struct socket * sock,
int level, int optname)
{
return security_ops->socket_setsockopt(sock, level, optname);
}
static inline int security_socket_shutdown(struct socket * sock, int how)
{
return security_ops->socket_shutdown(sock, how);
}
static inline int security_sock_rcv_skb (struct sock * sk,
struct sk_buff * skb)
{
return security_ops->socket_sock_rcv_skb (sk, skb);
}
#else /* CONFIG_SECURITY_NETWORK */
static inline int security_unix_stream_connect(struct socket * sock,
struct socket * other,
struct sock * newsk)
{
return 0;
}
static inline int security_unix_may_send(struct socket * sock,
struct socket * other)
{
return 0;
}
static inline int security_socket_create (int family, int type, int protocol)
{
return 0;
}
static inline void security_socket_post_create(struct socket * sock,
int family,
int type,
int protocol)
{
}
static inline int security_socket_bind(struct socket * sock,
struct sockaddr * address,
int addrlen)
{
return 0;
}
static inline int security_socket_connect(struct socket * sock,
struct sockaddr * address,
int addrlen)
{
return 0;
}
static inline int security_socket_listen(struct socket * sock, int backlog)
{
return 0;
}
static inline int security_socket_accept(struct socket * sock,
struct socket * newsock)
{
return 0;
}
static inline void security_socket_post_accept(struct socket * sock,
struct socket * newsock)
{
}
static inline int security_socket_sendmsg(struct socket * sock,
struct msghdr * msg, int size)
{
return 0;
}
static inline int security_socket_recvmsg(struct socket * sock,
struct msghdr * msg, int size,
int flags)
{
return 0;
}
static inline int security_socket_getsockname(struct socket * sock)
{
return 0;
}
static inline int security_socket_getpeername(struct socket * sock)
{
return 0;
}
static inline int security_socket_getsockopt(struct socket * sock,
int level, int optname)
{
return 0;
}
static inline int security_socket_setsockopt(struct socket * sock,
int level, int optname)
{
return 0;
}
static inline int security_socket_shutdown(struct socket * sock, int how)
{
return 0;
}
static inline int security_sock_rcv_skb (struct sock * sk,
struct sk_buff * skb)
{
return 0;
}
#endif /* CONFIG_SECURITY_NETWORK */
#endif /* ! __LINUX_SECURITY_H */ #endif /* ! __LINUX_SECURITY_H */
...@@ -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) static inline int __sk_filter(struct sock *sk, struct sk_buff *skb, int needlock)
{ {
int pkt_len; int err = 0;
if (sk->filter) {
struct sk_filter *filter;
pkt_len = sk_run_filter(skb, filter->insns, filter->len); if (needlock)
if(!pkt_len) bh_lock_sock(sk);
return 1; /* Toss Packet */
filter = sk->filter;
if (filter) {
int pkt_len = sk_run_filter(skb, filter->insns,
filter->len);
if (!pkt_len)
err = -EPERM;
else else
skb_trim(skb, pkt_len); skb_trim(skb, pkt_len);
}
return 0; 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 /* It would be deadlock, if sock_queue_rcv_skb is used
with socket lock! We assume that users of this with socket lock! We assume that users of this
function are lock free. function are lock free.
*/ */
bh_lock_sock(sk); err = sk_filter(sk, skb, 1);
if ((filter = sk->filter) != NULL && sk_filter(skb, filter))
err = -EPERM;
bh_unlock_sock(sk);
if (err) if (err)
return err; /* Toss packet */ goto out;
}
#endif /* CONFIG_FILTER */
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 err = sk_filter(sk, skb, 0);
if (sk->filter) {
int err = 0;
if ((filter = sk->filter) != NULL && sk_filter(skb, sk->filter))
err = -EPERM; /* Toss packet */
if (err) if (err)
return err; goto out;
}
#endif /* CONFIG_FILTER */
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;
} }
......
...@@ -539,7 +539,7 @@ ipq_rcv_skb(struct sk_buff *skb) ...@@ -539,7 +539,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);
......
...@@ -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)
err = 0;
out:
return err; return err;
return 0; 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;
/* /*
...@@ -987,6 +998,10 @@ int sock_create(int family, int type, int protocol, struct socket **res) ...@@ -987,6 +998,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