X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/6d2010ae8f7a6078e10b361c6962983bab233e0f..d9a64523371fa019c4575bb400cbbc3a50ac9903:/bsd/kern/tty_tty.c diff --git a/bsd/kern/tty_tty.c b/bsd/kern/tty_tty.c index ec7bee445..84960728d 100644 --- a/bsd/kern/tty_tty.c +++ b/bsd/kern/tty_tty.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997-2006 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1997-2013 Apple Computer, Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -87,7 +87,9 @@ cttyopen(dev_t dev, int flag, __unused int mode, proc_t p) { vnode_t ttyvp = cttyvp(p); struct vfs_context context; - int error; + int error = 0; + int cttyflag, doclose = 0; + struct session *sessp; if (ttyvp == NULL) return (ENXIO); @@ -95,17 +97,60 @@ cttyopen(dev_t dev, int flag, __unused int mode, proc_t p) context.vc_thread = current_thread(); context.vc_ucred = kauth_cred_proc_ref(p); + sessp = proc_session(p); + session_lock(sessp); + cttyflag = sessp->s_flags & S_CTTYREF; + session_unlock(sessp); + /* * A little hack--this device, used by many processes, * happens to do an open on another device, which can * cause unhappiness if the second-level open blocks indefinitely * (as could be the case if the master side has hung up). Since * we know that this driver doesn't care about the serializing - * opens and closes, we can drop the lock. + * opens and closes, we can drop the lock. To avoid opencount leak, + * open the vnode only for the first time. */ - devsw_unlock(dev, S_IFCHR); - error = VNOP_OPEN(ttyvp, flag, &context); - devsw_lock(dev, S_IFCHR); + if (cttyflag == 0) { + devsw_unlock(dev, S_IFCHR); + error = VNOP_OPEN(ttyvp, flag, &context); + devsw_lock(dev, S_IFCHR); + + if (error) + goto out; + + /* + * If S_CTTYREF is set, some other thread did an open + * and was able to set the flag, now perform a close, else + * set the flag. + */ + session_lock(sessp); + if (cttyflag == (sessp->s_flags & S_CTTYREF)) + sessp->s_flags |= S_CTTYREF; + else + doclose = 1; + session_unlock(sessp); + + /* + * We have to take a reference here to make sure a close + * gets called during revoke. Note that once a controlling + * tty gets opened by this driver, the only way close will + * get called is when the session leader , whose controlling + * tty is ttyvp, exits and vnode is revoked. We cannot + * redirect close from this driver because underlying controlling + * terminal might change and close may get redirected to a + * wrong vnode causing panic. + */ + if (doclose) { + devsw_unlock(dev, S_IFCHR); + VNOP_CLOSE(ttyvp, flag, &context); + devsw_lock(dev, S_IFCHR); + } else { + error = vnode_ref(ttyvp); + } + } +out: + session_rele(sessp); vnode_put(ttyvp); kauth_cred_unref(&context.vc_ucred);