📄 hooks.c
字号:
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, NULL, &ad); if (rc) return rc; return avc_has_perm(newsid, sbsec->sid, SECCLASS_FILESYSTEM, FILESYSTEM__ASSOCIATE, NULL, &ad);}#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, &dsec->avcr, &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, &isec->avcr, &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, &old_dsec->avcr, &ad); if (rc) return rc; rc = avc_has_perm(tsec->sid, old_isec->sid, old_isec->sclass, FILE__RENAME, &old_isec->avcr, &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, &old_isec->avcr, &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,&new_dsec->avcr, &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), &new_isec->avcr, &ad); if (rc) return rc; } return 0;}/* Check whether a task can perform a filesystem operation. */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, NULL, 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;}/* Set an inode's SID to a specified value. */int inode_security_set_sid(struct inode *inode, u32 sid){ struct inode_security_struct *isec = inode->i_security; struct superblock_security_struct *sbsec = inode->i_sb->s_security; if (!sbsec->initialized) { /* Defer initialization to selinux_complete_init. */ return 0; } down(&isec->sem); isec->sclass = inode_mode_to_security_class(inode->i_mode); isec->sid = sid; isec->initialized = 1; up(&isec->sem); return 0;}/* Set the security attributes on a newly created file. */static int post_create(struct inode *dir, struct dentry *dentry){ struct task_security_struct *tsec; struct inode *inode; struct inode_security_struct *dsec; struct superblock_security_struct *sbsec; u32 newsid; char *context; unsigned int len; int rc; tsec = current->security; dsec = dir->i_security; sbsec = dir->i_sb->s_security; inode = dentry->d_inode; if (!inode) { /* Some file system types (e.g. NFS) may not instantiate a dentry for all create operations (e.g. symlink), so we have to check to see if the inode is non-NULL. */ printk(KERN_WARNING "post_create: no inode, dir (dev=%s, " "ino=%ld)\n", dir->i_sb->s_id, dir->i_ino); return 0; } if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) { newsid = tsec->create_sid; } else { rc = security_transition_sid(tsec->sid, dsec->sid, inode_mode_to_security_class(inode->i_mode), &newsid); if (rc) { printk(KERN_WARNING "post_create: " "security_transition_sid failed, rc=%d (dev=%s " "ino=%ld)\n", -rc, inode->i_sb->s_id, inode->i_ino); return rc; } } rc = inode_security_set_sid(inode, newsid); if (rc) { printk(KERN_WARNING "post_create: inode_security_set_sid " "failed, rc=%d (dev=%s ino=%ld)\n", -rc, inode->i_sb->s_id, inode->i_ino); return rc; } if (sbsec->behavior == SECURITY_FS_USE_XATTR && inode->i_op->setxattr) { /* Use extended attributes. */ rc = security_sid_to_context(newsid, &context, &len); if (rc) { printk(KERN_WARNING "post_create: sid_to_context " "failed, rc=%d (dev=%s ino=%ld)\n", -rc, inode->i_sb->s_id, inode->i_ino); return rc; } down(&inode->i_sem); rc = inode->i_op->setxattr(dentry, XATTR_NAME_SELINUX, context, len, 0); up(&inode->i_sem); kfree(context); if (rc < 0) { printk(KERN_WARNING "post_create: setxattr failed, " "rc=%d (dev=%s ino=%ld)\n", -rc, inode->i_sb->s_id, inode->i_ino); return rc; } } return 0;}/* 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 (!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){ int error; error = task_has_perm(current, target, PROCESS__SETCAP); if (error) return; 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(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_proc_get_sid(table->de, (op == 001) ? 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, 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, 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 file *f){ return file_has_perm(current, f, 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. * * We currently support three overcommit policies, which are set via the * vm.overcommit_memory sysctl. See Documentation/vm/overcommit-accounting * * Strict overcommit modes added 2002 Feb 26 by Alan Cox. * Additional code 2002 Jul 20 by Robert Love. */static int selinux_vm_enough_memory(long pages){ unsigned long free, allowed; int rc; struct task_security_struct *tsec = current->security; vm_acct_memory(pages); /* * Sometimes we want to use more memory than we have */ if (sysctl_overcommit_memory == OVERCOMMIT_ALWAYS) return 0; if (sysctl_overcommit_memory == OVERCOMMIT_GUESS) { free = get_page_cache_size(); free += nr_free_pages(); free += nr_swap_pages; /* * Any slabs which are created with the * SLAB_RECLAIM_ACCOUNT flag claim to have contents * which are reclaimable, under pressure. The dentry * cache and most inode caches should fall into this */ free += atomic_read(&slab_reclaim_pages); /* * Leave the last 3% for privileged processes. * Don't audit the check, as it is applied to all processes * that allocate mappings. */ rc = secondary_ops->capable(current, CAP_SYS_ADMIN); if (!rc) { rc = avc_has_perm_noaudit(tsec->sid, tsec->sid, SECCLASS_CAPABILITY, CAP_TO_MASK(CAP_SYS_ADMIN), NULL, NULL); } if (rc) free -= free / 32; if (free > pages) return 0; vm_unacct_memory(pages); return -ENOMEM; } allowed = (totalram_pages - hugetlb_total_pages()) * sysctl_overcommit_ratio / 100; allowed += total_swap_pages; if (atomic_read(&vm_committed_space) < allowed) return 0; vm_unacct_memory(pages); return -ENOMEM;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -