策略中学习【LSM】编写规则

最近涉及到了LSM的编写,在网上基本上搜不到关于LSM的编写规则和使用方法,LSM是我觉得菜鸟非常适合的一种访问控制策略编写,所以今天从SELinux的LSM代码学习。

在内核源码/security/SELinux中hook.c中定义了LSM模块的hook机制。hook主要根据的是struct security_operations结构体,里面提供了各种函数的回调机制。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. struct security_operations {  
  2.       int (*ptrace) (struct task_struct * parent, struct task_struct * child);  
  3.       int (*capget) (struct task_struct * target,  
  4.                    kernel_cap_t * effective,  
  5.                    kernel_cap_t * inheritable, kernel_cap_t * permitted);  
  6.       int (*capset_check) (struct task_struct * target,  
  7.                         kernel_cap_t * effective,  
  8.                         kernel_cap_t * inheritable,  
  9.                         kernel_cap_t * permitted);  
  10.       void (*capset_set) (struct task_struct * target,  
  11.                        kernel_cap_t * effective,  
  12.                        kernel_cap_t * inheritable,  
  13.                        kernel_cap_t * permitted);  
  14.       int (*capable) (struct task_struct * tsk, int cap);  
  15.       int (*acct) (struct file * file);  
  16.       int (*sysctl) (struct ctl_table * table, int op);  
  17.       int (*quotactl) (int cmds, int type, int id, struct super_block * sb);  
  18.       int (*quota_on) (struct dentry * dentry);  
  19.       int (*syslog) (int type);  
  20.       int (*settime) (struct timespec *ts, struct timezone *tz);  
  21.       int (*vm_enough_memory) (long pages);  
  22.    
  23.       int (*bprm_alloc_security) (struct linux_binprm * bprm);  
  24.       void (*bprm_free_security) (struct linux_binprm * bprm);  
  25.       void (*bprm_apply_creds) (struct linux_binprm * bprm, int unsafe);  
  26.       void (*bprm_post_apply_creds) (struct linux_binprm * bprm);  
  27.       int (*bprm_set_security) (struct linux_binprm * bprm);  
  28.       int (*bprm_check_security) (struct linux_binprm * bprm);  
  29.       int (*bprm_secureexec) (struct linux_binprm * bprm);  
  30.    
  31.       int (*sb_alloc_security) (struct super_block * sb);  
  32.       void (*sb_free_security) (struct super_block * sb);  
  33.       int (*sb_copy_data)(struct file_system_type *type,  
  34.                        void *orig, void *copy);  
  35.       int (*sb_kern_mount) (struct super_block *sb, void *data);  
  36.       int (*sb_statfs) (struct dentry *dentry);  
  37.       int (*sb_mount) (char *dev_name, struct nameidata * nd,  
  38.                      char *type, unsigned long flags, void *data);  
  39.       int (*sb_check_sb) (struct vfsmount * mnt, struct nameidata * nd);  
  40.       int (*sb_umount) (struct vfsmount * mnt, int flags);  
  41.       void (*sb_umount_close) (struct vfsmount * mnt);  
  42.       void (*sb_umount_busy) (struct vfsmount * mnt);  
  43.       void (*sb_post_remount) (struct vfsmount * mnt,  
  44.                             unsigned long flags, void *data);  
  45.       void (*sb_post_mountroot) (void);  
  46.       void (*sb_post_addmount) (struct vfsmount * mnt,  
  47.                             struct nameidata * mountpoint_nd);  
  48.       int (*sb_pivotroot) (struct nameidata * old_nd,  
  49.                         struct nameidata * new_nd);  
  50.       void (*sb_post_pivotroot) (struct nameidata * old_nd,  
  51.                              struct nameidata * new_nd);  
  52.    
  53.       int (*inode_alloc_security) (struct inode *inode);  
  54.       void (*inode_free_security) (struct inode *inode);  
  55.       int (*inode_init_security) (struct inode *inode, struct inode *dir,  
  56.                               char **name, void **value, size_t *len);  
  57.       int (*inode_create) (struct inode *dir,  
  58.                           struct dentry *dentry, int mode);  
  59.       int (*inode_link) (struct dentry *old_dentry,  
  60.                         struct inode *dir, struct dentry *new_dentry);  
  61.       int (*inode_unlink) (struct inode *dir, struct dentry *dentry);  
  62.       int (*inode_symlink) (struct inode *dir,  
  63.                            struct dentry *dentry, const char *old_name);  
  64.       int (*inode_mkdir) (struct inode *dir, struct dentry *dentry, int mode);  
  65.       int (*inode_rmdir) (struct inode *dir, struct dentry *dentry);  
  66.       int (*inode_mknod) (struct inode *dir, struct dentry *dentry,  
  67.                          int mode, dev_t dev);  
  68.       int (*inode_rename) (struct inode *old_dir, struct dentry *old_dentry,  
  69.                           struct inode *new_dir, struct dentry *new_dentry);  
  70.       int (*inode_readlink) (struct dentry *dentry);  
  71.       int (*inode_follow_link) (struct dentry *dentry, struct nameidata *nd);  
  72.       int (*inode_permission) (struct inode *inode, int mask, struct nameidata *nd);  
  73.       int (*inode_setattr)(struct dentry *dentry, struct iattr *attr);  
  74.       int (*inode_getattr) (struct vfsmount *mnt, struct dentry *dentry);  
  75.        void (*inode_delete) (struct inode *inode);  
  76.       int (*inode_setxattr) (struct dentry *dentry, char *name, void *value,  
  77.                           size_t size, int flags);  
  78.       void (*inode_post_setxattr) (struct dentry *dentry, char *name, void *value,  
  79.                                size_t size, int flags);  
  80.       int (*inode_getxattr) (struct dentry *dentry, char *name);  
  81.       int (*inode_listxattr) (struct dentry *dentry);  
  82.       int (*inode_removexattr) (struct dentry *dentry, char *name);  
  83.       const char *(*inode_xattr_getsuffix) (void);  
  84.     int (*inode_getsecurity)(const struct inode *inode, const char *name, void *buffer, size_t size, int err);  
  85.     int (*inode_setsecurity)(struct inode *inode, const char *name, const void *value, size_t size, int flags);  
  86.     int (*inode_listsecurity)(struct inode *inode, char *buffer, size_t buffer_size);  
  87.    
  88.       int (*file_permission) (struct file * file, int mask);  
  89.       int (*file_alloc_security) (struct file * file);  
  90.       void (*file_free_security) (struct file * file);  
  91.       int (*file_ioctl) (struct file * file, unsigned int cmd,  
  92.                       unsigned long arg);  
  93.       int (*file_mmap) (struct file * file,  
  94.                      unsigned long reqprot,  
  95.                      unsigned long prot, unsigned long flags);  
  96.       int (*file_mprotect) (struct vm_area_struct * vma,  
  97.                          unsigned long reqprot,  
  98.                          unsigned long prot);  
  99.       int (*file_lock) (struct file * file, unsigned int cmd);  
  100.       int (*file_fcntl) (struct file * file, unsigned int cmd,  
  101.                       unsigned long arg);  
  102.       int (*file_set_fowner) (struct file * file);  
  103.       int (*file_send_sigiotask) (struct task_struct * tsk,  
  104.                               struct fown_struct * fown, int sig);  
  105.       int (*file_receive) (struct file * file);  
  106.    
  107.       int (*task_create) (unsigned long clone_flags);  
  108.       int (*task_alloc_security) (struct task_struct * p);  
  109.       void (*task_free_security) (struct task_struct * p);  
  110.       int (*task_setuid) (uid_t id0, uid_t id1, uid_t id2, int flags);  
  111.       int (*task_post_setuid) (uid_t old_ruid /* or fsuid */ ,  
  112.                             uid_t old_euid, uid_t old_suid, int flags);  
  113.       int (*task_setgid) (gid_t id0, gid_t id1, gid_t id2, int flags);  
  114.       int (*task_setpgid) (struct task_struct * p, pid_t pgid);  
  115.       int (*task_getpgid) (struct task_struct * p);  
  116.       int (*task_getsid) (struct task_struct * p);  
  117.       void (*task_getsecid) (struct task_struct * p, u32 * secid);  
  118.       int (*task_setgroups) (struct group_info *group_info);  
  119.       int (*task_setnice) (struct task_struct * p, int nice);  
  120.       int (*task_setioprio) (struct task_struct * p, int ioprio);  
  121.       int (*task_getioprio) (struct task_struct * p);  
  122.       int (*task_setrlimit) (unsigned int resource, struct rlimit * new_rlim);  
  123.       int (*task_setscheduler) (struct task_struct * p, int policy,  
  124.                             struct sched_param * lp);  
  125.       int (*task_getscheduler) (struct task_struct * p);  
  126.       int (*task_movememory) (struct task_struct * p);  
  127.       int (*task_kill) (struct task_struct * p,  
  128.                      struct siginfo * info, int sig, u32 secid);  
  129.       int (*task_wait) (struct task_struct * p);  
  130.       int (*task_prctl) (int option, unsigned long arg2,  
  131.                       unsigned long arg3, unsigned long arg4,  
  132.                       unsigned long arg5);  
  133.       void (*task_reparent_to_init) (struct task_struct * p);  
  134.       void (*task_to_inode)(struct task_struct *p, struct inode *inode);  
  135.    
  136.       int (*ipc_permission) (struct kern_ipc_perm * ipcp, short flag);  
  137.    
  138.       int (*msg_msg_alloc_security) (struct msg_msg * msg);  
  139.       void (*msg_msg_free_security) (struct msg_msg * msg);  
  140.    
  141.       int (*msg_queue_alloc_security) (struct msg_queue * msq);  
  142.       void (*msg_queue_free_security) (struct msg_queue * msq);  
  143.       int (*msg_queue_associate) (struct msg_queue * msq, int msqf  
其中每个函数都是可以回调的,也就是hook。下面我以 task_kill为例理解SELinux的实现机制

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. static int selinux_task_kill(struct task_struct *p, struct siginfo *info,  
  2.                 int sig, u32 secid)  
  3. {  
  4.     u32 perm;  
  5.     int rc;  
  6.   
  7.     if (!sig)<span style="color: rgb(0, 130, 0); font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace; font-size: 14px; line-height: 15.390625px; background-color: rgb(224, 224, 224);">//sig表示的是信号,首先确定是否定义了信号,然后调用signal_to_av对信号进行分类</span>  
  8.         perm = PROCESS__SIGNULL; /* null signal; existence test */  
  9.     else  
  10.         perm = signal_to_av(sig);//返回perm,perm是本函数对sig的许可,会在下面调用<span style="font-family: 微软雅黑;">avc_has_perm作为参数</span>  
  11.     if (secid)  
  12.         rc = avc_has_perm(secid, task_sid(p),  
  13.                   SECCLASS_PROCESS, perm, NULL);  
  14.     else  
  15.         rc = current_has_perm(p, perm);  
  16.     return rc;//rc就是函数的返回值,0为可以执行,不能执行将会返回-EACCSE  
  17. }  
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. static inline u32 signal_to_av(int sig)  
  2. {  
  3.     u32 perm = 0;  
  4.   
  5.     switch (sig) {//中间两个杀进程的信号做何种处理可以选择,  
  6.         //处理的类型返回到perm  
  7.     case SIGCHLD:  
  8.         /* Commonly granted from child to parent. */  
  9.         perm = PROCESS__SIGCHLD;  
  10.         break;  
  11.     case SIGKILL:  
  12.         /* Cannot be caught or ignored */  
  13.         perm = PROCESS__SIGKILL;  
  14.         break;  
  15.     case SIGSTOP:  
  16.         /* Cannot be caught or ignored */  
  17.         perm = PROCESS__SIGSTOP;  
  18.         break;  
  19.     default:  
  20.         /* All other signals. */  
  21.         perm = PROCESS__SIGNAL;  
  22.         break;  
  23.     }  
  24.   
  25.     return perm;  
  26. }  
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. u32 secid为进程的sid这是SELinux的有的super id,每一个sid对应了一条安全上下文(也就是user,role,type),如果没有那么将会调用<span style="font-family: 微软雅黑;">current_has_perm获得当前的sid,并调用avc_has_perm确定权限。</span>  
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <pre name="code" class="cpp">/* 
  2.  * Check permission between current and another task, e.g. signal checks, 
  3.  * fork check, ptrace check, etc. 
  4.  * current is the actor and tsk2 is the target 
  5.  * - this uses current's subjective creds 
  6.  */  
  7. static int current_has_perm(const struct task_struct *tsk,  
  8.                 u32 perms)  
  9. {  
  10.     u32 sid, tsid;  
  11.   
  12.     sid = current_sid();  
  13.     tsid = task_sid(tsk);  
  14.     return avc_has_perm(sid, tsid, SECCLASS_PROCESS, perms, NULL);  
  15. }  


 
avc就是一个cache,存储着最近使用过的策略,这种cache思想到处都是比如MMU的内存映射。 
 

SELinux/ss中的avc.c 中avc_has_perm 会调用avc_has_perm_noaudit查看是否在cache中。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * avc_has_perm_noaudit - Check permissions but perform no auditing. 
  3.  * @ssid: source security identifier 
  4.  * @tsid: target security identifier 
  5.  * @tclass: target security class 
  6.  * @requested: requested permissions, interpreted based on @tclass 
  7.  * @flags:  AVC_STRICT or 0 
  8.  * @avd: access vector decisions 
  9.  * 
  10.  * Check the AVC to determine whether the @requested permissions are granted 
  11.  * for the SID pair (@ssid, @tsid), interpreting the permissions 
  12.  * based on @tclass, and call the security server on a cache miss to obtain 
  13.  * a new decision and add it to the cache.  Return a copy of the decisions 
  14.  * in @avd.  Return %0 if all @requested permissions are granted, 
  15.  * -%EACCES if any permissions are denied, or another -errno upon 
  16.  * other errors.  This function is typically called by avc_has_perm(), 
  17.  * but may also be called directly to separate permission checking from 
  18.  * auditing, e.g. in cases where a lock must be held for the check but 
  19.  * should be released for the auditing. 
  20.  */  
  21. int avc_has_perm_noaudit(u32 ssid, u32 tsid,  
  22.              u16 tclass, u32 requested,  
  23.              unsigned flags,  
  24.              struct av_decision *avd)//avc_has_perm根据前三个参数得到avd,avd->allow  
  25.                         //存储的就是许可的掩码,和request与得到答案  
  26. {  
  27.     struct avc_node *node;  
  28.     int rc = 0;  
  29.     u32 denied;  
  30.   
  31.     BUG_ON(!requested);  
  32.   
  33.     rcu_read_lock();  
  34.   
  35.     node = avc_lookup(ssid, tsid, tclass);  
  36.     if (unlikely(!node)) {//unlikely 不希望括号中的数值成立,在不成立的时候执行  
  37.         rcu_read_unlock();//这个就是cache中没有文件,需要读取ss文件的if条件语句  
  38.         security_compute_av(ssid, tsid, tclass, avd);  
  39.         rcu_read_lock();  
  40.         node = avc_insert(ssid, tsid, tclass, avd);  
  41.     } else {  
  42.         memcpy(avd, &node->ae.avd, sizeof(*avd));  
  43.         avd = &node->ae.avd;  
  44.     }  
  45.   
  46.     denied = requested & ~(avd->allowed);  
  47.   
  48.     if (denied) {//根据现有访问策略决定时候拒绝  
  49.         if (flags & AVC_STRICT)  
  50.             rc = -EACCES;  
  51.         else if (!selinux_enforcing || (avd->flags & AVD_FLAGS_PERMISSIVE))  
  52.             avc_update_node(AVC_CALLBACK_GRANT, requested, ssid,  
  53.                     tsid, tclass, avd->seqno);  
  54.         else  
  55.             rc = -EACCES;  
  56.     }  
  57.   
  58.     rcu_read_unlock();  
  59.     return rc;  
  60. }  
从上面的代码中我们可以看出,如果cache中miss,那么就会调用 security_compute_av,

这个函数将会访问到SELinux中的策略,作出决定这次行动是否合法,

并且将策略装入cache以便下次使用。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * security_compute_av - Compute access vector decisions. 
  3.  * @ssid: source security identifier 
  4.  * @tsid: target security identifier 
  5.  * @tclass: target security class 
  6.  * @avd: access vector decisions 访问向量策略-听起来吊炸天!!! 
  7.  * 
  8.  * Compute a set of access vector decisions based on the 
  9.  * SID pair (@ssid, @tsid) for the permissions in @tclass. 
  10.  */  
  11. void security_compute_av(u32 ssid,  
  12.              u32 tsid,  
  13.              u16 orig_tclass,  
  14.              struct av_decision *avd)  
  15. {  
  16.     u16 tclass;  
  17.     struct context *scontext = NULL, *tcontext = NULL;  
  18.   
  19.     read_lock(&policy_rwlock);  
  20.     avd_init(avd);  
  21.     if (!ss_initialized)  
  22.         goto allow;  
  23.   
  24.     scontext = sidtab_search(&sidtab, ssid);  
  25.     if (!scontext) {  
  26.         printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",  
  27.                __func__, ssid);  
  28.         goto out;  
  29.     }  
  30.   
  31.     /* permissive domain? */  
  32.     if (ebitmap_get_bit(&policydb.permissive_map, scontext->type))  
  33.         avd->flags |= AVD_FLAGS_PERMISSIVE;  
  34.   
  35.     tcontext = sidtab_search(&sidtab, tsid);  
  36.     if (!tcontext) {  
  37.         printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",  
  38.                __func__, tsid);  
  39.         goto out;  
  40.     }  
  41.   
  42.     tclass = unmap_class(orig_tclass);  
  43.     if (unlikely(orig_tclass && !tclass)) {  
  44.         if (policydb.allow_unknown)  
  45.             goto allow;  
  46.         goto out;  
  47.     }  
  48.     context_struct_compute_av(scontext, tcontext, tclass, avd);  
  49.     map_decision(orig_tclass, avd, policydb.allow_unknown);  
  50. out:  
  51.     read_unlock(&policy_rwlock);  
  52.     return;  
  53. allow:  
  54.     avd->allowed = 0xffffffff;  
  55.     goto out;  
  56. }  
  57.   
  58. void security_compute_av_user(u32 ssid,  
  59.                   u32 tsid,  
  60.                   u16 tclass,  
  61.                   struct av_decision *avd)  
  62. {  
  63.     struct context *scontext = NULL, *tcontext = NULL;  
  64.   
  65.     read_lock(&policy_rwlock);  
  66.     avd_init(avd);  
  67.     if (!ss_initialized)  
  68.         goto allow;  
  69.   
  70.     scontext = sidtab_search(&sidtab, ssid);  
  71.     if (!scontext) {  
  72.         printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",  
  73.                __func__, ssid);  
  74.         goto out;  
  75.     }  
  76.   
  77.     /* permissive domain? */  
  78.     if (ebitmap_get_bit(&policydb.permissive_map, scontext->type))  
  79.         avd->flags |= AVD_FLAGS_PERMISSIVE;  
  80.   
  81.     tcontext = sidtab_search(&sidtab, tsid);  
  82.     if (!tcontext) {  
  83.         printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",  
  84.                __func__, tsid);  
  85.         goto out;  
  86.     }  
  87.   
  88.     if (unlikely(!tclass)) {  
  89.         if (policydb.allow_unknown)  
  90.             goto allow;  
  91.         goto out;  
  92.     }  
  93.   
  94.     context_struct_compute_av(scontext, tcontext, tclass, avd);  
  95.  out:  
  96.     read_unlock(&policy_rwlock);  
  97.     return;  
  98. allow:  
  99.     avd->allowed = 0xffffffff;  
  100.     goto out;  
  101. }  


好了,至此LSM的一次hook就得到了一个结果,如果符合定义的策略就会执行。至于在函数 security_compute_av中的策略读取,等一些细节问题,我们下次再说。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值