📄 hooks.c
字号:
goto out_free; } sbsec->mntpoint_sid = sid; sbsec->behavior = SECURITY_FS_USE_MNTPOINT; } if (rootcontext) { struct inode *inode = sb->s_root->d_inode; struct inode_security_struct *isec = inode->i_security; rc = security_context_to_sid(rootcontext, strlen(rootcontext), &sid); if (rc) { printk(KERN_WARNING "SELinux: security_context_to_sid" "(%s) failed for (dev %s, type %s) errno=%d\n", rootcontext, sb->s_id, name, rc); goto out_free; } rc = may_context_mount_inode_relabel(sid, sbsec, tsec); if (rc) goto out_free; isec->sid = sid; isec->initialized = 1; } if (defcontext) { rc = security_context_to_sid(defcontext, strlen(defcontext), &sid); if (rc) { printk(KERN_WARNING "SELinux: security_context_to_sid" "(%s) failed for (dev %s, type %s) errno=%d\n", defcontext, sb->s_id, name, rc); goto out_free; } if (sid == sbsec->def_sid) goto out_free; rc = may_context_mount_inode_relabel(sid, sbsec, tsec); if (rc) goto out_free; sbsec->def_sid = sid; }out_free: if (alloc) { kfree(context); kfree(defcontext); kfree(fscontext); kfree(rootcontext); }out: return rc;}static int superblock_doinit(struct super_block *sb, void *data){ struct superblock_security_struct *sbsec = sb->s_security; struct dentry *root = sb->s_root; struct inode *inode = root->d_inode; int rc = 0; mutex_lock(&sbsec->lock); if (sbsec->initialized) goto out; if (!ss_initialized) { /* Defer initialization until selinux_complete_init, after the initial policy is loaded and the security server is ready to handle calls. */ spin_lock(&sb_security_lock); if (list_empty(&sbsec->list)) list_add(&sbsec->list, &superblock_security_head); spin_unlock(&sb_security_lock); goto out; } /* Determine the labeling behavior to use for this filesystem type. */ rc = security_fs_use(sb->s_type->name, &sbsec->behavior, &sbsec->sid); if (rc) { printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n", __FUNCTION__, sb->s_type->name, rc); goto out; } rc = try_context_mount(sb, data); if (rc) goto out; if (sbsec->behavior == SECURITY_FS_USE_XATTR) { /* Make sure that the xattr handler exists and that no error other than -ENODATA is returned by getxattr on the root directory. -ENODATA is ok, as this may be the first boot of the SELinux kernel before we have assigned xattr values to the filesystem. */ if (!inode->i_op->getxattr) { printk(KERN_WARNING "SELinux: (dev %s, type %s) has no " "xattr support\n", sb->s_id, sb->s_type->name); rc = -EOPNOTSUPP; goto out; } rc = inode->i_op->getxattr(root, XATTR_NAME_SELINUX, NULL, 0); if (rc < 0 && rc != -ENODATA) { if (rc == -EOPNOTSUPP) printk(KERN_WARNING "SELinux: (dev %s, type " "%s) has no security xattr handler\n", sb->s_id, sb->s_type->name); else printk(KERN_WARNING "SELinux: (dev %s, type " "%s) getxattr errno %d\n", sb->s_id, sb->s_type->name, -rc); goto out; } } if (strcmp(sb->s_type->name, "proc") == 0) sbsec->proc = 1; sbsec->initialized = 1; if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) { printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n", sb->s_id, sb->s_type->name); } else { printk(KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n", sb->s_id, sb->s_type->name, labeling_behaviors[sbsec->behavior-1]); } /* Initialize the root inode. */ rc = inode_doinit_with_dentry(sb->s_root->d_inode, sb->s_root); /* Initialize any other inodes associated with the superblock, e.g. inodes created prior to initial policy load or inodes created during get_sb by a pseudo filesystem that directly populates itself. */ spin_lock(&sbsec->isec_lock);next_inode: if (!list_empty(&sbsec->isec_head)) { struct inode_security_struct *isec = list_entry(sbsec->isec_head.next, struct inode_security_struct, list); struct inode *inode = isec->inode; spin_unlock(&sbsec->isec_lock); inode = igrab(inode); if (inode) { if (!IS_PRIVATE (inode)) inode_doinit(inode); iput(inode); } spin_lock(&sbsec->isec_lock); list_del_init(&isec->list); goto next_inode; } spin_unlock(&sbsec->isec_lock);out: mutex_unlock(&sbsec->lock); return rc;}static inline u16 inode_mode_to_security_class(umode_t mode){ switch (mode & S_IFMT) { case S_IFSOCK: return SECCLASS_SOCK_FILE; case S_IFLNK: return SECCLASS_LNK_FILE; case S_IFREG: return SECCLASS_FILE; case S_IFBLK: return SECCLASS_BLK_FILE; case S_IFDIR: return SECCLASS_DIR; case S_IFCHR: return SECCLASS_CHR_FILE; case S_IFIFO: return SECCLASS_FIFO_FILE; } return SECCLASS_FILE;}static inline int default_protocol_stream(int protocol){ return (protocol == IPPROTO_IP || protocol == IPPROTO_TCP);}static inline int default_protocol_dgram(int protocol){ return (protocol == IPPROTO_IP || protocol == IPPROTO_UDP);}static inline u16 socket_type_to_security_class(int family, int type, int protocol){ switch (family) { case PF_UNIX: switch (type) { case SOCK_STREAM: case SOCK_SEQPACKET: return SECCLASS_UNIX_STREAM_SOCKET; case SOCK_DGRAM: return SECCLASS_UNIX_DGRAM_SOCKET; } break; case PF_INET: case PF_INET6: switch (type) { case SOCK_STREAM: if (default_protocol_stream(protocol)) return SECCLASS_TCP_SOCKET; else return SECCLASS_RAWIP_SOCKET; case SOCK_DGRAM: if (default_protocol_dgram(protocol)) return SECCLASS_UDP_SOCKET; else return SECCLASS_RAWIP_SOCKET; case SOCK_DCCP: return SECCLASS_DCCP_SOCKET; default: return SECCLASS_RAWIP_SOCKET; } break; case PF_NETLINK: switch (protocol) { case NETLINK_ROUTE: return SECCLASS_NETLINK_ROUTE_SOCKET; case NETLINK_FIREWALL: return SECCLASS_NETLINK_FIREWALL_SOCKET; case NETLINK_INET_DIAG: return SECCLASS_NETLINK_TCPDIAG_SOCKET; case NETLINK_NFLOG: return SECCLASS_NETLINK_NFLOG_SOCKET; case NETLINK_XFRM: return SECCLASS_NETLINK_XFRM_SOCKET; case NETLINK_SELINUX: return SECCLASS_NETLINK_SELINUX_SOCKET; case NETLINK_AUDIT: return SECCLASS_NETLINK_AUDIT_SOCKET; case NETLINK_IP6_FW: return SECCLASS_NETLINK_IP6FW_SOCKET; case NETLINK_DNRTMSG: return SECCLASS_NETLINK_DNRT_SOCKET; case NETLINK_KOBJECT_UEVENT: return SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET; default: return SECCLASS_NETLINK_SOCKET; } case PF_PACKET: return SECCLASS_PACKET_SOCKET; case PF_KEY: return SECCLASS_KEY_SOCKET; case PF_APPLETALK: return SECCLASS_APPLETALK_SOCKET; } return SECCLASS_SOCKET;}#ifdef CONFIG_PROC_FSstatic int selinux_proc_get_sid(struct proc_dir_entry *de, u16 tclass, u32 *sid){ int buflen, rc; char *buffer, *path, *end; buffer = (char*)__get_free_page(GFP_KERNEL); if (!buffer) return -ENOMEM; buflen = PAGE_SIZE; end = buffer+buflen; *--end = '\0'; buflen--; path = end-1; *path = '/'; while (de && de != de->parent) { buflen -= de->namelen + 1; if (buflen < 0) break; end -= de->namelen; memcpy(end, de->name, de->namelen); *--end = '/'; path = end; de = de->parent; } rc = security_genfs_sid("proc", path, tclass, sid); free_page((unsigned long)buffer); return rc;}#elsestatic int selinux_proc_get_sid(struct proc_dir_entry *de, u16 tclass, u32 *sid){ return -EINVAL;}#endif/* The inode's security attributes must be initialized before first use. */static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry){ struct superblock_security_struct *sbsec = NULL; struct inode_security_struct *isec = inode->i_security; u32 sid; struct dentry *dentry;#define INITCONTEXTLEN 255 char *context = NULL; unsigned len = 0; int rc = 0; if (isec->initialized) goto out; mutex_lock(&isec->lock); if (isec->initialized) goto out_unlock; sbsec = inode->i_sb->s_security; if (!sbsec->initialized) { /* Defer initialization until selinux_complete_init, after the initial policy is loaded and the security server is ready to handle calls. */ spin_lock(&sbsec->isec_lock); if (list_empty(&isec->list)) list_add(&isec->list, &sbsec->isec_head); spin_unlock(&sbsec->isec_lock); goto out_unlock; } switch (sbsec->behavior) { case SECURITY_FS_USE_XATTR: if (!inode->i_op->getxattr) { isec->sid = sbsec->def_sid; break; } /* Need a dentry, since the xattr API requires one. Life would be simpler if we could just pass the inode. */ if (opt_dentry) { /* Called from d_instantiate or d_splice_alias. */ dentry = dget(opt_dentry); } else { /* Called from selinux_complete_init, try to find a dentry. */ dentry = d_find_alias(inode); } if (!dentry) { printk(KERN_WARNING "%s: no dentry for dev=%s " "ino=%ld\n", __FUNCTION__, inode->i_sb->s_id, inode->i_ino); goto out_unlock; } len = INITCONTEXTLEN; context = kmalloc(len, GFP_KERNEL); if (!context) { rc = -ENOMEM; dput(dentry); goto out_unlock; } rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX, context, len); if (rc == -ERANGE) { /* Need a larger buffer. Query for the right size. */ rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX, NULL, 0); if (rc < 0) { dput(dentry); goto out_unlock; } kfree(context); len = rc; context = kmalloc(len, GFP_KERNEL); if (!context) { rc = -ENOMEM; dput(dentry); goto out_unlock; } rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX, context, len); } dput(dentry); if (rc < 0) { if (rc != -ENODATA) { printk(KERN_WARNING "%s: getxattr returned " "%d for dev=%s ino=%ld\n", __FUNCTION__, -rc, inode->i_sb->s_id, inode->i_ino); kfree(context); goto out_unlock; } /* Map ENODATA to the default file SID */ sid = sbsec->def_sid; rc = 0; } else { rc = security_context_to_sid_default(context, rc, &sid, sbsec->def_sid); if (rc) { printk(KERN_WARNING "%s: context_to_sid(%s) " "returned %d for dev=%s ino=%ld\n", __FUNCTION__, context, -rc, inode->i_sb->s_id, inode->i_ino); kfree(context); /* Leave with the unlabeled SID */ rc = 0; break; } } kfree(context); isec->sid = sid; break; case SECURITY_FS_USE_TASK: isec->sid = isec->task_sid; break; case SECURITY_FS_USE_TRANS: /* Default to the fs SID. */ isec->sid = sbsec->sid; /* Try to obtain a transition SID. */ isec->sclass = inode_mode_to_security_class(inode->i_mode); rc = security_transition_sid(isec->task_sid, sbsec->sid, isec->sclass, &sid); if (rc) goto out_unlock; isec->sid = sid; break; case SECURITY_FS_USE_MNTPOINT: isec->sid = sbsec->mntpoint_sid; break; default: /* Default to the fs superblock SID. */ isec->sid = sbsec->sid; if (sbsec->proc) { struct proc_inode *proci = PROC_I(inode); if (proci->pde) { isec->sclass = inode_mode_to_security_class(inode->i_mode); rc = selinux_proc_get_sid(proci->pde, isec->sclass, &sid); if (rc) goto out_unlock; isec->sid = sid; } } break; } isec->initialized = 1;out_unlock: mutex_unlock(&isec->lock);out: if (isec->sclass == SECCLASS_FILE) isec->sclass = inode_mode_to_security_class(inode->i_mode); return rc;}/* Convert a Linux signal to an access vector. */static inline u32 signal_to_av(int sig){ u32 perm = 0; switch (sig) { case SIGCHLD: /* Commonly granted from child to parent. */ perm = PROCESS__SIGCHLD; break; case SIGKILL: /* Cannot be caught or ignored */ perm = PROCESS__SIGKILL; break; case SIGSTOP: /* Cannot be caught or ignored */ perm = PROCESS__SIGSTOP; break; default: /* All other signals. */ perm = PROCESS__SIGNAL; break; } return perm;}/* Check permission betweeen a pair of tasks, e.g. signal checks, fork check, ptrace check, etc. */static int task_has_perm(struct task_struct *tsk1, struct task_struct *tsk2, u32 perms){ struct task_security_struct *tsec1, *tsec2; tsec1 = tsk1->security; tsec2 = tsk2->security; return avc_has_perm(tsec1->sid, tsec2->sid, SECCLASS_PROCESS, perms, NULL);}/* Check whether a task is allowed to use a capability. */static int task_has_capability(struct task_struct *tsk, int cap){ struct task_security_struct *tsec; struct avc_audit_data ad; tsec = tsk->security; AVC_AUDIT_DATA_INIT(&ad,CAP); ad.tsk = tsk; ad.u.cap = cap; return avc_has_perm(tsec->sid, tsec->sid, SECCLASS_CAPABILITY, CAP_TO_MASK(cap), &ad);}/* Check whether a task is allowed to use a system operation. */static int task_has_system(struct task_struct *tsk, u32 perms){ struct task_security_struct *tsec; tsec = tsk->security; return avc_has_perm(tsec->sid, SECINITSID_KERNEL, SECCLASS_SYSTEM, perms, NULL);}/* Check whether a task has a particular permission to an inode. The 'adp' parameter is optional and allows other audit
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -