From: Jef Driesen on
On 29/01/2010 13:41, David Schwartz wrote:
> On Jan 29, 3:11 am, Jef Driesen<jefdrie...(a)hotmail.com.invalid>
> wrote:
>
>> I have another "client" application that wants to communicate with the
>> simulated device, by opening the slave side of the pty. Since I don't
>> want any other process to interfere with the communication, I would like
>> to set TIOCEXCL. So that any other process is denied access, including
>> another instance of my own client app.
>
> But that's not what you want. You want another instance of your client
> app to be allowed access if and only if the previous instance has
> terminated. In other words, you want something unusual.

That's not entirely correct.

What I want is that if my app is terminated, the pty slave becomes
available again to any other process, not only a new instance of my app.
Thus I don't want my application to be treated special.

>> The current situation with a shared TIOCEXCL flag, is that the slave pty
>> remains locked, and any other process that attempts to communicate with
>> my server app will fail with EBUSY. Thus the server process is still
>> running, but it can't accept new connections. Since it doesn't know the
>> client app has disconnected, the only thing I can do is manually kill
>> the server process and restart it. But the kernel does know that the
>> client app has disconnected!
>
> Right, so code what you want. You want something unusual, so code it.
> It won't happen by magic.

One of the reasons why I started this topic is that I don't know how to
workaround the issue. Clearing the TIOCEXCL on close only works if the
app exits properly. And that doesn't always happen.

>> Now imagine that we replace the pty with a socket. If a client app
>> closes the socket, I expect that another client can connect. Not that
>> the server app remains locked.
>
> Right, but if you add another process that also holds a handle to the
> same connection, that's not what you'll get.

If there is a second process that holds a handle to the same slave pty,
my handle isn't the last one and the TIOCEXCL flag doesn't need to be
cleared. Actually my reason for using TIOCEXCL is to make sure there can
only be one process at a time.

> You'd be mighty pissed if you didn't realize this issue and some
> malicious program managed to crash your client side and then open your
> pty while it's still connected to the same master!

If some malicious program manages to crash my client app, and then opens
the pty, that's fine for me. That's not what I want to protect against.
I only want to make sure that while my app is communicating, no other
process can accidentally mess up the communication by reading/writing
data from/to the pty.

A common scenario is that I have a number of simulator apps running in
parallel, to be able to run a few tests in parallel. But sometimes I try
to connect a client app A to a simulator that is still communicating
with another client app B. Since that will screw up the communication
with app B, I would like to see that app A fails to open the pty.
From: Rainer Weikusat on
Jef Driesen <jefdriesen(a)hotmail.com.invalid> writes:

[...]

> I fully understand that the kernel can only release resources at the
> last close. But in my situation, when the client app closes the slave
> pty, that was the last reference. Of course the server app still has
> the master pty open. So the kernel obviously can't release the entire
> pty, but it can release slave side resources such as the TIOCEXCL
> flag.

The tty_ioctl(4) man page documents TIOCEXCL as

Exclusive mode
TIOCEXCL void
Put the tty into exclusive mode. No further open(2)
operations on the terminal are permitted.

This makes some sense when understanding the historical context: A
'tty device' is associated with some 'channel' (eg, a modem or a real
terminal) which allows user logins into the system and it is
implicitly closed when the user logs out and then reopened by getty
(running as root). I assume that the purpose of this flag was mainly
to implement mesg (=> mesg(1)) so that users can block other users
from 'talking' to them with write (=> write(1)). That's arguably not
what you want and what you would like to have isn't unreasonable per
se but it is documented in this way and hence, must be a feature :->
From: Rainer Weikusat on
Jef Driesen <jefdriesen(a)hotmail.com.invalid> writes:
> On 29/01/2010 13:41, David Schwartz wrote:

[...]

> One of the reasons why I started this topic is that I don't know how
> to workaround the issue. Clearing the TIOCEXCL on close only works if
> the app exits properly. And that doesn't always happen.

The simple workaround for this is to open the pty, set the flag, fork
and let the child continue with running the program while the parent
waits until the child dies (and then clears the flag before exiting
itself).

[...]

> A common scenario is that I have a number of simulator apps running in
> parallel, to be able to run a few tests in parallel. But sometimes I
> try to connect a client app A to a simulator that is still
> communicating with another client app B. Since that will screw up the
> communication with app B, I would like to see that app A fails to open
> the pty.

A better solution for this could be to try to acquire a fcntl-style
lock on the pty file descriptor. This won't help against 'rogue
processes' which don't implement the same locking protocol for
accessing the device, but it would be sufficient for this situation
(and released automatically once a descriptor refering to the pty is
closed, which happens automatically when the process terminates).
From: David Schwartz on
On Jan 29, 5:37 am, Jef Driesen <jefdrie...(a)hotmail.com.invalid>
wrote:

> One of the reasons why I started this topic is that I don't know how to
> workaround the issue. Clearing the TIOCEXCL on close only works if the
> app exits properly. And that doesn't always happen.

Code exactly the behavior you want. If your app terminates abnormally,
have another application clear the TIOCEXCL flag.

> If some malicious program manages to crash my client app, and then opens
> the pty, that's fine for me. That's not what I want to protect against.
> I only want to make sure that while my app is communicating, no other
> process can accidentally mess up the communication by reading/writing
> data from/to the pty.

Right, you have very, very unusual requirements. It would be strange
if the system magically just happened to meet them. In fact, the
system meets the more common set of requirements where you want to
ensure you have exclusive access to the pty until the pty is released.

Code what you want.

DS
From: Jef Driesen on
On 29/01/2010 14:55, Rainer Weikusat wrote:
> Jef Driesen<jefdriesen(a)hotmail.com.invalid> writes:
>> On 29/01/2010 13:41, David Schwartz wrote:
>
> [...]
>
>> One of the reasons why I started this topic is that I don't know how
>> to workaround the issue. Clearing the TIOCEXCL on close only works if
>> the app exits properly. And that doesn't always happen.
>
> The simple workaround for this is to open the pty, set the flag, fork
> and let the child continue with running the program while the parent
> waits until the child dies (and then clears the flag before exiting
> itself).

I can't do that, because the pty code is part of a library. Thus the
code can be called from many types of applications (gui, multithreaded,
etc) and therefore I can't fork.

> [...]
>
>> A common scenario is that I have a number of simulator apps running in
>> parallel, to be able to run a few tests in parallel. But sometimes I
>> try to connect a client app A to a simulator that is still
>> communicating with another client app B. Since that will screw up the
>> communication with app B, I would like to see that app A fails to open
>> the pty.
>
> A better solution for this could be to try to acquire a fcntl-style
> lock on the pty file descriptor. This won't help against 'rogue
> processes' which don't implement the same locking protocol for
> accessing the device, but it would be sufficient for this situation
> (and released automatically once a descriptor refering to the pty is
> closed, which happens automatically when the process terminates).

That would work fine in my development environment (e.g. the scenario I
described above). But it won't work to protect against apps that do not
use the fcntl locking. And those are the reason why I was looking after
TIOCEXCL in the first place :-)