📄 hooks.c
字号:
/* binprm security operations */static int selinux_bprm_alloc_security(struct linux_binprm *bprm){ struct bprm_security_struct *bsec; bsec = kzalloc(sizeof(struct bprm_security_struct), GFP_KERNEL); if (!bsec) return -ENOMEM; bsec->bprm = bprm; bsec->sid = SECINITSID_UNLABELED; bsec->set = 0; bprm->security = bsec; return 0;}static int selinux_bprm_set_security(struct linux_binprm *bprm){ struct task_security_struct *tsec; struct inode *inode = bprm->file->f_path.dentry->d_inode; struct inode_security_struct *isec; struct bprm_security_struct *bsec; u32 newsid; struct avc_audit_data ad; int rc; rc = secondary_ops->bprm_set_security(bprm); if (rc) return rc; bsec = bprm->security; if (bsec->set) return 0; tsec = current->security; isec = inode->i_security; /* Default to the current task SID. */ bsec->sid = tsec->sid; /* Reset fs, key, and sock SIDs on execve. */ tsec->create_sid = 0; tsec->keycreate_sid = 0; tsec->sockcreate_sid = 0; if (tsec->exec_sid) { newsid = tsec->exec_sid; /* Reset exec SID on execve. */ tsec->exec_sid = 0; } else { /* Check for a default transition on this program. */ rc = security_transition_sid(tsec->sid, isec->sid, SECCLASS_PROCESS, &newsid); if (rc) return rc; } AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.mnt = bprm->file->f_path.mnt; ad.u.fs.dentry = bprm->file->f_path.dentry; if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) newsid = tsec->sid; if (tsec->sid == newsid) { rc = avc_has_perm(tsec->sid, isec->sid, SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad); if (rc) return rc; } else { /* Check permissions for the transition. */ rc = avc_has_perm(tsec->sid, newsid, SECCLASS_PROCESS, PROCESS__TRANSITION, &ad); if (rc) return rc; rc = avc_has_perm(newsid, isec->sid, SECCLASS_FILE, FILE__ENTRYPOINT, &ad); if (rc) return rc; /* Clear any possibly unsafe personality bits on exec: */ current->personality &= ~PER_CLEAR_ON_SETID; /* Set the security field to the new SID. */ bsec->sid = newsid; } bsec->set = 1; return 0;}static int selinux_bprm_check_security (struct linux_binprm *bprm){ return secondary_ops->bprm_check_security(bprm);}static int selinux_bprm_secureexec (struct linux_binprm *bprm){ struct task_security_struct *tsec = current->security; int atsecure = 0; if (tsec->osid != tsec->sid) { /* Enable secure mode for SIDs transitions unless the noatsecure permission is granted between the two SIDs, i.e. ahp returns 0. */ atsecure = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS, PROCESS__NOATSECURE, NULL); } return (atsecure || secondary_ops->bprm_secureexec(bprm));}static void selinux_bprm_free_security(struct linux_binprm *bprm){ kfree(bprm->security); bprm->security = NULL;}extern struct vfsmount *selinuxfs_mount;extern struct dentry *selinux_null;/* Derived from fs/exec.c:flush_old_files. */static inline void flush_unauthorized_files(struct files_struct * files){ struct avc_audit_data ad; struct file *file, *devnull = NULL; struct tty_struct *tty; struct fdtable *fdt; long j = -1; int drop_tty = 0; mutex_lock(&tty_mutex); tty = get_current_tty(); if (tty) { file_list_lock(); file = list_entry(tty->tty_files.next, typeof(*file), f_u.fu_list); if (file) { /* Revalidate access to controlling tty. Use inode_has_perm on the tty inode directly rather than using file_has_perm, as this particular open file may belong to another process and we are only interested in the inode-based check here. */ struct inode *inode = file->f_path.dentry->d_inode; if (inode_has_perm(current, inode, FILE__READ | FILE__WRITE, NULL)) { drop_tty = 1; } } file_list_unlock(); } mutex_unlock(&tty_mutex); /* Reset controlling tty. */ if (drop_tty) no_tty(); /* Revalidate access to inherited open files. */ AVC_AUDIT_DATA_INIT(&ad,FS); spin_lock(&files->file_lock); for (;;) { unsigned long set, i; int fd; j++; i = j * __NFDBITS; fdt = files_fdtable(files); if (i >= fdt->max_fds) break; set = fdt->open_fds->fds_bits[j]; if (!set) continue; spin_unlock(&files->file_lock); for ( ; set ; i++,set >>= 1) { if (set & 1) { file = fget(i); if (!file) continue; if (file_has_perm(current, file, file_to_av(file))) { sys_close(i); fd = get_unused_fd(); if (fd != i) { if (fd >= 0) put_unused_fd(fd); fput(file); continue; } if (devnull) { get_file(devnull); } else { devnull = dentry_open(dget(selinux_null), mntget(selinuxfs_mount), O_RDWR); if (IS_ERR(devnull)) { devnull = NULL; put_unused_fd(fd); fput(file); continue; } } fd_install(fd, devnull); } fput(file); } } spin_lock(&files->file_lock); } spin_unlock(&files->file_lock);}static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe){ struct task_security_struct *tsec; struct bprm_security_struct *bsec; u32 sid; int rc; secondary_ops->bprm_apply_creds(bprm, unsafe); tsec = current->security; bsec = bprm->security; sid = bsec->sid; tsec->osid = tsec->sid; bsec->unsafe = 0; if (tsec->sid != sid) { /* Check for shared state. If not ok, leave SID unchanged and kill. */ if (unsafe & LSM_UNSAFE_SHARE) { rc = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS, PROCESS__SHARE, NULL); if (rc) { bsec->unsafe = 1; return; } } /* Check for ptracing, and update the task SID if ok. Otherwise, leave SID unchanged and kill. */ if (unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) { rc = avc_has_perm(tsec->ptrace_sid, sid, SECCLASS_PROCESS, PROCESS__PTRACE, NULL); if (rc) { bsec->unsafe = 1; return; } } tsec->sid = sid; }}/* * called after apply_creds without the task lock held */static void selinux_bprm_post_apply_creds(struct linux_binprm *bprm){ struct task_security_struct *tsec; struct rlimit *rlim, *initrlim; struct itimerval itimer; struct bprm_security_struct *bsec; int rc, i; tsec = current->security; bsec = bprm->security; if (bsec->unsafe) { force_sig_specific(SIGKILL, current); return; } if (tsec->osid == tsec->sid) return; /* Close files for which the new task SID is not authorized. */ flush_unauthorized_files(current->files); /* Check whether the new SID can inherit signal state from the old SID. If not, clear itimers to avoid subsequent signal generation and flush and unblock signals. This must occur _after_ the task SID has been updated so that any kill done after the flush will be checked against the new SID. */ rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL); if (rc) { memset(&itimer, 0, sizeof itimer); for (i = 0; i < 3; i++) do_setitimer(i, &itimer, NULL); flush_signals(current); spin_lock_irq(¤t->sighand->siglock); flush_signal_handlers(current, 1); sigemptyset(¤t->blocked); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); } /* Always clear parent death signal on SID transitions. */ current->pdeath_signal = 0; /* Check whether the new SID can inherit resource limits from the old SID. If not, reset all soft limits to the lower of the current task's hard limit and the init task's soft limit. Note that the setting of hard limits (even to lower them) can be controlled by the setrlimit check. The inclusion of the init task's soft limit into the computation is to avoid resetting soft limits higher than the default soft limit for cases where the default is lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK.*/ rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS, PROCESS__RLIMITINH, NULL); if (rc) { for (i = 0; i < RLIM_NLIMITS; i++) { rlim = current->signal->rlim + i; initrlim = init_task.signal->rlim+i; rlim->rlim_cur = min(rlim->rlim_max,initrlim->rlim_cur); } if (current->signal->rlim[RLIMIT_CPU].rlim_cur != RLIM_INFINITY) { /* * This will cause RLIMIT_CPU calculations * to be refigured. */ current->it_prof_expires = jiffies_to_cputime(1); } } /* Wake up the parent if it is waiting so that it can recheck wait permission to the new task SID. */ wake_up_interruptible(¤t->parent->signal->wait_chldexit);}/* superblock security operations */static int selinux_sb_alloc_security(struct super_block *sb){ return superblock_alloc_security(sb);}static void selinux_sb_free_security(struct super_block *sb){ superblock_free_security(sb);}static inline int match_prefix(char *prefix, int plen, char *option, int olen){ if (plen > olen) return 0; return !memcmp(prefix, option, plen);}static inline int selinux_option(char *option, int len){ return (match_prefix("context=", sizeof("context=")-1, option, len) || match_prefix("fscontext=", sizeof("fscontext=")-1, option, len) || match_prefix("defcontext=", sizeof("defcontext=")-1, option, len) || match_prefix("rootcontext=", sizeof("rootcontext=")-1, option, len));}static inline void take_option(char **to, char *from, int *first, int len){ if (!*first) { **to = ','; *to += 1; } else *first = 0; memcpy(*to, from, len); *to += len;}static inline void take_selinux_option(char **to, char *from, int *first, int len){ int current_size = 0; if (!*first) { **to = '|'; *to += 1; } else *first = 0; while (current_size < len) { if (*from != '"') { **to = *from; *to += 1; } from += 1; current_size += 1; }}static int selinux_sb_copy_data(struct file_system_type *type, void *orig, void *copy){ int fnosec, fsec, rc = 0; char *in_save, *in_curr, *in_end; char *sec_curr, *nosec_save, *nosec; int open_quote = 0; in_curr = orig; sec_curr = copy; /* Binary mount data: just copy */ if (type->fs_flags & FS_BINARY_MOUNTDATA) { copy_page(sec_curr, in_curr); goto out; } nosec = (char *)get_zeroed_page(GFP_KERNEL); if (!nosec) { rc = -ENOMEM; goto out; } nosec_save = nosec; fnosec = fsec = 1; in_save = in_end = orig; do { if (*in_end == '"') open_quote = !open_quote; if ((*in_end == ',' && open_quote == 0) || *in_end == '\0') { int len = in_end - in_curr; if (selinux_option(in_curr, len)) take_selinux_option(&sec_curr, in_curr, &fsec, len); else take_option(&nosec, in_curr, &fnosec, len); in_curr = in_end + 1; } } while (*in_end++); strcpy(in_save, nosec_save); free_page((unsigned long)nosec_save);out: return rc;}static int selinux_sb_kern_mount(struct super_block *sb, void *data){ struct avc_audit_data ad; int rc; rc = superblock_doinit(sb, data); if (rc) return rc; AVC_AUDIT_DATA_INIT(&ad,FS); ad.u.fs.dentry = sb->s_root; return superblock_has_perm(current, sb, FILESYSTEM__MOUNT, &ad);}static int selinux_sb_statfs(struct dentry *dentry){ struct avc_audit_data ad; AVC_AUDIT_DATA_INIT(&ad,FS); ad.u.fs.dentry = dentry->d_sb->s_root; return superblock_has_perm(current, dentry->d_sb, FILESYSTEM__GETATTR, &ad);}static int selinux_mount(char * dev_name, struct nameidata *nd, char * type, unsigned long flags, void * data){ int rc; rc = secondary_ops->sb_mount(dev_name, nd, type, flags, data); if (rc) return rc; if (flags & MS_REMOUNT) return superblock_has_perm(current, nd->mnt->mnt_sb, FILESYSTEM__REMOUNT, NULL); else return dentry_has_perm(current, nd->mnt, nd->dentry, FILE__MOUNTON);}static int selinux_umount(struct vfsmount *mnt, int flags){ int rc; rc = secondary_ops->sb_umount(mnt, flags); if (rc) return rc; return superblock_has_perm(current,mnt->mnt_sb, FILESYSTEM__UNMOUNT,NULL);}/* inode security operations */static int selinux_inode_alloc_security(struct inode *inode){ return inode_alloc_security(inode);}static void selinux_inode_free_security(struct inode *inode){ inode_free_security(inode);}static int selinux_inode_init_security(struct inode *inode, struct inode *dir, char **name, void **value, size_t *len){ struct task_security_struct *tsec; struct inode_security_struct *dsec; struct superblock_security_struct *sbsec; u32 newsid, clen; int rc; char *namep = NULL, *context; tsec = current->security; dsec = dir->i_security; sbsec = dir->i_sb->s_security; 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),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -