📄 hooks.c
字号:
data to be passed (e.g. the dentry). */static int inode_has_perm(struct task_struct *tsk, struct inode *inode, u32 perms, struct avc_audit_data *adp){ struct task_security_struct *tsec; struct inode_security_struct *isec; struct avc_audit_data ad; if (unlikely (IS_PRIVATE (inode))) return 0; tsec = tsk->security; isec = inode->i_security; if (!adp) { adp = &ad; AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.inode = inode; } return avc_has_perm(tsec->sid, isec->sid, isec->sclass, perms, adp);}/* Same as inode_has_perm, but pass explicit audit data containing the dentry to help the auditing code to more easily generate the pathname if needed. */static inline int dentry_has_perm(struct task_struct *tsk, struct vfsmount *mnt, struct dentry *dentry, u32 av){ struct inode *inode = dentry->d_inode; struct avc_audit_data ad; AVC_AUDIT_DATA_INIT(&ad,FS); ad.u.fs.mnt = mnt; ad.u.fs.dentry = dentry; return inode_has_perm(tsk, inode, av, &ad);}/* Check whether a task can use an open file descriptor to access an inode in a given way. Check access to the descriptor itself, and then use dentry_has_perm to check a particular permission to the file. Access to the descriptor is implicitly granted if it has the same SID as the process. If av is zero, then access to the file is not checked, e.g. for cases where only the descriptor is affected like seek. */static int file_has_perm(struct task_struct *tsk, struct file *file, u32 av){ struct task_security_struct *tsec = tsk->security; struct file_security_struct *fsec = file->f_security; struct vfsmount *mnt = file->f_path.mnt; struct dentry *dentry = file->f_path.dentry; struct inode *inode = dentry->d_inode; struct avc_audit_data ad; int rc; AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.mnt = mnt; ad.u.fs.dentry = dentry; if (tsec->sid != fsec->sid) { rc = avc_has_perm(tsec->sid, fsec->sid, SECCLASS_FD, FD__USE, &ad); if (rc) return rc; } /* av is zero if only checking access to the descriptor. */ if (av) return inode_has_perm(tsk, inode, av, &ad); return 0;}/* Check whether a task can create a file. */static int may_create(struct inode *dir, struct dentry *dentry, u16 tclass){ struct task_security_struct *tsec; struct inode_security_struct *dsec; struct superblock_security_struct *sbsec; u32 newsid; struct avc_audit_data ad; int rc; tsec = current->security; dsec = dir->i_security; sbsec = dir->i_sb->s_security; AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.dentry = dentry; rc = avc_has_perm(tsec->sid, dsec->sid, SECCLASS_DIR, DIR__ADD_NAME | DIR__SEARCH, &ad); if (rc) return rc; if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) { newsid = tsec->create_sid; } else { rc = security_transition_sid(tsec->sid, dsec->sid, tclass, &newsid); if (rc) return rc; } rc = avc_has_perm(tsec->sid, newsid, tclass, FILE__CREATE, &ad); if (rc) return rc; return avc_has_perm(newsid, sbsec->sid, SECCLASS_FILESYSTEM, FILESYSTEM__ASSOCIATE, &ad);}/* Check whether a task can create a key. */static int may_create_key(u32 ksid, struct task_struct *ctx){ struct task_security_struct *tsec; tsec = ctx->security; return avc_has_perm(tsec->sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);}#define MAY_LINK 0#define MAY_UNLINK 1#define MAY_RMDIR 2/* Check whether a task can link, unlink, or rmdir a file/directory. */static int may_link(struct inode *dir, struct dentry *dentry, int kind){ struct task_security_struct *tsec; struct inode_security_struct *dsec, *isec; struct avc_audit_data ad; u32 av; int rc; tsec = current->security; dsec = dir->i_security; isec = dentry->d_inode->i_security; AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.dentry = dentry; av = DIR__SEARCH; av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME); rc = avc_has_perm(tsec->sid, dsec->sid, SECCLASS_DIR, av, &ad); if (rc) return rc; switch (kind) { case MAY_LINK: av = FILE__LINK; break; case MAY_UNLINK: av = FILE__UNLINK; break; case MAY_RMDIR: av = DIR__RMDIR; break; default: printk(KERN_WARNING "may_link: unrecognized kind %d\n", kind); return 0; } rc = avc_has_perm(tsec->sid, isec->sid, isec->sclass, av, &ad); return rc;}static inline int may_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry){ struct task_security_struct *tsec; struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec; struct avc_audit_data ad; u32 av; int old_is_dir, new_is_dir; int rc; tsec = current->security; old_dsec = old_dir->i_security; old_isec = old_dentry->d_inode->i_security; old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode); new_dsec = new_dir->i_security; AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.dentry = old_dentry; rc = avc_has_perm(tsec->sid, old_dsec->sid, SECCLASS_DIR, DIR__REMOVE_NAME | DIR__SEARCH, &ad); if (rc) return rc; rc = avc_has_perm(tsec->sid, old_isec->sid, old_isec->sclass, FILE__RENAME, &ad); if (rc) return rc; if (old_is_dir && new_dir != old_dir) { rc = avc_has_perm(tsec->sid, old_isec->sid, old_isec->sclass, DIR__REPARENT, &ad); if (rc) return rc; } ad.u.fs.dentry = new_dentry; av = DIR__ADD_NAME | DIR__SEARCH; if (new_dentry->d_inode) av |= DIR__REMOVE_NAME; rc = avc_has_perm(tsec->sid, new_dsec->sid, SECCLASS_DIR, av, &ad); if (rc) return rc; if (new_dentry->d_inode) { new_isec = new_dentry->d_inode->i_security; new_is_dir = S_ISDIR(new_dentry->d_inode->i_mode); rc = avc_has_perm(tsec->sid, new_isec->sid, new_isec->sclass, (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad); if (rc) return rc; } return 0;}/* Check whether a task can perform a filesystem operation. */static int superblock_has_perm(struct task_struct *tsk, struct super_block *sb, u32 perms, struct avc_audit_data *ad){ struct task_security_struct *tsec; struct superblock_security_struct *sbsec; tsec = tsk->security; sbsec = sb->s_security; return avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);}/* Convert a Linux mode and permission mask to an access vector. */static inline u32 file_mask_to_av(int mode, int mask){ u32 av = 0; if ((mode & S_IFMT) != S_IFDIR) { if (mask & MAY_EXEC) av |= FILE__EXECUTE; if (mask & MAY_READ) av |= FILE__READ; if (mask & MAY_APPEND) av |= FILE__APPEND; else if (mask & MAY_WRITE) av |= FILE__WRITE; } else { if (mask & MAY_EXEC) av |= DIR__SEARCH; if (mask & MAY_WRITE) av |= DIR__WRITE; if (mask & MAY_READ) av |= DIR__READ; } return av;}/* Convert a Linux file to an access vector. */static inline u32 file_to_av(struct file *file){ u32 av = 0; if (file->f_mode & FMODE_READ) av |= FILE__READ; if (file->f_mode & FMODE_WRITE) { if (file->f_flags & O_APPEND) av |= FILE__APPEND; else av |= FILE__WRITE; } return av;}/* Hook functions begin here. */static int selinux_ptrace(struct task_struct *parent, struct task_struct *child){ struct task_security_struct *psec = parent->security; struct task_security_struct *csec = child->security; int rc; rc = secondary_ops->ptrace(parent,child); if (rc) return rc; rc = task_has_perm(parent, child, PROCESS__PTRACE); /* Save the SID of the tracing process for later use in apply_creds. */ if (!(child->ptrace & PT_PTRACED) && !rc) csec->ptrace_sid = psec->sid; return rc;}static int selinux_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted){ int error; error = task_has_perm(current, target, PROCESS__GETCAP); if (error) return error; return secondary_ops->capget(target, effective, inheritable, permitted);}static int selinux_capset_check(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted){ int error; error = secondary_ops->capset_check(target, effective, inheritable, permitted); if (error) return error; return task_has_perm(current, target, PROCESS__SETCAP);}static void selinux_capset_set(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted){ secondary_ops->capset_set(target, effective, inheritable, permitted);}static int selinux_capable(struct task_struct *tsk, int cap){ int rc; rc = secondary_ops->capable(tsk, cap); if (rc) return rc; return task_has_capability(tsk,cap);}static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid){ int buflen, rc; char *buffer, *path, *end; rc = -ENOMEM; buffer = (char*)__get_free_page(GFP_KERNEL); if (!buffer) goto out; buflen = PAGE_SIZE; end = buffer+buflen; *--end = '\0'; buflen--; path = end-1; *path = '/'; while (table) { const char *name = table->procname; size_t namelen = strlen(name); buflen -= namelen + 1; if (buflen < 0) goto out_free; end -= namelen; memcpy(end, name, namelen); *--end = '/'; path = end; table = table->parent; } buflen -= 4; if (buflen < 0) goto out_free; end -= 4; memcpy(end, "/sys", 4); path = end; rc = security_genfs_sid("proc", path, tclass, sid);out_free: free_page((unsigned long)buffer);out: return rc;}static int selinux_sysctl(ctl_table *table, int op){ int error = 0; u32 av; struct task_security_struct *tsec; u32 tsid; int rc; rc = secondary_ops->sysctl(table, op); if (rc) return rc; tsec = current->security; rc = selinux_sysctl_get_sid(table, (op == 0001) ? SECCLASS_DIR : SECCLASS_FILE, &tsid); if (rc) { /* Default to the well-defined sysctl SID. */ tsid = SECINITSID_SYSCTL; } /* The op values are "defined" in sysctl.c, thereby creating * a bad coupling between this module and sysctl.c */ if(op == 001) { error = avc_has_perm(tsec->sid, tsid, SECCLASS_DIR, DIR__SEARCH, NULL); } else { av = 0; if (op & 004) av |= FILE__READ; if (op & 002) av |= FILE__WRITE; if (av) error = avc_has_perm(tsec->sid, tsid, SECCLASS_FILE, av, NULL); } return error;}static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb){ int rc = 0; if (!sb) return 0; switch (cmds) { case Q_SYNC: case Q_QUOTAON: case Q_QUOTAOFF: case Q_SETINFO: case Q_SETQUOTA: rc = superblock_has_perm(current, sb, FILESYSTEM__QUOTAMOD, NULL); break; case Q_GETFMT: case Q_GETINFO: case Q_GETQUOTA: rc = superblock_has_perm(current, sb, FILESYSTEM__QUOTAGET, NULL); break; default: rc = 0; /* let the kernel handle invalid cmds */ break; } return rc;}static int selinux_quota_on(struct dentry *dentry){ return dentry_has_perm(current, NULL, dentry, FILE__QUOTAON);}static int selinux_syslog(int type){ int rc; rc = secondary_ops->syslog(type); if (rc) return rc; switch (type) { case 3: /* Read last kernel messages */ case 10: /* Return size of the log buffer */ rc = task_has_system(current, SYSTEM__SYSLOG_READ); break; case 6: /* Disable logging to console */ case 7: /* Enable logging to console */ case 8: /* Set level of messages printed to console */ rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE); break; case 0: /* Close log */ case 1: /* Open log */ case 2: /* Read from log */ case 4: /* Read/clear last kernel messages */ case 5: /* Clear ring buffer */ default: rc = task_has_system(current, SYSTEM__SYSLOG_MOD); break; } return rc;}/* * Check that a process has enough memory to allocate a new virtual * mapping. 0 means there is enough memory for the allocation to * succeed and -ENOMEM implies there is not. * * Note that secondary_ops->capable and task_has_perm_noaudit return 0 * if the capability is granted, but __vm_enough_memory requires 1 if * the capability is granted. * * Do not audit the selinux permission check, as this is applied to all * processes that allocate mappings. */static int selinux_vm_enough_memory(struct mm_struct *mm, long pages){ int rc, cap_sys_admin = 0; struct task_security_struct *tsec = current->security; rc = secondary_ops->capable(current, CAP_SYS_ADMIN); if (rc == 0) rc = avc_has_perm_noaudit(tsec->sid, tsec->sid, SECCLASS_CAPABILITY, CAP_TO_MASK(CAP_SYS_ADMIN), 0, NULL); if (rc == 0) cap_sys_admin = 1; return __vm_enough_memory(mm, pages, cap_sys_admin);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -