ATTR_MODE,ATTR_UID,ATTR_GID,ATTR_ATIME_SET,ATTR_MTIME_SET中的一项,就需要对FILE_SETATTR权限进行检查。最后还得对 FILE_WRITE权限进行检查。
int (*inode_getattr) (struct vfsmount *mnt, struct dentry *dentry);
只需要检查进程对dentry的inode节点的FILE_GETATTR权限即可。
int (*inode_setxattr) (struct dentry *dentry, char *name, void *value,size_t size, int flags); 该函数的主要功能是对设置扩展属性进行权限检查,由于涉及到进程,超级块,和inode节点,因此比较复杂。如果我们不能识别所设置的属性值,就简单的对FILE_SETATTR权限做检查。否则,就需要对检查当前进程对inode的FILE_RELABLELFROM权限进行检查。接着通过security_context_to_sid查找到value的sid,并检查当前进程对该sid是否具有FILE_RELABELTO的权限。下一步是需要对当前的类型转换进行验证,看是否合法。最后,还需要检查新sid对超级块是否具有FILESYSTEM_ASSOCIATE权限。 void (*inode_post_setxattr) (struct dentry *dentry, char *name, void *value, size_t size, int flags); 成功设置扩展属性后,对inode安全域进行更新。再次调用上一个函数中调用的security_context_to_sid,查找出新的sid,并把inode安全域的sid设置为新的sid。 int (*inode_getxattr) (struct dentry *dentry, char *name); int (*inode_listxattr) (struct dentry *dentry); 上述两个函数都是对文件的扩展属性的读权限进行检查,所以都是对FILE_GETATTR权限进行检查。并不需要做任何其它操作。 int (*inode_removexattr) (struct dentry *dentry, char *name); 首先需要识别扩展属性,如果扩展属性没有定义,就直接对FILE_SETATTR权限进行检查。(这里貌似有写问题) const char *(*inode_xattr_getsuffix) (void);
获取inode扩展属性的后缀
int (*inode_getsecurity)(const struct inode *inode, const char *name, void *buffer, size_t size, int err);
获取inode的安全上下文,并把它放在buffer中。
int (*inode_setsecurity)(struct inode *inode, const char *name, const void *value, size_t size, int flags);
设置inode的安全上下文,该安全上下文保存在value当中。
int (*inode_listsecurity)(struct inode *inode, char *buffer, size_t buffer_size);
将扩展属性XATTR_NAME_SELINUX输出到buffer当中。
File Hooks
File的安全结构如下:(解决了file结构不确定的问题了) struct file_security_struct { struct file *file; /* 指向所属主体 */ u32 sid; /* 打开文件的描述符sid */ u32 fown_sid; /* 文件所有者的sid */ };
int (*file_permission) (struct file * file, int mask);
通过文件的掩码mask,计算出所要检查的权限,再通过file_has_perm进行权限检查。最后含需要验证socket文件是否已经打上标签,先查看该文件是不是socket文件,如果是socket文件,先查看文件是否打上标签,如果没有,则根据inode的SID给它打上标签。
int (*file_alloc_security) (struct file * file);
给file的安全结构分配内存,并初始化。Sid和fown_sid数据成员都赋值为当前进程的sid。
void (*file_free_security) (struct file * file); 和其它释放内存一样。
int (*file_ioctl) (struct file * file, unsigned int cmd, unsigned long arg); 根据cmd参数,检查当前进程对file结构相应的权限。
int (*file_mmap) (struct file * file,unsigned long reqprot, unsigned long prot,unsigned long flags, unsigned long addr,unsigned long addr_only);
mmap执行文件的内存操作,并将映射放入进程的地址空间。file_mmap函数的功能是在执行mmap之前进行权限检查。
int (*file_mprotect) (struct vm_area_struct * vma,unsigned long reqprot,unsigned long prot);
在改变内存访问权限之前进行权限检查。
int (*file_lock) (struct file * file, unsigned int cmd);
调用file_has_perm检查当前进程对file对象的FILE_LOCK权限。
int (*file_fcntl) (struct file * file, unsigned int cmd,unsigned long arg);
根据cmd的值,调用file_has_perm检查当前进程对file对象的特定权限。
int (*file_set_fowner) (struct file * file);
设置file的安全结构的fown_sid数据成员。
int (*file_send_sigiotask) (struct task_struct * tsk, struct fown_struct * fown, int sig); 检查file向进程tsk的发送io信号的权限。
int (*file_receive) (struct file * file);
该钩子函数允许安全模块去控制进程通过socket IPC接收一个打开的文件描述符。
2.5.5 Network Hooks
安全结构:
struct sk_security_struct { struct sock *sk; /* 指向所属主体对象*/ u32 sid; /*对象 SID */ u32 peer_sid; /* 对等对象的SID*/ #ifdef CONFIG_NETLABEL
u16 sclass; /* sock安全类型*/ enum { /* 网络标签状态*/ NLBL_UNSET = 0, NLBL_REQUIRE, NLBL_LABELED, } nlbl_state; spinlock_t nlbl_lock; /* 保护网络标签状态 */ #endif };
int (*unix_stream_connect) (struct socket * sock,struct socket * other, struct sock * newsk);
在建立UNIX流连接时,检查UNIX_STREAM_SOCKET__CONNECTTO权限,主体是sock,客体对象是other。并为newsk分配sid。
int (*unix_may_send) (struct socket * sock, struct socket * other);
在连接或发送一个数据报是进行策略检查。主体是sock,客体是other,检查的权限是SOCKET_SENDTO.
int (*socket_create) (int family, int type, int protocol, int kern); 创建套接字时,对SOCKET_CREATE进行检查,主体是当前进程。客体的sid:newsid = tsec->sockcreate_sid ? : tsec->sid。
int (*socket_post_create) (struct socket * sock, int family, int type, int protocol, int kern);
套接字创建成功后,设置套接字的安全结构,由于套接字是一种特殊的文件,所以不仅要设置inode_security_struct,还需要设置sk_security_struct安全结构。
int (*socket_bind) (struct socket * sock,struct sockaddr * address, int addrlen); 检查SOCKET_BIND权限,主体是当前进程,客体是sock。
int (*socket_connect) (struct socket * sock,struct sockaddr * address, int addrlen); 先调用socket_has_perm检查SOCKET_CONNECT权限,主体是当前进程,客体是sock。如果是TCP或DCCP套接字,还需检查name_connect的权限。主体是sock的inode,客体是端口,客体类型是inode的客体类型。权限码是TCP_SOCKET__NAME_CONNECT 或DCCP_SOCKET__NAME_CONNECT。
int (*socket_listen) (struct socket * sock, int backlog); 调用socket_has_perm,检查SOCKET_LISTEN权限,主体是当前进程,客体是sock。客体对象是sock的客体类型。
int (*socket_accept) (struct socket * sock, struct socket * newsock); 调用socket_has_perm,检查SOCKET_ACCEPT权限,主体是当前进程,客体是sock。并设置newsock的inode的安全结构。
int (*socket_sendmsg) (struct socket * sock,struct msghdr * msg, int size); 先检查当前进程对sock的SOCKET_WRITE的权限,接着验证套接字是否是NetLabel标签。实现该功能的是selinux_netlbl_inode_permission(struct inode *inode,int mask),查找文件的inode,并查看该套接字是否标记为被NetLabel保护,然后验证该套接字是否已经打上标记,如果没有,就用inode的sid立即给套接字打上标签。
int (*socket_recvmsg) (struct socket * sock,struct msghdr * msg, int size, int flags); 检查当前进程对sock的SOCKET_READ的访问权限。
int (*socket_getsockname) (struct socket * sock);
检查当前进程对sock的SOCKET_GETATTR的权限。
int (*socket_getpeername) (struct socket * sock);
调用socket_has_perm检查当前进程对sock的SOCKET_GETATTR权限。
int (*socket_getsockopt) (struct socket * sock, int level, int optname);
调用socket_has_perm检查当前进程对sock的SOCKET_GETOPT权限。 int (*socket_setsockopt) (struct socket * sock, int level, int optname);
先调用socket_has_perm检查当前进程对sock的SOCKET_SETOPT权限。接着调用selinux_netlbl_socket_setsockopt(),不允许用户删除NetLabel。该函数首先检查setsockopt()函数,如果用户企图替换套接字IP选项和套接字的NetLabel,就阻止该操作的继续执行。
int (*socket_shutdown) (struct socket * sock, int how);
调用socket_has_perm检查当前进程对sock的SOCKET_SHUTDOWN权限。
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);
给sock分配安全域或释放安全域,安全域为sk_security_struct
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,

