block network access for certain users/groups

13 views
Skip to first unread message

Elmar Stellnberger

unread,
Aug 25, 2010, 7:09:34 AM8/25/10
to net...@vger.kernel.org, netfilt...@vger.kernel.org
Please answer my question:
It has not been answered, yet.
Thanks for hints like whether to use DROP or REJECT but please answer
my question!

I wanna be pointed on how to implement a per user package selection.
Something similar pretends to be already implemented if you view the
man page, but
it is only implemented for outgoing packages and it even does not work
correctly
(blocking outgoing ICMP-ping requests but with lynx you can happily
view localhost:631
though the rule is on top and applies to any kind of package (raw,
tcp, udp)). We have
already checked this thouroughly.


I need to block network access for certain users/groups, fully:

iptables -A mychain -m owner --gid-owner blockedusergroup -j REJECT

...drops ping packages in the output chain but lets my user happily
connect to localhost:631 or any other http address. In deed the rule
above is therefore pretty useless.

I need to block ALL incoming and outgoing packages for a certain user/group.
At the moment there is only insufficient blocking for outgoing
packages available.

Can you help me?
What will I have to do to implement network access restrictions on a
per user/group basis?
Logging such packages is already possible. Why is blocking them not?

... and yes I have already checked the whole iptables -L -v.
The rule is there and would have been supposed to work.

Yours,
Elmar Stellnberger
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majo...@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

Tetsuo Handa

unread,
Aug 25, 2010, 7:58:14 AM8/25/10
to este...@gmail.com, net...@vger.kernel.org, netfilt...@vger.kernel.org
Elmar Stellnberger wrote:
> Please answer my question:
> It has not been answered, yet.
> Thanks for hints like whether to use DROP or REJECT but please answer
> my question!
>
> I wanna be pointed on how to implement a per user package selection.

A package sounds something like application. What you want to do is
"packet selection" (like iptables) rather than "package selection"
(like rpm/dpkg). Please "sed -e 's/package/packet/g'"...

> Something similar pretends to be already implemented if you view the
> man page, but
> it is only implemented for outgoing packages and it even does not work
> correctly
> (blocking outgoing ICMP-ping requests but with lynx you can happily
> view localhost:631
> though the rule is on top and applies to any kind of package (raw,
> tcp, udp)). We have
> already checked this thouroughly.

Regarding incoming packets, it is impossible to perform packet filtering based
on uid/gid because the uid/gid who picks up the packet is not known until a
user issues accept()/recvmsg(). The socket's owner may change between the
moment iptables inspected the packet and the moment a user picks up the packet
because it is possible to send the socket's file descriptor via Unix domain
socket or call setuid()/setgid().

> I need to block network access for certain users/groups, fully:
>
> iptables -A mychain -m owner --gid-owner blockedusergroup -j REJECT
>
> ...drops ping packages in the output chain but lets my user happily
> connect to localhost:631 or any other http address. In deed the rule
> above is therefore pretty useless.
>
> I need to block ALL incoming and outgoing packages for a certain user/group.
> At the moment there is only insufficient blocking for outgoing
> packages available.
>
> Can you help me?
> What will I have to do to implement network access restrictions on a
> per user/group basis?

The only way that makes possible to block access by blockedusergroup is to
insert hooks like http://tomoyo.sourceforge.jp/cgi-bin/lxr/source/net/ipv4/udp.c#L1144
and http://tomoyo.sourceforge.jp/cgi-bin/lxr/source/net/socket.c#L1504 .
But such hooks are not acceptable for upstream kernel. Please see
http://kerneltrap.org/mailarchive/linux-netdev/2010/7/21/6281491 for
discussion on these hooks.

> Logging such packages is already possible. Why is blocking them not?
>
> ... and yes I have already checked the whole iptables -L -v.
> The rule is there and would have been supposed to work.
>
> Yours,
> Elmar Stellnberger
--

To unsubscribe from this list: send the line "unsubscribe netdev" in

Hagen Paul Pfeifer

unread,
Aug 25, 2010, 12:02:34 PM8/25/10
to Elmar Stellnberger, net...@vger.kernel.org, netfilt...@vger.kernel.org
* Elmar Stellnberger | 2010-08-25 13:09:34 [+0200]:

>What will I have to do to implement network access restrictions on a
>per user/group basis?

AppArmor, SELinux, ... ?

Hagen
--
To unsubscribe from this list: send the line "unsubscribe netdev" in

Tetsuo Handa

unread,
Aug 26, 2010, 8:28:37 AM8/26/10
to este...@gmail.com, net...@vger.kernel.org, netfilt...@vger.kernel.org
Tetsuo Handa wrote:

> Elmar Stellnberger wrote:
> > I need to block network access for certain users/groups, fully:
Oh, I thought you want to partially block communication by specific user.

You want to entirely block communication by specific user? Then, it is easy.
You can block all socket syscalls by that user using LSM.
I made an example LSM module which can be added as a loadable kernel module
( http://www.youtube.com/watch?v=wG8BTLMu5wo ). You can modify it as you like.

You can compile and load below module provided that your kernel config has
CONFIG_SECURITY_NETWORK=y .

Did this module answer your question?

Thanks.
----------------------------------------
/*
* Uid-NoSock Linux Security Module
*
* Author: Tetsuo Handa <penguin...@I-love.SAKURA.ne.jp>
*
* This module blocks socket syscalls by specific UID. Use at your own risk.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*/
/*
* Place this file (uid_nosock.c) in some directory and create Makefile
* containing a line
*
* obj-m += uid_nosock.o
*
* and run
*
* make SUBDIRS=directory_containing_this_file/ modules modules_install
*
*/
#include <linux/security.h>
#ifndef CONFIG_SECURITY_NETWORK
#error This module depends on CONFIG_SECURITY_NETWORK=y
#endif
#ifndef CONFIG_SECURITY
#error This module depends on CONFIG_SECURITY=y
#endif
#ifndef CONFIG_KALLSYMS
#error This module depends on CONFIG_KALLSYMS=y
#endif
#ifndef CONFIG_MODULES
#error This module depends on CONFIG_MODULES=y
#endif
#include <linux/module.h>
#include <linux/pid_namespace.h>
#include <linux/mount.h>
#include <linux/fs_struct.h>
static struct security_operations original_security_ops;

/* UID to block socket syscalls. */
#define UID_NOSOCK_REJECT_UID 500

static bool uid_nosock_deny(void)
{
return current_uid() == UID_NOSOCK_REJECT_UID;
}

static int uid_nosock_socket_create(int family, int type, int protocol,
int kern)
{
if (uid_nosock_deny())
return -EPERM;
return original_security_ops.socket_create(family, type, protocol,
kern);
}

static int uid_nosock_socket_bind(struct socket *sock,
struct sockaddr *address, int addrlen)
{
if (uid_nosock_deny())
return -EPERM;
return original_security_ops.socket_bind(sock, address, addrlen);
}

static int uid_nosock_socket_connect(struct socket *sock,
struct sockaddr *address, int addrlen)
{
if (uid_nosock_deny())
return -EPERM;
return original_security_ops.socket_connect(sock, address, addrlen);
}

static int uid_nosock_socket_listen(struct socket *sock, int backlog)
{
if (uid_nosock_deny())
return -EPERM;
return original_security_ops.socket_listen(sock, backlog);
}

static int uid_nosock_socket_accept(struct socket *sock,
struct socket *newsock)
{
if (uid_nosock_deny())
return -EPERM;
return original_security_ops.socket_accept(sock, newsock);
}

static int uid_nosock_socket_sendmsg(struct socket *sock, struct msghdr *msg,
int size)
{
if (uid_nosock_deny())
return -EPERM;
return original_security_ops.socket_sendmsg(sock, msg, size);
}

static int uid_nosock_socket_recvmsg(struct socket *sock, struct msghdr *msg,
int size, int flags)
{
if (uid_nosock_deny())
return -EPERM;
return original_security_ops.socket_recvmsg(sock, msg, size, flags);
}

static int uid_nosock_socket_getsockname(struct socket *sock)
{
if (uid_nosock_deny())
return -EPERM;
return original_security_ops.socket_getsockname(sock);
}

static int uid_nosock_socket_getpeername(struct socket *sock)
{
if (uid_nosock_deny())
return -EPERM;
return original_security_ops.socket_getpeername(sock);
}

static int uid_nosock_socket_getsockopt(struct socket *sock, int level,
int optname)
{
if (uid_nosock_deny())
return -EPERM;
return original_security_ops.socket_getsockopt(sock, level, optname);
}

static int uid_nosock_socket_setsockopt(struct socket *sock, int level,
int optname)
{
if (uid_nosock_deny())
return -EPERM;
return original_security_ops.socket_setsockopt(sock, level, optname);
}

/* Find symbols from /proc/kallsyms . */
static void *__init uid_nosock_find_symbol(const char *keyline)
{
struct file *file;
char *buf;
unsigned long entry = 0;
{
struct fs_struct *fs = current->fs;
struct vfsmount *mnt = current->nsproxy->pid_ns->proc_mnt;
struct path old_path;
struct path new_path = { mnt, mnt->mnt_root };
spin_lock(&fs->lock); /* was write_lock() till 2.6.35. */
old_path = fs->pwd;
fs->pwd = new_path;
spin_unlock(&fs->lock);
file = filp_open("kallsyms", O_RDONLY, 0);
spin_lock(&fs->lock);
fs->pwd = old_path;
spin_unlock(&fs->lock);
}
if (IS_ERR(file))
goto out;
buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (buf) {
int len;
int offset = 0;
while ((len = kernel_read(file, offset, buf,
PAGE_SIZE - 1)) > 0) {
char *cp;
buf[len] = '\0';
cp = strrchr(buf, '\n');
if (!cp)
break;
*(cp + 1) = '\0';
offset += strlen(buf);
cp = strstr(buf, keyline);
if (!cp)
continue;
*cp = '\0';
while (cp > buf && *(cp - 1) != '\n')
cp--;
entry = simple_strtoul(cp, NULL, 16);
break;
}
kfree(buf);
}
filp_close(file, NULL);
out:
return (void *) entry;
}

/* Never mark this variable as __initdata . */
static struct security_operations *uid_nosock_security_ops;

/* Never mark this function as __init . */
static int uid_nosock_addr_calculator(struct file *file)
{
return uid_nosock_security_ops->file_alloc_security(file);
}

static int __init uid_nosock_init(void)
{
struct security_operations **ptr;
struct security_operations *ops;
int i;
const u8 *cp;
/*
* Guess "struct security_operations *security_ops;".
* This trick depends on below assumptions.
*
* (1) Compiler generates identical code for security_file_alloc() and
* uid_nosock_addr_calculator().
* (2) uid_nosock_security_ops is found within 128 bytes from
* uid_nosock_addr_calculator, even if additional code (e.g. debug
* symbols) is added.
* (3) It is safe to read 128 bytes from uid_nosock_addr_calculator.
* (4) uid_nosock_security_ops != Byte code except
* uid_nosock_security_ops.
*/
cp = (const u8 *) uid_nosock_addr_calculator;
for (i = 0; i < 128; i++) {
if (sizeof(uid_nosock_security_ops) == sizeof(u32)) {
if (*(u32 *) cp == (u32) &uid_nosock_security_ops)
break;
} else if (sizeof(uid_nosock_security_ops) == sizeof(u64)) {
if (*(u64 *) cp == (u64) &uid_nosock_security_ops)
break;
}
cp++;
}
if (i == 128) {
printk(KERN_ERR
"Can't resolve uid_nosock_security_ops structure.\n");
return -EINVAL;
}
cp = (const u8 *) uid_nosock_find_symbol(" security_file_alloc\n");
if (!cp) {
printk(KERN_ERR "Can't resolve security_file_alloc().\n");
return -EINVAL;
}
/* This should be "struct security_operations *security_ops;". */
ptr = *(struct security_operations ***) (cp + i);
if (!ptr) {
printk(KERN_ERR "Can't resolve security_ops structure.\n");
return -EINVAL;
}
ops = *ptr;
if (!ops) {
printk(KERN_ERR "No security_operations registered.\n");
return -EINVAL;
}
memmove(&original_security_ops, ops, sizeof(original_security_ops));
smp_mb();
BUG_ON(ops->socket_create == uid_nosock_socket_create ||
ops->socket_bind == uid_nosock_socket_bind ||
ops->socket_connect == uid_nosock_socket_connect ||
ops->socket_listen == uid_nosock_socket_listen ||
ops->socket_accept == uid_nosock_socket_accept ||
ops->socket_sendmsg == uid_nosock_socket_sendmsg ||
ops->socket_recvmsg == uid_nosock_socket_recvmsg ||
ops->socket_getsockname == uid_nosock_socket_getsockname ||
ops->socket_getpeername == uid_nosock_socket_getpeername ||
ops->socket_getsockopt == uid_nosock_socket_getsockopt ||
ops->socket_setsockopt == uid_nosock_socket_setsockopt);
ops->socket_create = uid_nosock_socket_create;
ops->socket_bind = uid_nosock_socket_bind;
ops->socket_connect = uid_nosock_socket_connect;
ops->socket_listen = uid_nosock_socket_listen;
ops->socket_accept = uid_nosock_socket_accept;
ops->socket_sendmsg = uid_nosock_socket_sendmsg;
ops->socket_recvmsg = uid_nosock_socket_recvmsg;
ops->socket_getsockname = uid_nosock_socket_getsockname;
ops->socket_getpeername = uid_nosock_socket_getpeername;
ops->socket_getsockopt = uid_nosock_socket_getsockopt;
ops->socket_setsockopt = uid_nosock_socket_setsockopt;
printk(KERN_INFO "Uid-Nosock: Blocking socket syscalls by uid=%u.\n",
UID_NOSOCK_REJECT_UID);
return 0;
}

module_init(uid_nosock_init);
MODULE_LICENSE("GPL");
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in

Elmar Stellnberger

unread,
Aug 30, 2010, 7:36:23 AM8/30/10
to Tetsuo Handa, net...@vger.kernel.org, netfilt...@vger.kernel.org
Many Thnaks.
This is exactly what I have been looking for!
However if I compile the kernel module and try to load it that results
in a kernel hang that I can only escape by Alt-PrnScr-S-U-B, no matter
whether the module is loaded on boot time or in rl5. I have checked
all required kernel options and built it like the following (using
openSUSE 11.3):

make -C /lib/modules/`uname -r`/build SUBDIRS=~+/ modules || exit $?
install -m 644 nwusrblock-module /lib/modules/`uname
-r`/kernel/drivers/nwusrblock-module
/sbin/depmod -a
modprobe nwusrblock-modul

2010/8/26, Tetsuo Handa <penguin...@i-love.sakura.ne.jp>:

To unsubscribe from this list: send the line "unsubscribe netdev" in

Tetsuo Handa

unread,
Aug 30, 2010, 7:55:43 AM8/30/10
to este...@gmail.com, net...@vger.kernel.org, netfilt...@vger.kernel.org
Elmar Stellnberger wrote:
> However if I compile the kernel module and try to load it that results
> in a kernel hang that I can only escape by Alt-PrnScr-S-U-B, no matter
> whether the module is loaded on boot time or in rl5. I have checked
> all required kernel options and built it like the following (using
> openSUSE 11.3):

This module is for 2.6.36 but openSUSE 11.3 uses 2.6.34 . Did you change
below spin_lock() to write_lock() and spin_unlock() to write_unlock()?

> > {
> > struct fs_struct *fs = current->fs;
> > struct vfsmount *mnt = current->nsproxy->pid_ns->proc_mnt;
> > struct path old_path;
> > struct path new_path = { mnt, mnt->mnt_root };
> > spin_lock(&fs->lock); /* was write_lock() till 2.6.35. */
> > old_path = fs->pwd;
> > fs->pwd = new_path;
> > spin_unlock(&fs->lock);
> > file = filp_open("kallsyms", O_RDONLY, 0);
> > spin_lock(&fs->lock);
> > fs->pwd = old_path;
> > spin_unlock(&fs->lock);
> > }

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in

ladder...@gmail.com

unread,
Apr 5, 2012, 4:54:52 AM4/5/12
to linu...@googlegroups.com, net...@vger.kernel.org, netfilt...@vger.kernel.org
SurveilStar is really a good choice.
Reply all
Reply to author
Forward
0 new messages