Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

[suggestion] endpoints and PIDs

75 views
Skip to first unread message

ko...@fiit.stuba.sk

unread,
Aug 5, 2006, 12:26:14 PM8/5/06
to
Hi,

The purpose of PIDs is to uniquely identify the processes with respect
to UNIX system calls.

The purpose of endpoints is to uniquely identify processes with respect
to Minix IPC primitives, as well as provide mapping to the process
table(s) as well as disambiguation about various processes which might
(over time) occupy the same slot).

Could not and should not there be only a single such identifier? Would
not it make the code a bit smaller? Do you think that this would be a
good idea?

As a side effect of this, if normal user-space Minix processes were
allowed to communicate with each other freely by means of Minix
primitives, they could address each other. PID cannot be used with
`send' and `receive' (or whatever) Minix IPC primitives. This might be
also interesting.

Regards
--
Matej Kosik

GgMariotti

unread,
Aug 6, 2006, 4:56:32 AM8/6/06
to

maybe I'm wrong,but isn'it it a system design decision to have 2
distinct identifiers,one on the outside world and one on the inside?And
the normal user processes,shouldn't they use the usual unix system
calls to communicate with each other to enforce security and to be
POSIX compliant?If you let normal user processes use the MINIX message
primitives,they could freely go on deadlocks;am I wrong?

ko...@fiit.stuba.sk

unread,
Aug 6, 2006, 7:46:18 AM8/6/06
to
GgMariotti wrote:
> ko...@fiit.stuba.sk wrote:
> > Hi,
> >
> > The purpose of PIDs is to uniquely identify the processes with respect
> > to UNIX system calls.
> >
> > The purpose of endpoints is to uniquely identify processes with respect
> > to Minix IPC primitives, as well as provide mapping to the process
> > table(s) as well as disambiguation about various processes which might
> > (over time) occupy the same slot).
> >
> > Could not and should not there be only a single such identifier? Would
> > not it make the code a bit smaller? Do you think that this would be a
> > good idea?
> >
> > As a side effect of this, if normal user-space Minix processes were
> > allowed to communicate with each other freely by means of Minix
> > primitives, they could address each other. PID cannot be used with
> > `send' and `receive' (or whatever) Minix IPC primitives. This might be
> > also interesting.
> >
> > Regards
> > --
> > Matej Kosik
>
> maybe I'm wrong,but isn'it it a system design decision to have 2
> distinct identifiers,one on the outside world and one on the inside?

I admit that this is only a speculation but seeing two distinct unique
identifiers of the same thing instead of one is suspicious. Therefore I
ask if the two cannot be unified. This change would be transparent to
the user-space processes.

(although for humans, those actual endpoint numbers are ugly because
they change drastically over time. However, the programs themselves do
not care. Maybe the generation size could be made smaller so that the
actual endpoint numbers would more resemble PIDs.)

> And
> the normal user processes,shouldn't they use the usual unix system
> calls to communicate with each other to enforce security and to be
> POSIX compliant?If you let normal user processes use the MINIX message
> primitives,they could freely go on deadlocks;am I wrong?

You are right. The reasons why I (in my personal Minix installation)
removed restrictions concerning IPC primitives utilization is because I
wanted to make experiments with other communication primitives I tried
to implement (I am not that far yet) and I wanted to let user-space
processes to use them. Such user-space processes need endpoints.
However, later I found out that there is `getprocnr' system call which
I will try to use to transform PIDs o endpoints. It is not a big
problem.

Current Minix IPC also does not prevent deadlocks. It only isolates the
problem in the system processes and device drivers. Bad user-space
processes cannot cause system-wide deadlocks now. Bad drivers could,
very easily. I think this is a security problem because if you got a
device driver from a third party (perhaps in a binary form), then you
have to trust it (among other things) that it will not cause deadlock.
Ideally, bad driver would cause deadlock solely in the process which
tried to directly or indirectly use it. Not in the whole operating
system.

Philip Homburg

unread,
Aug 7, 2006, 4:09:49 AM8/7/06
to
In article <1154864778....@i42g2000cwa.googlegroups.com>,

ko...@fiit.stuba.sk <ko...@fiit.stuba.sk> wrote:
>(although for humans, those actual endpoint numbers are ugly because
>they change drastically over time. However, the programs themselves do
>not care. Maybe the generation size could be made smaller so that the
>actual endpoint numbers would more resemble PIDs.)

No, if anything, generation numbers should be made bigger to make sure
that endpoints are never re-used.

>Current Minix IPC also does not prevent deadlocks. It only isolates the
>problem in the system processes and device drivers. Bad user-space
>processes cannot cause system-wide deadlocks now. Bad drivers could,
>very easily. I think this is a security problem because if you got a
>device driver from a third party (perhaps in a binary form), then you
>have to trust it (among other things) that it will not cause deadlock.
>Ideally, bad driver would cause deadlock solely in the process which
>tried to directly or indirectly use it. Not in the whole operating
>system.

At the moment, drivers still have too much power to allow completely
untrusted drivers. However, this is work in progress. Over time, drivers
will be more and more contrained to their own sandboxes.

However, I'm not convinced that the Minix message passing mechanism is
a great way to do IPC between user processes.


--
That was it. Done. The faulty Monk was turned out into the desert where it
could believe what it liked, including the idea that it had been hard done
by. It was allowed to keep its horse, since horses were so cheap to make.
-- Douglas Adams in Dirk Gently's Holistic Detective Agency

Ben Gras

unread,
Aug 7, 2006, 8:11:17 AM8/7/06
to
All,

> Could not and should not there be only a single such identifier? Would
> not it make the code a bit smaller? Do you think that this would be a
> good idea?

On the surface, yes.

Reasons this wasn't done, however, are:
. Currently, only PM knows about pids, not the kernel.
. Endpoints have to have maximum wraparound time, pids
can't easily go beyond 30000 without confusing e.g.
the shell.
. The mapping from an endpoint to a process slot and
the verification of generation have to be very fast,
which is very inconvenient for pids, unless we give
pids the human-unfriendly endpoint encoding.
. Endpoint numbers have to be able to be negative (for task
numbers) which has other special meanings for pids.
. Endpoints have other special values, most notably ANY, which
aren't special to pids, but may never correspond to a real
process.

These are the main reasons we have two such identifiers, for now.

=Ben


Armin Steinhoff

unread,
Aug 10, 2006, 11:42:35 AM8/10/06
to
Philip Homburg wrote:
> In article <1154864778....@i42g2000cwa.googlegroups.com>,
> ko...@fiit.stuba.sk <ko...@fiit.stuba.sk> wrote:
>
>>(although for humans, those actual endpoint numbers are ugly because
>>they change drastically over time. However, the programs themselves do
>>not care. Maybe the generation size could be made smaller so that the
>>actual endpoint numbers would more resemble PIDs.)
>
>
> No, if anything, generation numbers should be made bigger to make sure
> that endpoints are never re-used.
>
>
>>Current Minix IPC also does not prevent deadlocks. It only isolates the
>>problem in the system processes and device drivers. Bad user-space
>>processes cannot cause system-wide deadlocks now. Bad drivers could,
>>very easily. I think this is a security problem because if you got a
>>device driver from a third party (perhaps in a binary form), then you
>>have to trust it (among other things) that it will not cause deadlock.
>>Ideally, bad driver would cause deadlock solely in the process which
>>tried to directly or indirectly use it. Not in the whole operating
>>system.
>
>
> At the moment, drivers still have too much power to allow completely
> untrusted drivers. However, this is work in progress. Over time, drivers
> will be more and more contrained to their own sandboxes.
>
> However, I'm not convinced that the Minix message passing mechanism is
> a great way to do IPC between user processes.

Why?? message passing between processes and threads is the default
communication primitive for QNX. And it is very useful!

Regards

--Armin

>
>

Philip Homburg

unread,
Aug 10, 2006, 3:37:46 PM8/10/06
to
In article <ebfk4e$2b4$03$1...@news.t-online.com>,
Armin Steinhoff <a-ste...@web.de> wrote:

>Philip Homburg wrote:
>> However, I'm not convinced that the Minix message passing mechanism is
>> a great way to do IPC between user processes.
>
>Why?? message passing between processes and threads is the default
>communication primitive for QNX. And it is very useful!

I'm not saying that message passing is a bad idea. It is just that the
Minix 3 kernel may not be the right place to implement it for communication
between user processes.

For example, at the moment a receive call will not be interrupted to
invoke a signal handler. Do we want to add code to the kernel to handle
that (and many other problems) or is it better to add some kind of
message passing mechanism to FS?

ko...@fiit.stuba.sk

unread,
Aug 10, 2006, 7:54:39 PM8/10/06
to
Hi,

Philip Homburg wrote:
> In article <ebfk4e$2b4$03$1...@news.t-online.com>,
> Armin Steinhoff <a-ste...@web.de> wrote:
> >Philip Homburg wrote:
> >> However, I'm not convinced that the Minix message passing mechanism is
> >> a great way to do IPC between user processes.
> >
> >Why?? message passing between processes and threads is the default
> >communication primitive for QNX. And it is very useful!
>
> I'm not saying that message passing is a bad idea. It is just that the
> Minix 3 kernel may not be the right place to implement it for communication
> between user processes.
>
> For example, at the moment a receive call will not be interrupted to
> invoke a signal handler. Do we want to add code to the kernel to handle
> that (and many other problems) or is it better to add some kind of
> message passing mechanism to FS?

Forgive me for joining. This discussion is interesting.

I believe that there is nothing wrong on connecting user-space programs
directly via IPC mechanisms provided by the kernel. But even if we
disregard user-space processes, the operating system components (the
kernel, system task, clock, servers, device drivers) must communicate
somehow. Now they communicate by means of
- sendrec
- send
- receive
- notify
- echo
primitives. The question is, if they are all right. I think, these
mechanisms are too weak to avoid problem sketched here:
http://altair.dcs.elf.stuba.sk/wiki/Minix/Toy0
http://altair.dcs.elf.stuba.sk/~kosik/minix/toys/toy0/toy0.c.txt
If I run a driver created by (possibly malicious) third party, that
driver can do many bad things I can't prevent him to do. One of the bad
things is that he can cause denial of service---as shown in the `toy0'
example. Does this problem deserve to be solved?

One possible way I would like to explore is relying on different set of
communication primitives. I would like to add these:
- post .... asynchronous send (don't block)
- fetch .... pop a message from own mailbox (if there is any, otherwise
block)
These two are already implemented and tested a bit. I am not yet sure
what to do if during `post' dynamic allocation of a necessary memory
chunk for buffering the message to be posted fails (the pool of free
atoms is exhausted). Should the `post' call simply fail (as now) or
should it block? That is open. Open issue also is how big the pool
should be.

It seems to me obvious that the two other IPC primitives
- validate .... mark specific remote chunk of memory as valid
- when .... block until a given chunk of memory in local address space
becomes valid (unless it already is valid) are needed.

Maybe with these IPC primitives it would be impossible to write such a
device driver which could cause denial of service of the whole system.
The FS simply tells the driver what to do and will not block. The only
bad thing such driver could do is that
- it either lets user-process (which indirectly via FS requested its
service) blocked for ever
- or it gives it a nonsense data

Banning of arbitrary scribbling over remote address space could be
later perhaps also implemented. But that is a different problem I am
not dealing with now.

These ideas are premature but this partially why I think Minix is
interesting.
--
Matej

Philip Homburg

unread,
Aug 12, 2006, 10:59:41 AM8/12/06
to
In article <1155254079.9...@p79g2000cwp.googlegroups.com>,

ko...@fiit.stuba.sk <ko...@fiit.stuba.sk> wrote:
>I believe that there is nothing wrong on connecting user-space programs
>directly via IPC mechanisms provided by the kernel.
[...]

>The question is, if they are all right. I think, these
>mechanisms are too weak to avoid problem sketched here:
>http://altair.dcs.elf.stuba.sk/wiki/Minix/Toy0
>http://altair.dcs.elf.stuba.sk/~kosik/minix/toys/toy0/toy0.c.txt
>If I run a driver created by (possibly malicious) third party, that
>driver can do many bad things I can't prevent him to do. One of the bad
>things is that he can cause denial of service---as shown in the `toy0'
>example. Does this problem deserve to be solved?

For drivers, it is still an open question whether drivers should be
assumed to be buggy, or malicious.

On current PC hardware, malicious drivers for PCI hardware are a problem.
PCI devices have full access to system memory, and in many cases, bus
master DMA allows the driver to change arbitrary memory locations.

To make things worse, there is also the possibility of denial of service
attacks through interrupt sharing. And it is sometimes suggested that
locking on PCI bus also cause problems (but I don't know the details).

On top of that there are large amounts of code in Minix that do not
validate the contents of messages well enough to handle malicious drivers.

In other words, the problem is much bigger than just the message
passing primitives.

If you can't solve one part (especially the PCI bus master part) you have
to drop the assumption that drivers are malicious, otherwise, you end
up with an insecure system.

>One possible way I would like to explore is relying on different set of
>communication primitives. I would like to add these:
>- post .... asynchronous send (don't block)
>- fetch .... pop a message from own mailbox (if there is any, otherwise
>block)
>These two are already implemented and tested a bit.

Unfortunately, this does not really change anything in your example. The
systems hangs with the toy0 driver because FS remains forever blocked in
a receive call. Your 'fetch' primitive is already available in the
form of 'receive(ANY, ...)'. However, limiting FS to just receive(ANY, ...)
call requires significant changes to FS.

>These two are already implemented and tested a bit. I am not yet sure
>what to do if during `post' dynamic allocation of a necessary memory
>chunk for buffering the message to be posted fails (the pool of free
>atoms is exhausted).

But this is the thing you should know before implementing things. Certainly
when drivers are assumed to be malicious, you have to assume that buffers
will be full most of the time. And you have to be able to guarantee that
the system remains available when that happens.

>It seems to me obvious that the two other IPC primitives
>- validate .... mark specific remote chunk of memory as valid
>- when .... block until a given chunk of memory in local address space
>becomes valid (unless it already is valid) are needed.

>Banning of arbitrary scribbling over remote address space could be


>later perhaps also implemented. But that is a different problem I am
>not dealing with now.

Something like this has been implemented recently in Minix 3. The basic
model is that a process can export part of its address space to
another process.

I note that you didn't say anything specific about whether making the kernel
IPC calls available for general IPC between user processes is a good idea
or not.

Independent of device driver security, issues like interaction with signals
still require additional code in the kernel.

ko...@fiit.stuba.sk

unread,
Aug 14, 2006, 6:28:56 PM8/14/06
to

Ability to plug in drivers whom we do not have to trust would be nice.
If it is physically impossible, it is a pity. Thank you for pointing
this out.

>
> >One possible way I would like to explore is relying on different set of
> >communication primitives. I would like to add these:
> >- post .... asynchronous send (don't block)
> >- fetch .... pop a message from own mailbox (if there is any, otherwise
> >block)
> >These two are already implemented and tested a bit.
>
> Unfortunately, this does not really change anything in your example. The
> systems hangs with the toy0 driver because FS remains forever blocked in
> a receive call. Your 'fetch' primitive is already available in the
> form of 'receive(ANY, ...)'.

Almost, but not completely. Doing `fetch' does not involve (such)
synchronization with the sender of the fetched message. The message (if
there is any) is simply withdrawn from the head of the mailbox. Each
process has (naturally) its own mailbox.

The employed communication if some process tries to read from (e.g.)
/dev/mem could be:

- the client process posts FS its request
(file descriptor, read operation, where to store the read data)
it would not be blocked at this moment yet
- it could (immediatelly or anytime later) perform a IPC primitive
which would block this client until designated memory area is "valid"
(i.e. filled with data this client wanted).
- FS would find out which device driver is responsible and it would
forward it this request
(FS would not block because it does not care anymore what happens
next)
- the device driver would do all the necessary stuff and finally copy
proper data to the remote memory region
- the device driver would (with special IPC primitive) mark that memory
region as valid (this unblocks the client waiting on that region to be
validated).

That semantics of `post', `fetch', `wait' and `validate' is imprecise
but hopefully you guess what I mean.

The SEND and RECEIVE primitives are advantageous because there is no
need for buffers. But they impose many restrictions. For example
- processes must be partially ordered and the "lower" processes cannot
SEND messages to processes above them. If there exists such a partial
order, everything is fine (although a bit restricting). Did anyone
check this property for Minix (if it has sense)? It it does not hold,
there could be deadlock hazards. This is why you seem to use
`lock_notify' when you talk from KERNEL to some process above it (e.g.
in `kputc'). This might seem as a hack a bit.
- the SEND always blocks the sender if the receiver is not in the
RECEIVING state. If the sender is not interested in the result of that
operation (because it is not its business or because it will reveal it
in some other way), it will be unnecessarly blocked and cannot continue
to do some useful stuff of its own.

Is somewhere comparison of various possible useful IPC primitives and
why Minix has those current ones or some kind of explanation of this
decision?

Different IPC mechanisms are also described here
http://www.erights.org/talks/thesis/index.html
(see for example: §2.5, §2.6, §16.1, §16.2, §19.3)
They are more useful for distributed systems although I could very much
image their usefulness for communication among normal processes
residing on the same computer. I am not sure, though, if they are
suitable communication means in case of microkernel servers. Initially
I hoped so but now I am not sure. I do not know what others thing about
it.

Ben Gras

unread,
Aug 15, 2006, 3:45:22 AM8/15/06
to
All,

> Did anyone
> check this property for Minix (if it has sense)? It it does not hold,
> there could be deadlock hazards. This is why you seem to use
> `lock_notify' when you talk from KERNEL to some process above it (e.g.
> in `kputc'). This might seem as a hack a bit.

No, that's something else. The 'notify' primitive is different from
send and receive. notify doesn't block the sender, and generates a
pseudomessage at the receiver. The lock_* functions are called that
because they disable interrupts, which processes in kernel address
space have to use because they access shared data structures.

It is true, indeed, that one of the applications of notifies is to get
the attention (because no actual message can be sent, it's just a ping)
of a process without risking deadlocks.

=Ben


0 new messages