Next Previous Contents

3. Implementation

LIDS extend its protection from FILESYSTEM, CAPABILITY to SOCKET by adding some data structure and also extent it by providing a patch to NETFILTER to make LIDS work with NETFILTER seamlessly.

3.1 Data Structure for Socket

First of all, LIDS has a central ACL database. It contains all the ACL predefined. When a process executed, kernel will attach an ACL to it based on the search on the database. The TASK ACL defined as,


/* security/lids/include/linux/lidsif.h */
struct lids_sys_acl {
        unsigned long int ino;          /* the subject node number */
        unsigned long flags;            /* capability flags */
        unsigned long lids_cap;         /* Move from tsk*/
        unsigned long socket;           /* socket */
        struct lids_cap cap[32];        /* inheritable array*/
        int forked;                     /* fork tags */
        int mark;                     /* fork tags */
        int port[LIDS_PORT_ITEM][2];
        struct lids_acl *lids_acl;      /* object acl */
        struct lids_acl *lids_domain;
        kdev_t  dev;                    /* the subject dev number */
        struct task_struct *tsk;        /* back to the pointer */
};
/*  end of lids_sys_acl */

You will see there is member "socket" in the structure. "socket" is a 32bits integer, each bit will represent a socket operation which defined as,


/* security/lids/include/linux/lidsif.h */
#define LIDS_SOCKET_CREATE      0
#define LIDS_SOCKET_CONNECT     1
#define LIDS_SOCKET_BIND        2
#define LIDS_SOCKET_LISTEN      3
#define LIDS_SOCKET_ACCEPT      4
#define LIDS_SOCKET_SENDMSG     5
#define LIDS_SOCKET_RECVMSG     6
#define LIDS_SOCKET_GETSOCKNAME 7
#define LIDS_SOCKET_GETPEERNAME 8
#define LIDS_SOCKET_GETSOCKOPT  9
#define LIDS_SOCKET_SETSOCKOPT  10
#define LIDS_SOCKET_SHUTDOWN    11
#define LIDS_SOCKET_CREATE_TCP  12
#define LIDS_SOCKET_CREATE_UDP  13
#define LIDS_SOCKET_NF_MARK     14

When one bit set, it means "disable" that socket operation. But for NF_MARK is a special value here. when set, it means the process have the ability to mark the packet as a special value from "mark" in the same data structure.

3.2 socket operation restriction.

All the implementation use LSM hooks, for example, LSM provide a hooks to socket_create() as


/* net/socket.c */
int sock_create(int family, int type, int protocol, struct socket **res)
{
......
        err = security_socket_create(family, type, protocol);
        if (err)
                return err;
.....
}

and in LIDS, we register the hook first,


struct security_operations lids_security_ops = {
......
        .socket_create =                lids_socket_create,
...... 
}

and then, we implement the checking in lids_socket_create() as following,


/* security/lids/lids_lsm.c */
static int lids_socket_create (int family, int type, int protocol)
{
        if( lids_load && lids_local_load && family==AF_INET) {
                if ( lids_socket_perm(current,LIDS_SOCKET_CREATE) < 0 ) {
                        lids_security_alert("Attempt to create socket");
                        return -EPERM;
                }
                if( type == SOCK_DGRAM ) {
                        if ( lids_socket_perm(current,LIDS_SOCKET_CREATE_UDP) < 0 ) {
                                lids_security_alert("Attempt to create udp socket");
                                return -EPERM;
                        }
                } else if( type == SOCK_STREAM) {
                        if ( lids_socket_perm(current,LIDS_SOCKET_CREATE_TCP) < 0 ) {
                                lids_security_alert("Attempt to create tcp socket");
                                return -EPERM;
                        }
                }
        }
        return 0;
}
/* ---------------- end of socket_create ------------------------- */

the lids_socket_perm will check the current task's socket value, to see if correspond bit has been set or not, when set, it will return "-1" and the system_call will return an error "Permission Denied".

3.3 Packet Label and Netfilter

LIDS use inode->i_security to store the marker information. In the socket_create(), after the socket create a "sock" data, LSM has a hook named as socket_post_create(), we hook it as follow,


static void lids_socket_post_create (struct socket *sock, int family, int type,
                                    int protocol)
{
#ifdef CONFIG_LIDS_NF_MARK
        struct lids_sys_acl *tsk_sys_acl;
        struct ipt_mark_target_info  *markinfo; 

        if( lids_load && lids_local_load && family==AF_INET) { 
                if ( lids_socket_perm(current,LIDS_SOCKET_NF_MARK) < 0 ) {
                        struct inode *inode = SOCK_INODE(sock);

                        if(inode) {
                                tsk_sys_acl=  current->security;
                                markinfo = kmalloc(sizeof(struct ipt_mark_target_info),GFP_KERNEL);     
get mark info from the acl ---> markinfo->mark = tsk_sys_acl->mark;
mark it in i_security   ------> inode->i_security = markinfo;
                                LIDS_DBG("DEV: [%d %d] Mark socket as %d \n",
                                        current->pid, current->parent->pid,
                                       markinfo->mark); 
                        }
                }
        }
#endif
        return;
}

/* ------------------------ */

But this is not end yet, because the packet do not get the mark info yet. LIDS provide a patch to netfilter's MARK module, ipt_MARK.c,


/* net/ipv4/netfilter/ipt_MARK.c */

static unsigned int target(struct sk_buff **pskb,
.......
#ifdef CONFIG_LIDS_NF_MARK
        if(hooknum == NF_IP_LOCAL_OUT) {
                struct iphdr *iph = (*pskb)->nh.iph;
                struct inode *inode; 

                if (!(*pskb)->sk || !(*pskb)->sk->socket) {
                        return IPT_CONTINUE;
                }
                inode = SOCK_INODE((*pskb)->sk->socket);
                if(!inode || !inode->i_security) 
                        return IPT_CONTINUE;

/* following code mark the packet based on the markinfo get from i_security */
                markinfo = (struct ipt_mark_target_info *)(inode->i_security);
                if((*pskb)->nfmark != markinfo->mark) {
                        (*pskb)->nfmark = markinfo->mark;
                        (*pskb)->nfcache |= NFC_ALTERED;
                }
        }
#endif
        return IPT_CONTINUE;
}
/* --------------- end of ipt_MARK patch -----------*/

The patch mark the packet based on the i_security value to the "nfmark". After that, the packet marking finished. You need a rule to active this marking, a rule like this will work,


        # iptables -A OUTPUT -t mangle -j MARK --set-mark 0

After that, all the packets generated will marked by a special value and we can use netfilter iptables rules to restrict it. We will show some examples based on it in the next section.


Next Previous Contents