|
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中的相关函数。 |
|