* [PATCH net-2.6.25] Add packet filtering based on process's security context.
@ 2008-01-22 15:16 Tetsuo Handa
2008-01-22 16:49 ` Casey Schaufler
2008-01-24 11:47 ` [PATCH net-2.6.25] Add packet filtering based on process's " Tetsuo Handa
0 siblings, 2 replies; 9+ messages in thread
From: Tetsuo Handa @ 2008-01-22 15:16 UTC (permalink / raw)
To: netdev, davem; +Cc: linux-security-module, netfilter-devel
This patch modifies security_socket_post_accept() and introduces
security_socket_post_recv_datagram() LSM hooks.
Currently, security_socket_post_accept() is called *after* fd_install()
at sys_accept(). This means that userland process might access accept()ed
but not yet properly labeled socket.
I believe this security_socket_post_accept() should be called *before*
fd_install() for the three reasons.
* The userland process will always access proper context labeled by
security_socket_post_accept() rather than default context labeled by
security_inode_alloc() (called from alloc_inode() from new_inode() from
sock_alloc() from sys_accept()). This gives a security module
a chance to perform access control based on proper context.
* If security_socket_post_accept() failed to assign proper context
(e.g. -ENOMEM), the accept()ed socket can't have proper context.
Use of void for security_socket_post_accept() deprives a security module
of a chance to abandon the accept()ed socket.
* A security module can perform connection filtering based on
process's security context.
If security_socket_post_accept() is called after fd_install(),
it is too late to do so because the accept()ed socket is already visible
to userland processes.
Currently, there is no way to directly map security context from incoming
packet to user process. This is because the creator or owner of a socket is
not always the receiver of an incoming packet. The userland process who
receives the incoming packet is not known until a process calls sys_recvmsg().
So, I want to add a LSM hook to give a security module a chance to control
after the recipient of the incoming packet is known.
Signed-off-by: Kentaro Takeda <takedakn@nttdata.co.jp>
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
---
include/linux/security.h | 34 +++++++++++++++++++++++++++++-----
net/core/datagram.c | 29 ++++++++++++++++++++++++++++-
net/socket.c | 7 +++++--
security/dummy.c | 13 ++++++++++---
security/security.c | 10 ++++++++--
5 files changed, 80 insertions(+), 13 deletions(-)
--- net-2.6.25.orig/include/linux/security.h
+++ net-2.6.25/include/linux/security.h
@@ -781,8 +781,12 @@ struct request_sock;
* @socket_post_accept:
* This hook allows a security module to copy security
* information into the newly created socket's inode.
+ * This hook also allows a security module to filter connections
+ * from unwanted peers based on the process accepting this connection.
+ * The connection will be aborted if this hook returns nonzero.
* @sock contains the listening socket structure.
* @newsock contains the newly created server socket for connection.
+ * Return 0 if permission is granted.
* @socket_sendmsg:
* Check permission before transmitting a message to another socket.
* @sock contains the socket structure.
@@ -796,6 +800,15 @@ struct request_sock;
* @size contains the size of message structure.
* @flags contains the operational flags.
* Return 0 if permission is granted.
+ * @socket_post_recv_datagram:
+ * Check permission after receiving a datagram.
+ * This hook allows a security module to filter packets
+ * from unwanted peers based on the process receiving this datagram.
+ * The packet will be discarded if this hook returns nonzero.
+ * @sk contains the socket.
+ * @skb contains the socket buffer.
+ * @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.
@@ -1387,12 +1400,13 @@ struct security_operations {
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_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_post_recv_datagram) (struct sock *sk, struct sk_buff *skb,
+ unsigned int flags);
int (*socket_getsockname) (struct socket * sock);
int (*socket_getpeername) (struct socket * sock);
int (*socket_getsockopt) (struct socket * sock, int level, int optname);
@@ -2297,10 +2311,12 @@ int security_socket_bind(struct socket *
int security_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen);
int security_socket_listen(struct socket *sock, int backlog);
int security_socket_accept(struct socket *sock, struct socket *newsock);
-void security_socket_post_accept(struct socket *sock, struct socket *newsock);
+int security_socket_post_accept(struct socket *sock, struct socket *newsock);
int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size);
int security_socket_recvmsg(struct socket *sock, struct msghdr *msg,
int size, int flags);
+int security_socket_post_recv_datagram(struct sock *sk, struct sk_buff *skb,
+ unsigned int flags);
int security_socket_getsockname(struct socket *sock);
int security_socket_getpeername(struct socket *sock);
int security_socket_getsockopt(struct socket *sock, int level, int optname);
@@ -2376,9 +2392,10 @@ static inline int security_socket_accept
return 0;
}
-static inline void security_socket_post_accept(struct socket * sock,
- struct socket * newsock)
+static inline int security_socket_post_accept(struct socket *sock,
+ struct socket *newsock)
{
+ return 0;
}
static inline int security_socket_sendmsg(struct socket * sock,
@@ -2394,6 +2411,13 @@ static inline int security_socket_recvms
return 0;
}
+static inline int security_socket_post_recv_datagram(struct sock *sk,
+ struct sk_buff *skb,
+ unsigned int flags)
+{
+ return 0;
+}
+
static inline int security_socket_getsockname(struct socket * sock)
{
return 0;
--- net-2.6.25.orig/net/socket.c
+++ net-2.6.25/net/socket.c
@@ -1454,13 +1454,16 @@ asmlinkage long sys_accept(int fd, struc
goto out_fd;
}
+ /* Filter connections from unwanted peers. */
+ err = security_socket_post_accept(sock, newsock);
+ if (err)
+ goto out_fd;
+
/* File flags are not inherited via accept() unlike another OSes. */
fd_install(newfd, newfile);
err = newfd;
- security_socket_post_accept(sock, newsock);
-
out_put:
fput_light(sock->file, fput_needed);
out:
--- net-2.6.25.orig/security/dummy.c
+++ net-2.6.25/security/dummy.c
@@ -748,10 +748,10 @@ static int dummy_socket_accept (struct s
return 0;
}
-static void dummy_socket_post_accept (struct socket *sock,
- struct socket *newsock)
+static int dummy_socket_post_accept(struct socket *sock,
+ struct socket *newsock)
{
- return;
+ return 0;
}
static int dummy_socket_sendmsg (struct socket *sock, struct msghdr *msg,
@@ -766,6 +766,12 @@ static int dummy_socket_recvmsg (struct
return 0;
}
+static int dummy_socket_post_recv_datagram(struct sock *sk, struct sk_buff *skb,
+ unsigned int flags)
+{
+ return 0;
+}
+
static int dummy_socket_getsockname (struct socket *sock)
{
return 0;
@@ -1099,6 +1105,7 @@ void security_fixup_ops (struct security
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_post_recv_datagram);
set_to_dummy_if_null(ops, socket_getsockname);
set_to_dummy_if_null(ops, socket_getpeername);
set_to_dummy_if_null(ops, socket_setsockopt);
--- net-2.6.25.orig/net/core/datagram.c
+++ net-2.6.25/net/core/datagram.c
@@ -55,6 +55,7 @@
#include <net/checksum.h>
#include <net/sock.h>
#include <net/tcp_states.h>
+#include <linux/security.h>
/*
* Is a socket 'connection oriented' ?
@@ -148,6 +149,7 @@ struct sk_buff *__skb_recv_datagram(stru
{
struct sk_buff *skb;
long timeo;
+ unsigned long cpu_flags;
/*
* Caller is allowed not to check sk->sk_err before skb_recv_datagram()
*/
@@ -165,7 +167,6 @@ struct sk_buff *__skb_recv_datagram(stru
* Look at current nfs client by the way...
* However, this function was corrent in any case. 8)
*/
- unsigned long cpu_flags;
spin_lock_irqsave(&sk->sk_receive_queue.lock, cpu_flags);
skb = skb_peek(&sk->sk_receive_queue);
@@ -179,6 +180,14 @@ struct sk_buff *__skb_recv_datagram(stru
}
spin_unlock_irqrestore(&sk->sk_receive_queue.lock, cpu_flags);
+ /* Filter packets from unwanted peers. */
+ if (skb) {
+ error = security_socket_post_recv_datagram(sk, skb,
+ flags);
+ if (error)
+ goto force_dequeue;
+ }
+
if (skb)
return skb;
@@ -191,6 +200,24 @@ struct sk_buff *__skb_recv_datagram(stru
return NULL;
+force_dequeue:
+ /* Drop this packet because LSM says "Don't pass it to the caller". */
+ if (!(flags & MSG_PEEK))
+ goto no_peek;
+ /*
+ * If this packet is MSG_PEEK'ed, dequeue it forcibly
+ * so that this packet won't prevent the caller from picking up
+ * next packet.
+ */
+ spin_lock_irqsave(&sk->sk_receive_queue.lock, cpu_flags);
+ if (skb == skb_peek(&sk->sk_receive_queue)) {
+ __skb_unlink(skb, &sk->sk_receive_queue);
+ atomic_dec(&skb->users);
+ /* Do I have something to do with skb->peeked ? */
+ }
+ spin_unlock_irqrestore(&sk->sk_receive_queue.lock, cpu_flags);
+no_peek:
+ kfree_skb(skb);
no_packet:
*err = error;
return NULL;
--- net-2.6.25.orig/security/security.c
+++ net-2.6.25/security/security.c
@@ -869,9 +869,9 @@ int security_socket_accept(struct socket
return security_ops->socket_accept(sock, newsock);
}
-void security_socket_post_accept(struct socket *sock, struct socket *newsock)
+int security_socket_post_accept(struct socket *sock, struct socket *newsock)
{
- security_ops->socket_post_accept(sock, newsock);
+ return security_ops->socket_post_accept(sock, newsock);
}
int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size)
@@ -885,6 +885,12 @@ int security_socket_recvmsg(struct socke
return security_ops->socket_recvmsg(sock, msg, size, flags);
}
+int security_socket_post_recv_datagram(struct sock *sk, struct sk_buff *skb,
+ unsigned int flags)
+{
+ return security_ops->socket_post_recv_datagram(sk, skb, flags);
+}
+
int security_socket_getsockname(struct socket *sock)
{
return security_ops->socket_getsockname(sock);
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH net-2.6.25] Add packet filtering based on process's security context.
2008-01-22 15:16 [PATCH net-2.6.25] Add packet filtering based on process's security context Tetsuo Handa
@ 2008-01-22 16:49 ` Casey Schaufler
2008-01-23 1:26 ` [PATCH net-2.6.25] Add packet filtering based on process\'s " Tetsuo Handa
2008-01-24 11:47 ` [PATCH net-2.6.25] Add packet filtering based on process's " Tetsuo Handa
1 sibling, 1 reply; 9+ messages in thread
From: Casey Schaufler @ 2008-01-22 16:49 UTC (permalink / raw)
To: Tetsuo Handa, netdev, davem; +Cc: linux-security-module, netfilter-devel
--- Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> wrote:
> ...
>
> Currently, there is no way to directly map security context from incoming
> packet to user process. This is because the creator or owner of a socket is
> not always the receiver of an incoming packet. The userland process who
> receives the incoming packet is not known until a process calls
> sys_recvmsg().
> So, I want to add a LSM hook to give a security module a chance to control
> after the recipient of the incoming packet is known.
Do you have a real situation where two user processes with different
security contexts share a socket? How do you get into that situation,
and is it appropriate to have that situation in your security scheme?
Can this occur without using privilege?
Casey Schaufler
casey@schaufler-ca.com
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH net-2.6.25] Add packet filtering based on process\'s security context.
2008-01-22 16:49 ` Casey Schaufler
@ 2008-01-23 1:26 ` Tetsuo Handa
0 siblings, 0 replies; 9+ messages in thread
From: Tetsuo Handa @ 2008-01-23 1:26 UTC (permalink / raw)
To: casey; +Cc: linux-security-module, netfilter-devel, netdev, davem
Hello.
Casey Schaufler wrote:
> Do you have a real situation where two user processes with different
> security contexts share a socket? How do you get into that situation,
> and is it appropriate to have that situation in your security scheme?
> Can this occur without using privilege?
I hope such situation won't occur, as I have mentioned in the previous
posting.
| Precautions: This approach has a side effect which unlikely occurs.
|
| If a socket is shared by multiple processes with differnt policy,
| the process who should be able to accept this connection
| will not be able to accept this connection
| because socket_post_accept() aborts this connection.
| But if socket_post_accept() doesn't abort this connection,
| the process who must not be able to accept this connection
| will repeat accept() forever, which is a worse side effect.
|
| Similarly, if a socket is shared by multiple processes with differnt policy,
| the process who should be able to pick up this datagram
| will not be able to pick up this datagram
| because socket_post_recv_datagram() discards this datagram.
| But if socket_post_recv_datagram() doesn't discard this datagram,
| the process who must not be able to pick up this datagram
| will repeat recvmsg() forever, which is a worse side effect.
|
| So, don't give different permissions between processes who shares one socket.
| Otherwise, some connections/datagrams cannot be delivered to intended process.
But it is possible to write a code like
---------- app3.c start ----------
/* gcc -Wall -O2 -o /tmp/app3 app3.c */
#include <fcntl.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
const int fd1 = socket(PF_INET, SOCK_DGRAM, 0), fd2 = socket(PF_INET, SOCK_DGRAM, 0);
struct sockaddr_in addr;
char buf[16];
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(10000);
fprintf(stderr, "%s started.\n", argv[0]);
if (bind(fd1, (struct sockaddr *) &addr, sizeof(addr))) {
fprintf(stderr, "Can't bind()\n");
return 1;
}
if (sendto(fd2, "hello\n", 6, 0, (struct sockaddr *) &addr, sizeof(addr)) != 6 ||
sendto(fd2, "world\n", 6, 0, (struct sockaddr *) &addr, sizeof(addr)) != 6) {
fprintf(stderr, "Can't sendto()\n");
return 1;
}
while (1) {
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(fd1, &rfds);
select(fd1 + 1, &rfds, NULL, NULL, NULL);
if (FD_ISSET(fd1, &rfds)) break;
fprintf(stderr, "Can't select()\n");
return 1;
}
if (fcntl(fd1, FD_CLOEXEC, 0)) {
fprintf(stderr, "Can't fcntl()\n");
return 1;
}
snprintf(buf, sizeof(buf), "%d", fd1);
execlp("/tmp/app4", "app4", buf, NULL);
fprintf(stderr, "Can't execve()\n");
return 1;
}
---------- app3.c end ----------
---------- app4.c start ----------
/* gcc -Wall -O2 -o /tmp/app4 app4.c */
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
int fd;
if (argc != 2) {
fprintf(stderr, "Bad parameter.\n");
return 1;
}
fprintf(stderr, "%s started.\n", argv[0]);
fd = atoi(argv[1]);
while (1) {
struct sockaddr_in addr;
socklen_t size = sizeof(addr);
char buffer[1024];
int len;
len = recvfrom(fd, buffer, sizeof(buffer), 0, (struct sockaddr *) &addr, &size);
if (len == EOF) {
fprintf(stderr, "Can't recvfrom()\n");
return 1;
}
write(1, buffer, len);
}
return 0;
}
---------- app4.c end ----------
and assign different policy to /tmp/app1 and /tmp/app2 .
Therefore, I want to check at sys_recvmsg() time.
(Usage: Compile app3 and app4 and run /tmp/app3 .)
For TCP's case, see http://www.mail-archive.com/linux-security-module@vger.kernel.org/msg02531.html
What I want to do is perform connection/packet filtering
with the recipient of the incoming connection/packet known.
My security scheme controls based on the recipient of the incoming connection/packet.
In this case, not /tmp/app1 or /tmp/app3 , but /tmp/app2 or /tmp/app4.
This case occurs without using privilege.
Regards.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH net-2.6.25] Add packet filtering based on process's security context.
2008-01-22 15:16 [PATCH net-2.6.25] Add packet filtering based on process's security context Tetsuo Handa
2008-01-22 16:49 ` Casey Schaufler
@ 2008-01-24 11:47 ` Tetsuo Handa
2008-01-24 15:03 ` Paul Moore
1 sibling, 1 reply; 9+ messages in thread
From: Tetsuo Handa @ 2008-01-24 11:47 UTC (permalink / raw)
To: netdev, davem; +Cc: linux-security-module, netfilter-devel
Hello.
Are there any remaining questions/problems about this patch?
If none, I want this patch applied to net-2.6.25 tree.
Regards.
---------------
This patch modifies security_socket_post_accept() and introduces
security_socket_post_recv_datagram() LSM hooks.
Currently, security_socket_post_accept() is called *after* fd_install()
at sys_accept(). This means that userland process might access accept()ed
but not yet properly labeled socket.
I believe this security_socket_post_accept() should be called *before*
fd_install() for the three reasons.
* The userland process will always access proper context labeled by
security_socket_post_accept() rather than default context labeled by
security_inode_alloc() (called from alloc_inode() from new_inode() from
sock_alloc() from sys_accept()). This gives a security module
a chance to perform access control based on proper context.
* If security_socket_post_accept() failed to assign proper context
(e.g. -ENOMEM), the accept()ed socket can't have proper context.
Use of void for security_socket_post_accept() deprives a security module
of a chance to abandon the accept()ed socket.
* A security module can perform connection filtering based on
process's security context.
If security_socket_post_accept() is called after fd_install(),
it is too late to do so because the accept()ed socket is already visible
to userland processes.
Currently, there is no way to directly map security context from incoming
packet to user process. This is because the creator or owner of a socket is
not always the receiver of an incoming packet. The userland process who
receives the incoming packet is not known until a process calls sys_recvmsg().
So, I want to add a LSM hook to give a security module a chance to control
after the recipient of the incoming packet is known.
Signed-off-by: Kentaro Takeda <takedakn@nttdata.co.jp>
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
---
include/linux/security.h | 34 +++++++++++++++++++++++++++++-----
net/core/datagram.c | 29 ++++++++++++++++++++++++++++-
net/socket.c | 7 +++++--
security/dummy.c | 13 ++++++++++---
security/security.c | 10 ++++++++--
5 files changed, 80 insertions(+), 13 deletions(-)
--- net-2.6.25.orig/include/linux/security.h
+++ net-2.6.25/include/linux/security.h
@@ -781,8 +781,12 @@ struct request_sock;
* @socket_post_accept:
* This hook allows a security module to copy security
* information into the newly created socket's inode.
+ * This hook also allows a security module to filter connections
+ * from unwanted peers based on the process accepting this connection.
+ * The connection will be aborted if this hook returns nonzero.
* @sock contains the listening socket structure.
* @newsock contains the newly created server socket for connection.
+ * Return 0 if permission is granted.
* @socket_sendmsg:
* Check permission before transmitting a message to another socket.
* @sock contains the socket structure.
@@ -796,6 +800,15 @@ struct request_sock;
* @size contains the size of message structure.
* @flags contains the operational flags.
* Return 0 if permission is granted.
+ * @socket_post_recv_datagram:
+ * Check permission after receiving a datagram.
+ * This hook allows a security module to filter packets
+ * from unwanted peers based on the process receiving this datagram.
+ * The packet will be discarded if this hook returns nonzero.
+ * @sk contains the socket.
+ * @skb contains the socket buffer.
+ * @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.
@@ -1387,12 +1400,13 @@ struct security_operations {
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_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_post_recv_datagram) (struct sock *sk, struct sk_buff *skb,
+ unsigned int flags);
int (*socket_getsockname) (struct socket * sock);
int (*socket_getpeername) (struct socket * sock);
int (*socket_getsockopt) (struct socket * sock, int level, int optname);
@@ -2297,10 +2311,12 @@ int security_socket_bind(struct socket *
int security_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen);
int security_socket_listen(struct socket *sock, int backlog);
int security_socket_accept(struct socket *sock, struct socket *newsock);
-void security_socket_post_accept(struct socket *sock, struct socket *newsock);
+int security_socket_post_accept(struct socket *sock, struct socket *newsock);
int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size);
int security_socket_recvmsg(struct socket *sock, struct msghdr *msg,
int size, int flags);
+int security_socket_post_recv_datagram(struct sock *sk, struct sk_buff *skb,
+ unsigned int flags);
int security_socket_getsockname(struct socket *sock);
int security_socket_getpeername(struct socket *sock);
int security_socket_getsockopt(struct socket *sock, int level, int optname);
@@ -2376,9 +2392,10 @@ static inline int security_socket_accept
return 0;
}
-static inline void security_socket_post_accept(struct socket * sock,
- struct socket * newsock)
+static inline int security_socket_post_accept(struct socket *sock,
+ struct socket *newsock)
{
+ return 0;
}
static inline int security_socket_sendmsg(struct socket * sock,
@@ -2394,6 +2411,13 @@ static inline int security_socket_recvms
return 0;
}
+static inline int security_socket_post_recv_datagram(struct sock *sk,
+ struct sk_buff *skb,
+ unsigned int flags)
+{
+ return 0;
+}
+
static inline int security_socket_getsockname(struct socket * sock)
{
return 0;
--- net-2.6.25.orig/net/socket.c
+++ net-2.6.25/net/socket.c
@@ -1454,13 +1454,16 @@ asmlinkage long sys_accept(int fd, struc
goto out_fd;
}
+ /* Filter connections from unwanted peers. */
+ err = security_socket_post_accept(sock, newsock);
+ if (err)
+ goto out_fd;
+
/* File flags are not inherited via accept() unlike another OSes. */
fd_install(newfd, newfile);
err = newfd;
- security_socket_post_accept(sock, newsock);
-
out_put:
fput_light(sock->file, fput_needed);
out:
--- net-2.6.25.orig/security/dummy.c
+++ net-2.6.25/security/dummy.c
@@ -748,10 +748,10 @@ static int dummy_socket_accept (struct s
return 0;
}
-static void dummy_socket_post_accept (struct socket *sock,
- struct socket *newsock)
+static int dummy_socket_post_accept(struct socket *sock,
+ struct socket *newsock)
{
- return;
+ return 0;
}
static int dummy_socket_sendmsg (struct socket *sock, struct msghdr *msg,
@@ -766,6 +766,12 @@ static int dummy_socket_recvmsg (struct
return 0;
}
+static int dummy_socket_post_recv_datagram(struct sock *sk, struct sk_buff *skb,
+ unsigned int flags)
+{
+ return 0;
+}
+
static int dummy_socket_getsockname (struct socket *sock)
{
return 0;
@@ -1099,6 +1105,7 @@ void security_fixup_ops (struct security
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_post_recv_datagram);
set_to_dummy_if_null(ops, socket_getsockname);
set_to_dummy_if_null(ops, socket_getpeername);
set_to_dummy_if_null(ops, socket_setsockopt);
--- net-2.6.25.orig/net/core/datagram.c
+++ net-2.6.25/net/core/datagram.c
@@ -55,6 +55,7 @@
#include <net/checksum.h>
#include <net/sock.h>
#include <net/tcp_states.h>
+#include <linux/security.h>
/*
* Is a socket 'connection oriented' ?
@@ -148,6 +149,7 @@ struct sk_buff *__skb_recv_datagram(stru
{
struct sk_buff *skb;
long timeo;
+ unsigned long cpu_flags;
/*
* Caller is allowed not to check sk->sk_err before skb_recv_datagram()
*/
@@ -165,7 +167,6 @@ struct sk_buff *__skb_recv_datagram(stru
* Look at current nfs client by the way...
* However, this function was corrent in any case. 8)
*/
- unsigned long cpu_flags;
spin_lock_irqsave(&sk->sk_receive_queue.lock, cpu_flags);
skb = skb_peek(&sk->sk_receive_queue);
@@ -179,6 +180,14 @@ struct sk_buff *__skb_recv_datagram(stru
}
spin_unlock_irqrestore(&sk->sk_receive_queue.lock, cpu_flags);
+ /* Filter packets from unwanted peers. */
+ if (skb) {
+ error = security_socket_post_recv_datagram(sk, skb,
+ flags);
+ if (error)
+ goto force_dequeue;
+ }
+
if (skb)
return skb;
@@ -191,6 +200,24 @@ struct sk_buff *__skb_recv_datagram(stru
return NULL;
+force_dequeue:
+ /* Drop this packet because LSM says "Don't pass it to the caller". */
+ if (!(flags & MSG_PEEK))
+ goto no_peek;
+ /*
+ * If this packet is MSG_PEEK'ed, dequeue it forcibly
+ * so that this packet won't prevent the caller from picking up
+ * next packet.
+ */
+ spin_lock_irqsave(&sk->sk_receive_queue.lock, cpu_flags);
+ if (skb == skb_peek(&sk->sk_receive_queue)) {
+ __skb_unlink(skb, &sk->sk_receive_queue);
+ atomic_dec(&skb->users);
+ /* Do I have something to do with skb->peeked ? */
+ }
+ spin_unlock_irqrestore(&sk->sk_receive_queue.lock, cpu_flags);
+no_peek:
+ kfree_skb(skb);
no_packet:
*err = error;
return NULL;
--- net-2.6.25.orig/security/security.c
+++ net-2.6.25/security/security.c
@@ -869,9 +869,9 @@ int security_socket_accept(struct socket
return security_ops->socket_accept(sock, newsock);
}
-void security_socket_post_accept(struct socket *sock, struct socket *newsock)
+int security_socket_post_accept(struct socket *sock, struct socket *newsock)
{
- security_ops->socket_post_accept(sock, newsock);
+ return security_ops->socket_post_accept(sock, newsock);
}
int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size)
@@ -885,6 +885,12 @@ int security_socket_recvmsg(struct socke
return security_ops->socket_recvmsg(sock, msg, size, flags);
}
+int security_socket_post_recv_datagram(struct sock *sk, struct sk_buff *skb,
+ unsigned int flags)
+{
+ return security_ops->socket_post_recv_datagram(sk, skb, flags);
+}
+
int security_socket_getsockname(struct socket *sock)
{
return security_ops->socket_getsockname(sock);
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH net-2.6.25] Add packet filtering based on process's security context.
2008-01-24 11:47 ` [PATCH net-2.6.25] Add packet filtering based on process's " Tetsuo Handa
@ 2008-01-24 15:03 ` Paul Moore
0 siblings, 0 replies; 9+ messages in thread
From: Paul Moore @ 2008-01-24 15:03 UTC (permalink / raw)
To: Tetsuo Handa; +Cc: netdev, davem, linux-security-module, netfilter-devel
On Thursday 24 January 2008 6:47:55 am Tetsuo Handa wrote:
> Are there any remaining questions/problems about this patch?
> If none, I want this patch applied to net-2.6.25 tree.
Hello,
Taking into consideration that there are no current in-tree users of
this patch and the only known user of this functionality is TOMOYO,
which is still dealing with some unresolved VFS issues, I suggest not
merging this patch at the current time. My recommendation is to
continue to work on resolving the VFS issues (which it appears you are
working on) and then submitting all of the required TOMOYO changes at
once.
As a general rule, removing functionality from the kernel tends to be
much more difficult then adding it.
--
paul moore
linux security @ hp
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH net-2.6.25] Add packet filtering based on process's security context.
@ 2007-12-31 6:21 Tetsuo Handa
0 siblings, 0 replies; 9+ messages in thread
From: Tetsuo Handa @ 2007-12-31 6:21 UTC (permalink / raw)
To: netdev, netfilter-devel, linux-security-module; +Cc: sam
Hello.
This is a repost of a patch submitted at http://lkml.org/lkml/2007/11/19/545 .
Current status is that I'm waiting for Samir Bellabes's answer
whether we can handle the following example without this patch.
Tetsuo Handa wrote:
> Hello.
>
> Samir Bellabes wrote:
> > >> what differences between you approach and netfilter in this case ? if
> > >> it's about packet filtering, you already have all you wishes in
> > >> netfilter project.
> > > Except a hook for making decision with the name of process who picks that packet up known.
> >
> > I think that we really don't need it, because we can catch the
> > informations as I explained.
>
> Well, I haven't understood yet why we don't need it.
>
> How can you know the the name of process who copies that datagram to its userspace memory?
> A socket may be shared by multiple different executable files,
> so the name of the executable file is not known until
> one of processes who share the socket issues accept()/recvmsg() syscall.
>
> Are you saying that I should not use the name of the executable file?
>
> Regards.
>
Tetsuo Handa wrote:
> Hello.
>
> I made an example.
>
> Usage:
>
> Compile app1 and app2 and run /tmp/app1 .
>
> Run something like
> curl http://localhost:10000/
> to connect to /tmp/app1.
>
> I want to know that */tmp/app2* accepts TCP connection
> so that the user can control
> whether this TCP connection from 127.0.0.1 port N
> should be accepted by */tmp/app2* or not.
>
> How can we do this without socket_post_accept() change?
>
> Regards.
>
> ---------- app1.c start ----------
> /* gcc -Wall -O2 -o /tmp/app1 app1.c */
> #include <fcntl.h>
> #include <netinet/in.h>
> #include <stdio.h>
> #include <string.h>
> #include <sys/select.h>
> #include <sys/socket.h>
> #include <sys/types.h>
> #include <unistd.h>
>
> int main(int argc, char *argv[]) {
> const int fd = socket(PF_INET, SOCK_STREAM, 0);
> struct sockaddr_in addr;
> char buf[16];
> memset(&addr, 0, sizeof(addr));
> addr.sin_family = AF_INET;
> addr.sin_addr.s_addr = htonl(INADDR_ANY);
> addr.sin_port = htons(10000);
> fprintf(stderr, "%s started.\n", argv[0]);
> if (bind(fd, (struct sockaddr *) &addr, sizeof(addr))) {
> fprintf(stderr, "Can't bind()\n");
> return 1;
> } else if (listen(fd, 5)) {
> fprintf(stderr, "Can't listen()\n");
> return 1;
> }
> while (1) {
> fd_set rfds;
> FD_ZERO(&rfds);
> FD_SET(fd, &rfds);
> select(fd + 1, &rfds, NULL, NULL, NULL);
> if (FD_ISSET(fd, &rfds)) break;
> fprintf(stderr, "Can't select()\n");
> return 1;
> }
> if (fcntl(fd, FD_CLOEXEC, 0)) {
> fprintf(stderr, "Can't fcntl()\n");
> return 1;
> }
> snprintf(buf, sizeof(buf), "%d", fd);
> execlp("/tmp/app2", "app2", buf, NULL);
> fprintf(stderr, "Can't execve()\n");
> return 1;
> }
> ---------- app1.c end ----------
>
> ---------- app2.c start ----------
> /* gcc -Wall -O2 -o /tmp/app2 app2.c */
> #include <netinet/in.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <sys/socket.h>
> #include <sys/types.h>
> #include <unistd.h>
>
> int main(int argc, char *argv[]) {
> int lfd;
> if (argc != 2) {
> fprintf(stderr, "Bad parameter.\n");
> return 1;
> }
> fprintf(stderr, "%s started.\n", argv[0]);
> lfd = atoi(argv[1]);
> while (1) {
> struct sockaddr_in addr;
> socklen_t size = sizeof(addr);
> int fd = accept(lfd, (struct sockaddr *) &addr, &size);
> char c;
> if (fd == EOF) {
> fprintf(stderr, "Can't accept()\n");
> return 1;
> }
> while (read(fd, &c, 1) == 1 && write(fd, &c, 1) == 1);
> close(fd);
> }
> return 0;
> }
> ---------- app2.c end ----------
>
Regards.
----------
Subject: Add packet filtering based on process's security context.
This patch allows LSM modules filter incoming connections/datagrams
based on the process's security context who is attempting to pick up.
There are already hooks to filter incoming connections/datagrams
based on the socket's security context, but these hooks are not
applicable when one wants to do TCP Wrapper-like filtering
(e.g. App1 is permitted to accept TCP connections from 192.168.0.0/16).
Precautions: This approach has a side effect which unlikely occurs.
If a socket is shared by multiple processes with differnt policy,
the process who should be able to accept this connection
will not be able to accept this connection
because socket_post_accept() aborts this connection.
But if socket_post_accept() doesn't abort this connection,
the process who must not be able to accept this connection
will repeat accept() forever, which is a worse side effect.
Similarly, if a socket is shared by multiple processes with differnt policy,
the process who should be able to pick up this datagram
will not be able to pick up this datagram
because socket_post_recv_datagram() discards this datagram.
But if socket_post_recv_datagram() doesn't discard this datagram,
the process who must not be able to pick up this datagram
will repeat recvmsg() forever, which is a worse side effect.
So, don't give different permissions between processes who shares one socket.
Otherwise, some connections/datagrams cannot be delivered to intended process.
Signed-off-by: Kentaro Takeda <takedakn@nttdata.co.jp>
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
---
include/linux/security.h | 34 +++++++++++++++++++++++++++++-----
net/core/datagram.c | 29 ++++++++++++++++++++++++++++-
net/socket.c | 7 +++++--
security/dummy.c | 13 ++++++++++---
security/security.c | 10 ++++++++--
5 files changed, 80 insertions(+), 13 deletions(-)
--- net-2.6.25.orig/include/linux/security.h
+++ net-2.6.25/include/linux/security.h
@@ -781,8 +781,12 @@ struct request_sock;
* @socket_post_accept:
* This hook allows a security module to copy security
* information into the newly created socket's inode.
+ * This hook also allows a security module to filter connections
+ * from unwanted peers based on the process accepting this connection.
+ * The connection will be aborted if this hook returns nonzero.
* @sock contains the listening socket structure.
* @newsock contains the newly created server socket for connection.
+ * Return 0 if permission is granted.
* @socket_sendmsg:
* Check permission before transmitting a message to another socket.
* @sock contains the socket structure.
@@ -796,6 +800,15 @@ struct request_sock;
* @size contains the size of message structure.
* @flags contains the operational flags.
* Return 0 if permission is granted.
+ * @socket_post_recv_datagram:
+ * Check permission after receiving a datagram.
+ * This hook allows a security module to filter packets
+ * from unwanted peers based on the process receiving this datagram.
+ * The packet will be discarded if this hook returns nonzero.
+ * @sk contains the socket.
+ * @skb contains the socket buffer.
+ * @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.
@@ -1387,12 +1400,13 @@ struct security_operations {
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_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_post_recv_datagram) (struct sock *sk, struct sk_buff *skb,
+ unsigned int flags);
int (*socket_getsockname) (struct socket * sock);
int (*socket_getpeername) (struct socket * sock);
int (*socket_getsockopt) (struct socket * sock, int level, int optname);
@@ -2297,10 +2311,12 @@ int security_socket_bind(struct socket *
int security_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen);
int security_socket_listen(struct socket *sock, int backlog);
int security_socket_accept(struct socket *sock, struct socket *newsock);
-void security_socket_post_accept(struct socket *sock, struct socket *newsock);
+int security_socket_post_accept(struct socket *sock, struct socket *newsock);
int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size);
int security_socket_recvmsg(struct socket *sock, struct msghdr *msg,
int size, int flags);
+int security_socket_post_recv_datagram(struct sock *sk, struct sk_buff *skb,
+ unsigned int flags);
int security_socket_getsockname(struct socket *sock);
int security_socket_getpeername(struct socket *sock);
int security_socket_getsockopt(struct socket *sock, int level, int optname);
@@ -2376,9 +2392,10 @@ static inline int security_socket_accept
return 0;
}
-static inline void security_socket_post_accept(struct socket * sock,
- struct socket * newsock)
+static inline int security_socket_post_accept(struct socket *sock,
+ struct socket *newsock)
{
+ return 0;
}
static inline int security_socket_sendmsg(struct socket * sock,
@@ -2394,6 +2411,13 @@ static inline int security_socket_recvms
return 0;
}
+static inline int security_socket_post_recv_datagram(struct sock *sk,
+ struct sk_buff *skb,
+ unsigned int flags)
+{
+ return 0;
+}
+
static inline int security_socket_getsockname(struct socket * sock)
{
return 0;
--- net-2.6.25.orig/net/socket.c
+++ net-2.6.25/net/socket.c
@@ -1454,13 +1454,16 @@ asmlinkage long sys_accept(int fd, struc
goto out_fd;
}
+ /* Filter connections from unwanted peers. */
+ err = security_socket_post_accept(sock, newsock);
+ if (err)
+ goto out_fd;
+
/* File flags are not inherited via accept() unlike another OSes. */
fd_install(newfd, newfile);
err = newfd;
- security_socket_post_accept(sock, newsock);
-
out_put:
fput_light(sock->file, fput_needed);
out:
--- net-2.6.25.orig/security/dummy.c
+++ net-2.6.25/security/dummy.c
@@ -748,10 +748,10 @@ static int dummy_socket_accept (struct s
return 0;
}
-static void dummy_socket_post_accept (struct socket *sock,
- struct socket *newsock)
+static int dummy_socket_post_accept(struct socket *sock,
+ struct socket *newsock)
{
- return;
+ return 0;
}
static int dummy_socket_sendmsg (struct socket *sock, struct msghdr *msg,
@@ -766,6 +766,12 @@ static int dummy_socket_recvmsg (struct
return 0;
}
+static int dummy_socket_post_recv_datagram(struct sock *sk, struct sk_buff *skb,
+ unsigned int flags)
+{
+ return 0;
+}
+
static int dummy_socket_getsockname (struct socket *sock)
{
return 0;
@@ -1099,6 +1105,7 @@ void security_fixup_ops (struct security
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_post_recv_datagram);
set_to_dummy_if_null(ops, socket_getsockname);
set_to_dummy_if_null(ops, socket_getpeername);
set_to_dummy_if_null(ops, socket_setsockopt);
--- net-2.6.25.orig/net/core/datagram.c
+++ net-2.6.25/net/core/datagram.c
@@ -55,6 +55,7 @@
#include <net/checksum.h>
#include <net/sock.h>
#include <net/tcp_states.h>
+#include <linux/security.h>
/*
* Is a socket 'connection oriented' ?
@@ -148,6 +149,7 @@ struct sk_buff *__skb_recv_datagram(stru
{
struct sk_buff *skb;
long timeo;
+ unsigned long cpu_flags;
/*
* Caller is allowed not to check sk->sk_err before skb_recv_datagram()
*/
@@ -165,7 +167,6 @@ struct sk_buff *__skb_recv_datagram(stru
* Look at current nfs client by the way...
* However, this function was corrent in any case. 8)
*/
- unsigned long cpu_flags;
spin_lock_irqsave(&sk->sk_receive_queue.lock, cpu_flags);
skb = skb_peek(&sk->sk_receive_queue);
@@ -179,6 +180,14 @@ struct sk_buff *__skb_recv_datagram(stru
}
spin_unlock_irqrestore(&sk->sk_receive_queue.lock, cpu_flags);
+ /* Filter packets from unwanted peers. */
+ if (skb) {
+ error = security_socket_post_recv_datagram(sk, skb,
+ flags);
+ if (error)
+ goto force_dequeue;
+ }
+
if (skb)
return skb;
@@ -191,6 +200,24 @@ struct sk_buff *__skb_recv_datagram(stru
return NULL;
+force_dequeue:
+ /* Drop this packet because LSM says "Don't pass it to the caller". */
+ if (!(flags & MSG_PEEK))
+ goto no_peek;
+ /*
+ * If this packet is MSG_PEEK'ed, dequeue it forcibly
+ * so that this packet won't prevent the caller from picking up
+ * next packet.
+ */
+ spin_lock_irqsave(&sk->sk_receive_queue.lock, cpu_flags);
+ if (skb == skb_peek(&sk->sk_receive_queue)) {
+ __skb_unlink(skb, &sk->sk_receive_queue);
+ atomic_dec(&skb->users);
+ /* Do I have something to do with skb->peeked ? */
+ }
+ spin_unlock_irqrestore(&sk->sk_receive_queue.lock, cpu_flags);
+no_peek:
+ kfree_skb(skb);
no_packet:
*err = error;
return NULL;
--- net-2.6.25.orig/security/security.c
+++ net-2.6.25/security/security.c
@@ -869,9 +869,9 @@ int security_socket_accept(struct socket
return security_ops->socket_accept(sock, newsock);
}
-void security_socket_post_accept(struct socket *sock, struct socket *newsock)
+int security_socket_post_accept(struct socket *sock, struct socket *newsock)
{
- security_ops->socket_post_accept(sock, newsock);
+ return security_ops->socket_post_accept(sock, newsock);
}
int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size)
@@ -885,6 +885,12 @@ int security_socket_recvmsg(struct socke
return security_ops->socket_recvmsg(sock, msg, size, flags);
}
+int security_socket_post_recv_datagram(struct sock *sk, struct sk_buff *skb,
+ unsigned int flags)
+{
+ return security_ops->socket_post_recv_datagram(sk, skb, flags);
+}
+
int security_socket_getsockname(struct socket *sock)
{
return security_ops->socket_getsockname(sock);
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH] Add packet filtering based on process's security context.
@ 2007-11-21 12:30 Tetsuo Handa
2007-11-22 13:35 ` [PATCH net-2.6.25] " Tetsuo Handa
0 siblings, 1 reply; 9+ messages in thread
From: Tetsuo Handa @ 2007-11-21 12:30 UTC (permalink / raw)
To: herbert; +Cc: netdev, davem
Hello.
This patch comes from a thread at http://lkml.org/lkml/2007/11/16/155 .
I want to use IP/port based access control for incoming connections/datagrams.
This idea was discussed for several times, but there is no approach that satisfies
both "it can decide based on the recipient's process" and
"it can sleep so that the LSM hook can query userspace for an access decision".
Thus, I'd like to add one new LSM hook in net/core/datagram.c and
change return type of one existing LSM hook in net/socket.c .
Regards.
-----
Subject: Add packet filtering based on process's security context.
This patch allows LSM modules filter incoming connections/datagrams
based on the process's security context who is attempting to pick up.
There are already hooks to filter incoming connections/datagrams
based on the socket's security context, but these hooks are not
applicable when one wants to do TCP Wrapper-like filtering
(e.g. App1 is permitted to accept TCP connections from 192.168.0.0/16).
Precautions: This approach has a side effect which unlikely occurs.
If a socket is shared by multiple processes with differnt policy,
the process who should be able to accept this connection
will not be able to accept this connection
because socket_post_accept() aborts this connection.
But if socket_post_accept() doesn't abort this connection,
the process who must not be able to accept this connection
will repeat accept() forever, which is a worse side effect.
Similarly, if a socket is shared by multiple processes with differnt policy,
the process who should be able to pick up this datagram
will not be able to pick up this datagram
because socket_post_recv_datagram() discards this datagram.
But if socket_post_recv_datagram() doesn't discard this datagram,
the process who must not be able to pick up this datagram
will repeat recvmsg() forever, which is a worse side effect.
So, don't give different permissions between processes who shares one socket.
Otherwise, some connections/datagrams cannot be delivered to intended process.
Signed-off-by: Kentaro Takeda <takedakn@nttdata.co.jp>
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
include/linux/security.h | 34 +++++++++++++++++++++++++++++-----
net/core/datagram.c | 26 ++++++++++++++++++++++++--
net/socket.c | 7 +++++--
security/dummy.c | 13 ++++++++++---
security/security.c | 10 ++++++++--
5 files changed, 76 insertions(+), 14 deletions(-)
--- linux-2.6-mm.orig/include/linux/security.h
+++ linux-2.6-mm/include/linux/security.h
@@ -778,8 +778,12 @@ struct request_sock;
* @socket_post_accept:
* This hook allows a security module to copy security
* information into the newly created socket's inode.
+ * This hook also allows a security module to filter connections
+ * from unwanted peers based on the process accepting this connection.
+ * The connection will be aborted if this hook returns nonzero.
* @sock contains the listening socket structure.
* @newsock contains the newly created server socket for connection.
+ * Return 0 if permission is granted.
* @socket_sendmsg:
* Check permission before transmitting a message to another socket.
* @sock contains the socket structure.
@@ -793,6 +797,15 @@ struct request_sock;
* @size contains the size of message structure.
* @flags contains the operational flags.
* Return 0 if permission is granted.
+ * @socket_post_recv_datagram:
+ * Check permission after receiving a datagram.
+ * This hook allows a security module to filter packets
+ * from unwanted peers based on the process receiving this datagram.
+ * The packet will be discarded if this hook returns nonzero.
+ * @sk contains the socket.
+ * @skb contains the socket buffer (may be NULL).
+ * @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.
@@ -1389,12 +1402,13 @@ struct security_operations {
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_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_post_recv_datagram) (struct sock *sk, struct sk_buff *skb,
+ unsigned int flags);
int (*socket_getsockname) (struct socket * sock);
int (*socket_getpeername) (struct socket * sock);
int (*socket_getsockopt) (struct socket * sock, int level, int optname);
@@ -2307,10 +2321,12 @@ int security_socket_bind(struct socket *
int security_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen);
int security_socket_listen(struct socket *sock, int backlog);
int security_socket_accept(struct socket *sock, struct socket *newsock);
-void security_socket_post_accept(struct socket *sock, struct socket *newsock);
+int security_socket_post_accept(struct socket *sock, struct socket *newsock);
int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size);
int security_socket_recvmsg(struct socket *sock, struct msghdr *msg,
int size, int flags);
+int security_socket_post_recv_datagram(struct sock *sk, struct sk_buff *skb,
+ unsigned int flags);
int security_socket_getsockname(struct socket *sock);
int security_socket_getpeername(struct socket *sock);
int security_socket_getsockopt(struct socket *sock, int level, int optname);
@@ -2386,9 +2402,10 @@ static inline int security_socket_accept
return 0;
}
-static inline void security_socket_post_accept(struct socket * sock,
- struct socket * newsock)
+static inline int security_socket_post_accept(struct socket *sock,
+ struct socket *newsock)
{
+ return 0;
}
static inline int security_socket_sendmsg(struct socket * sock,
@@ -2404,6 +2421,13 @@ static inline int security_socket_recvms
return 0;
}
+static inline int security_socket_post_recv_datagram(struct sock *sk,
+ struct sk_buff *skb,
+ unsigned int flags)
+{
+ return 0;
+}
+
static inline int security_socket_getsockname(struct socket * sock)
{
return 0;
--- linux-2.6-mm.orig/net/socket.c
+++ linux-2.6-mm/net/socket.c
@@ -1442,13 +1442,16 @@ asmlinkage long sys_accept(int fd, struc
goto out_fd;
}
+ /* Filter connections from unwanted peers. */
+ err = security_socket_post_accept(sock, newsock);
+ if (err)
+ goto out_fd;
+
/* File flags are not inherited via accept() unlike another OSes. */
fd_install(newfd, newfile);
err = newfd;
- security_socket_post_accept(sock, newsock);
-
out_put:
fput_light(sock->file, fput_needed);
out:
--- linux-2.6-mm.orig/security/dummy.c
+++ linux-2.6-mm/security/dummy.c
@@ -753,10 +753,10 @@ static int dummy_socket_accept (struct s
return 0;
}
-static void dummy_socket_post_accept (struct socket *sock,
- struct socket *newsock)
+static int dummy_socket_post_accept(struct socket *sock,
+ struct socket *newsock)
{
- return;
+ return 0;
}
static int dummy_socket_sendmsg (struct socket *sock, struct msghdr *msg,
@@ -771,6 +771,12 @@ static int dummy_socket_recvmsg (struct
return 0;
}
+static int dummy_socket_post_recv_datagram(struct sock *sk, struct sk_buff *skb,
+ unsigned int flags)
+{
+ return 0;
+}
+
static int dummy_socket_getsockname (struct socket *sock)
{
return 0;
@@ -1110,6 +1116,7 @@ void security_fixup_ops (struct security
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_post_recv_datagram);
set_to_dummy_if_null(ops, socket_getsockname);
set_to_dummy_if_null(ops, socket_getpeername);
set_to_dummy_if_null(ops, socket_setsockopt);
--- linux-2.6-mm.orig/net/core/datagram.c
+++ linux-2.6-mm/net/core/datagram.c
@@ -55,6 +55,7 @@
#include <net/checksum.h>
#include <net/sock.h>
#include <net/tcp_states.h>
+#include <linux/security.h>
/*
* Is a socket 'connection oriented' ?
@@ -148,6 +149,7 @@ struct sk_buff *skb_recv_datagram(struct
{
struct sk_buff *skb;
long timeo;
+ unsigned long cpu_flags;
/*
* Caller is allowed not to check sk->sk_err before skb_recv_datagram()
*/
@@ -166,8 +168,6 @@ struct sk_buff *skb_recv_datagram(struct
* However, this function was corrent in any case. 8)
*/
if (flags & MSG_PEEK) {
- unsigned long cpu_flags;
-
spin_lock_irqsave(&sk->sk_receive_queue.lock,
cpu_flags);
skb = skb_peek(&sk->sk_receive_queue);
@@ -178,6 +178,11 @@ struct sk_buff *skb_recv_datagram(struct
} else
skb = skb_dequeue(&sk->sk_receive_queue);
+ /* Filter packets from unwanted peers. */
+ error = security_socket_post_recv_datagram(sk, skb, flags);
+ if (error)
+ goto force_dequeue;
+
if (skb)
return skb;
@@ -190,6 +195,23 @@ struct sk_buff *skb_recv_datagram(struct
return NULL;
+force_dequeue:
+ /* Drop this packet because LSM says "Don't pass it to the caller". */
+ if (!(flags & MSG_PEEK))
+ goto no_peek;
+ /*
+ * If this packet is MSG_PEEK'ed, dequeue it forcibly
+ * so that this packet won't prevent the caller from picking up
+ * next packet.
+ */
+ spin_lock_irqsave(&sk->sk_receive_queue.lock, cpu_flags);
+ if (skb == skb_peek(&sk->sk_receive_queue)) {
+ __skb_unlink(skb, &sk->sk_receive_queue);
+ atomic_dec(&skb->users);
+ }
+ spin_unlock_irqrestore(&sk->sk_receive_queue.lock, cpu_flags);
+no_peek:
+ kfree_skb(skb);
no_packet:
*err = error;
return NULL;
--- linux-2.6-mm.orig/security/security.c
+++ linux-2.6-mm/security/security.c
@@ -875,9 +875,9 @@ int security_socket_accept(struct socket
return security_ops->socket_accept(sock, newsock);
}
-void security_socket_post_accept(struct socket *sock, struct socket *newsock)
+int security_socket_post_accept(struct socket *sock, struct socket *newsock)
{
- security_ops->socket_post_accept(sock, newsock);
+ return security_ops->socket_post_accept(sock, newsock);
}
int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size)
@@ -891,6 +891,12 @@ int security_socket_recvmsg(struct socke
return security_ops->socket_recvmsg(sock, msg, size, flags);
}
+int security_socket_post_recv_datagram(struct sock *sk, struct sk_buff *skb,
+ unsigned int flags)
+{
+ return security_ops->socket_post_recv_datagram(sk, skb, flags);
+}
+
int security_socket_getsockname(struct socket *sock)
{
return security_ops->socket_getsockname(sock);
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH net-2.6.25] Add packet filtering based on process's security context.
2007-11-21 12:30 [PATCH] " Tetsuo Handa
@ 2007-11-22 13:35 ` Tetsuo Handa
2007-11-22 23:29 ` James Morris
0 siblings, 1 reply; 9+ messages in thread
From: Tetsuo Handa @ 2007-11-22 13:35 UTC (permalink / raw)
To: herbert; +Cc: netdev, davem
Hello.
Herbert Xu wrote:
> On Thu, Nov 22, 2007 at 09:57:14PM +0900, Tetsuo Handa wrote:
> >
> > But you say that I should make patches based on the net-2.6.25 tree.
> > Which tree ("-mm" or "net-2.6.25") should I use for making this patch?
>
> The net-2.6.25 tree is the one. Please use the tree at
>
> git://git.kernel.org/pub/scm/linux/kernel/git/herbert/net-2.6.25.git/
>
> while Dave is away.
Thank you.
I refreshed the patch based on net-2.6.25 tree.
Regards.
-----
Subject: Add packet filtering based on process's security context.
This patch allows LSM modules filter incoming connections/datagrams
based on the process's security context who is attempting to pick up.
There are already hooks to filter incoming connections/datagrams
based on the socket's security context, but these hooks are not
applicable when one wants to do TCP Wrapper-like filtering
(e.g. App1 is permitted to accept TCP connections from 192.168.0.0/16).
Precautions: This approach has a side effect which unlikely occurs.
If a socket is shared by multiple processes with differnt policy,
the process who should be able to accept this connection
will not be able to accept this connection
because socket_post_accept() aborts this connection.
But if socket_post_accept() doesn't abort this connection,
the process who must not be able to accept this connection
will repeat accept() forever, which is a worse side effect.
Similarly, if a socket is shared by multiple processes with differnt policy,
the process who should be able to pick up this datagram
will not be able to pick up this datagram
because socket_post_recv_datagram() discards this datagram.
But if socket_post_recv_datagram() doesn't discard this datagram,
the process who must not be able to pick up this datagram
will repeat recvmsg() forever, which is a worse side effect.
So, don't give different permissions between processes who share one socket.
Otherwise, some connections/datagrams cannot be delivered to intended process.
Signed-off-by: Kentaro Takeda <takedakn@nttdata.co.jp>
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
include/linux/security.h | 34 +++++++++++++++++++++++++++++-----
net/core/datagram.c | 26 ++++++++++++++++++++++++--
net/socket.c | 7 +++++--
security/dummy.c | 13 ++++++++++---
security/security.c | 10 ++++++++--
5 files changed, 76 insertions(+), 14 deletions(-)
--- net-2.6.25.orig/include/linux/security.h
+++ net-2.6.25/include/linux/security.h
@@ -781,8 +781,12 @@ struct request_sock;
* @socket_post_accept:
* This hook allows a security module to copy security
* information into the newly created socket's inode.
+ * This hook also allows a security module to filter connections
+ * from unwanted peers based on the process accepting this connection.
+ * The connection will be aborted if this hook returns nonzero.
* @sock contains the listening socket structure.
* @newsock contains the newly created server socket for connection.
+ * Return 0 if permission is granted.
* @socket_sendmsg:
* Check permission before transmitting a message to another socket.
* @sock contains the socket structure.
@@ -796,6 +800,15 @@ struct request_sock;
* @size contains the size of message structure.
* @flags contains the operational flags.
* Return 0 if permission is granted.
+ * @socket_post_recv_datagram:
+ * Check permission after receiving a datagram.
+ * This hook allows a security module to filter packets
+ * from unwanted peers based on the process receiving this datagram.
+ * The packet will be discarded if this hook returns nonzero.
+ * @sk contains the socket.
+ * @skb contains the socket buffer (may be NULL).
+ * @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.
@@ -1387,12 +1400,13 @@ struct security_operations {
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_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_post_recv_datagram) (struct sock *sk, struct sk_buff *skb,
+ unsigned int flags);
int (*socket_getsockname) (struct socket * sock);
int (*socket_getpeername) (struct socket * sock);
int (*socket_getsockopt) (struct socket * sock, int level, int optname);
@@ -2297,10 +2311,12 @@ int security_socket_bind(struct socket *
int security_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen);
int security_socket_listen(struct socket *sock, int backlog);
int security_socket_accept(struct socket *sock, struct socket *newsock);
-void security_socket_post_accept(struct socket *sock, struct socket *newsock);
+int security_socket_post_accept(struct socket *sock, struct socket *newsock);
int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size);
int security_socket_recvmsg(struct socket *sock, struct msghdr *msg,
int size, int flags);
+int security_socket_post_recv_datagram(struct sock *sk, struct sk_buff *skb,
+ unsigned int flags);
int security_socket_getsockname(struct socket *sock);
int security_socket_getpeername(struct socket *sock);
int security_socket_getsockopt(struct socket *sock, int level, int optname);
@@ -2376,9 +2392,10 @@ static inline int security_socket_accept
return 0;
}
-static inline void security_socket_post_accept(struct socket * sock,
- struct socket * newsock)
+static inline int security_socket_post_accept(struct socket *sock,
+ struct socket *newsock)
{
+ return 0;
}
static inline int security_socket_sendmsg(struct socket * sock,
@@ -2394,6 +2411,13 @@ static inline int security_socket_recvms
return 0;
}
+static inline int security_socket_post_recv_datagram(struct sock *sk,
+ struct sk_buff *skb,
+ unsigned int flags)
+{
+ return 0;
+}
+
static inline int security_socket_getsockname(struct socket * sock)
{
return 0;
--- net-2.6.25.orig/net/socket.c
+++ net-2.6.25/net/socket.c
@@ -1455,13 +1455,16 @@ asmlinkage long sys_accept(int fd, struc
goto out_fd;
}
+ /* Filter connections from unwanted peers. */
+ err = security_socket_post_accept(sock, newsock);
+ if (err)
+ goto out_fd;
+
/* File flags are not inherited via accept() unlike another OSes. */
fd_install(newfd, newfile);
err = newfd;
- security_socket_post_accept(sock, newsock);
-
out_put:
fput_light(sock->file, fput_needed);
out:
--- net-2.6.25.orig/security/dummy.c
+++ net-2.6.25/security/dummy.c
@@ -748,10 +748,10 @@ static int dummy_socket_accept (struct s
return 0;
}
-static void dummy_socket_post_accept (struct socket *sock,
- struct socket *newsock)
+static int dummy_socket_post_accept(struct socket *sock,
+ struct socket *newsock)
{
- return;
+ return 0;
}
static int dummy_socket_sendmsg (struct socket *sock, struct msghdr *msg,
@@ -766,6 +766,12 @@ static int dummy_socket_recvmsg (struct
return 0;
}
+static int dummy_socket_post_recv_datagram(struct sock *sk, struct sk_buff *skb,
+ unsigned int flags)
+{
+ return 0;
+}
+
static int dummy_socket_getsockname (struct socket *sock)
{
return 0;
@@ -1099,6 +1105,7 @@ void security_fixup_ops (struct security
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_post_recv_datagram);
set_to_dummy_if_null(ops, socket_getsockname);
set_to_dummy_if_null(ops, socket_getpeername);
set_to_dummy_if_null(ops, socket_setsockopt);
--- net-2.6.25.orig/net/core/datagram.c
+++ net-2.6.25/net/core/datagram.c
@@ -55,6 +55,7 @@
#include <net/checksum.h>
#include <net/sock.h>
#include <net/tcp_states.h>
+#include <linux/security.h>
/*
* Is a socket 'connection oriented' ?
@@ -148,6 +149,7 @@ struct sk_buff *skb_recv_datagram(struct
{
struct sk_buff *skb;
long timeo;
+ unsigned long cpu_flags;
/*
* Caller is allowed not to check sk->sk_err before skb_recv_datagram()
*/
@@ -166,8 +168,6 @@ struct sk_buff *skb_recv_datagram(struct
* However, this function was corrent in any case. 8)
*/
if (flags & MSG_PEEK) {
- unsigned long cpu_flags;
-
spin_lock_irqsave(&sk->sk_receive_queue.lock,
cpu_flags);
skb = skb_peek(&sk->sk_receive_queue);
@@ -178,6 +178,11 @@ struct sk_buff *skb_recv_datagram(struct
} else
skb = skb_dequeue(&sk->sk_receive_queue);
+ /* Filter packets from unwanted peers. */
+ error = security_socket_post_recv_datagram(sk, skb, flags);
+ if (error)
+ goto force_dequeue;
+
if (skb)
return skb;
@@ -190,6 +195,23 @@ struct sk_buff *skb_recv_datagram(struct
return NULL;
+force_dequeue:
+ /* Drop this packet because LSM says "Don't pass it to the caller". */
+ if (!(flags & MSG_PEEK))
+ goto no_peek;
+ /*
+ * If this packet is MSG_PEEK'ed, dequeue it forcibly
+ * so that this packet won't prevent the caller from picking up
+ * next packet.
+ */
+ spin_lock_irqsave(&sk->sk_receive_queue.lock, cpu_flags);
+ if (skb == skb_peek(&sk->sk_receive_queue)) {
+ __skb_unlink(skb, &sk->sk_receive_queue);
+ atomic_dec(&skb->users);
+ }
+ spin_unlock_irqrestore(&sk->sk_receive_queue.lock, cpu_flags);
+no_peek:
+ kfree_skb(skb);
no_packet:
*err = error;
return NULL;
--- net-2.6.25.orig/security/security.c
+++ net-2.6.25/security/security.c
@@ -869,9 +869,9 @@ int security_socket_accept(struct socket
return security_ops->socket_accept(sock, newsock);
}
-void security_socket_post_accept(struct socket *sock, struct socket *newsock)
+int security_socket_post_accept(struct socket *sock, struct socket *newsock)
{
- security_ops->socket_post_accept(sock, newsock);
+ return security_ops->socket_post_accept(sock, newsock);
}
int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size)
@@ -885,6 +885,12 @@ int security_socket_recvmsg(struct socke
return security_ops->socket_recvmsg(sock, msg, size, flags);
}
+int security_socket_post_recv_datagram(struct sock *sk, struct sk_buff *skb,
+ unsigned int flags)
+{
+ return security_ops->socket_post_recv_datagram(sk, skb, flags);
+}
+
int security_socket_getsockname(struct socket *sock)
{
return security_ops->socket_getsockname(sock);
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH net-2.6.25] Add packet filtering based on process's security context.
2007-11-22 13:35 ` [PATCH net-2.6.25] " Tetsuo Handa
@ 2007-11-22 23:29 ` James Morris
2007-12-03 7:58 ` Patrick McHardy
0 siblings, 1 reply; 9+ messages in thread
From: James Morris @ 2007-11-22 23:29 UTC (permalink / raw)
To: Tetsuo Handa
Cc: Herbert Xu, netdev, David S. Miller, linux-security-module,
Patrick McHardy, netfilter-devel, Stephen Smalley
On Thu, 22 Nov 2007, Tetsuo Handa wrote:
> This patch allows LSM modules filter incoming connections/datagrams
> based on the process's security context who is attempting to pick up.
>
> There are already hooks to filter incoming connections/datagrams
> based on the socket's security context, but these hooks are not
> applicable when one wants to do TCP Wrapper-like filtering
> (e.g. App1 is permitted to accept TCP connections from 192.168.0.0/16).
This functionality looks like it could be useful in that we currently have
no direct security mapping from incoming packet to user process, but only
to the receiving socket, as you mention. For SELinux, it may help us
simplify/clarify policy.
It's also been long-desired for netfilter/iptables, to allow ipt_owner to
work cleanly for incoming packets.
So, this probably needs to be implemented in a way which works for both LSM
and netfilter. There have been several discussions on the issue from the
netfilter side, although I don't know what the latest status of that is
(I've expanded the cc list to hopefully get some more feedback).
>From memory, one approach under discussion was to add netfilter hooks to
the transport layer, which could be invoked correctly by each type of
protocol when the target process is selected.
If this is done for netfilter, then an LSM hook is probably not needed at
all, as security modules can utilize netfilter hooks directly.
> Precautions: This approach has a side effect which unlikely occurs.
>
> If a socket is shared by multiple processes with differnt policy,
> the process who should be able to accept this connection
> will not be able to accept this connection
> because socket_post_accept() aborts this connection.
> But if socket_post_accept() doesn't abort this connection,
> the process who must not be able to accept this connection
> will repeat accept() forever, which is a worse side effect.
>
> Similarly, if a socket is shared by multiple processes with differnt policy,
> the process who should be able to pick up this datagram
> will not be able to pick up this datagram
> because socket_post_recv_datagram() discards this datagram.
> But if socket_post_recv_datagram() doesn't discard this datagram,
> the process who must not be able to pick up this datagram
> will repeat recvmsg() forever, which is a worse side effect.
>
> So, don't give different permissions between processes who share one socket.
> Otherwise, some connections/datagrams cannot be delivered to intended process.
These semantics changes are concerning, and lead me to wonder if there are
any more. Needs more review by networking folk.
- James
--
James Morris
<jmorris@namei.org>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH net-2.6.25] Add packet filtering based on process's security context.
2007-11-22 23:29 ` James Morris
@ 2007-12-03 7:58 ` Patrick McHardy
0 siblings, 0 replies; 9+ messages in thread
From: Patrick McHardy @ 2007-12-03 7:58 UTC (permalink / raw)
To: James Morris
Cc: Tetsuo Handa, Herbert Xu, netdev, David S. Miller,
linux-security-module, netfilter-devel, Stephen Smalley
James Morris wrote:
> On Thu, 22 Nov 2007, Tetsuo Handa wrote:
>
>> This patch allows LSM modules filter incoming connections/datagrams
>> based on the process's security context who is attempting to pick up.
>>
>> There are already hooks to filter incoming connections/datagrams
>> based on the socket's security context, but these hooks are not
>> applicable when one wants to do TCP Wrapper-like filtering
>> (e.g. App1 is permitted to accept TCP connections from 192.168.0.0/16).
>
> This functionality looks like it could be useful in that we currently have
> no direct security mapping from incoming packet to user process, but only
> to the receiving socket, as you mention. For SELinux, it may help us
> simplify/clarify policy.
>
> It's also been long-desired for netfilter/iptables, to allow ipt_owner to
> work cleanly for incoming packets.
>
> So, this probably needs to be implemented in a way which works for both LSM
> and netfilter. There have been several discussions on the issue from the
> netfilter side, although I don't know what the latest status of that is
> (I've expanded the cc list to hopefully get some more feedback).
No news on that. I'm also a bit sceptical if adding all this complexity
and overhead would really be worth it (considering only netfilter) just
to use the owner match and UID/GID matching. It wouldn't even be
accurate because there is not 1:1 mapping of sockets and processes.
I actually like Samir Bellabes' approach, which doesn't suffer from
these problems IIRC.
>>From memory, one approach under discussion was to add netfilter hooks to
> the transport layer, which could be invoked correctly by each type of
> protocol when the target process is selected.
We can only invoke the hooks after the socket lookup, but we don't
know which process is going to call recvmsg() for that socket.
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2008-01-24 15:03 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-01-22 15:16 [PATCH net-2.6.25] Add packet filtering based on process's security context Tetsuo Handa
2008-01-22 16:49 ` Casey Schaufler
2008-01-23 1:26 ` [PATCH net-2.6.25] Add packet filtering based on process\'s " Tetsuo Handa
2008-01-24 11:47 ` [PATCH net-2.6.25] Add packet filtering based on process's " Tetsuo Handa
2008-01-24 15:03 ` Paul Moore
-- strict thread matches above, loose matches on Subject: below --
2007-12-31 6:21 Tetsuo Handa
2007-11-21 12:30 [PATCH] " Tetsuo Handa
2007-11-22 13:35 ` [PATCH net-2.6.25] " Tetsuo Handa
2007-11-22 23:29 ` James Morris
2007-12-03 7:58 ` Patrick McHardy
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).