LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 973|回复: 0

Linux Security Module的注册过程分析(2)

[复制链接]
发表于 2007-8-9 14:58:22 | 显示全部楼层 |阅读模式
int (*msg_queue_msgctl) (struct msg_queue * msq, int cmd);
       int (*msg_queue_msgsnd) (struct msg_queue * msq,
                             struct msg_msg * msg, int msqflg);
       int (*msg_queue_msgrcv) (struct msg_queue * msq,
                             struct msg_msg * msg,
                             struct task_struct * target,
                             long type, int mode);

       int (*shm_alloc_security) (struct shmid_kernel * shp);
       void (*shm_free_security) (struct shmid_kernel * shp);
       int (*shm_associate) (struct shmid_kernel * shp, int shmflg);
       int (*shm_shmctl) (struct shmid_kernel * shp, int cmd);
       int (*shm_shmat) (struct shmid_kernel * shp,
                       char __user *shmaddr, int shmflg);

       int (*sem_alloc_security) (struct sem_array * sma);
       void (*sem_free_security) (struct sem_array * sma);
       int (*sem_associate) (struct sem_array * sma, int semflg);
       int (*sem_semctl) (struct sem_array * sma, int cmd);
       int (*sem_semop) (struct sem_array * sma,
                       struct sembuf * sops, unsigned nsops, int alter);

       int (*netlink_send) (struct sock * sk, struct sk_buff * skb);
       int (*netlink_recv) (struct sk_buff * skb, int cap);

       /* allow module stacking */
       int (*register_security) (const char *name,
                                 struct security_operations *ops);
       int (*unregister_security) (const char *name,
                                   struct security_operations *ops);

       void (*d_instantiate) (struct dentry *dentry, struct inode *inode);

      int (*getprocattr)(struct task_struct *p, char *name, void *value, size_t size);
      int (*setprocattr)(struct task_struct *p, char *name, void *value, size_t size);
       int (*secid_to_secctx)(u32 secid, char **secdata, u32 *seclen);
       void (*release_secctx)(char *secdata, u32 seclen);

#ifdef CONFIG_SECURITY_NETWORK
       int (*unix_stream_connect) (struct socket * sock,
                                struct socket * other, struct sock * newsk);
       int (*unix_may_send) (struct socket * sock, struct socket * other);

       int (*socket_create) (int family, int type, int protocol, int kern);
       int (*socket_post_create) (struct socket * sock, int family,
                               int type, int protocol, int kern);
       int (*socket_bind) (struct socket * sock,
                         struct sockaddr * address, int addrlen);
       int (*socket_connect) (struct socket * sock,
                            struct sockaddr * address, int addrlen);
       int (*socket_listen) (struct socket * sock, int backlog);
       int (*socket_accept) (struct socket * sock, struct socket * newsock);
       void (*socket_post_accept) (struct socket * sock,
                                struct socket * newsock);
       int (*socket_sendmsg) (struct socket * sock,
                            struct msghdr * msg, int size);
       int (*socket_recvmsg) (struct socket * sock,
                            struct msghdr * msg, int size, int flags);
       int (*socket_getsockname) (struct socket * sock);
       int (*socket_getpeername) (struct socket * sock);
       int (*socket_getsockopt) (struct socket * sock, int level, int optname);
       int (*socket_setsockopt) (struct socket * sock, int level, int optname);
       int (*socket_shutdown) (struct socket * sock, int how);
       int (*socket_sock_rcv_skb) (struct sock * sk, struct sk_buff * skb);
       int (*socket_getpeersec_stream) (struct socket *sock, char __user *optval, int __user *optlen, unsigned len);
       int (*socket_getpeersec_dgram) (struct socket *sock, struct sk_buff *skb, u32 *secid);
       int (*sk_alloc_security) (struct sock *sk, int family, gfp_t priority);
       void (*sk_free_security) (struct sock *sk);
       void (*sk_clone_security) (const struct sock *sk, struct sock *newsk);
       void (*sk_getsecid) (struct sock *sk, u32 *secid);
       void (*sock_graft)(struct sock* sk, struct socket *parent);
       int (*inet_conn_request)(struct sock *sk, struct sk_buff *skb,
                                   struct request_sock *req);
       void (*inet_csk_clone)(struct sock *newsk, const struct request_sock *req);
       void (*inet_conn_established)(struct sock *sk, struct sk_buff *skb);
       void (*req_classify_flow)(const struct request_sock *req, struct flowi *fl);
#endif     /* CONFIG_SECURITY_NETWORK */

#ifdef CONFIG_SECURITY_NETWORK_XFRM
       int (*xfrm_policy_alloc_security) (struct xfrm_policy *xp,
                     struct xfrm_user_sec_ctx *sec_ctx);
       int (*xfrm_policy_clone_security) (struct xfrm_policy *old, struct xfrm_policy *new);
       void (*xfrm_policy_free_security) (struct xfrm_policy *xp);
       int (*xfrm_policy_delete_security) (struct xfrm_policy *xp);
       int (*xfrm_state_alloc_security) (struct xfrm_state *x,
              struct xfrm_user_sec_ctx *sec_ctx,
              u32 secid);
       void (*xfrm_state_free_security) (struct xfrm_state *x);
       int (*xfrm_state_delete_security) (struct xfrm_state *x);
       int (*xfrm_policy_lookup)(struct xfrm_policy *xp, u32 fl_secid, u8 dir);
       int (*xfrm_state_pol_flow_match)(struct xfrm_state *x,
                     struct xfrm_policy *xp, struct flowi *fl);
       int (*xfrm_decode_session)(struct sk_buff *skb, u32 *secid, int ckall);
#endif     /* CONFIG_SECURITY_NETWORK_XFRM */

       /* key management security hooks */
#ifdef CONFIG_KEYS
       int (*key_alloc)(struct key *key, struct task_struct *tsk, unsigned long flags);
       void (*key_free)(struct key *key);
       int (*key_permission)(key_ref_t key_ref,
                           struct task_struct *context,
                           key_perm_t perm);

#endif     /* CONFIG_KEYS */

};

dummy_security_ops的初始化是在上面给出的security_init中verify(&dummy_security_ops)函数实现的,它将参数XXX_ops中的所有空指针的函数,初始化为dummy.c中定义的dummy_XXX类型对应函数体,每个函数体只提供一个表示成功的返回值,而不执行任何操作。具体参见src/security/dummy.c。

dummy_security_ops初始化完成后,通过security_ops=&dummy_security_ops,使得security_ops指向一个不做任何操作的过滤层。再通过do_security_initcalls()加载具体配置的安全过滤模块。

在来看看do_security_initcalls()函数是怎么实现的:

static void __init do_security_initcalls(void)
{
       initcall_t *call;
       call = __security_initcall_start;
       while (call < __security_initcall_end) {
              (*call) ();
              call++;
       }
}

在系统中,security_initcall.init的函数总共有三个,分别为:capability_init(), rootplug_init()和selinux_init()。其中,selinux只能第一个注册(即作为security_ops上的第一个过滤层),否则注册会失败。selinux注册后,original_ops=secondary_ops=dummy_ops; securuty_ops=selinux_ops。前两者的注册方式完全一致,并且,在当前代码实现中,两者只能注册一个,另外一个在第一个注册成功后,即使以模块方式加载也会失败。例如,capability_init()注册后,secondary_ops=capability_ops; original_ops=dummy_ops; security_ops=selinux_ops。此时如果再调用rootplug_init(), 将因为security_ops!=dummy_security_ops而调用register_security失败,然后因为secondary_ops != original_ops而在调用security_ops->register_security即selinux_register_security函数中返回出错,原因为几经存在了一个第二层模块。

具体代码不在这里列出,有兴趣者可以到src/security/目录下分别查看capability.c, root_plug.c和selinux/hooks.c。

因此可见,主要得代码实现都是在selinux中实现的。以我所感兴趣的selinux_mount和selinux_umount为例,其代码如下:

static int selinux_mount(char * dev_name,
                         struct nameidata *nd,
                         char * type,
                         unsigned long flags,
                         void * data)
{
       int rc;

       rc = secondary_ops->sb_mount(dev_name, nd, type, flags, data);
       if (rc)
              return rc;

       if (flags & MS_REMOUNT)
              return superblock_has_perm(current, nd->mnt->mnt_sb,
                                         FILESYSTEM__REMOUNT, NULL);
       else
              return dentry_has_perm(current, nd->mnt, nd->dentry,
                                     FILE__MOUNTON);
}

static int selinux_umount(struct vfsmount *mnt, int flags)
{
       int rc;

       rc = secondary_ops->sb_umount(mnt, flags);
       if (rc)
              return rc;

       return superblock_has_perm(current,mnt->mnt_sb,
                                  FILESYSTEM__UNMOUNT,NULL);
}

由上面的ops赋值关系可知,secondary_ops->sb_mount和secondary_ops->sb_umount无论capability和root_plug是否加载,因为其在这两者中都没有定义实现,所以,为dummy_XXX函数,相关的代码如下:

static int dummy_sb_mount (char *dev_name, struct nameidata *nd, char *type,
                        unsigned long flags, void *data)
{
       return 0;
}

static int dummy_sb_check_sb (struct vfsmount *mnt, struct nameidata *nd)
{
       return 0;
}

static int dummy_sb_umount (struct vfsmount *mnt, int flags)
{
       return 0;
}

static void dummy_sb_umount_close (struct vfsmount *mnt)
{
       return;
}

static void dummy_sb_umount_busy (struct vfsmount *mnt)
{
       return;
}

static void dummy_sb_post_remount (struct vfsmount *mnt, unsigned long flags,
                               void *data)
{
       return;
}


static void dummy_sb_post_mountroot (void)
{
       return;
}

然后给出一定的pemmision的判断。permmision判断通过查找avc的hash表实现,它是以数据库的形式在内核维护的。在selinux中,ss目录下的文件负责维护security所有安全检查需要的数据库,对于数据库的详细操作和保存和加载,请参考src/security/selinux/ss/policydb.c中的相关函数。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表