/* Default to the fs superblock SID. */
isec->sid = sbsec->sid;
- if (sbsec->proc) {
+ if (sbsec->proc && !S_ISLNK(inode->i_mode)) {
struct proc_inode *proci = PROC_I(inode);
if (proci->pde) {
isec->sclass = inode_mode_to_security_class(inode->i_mode);
long j = -1;
int drop_tty = 0;
- mutex_lock(&tty_mutex);
tty = get_current_tty();
if (tty) {
file_list_lock();
}
}
file_list_unlock();
+ tty_kref_put(tty);
}
- mutex_unlock(&tty_mutex);
/* Reset controlling tty. */
if (drop_tty)
no_tty();
if (sid == 0)
return -EINVAL;
-
- /* Only allow single threaded processes to change context */
+ /*
+ * SELinux allows to change context in the following case only.
+ * - Single threaded processes.
+ * - Multi threaded processes intend to change its context into
+ * more restricted domain (defined by TYPEBOUNDS statement).
+ */
if (atomic_read(&p->mm->mm_users) != 1) {
struct task_struct *g, *t;
struct mm_struct *mm = p->mm;
do_each_thread(g, t) {
if (t->mm == mm && t != p) {
read_unlock(&tasklist_lock);
- return -EPERM;
+ error = security_bounded_transition(tsec->sid, sid);
+ if (!error)
+ goto boundary_ok;
+
+ return error;
}
} while_each_thread(g, t);
read_unlock(&tasklist_lock);
}
+boundary_ok:
/* Check permissions for the transition. */
error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,