summaryrefslogtreecommitdiff
path: root/debian/patches/protected_payload.patch
blob: f3bb45defbc9a1b116202d23e76334f9f8cdd218 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
diff --git a/doc/mach.texi b/doc/mach.texi
index d089224..6167b4b 100644
--- a/doc/mach.texi
+++ b/doc/mach.texi
@@ -1330,6 +1330,15 @@ which is conventionally used as a reply port by the recipient of the
 message.  The field must carry a send right, a send-once right,
 @code{MACH_PORT_NULL}, or @code{MACH_PORT_DEAD}.
 
+@item mach_port_t msgh_protected_payload
+The @code{msgh_protected_payload} field carries a payload that is set
+by the kernel during message delivery.  The payload is an opaque
+identifier that can be used by the receiver to lookup the associated
+data structure.
+
+It is only valid in received messages.  See @ref{Message Receive} for
+further information.
+
 @item mach_port_seqno_t msgh_seqno
 The @code{msgh_seqno} field provides a sequence number for the message.
 It is only valid in received messages; its value in sent messages is
@@ -1417,6 +1426,7 @@ types are predefined:
 @item MACH_MSG_TYPE_STRING
 @item MACH_MSG_TYPE_STRING_C
 @item MACH_MSG_TYPE_PORT_NAME
+@item MACH_MSG_TYPE_PROTECTED_PAYLOAD
 @end table
 
 The following predefined types specify port rights, and receive special
@@ -1435,6 +1445,11 @@ should be used in preference to @code{MACH_MSG_TYPE_INTEGER_32}.
 @item MACH_MSG_TYPE_MAKE_SEND_ONCE
 @end table
 
+The type @code{MACH_MSG_TYPE_PROTECTED_PAYLOAD} is used by the kernel
+to indicate that a delivered message carries a payload in the
+@code{msgh_protected_payload} field.  See @ref{Message Receive} for
+more information.
+
 @item msgt_size : 8
 The @code{msgt_size} field specifies the size of each datum, in bits.  For
 example, the msgt_size of @code{MACH_MSG_TYPE_INTEGER_32} data is 32.
@@ -1934,6 +1949,25 @@ loses the receive right after the message was dequeued from it, then
 right still exists, but isn't held by the caller, then
 @code{msgh_local_port} specifies @code{MACH_PORT_NULL}.
 
+Servers usually associate some state with a receive right.  To that
+end, they might use a hash table to look up the state for the port a
+message was sent to.  To optimize this, a task may associate an opaque
+@var{payload} with a receive right using the
+@code{mach_port_set_protected_payload} function.  Once this is done,
+the kernel will set the @code{msgh_protected_payload} field to
+@var{payload} when delivering a message to this right and indicate
+this by setting the local part of @code{msgh_bits} to
+@code{MACH_MSG_TYPE_PROTECTED_PAYLOAD}.
+
+The support for protected payloads was added to GNU Mach.  To preserve
+binary compatibility, the @code{msgh_local_port} and
+@code{msgh_local_port} share the same location.  This makes it
+possible to add the payload information without increasing the size of
+@code{mach_msg_header_t}.  This is an implementation detail.  Which
+field is valid is determined by the local part of the
+@code{msgh_bits}.  Existing software is not affected.  When a receive
+right is transferred to another task, its payload is cleared.
+
 Received messages are stamped with a sequence number, taken from the
 port from which the message was received.  (Messages received from a
 port set are stamped with a sequence number from the appropriate member
@@ -2715,6 +2749,41 @@ In addition to the normal diagnostic return codes from the call's server
 (normally the kernel), the call may return @code{mach_msg} return codes.
 @end deftypefun
 
+@deftypefun kern_return_t mach_port_set_protected_payload (@w{ipc_space_t @var{task}}, @w{mach_port_t @var{name}}, @w{unsigned long @var{payload}})
+The function @code{mach_port_set_protected_payload} sets the protected
+payload associated with the right @var{name} to @var{payload}.
+Section @ref{Message Receive} describes how setting a protected
+payload affects the messages delivered to @var{name}.
+
+The function returns @code{KERN_SUCCESS} if the call succeeded,
+@code{KERN_INVALID_TASK} if @var{task} was invalid,
+@code{KERN_INVALID_NAME} if @var{name} did not denote a right and
+@code{KERN_INVALID_RIGHT} if @var{name} denoted a right, but not a
+receive right.
+
+The @code{mach_port_set_protected_payload} call is actually an RPC to
+@var{task}, normally a send right for a task port, but potentially any
+send right.  In addition to the normal diagnostic return codes from
+the call's server (normally the kernel), the call may return
+@code{mach_msg} return codes.
+@end deftypefun
+
+@deftypefun kern_return_t mach_port_clear_protected_payload (@w{ipc_space_t @var{task}}, @w{mach_port_t @var{name}}, @w{unsigned long @var{payload}})
+The function @code{mach_port_clear_protected_payload} clears the
+protected payload associated with the right @var{name}.
+
+The function returns @code{KERN_SUCCESS} if the call succeeded,
+@code{KERN_INVALID_TASK} if @var{task} was invalid,
+@code{KERN_INVALID_NAME} if @var{name} did not denote a right and
+@code{KERN_INVALID_RIGHT} if @var{name} denoted a right, but not a
+receive right.
+
+The @code{mach_port_clear_protected_payload} call is actually an RPC
+to @var{task}, normally a send right for a task port, but potentially
+any send right.  In addition to the normal diagnostic return codes
+from the call's server (normally the kernel), the call may return
+@code{mach_msg} return codes.
+@end deftypefun
 
 @node Port Sets
 @subsection Port Sets
diff --git a/include/mach/mach_port.defs b/include/mach/mach_port.defs
index 769d892..c7e8526 100644
--- a/include/mach/mach_port.defs
+++ b/include/mach/mach_port.defs
@@ -349,3 +349,21 @@ skip; /* mach_port_create_act */
 
 #endif /* MIGRATING_THREADS */
 
+/*
+ *	Only valid for receive rights.
+ *	Set the protected payload for this right to the given value.
+ */
+
+routine mach_port_set_protected_payload(
+		task		: ipc_space_t;
+		name		: mach_port_name_t;
+		payload		: natural_t);
+
+/*
+ *	Only valid for receive rights.
+ *	Clear the protected payload for this right.
+ */
+
+routine mach_port_clear_protected_payload(
+		task		: ipc_space_t;
+		name		: mach_port_name_t);
diff --git a/include/mach/mach_types.defs b/include/mach/mach_types.defs
index bfce6cb..85ad653 100644
--- a/include/mach/mach_types.defs
+++ b/include/mach/mach_types.defs
@@ -139,6 +139,9 @@ type memory_object_t = mach_port_t
 #ifdef	MEMORY_OBJECT_INTRAN
 		intran: MEMORY_OBJECT_INTRAN
 #endif
+#ifdef	MEMORY_OBJECT_INTRAN_PAYLOAD
+		intranpayload: MEMORY_OBJECT_INTRAN_PAYLOAD
+#endif
 #ifdef	MEMORY_OBJECT_OUTTRAN
 		outtran: MEMORY_OBJECT_OUTTRAN
 #endif
diff --git a/include/mach/memory_object.defs b/include/mach/memory_object.defs
index 0ed8dbc..c6c1921 100644
--- a/include/mach/memory_object.defs
+++ b/include/mach/memory_object.defs
@@ -93,6 +93,10 @@ simpleroutine	memory_object_terminate(
 #ifdef	MEMORY_OBJECT_INTRAN
 						intran: MEMORY_OBJECT_INTRAN
 #endif
+#ifdef	MEMORY_OBJECT_INTRAN_PAYLOAD
+						intranpayload:
+						MEMORY_OBJECT_INTRAN_PAYLOAD
+#endif
 						;
 #if	SEQNOS
 	msgseqno seqno			: mach_port_seqno_t;
@@ -233,6 +237,9 @@ simpleroutine	memory_object_lock_completed(
 #ifdef	MEMORY_OBJECT_INTRAN
 			intran: MEMORY_OBJECT_INTRAN
 #endif
+#ifdef	MEMORY_OBJECT_INTRAN_PAYLOAD
+			intranpayload: MEMORY_OBJECT_INTRAN_PAYLOAD
+#endif
 			;
 #if	SEQNOS
 	msgseqno seqno			: mach_port_seqno_t;
@@ -268,6 +275,9 @@ simpleroutine	memory_object_supply_completed(
 #ifdef	MEMORY_OBJECT_INTRAN
 			intran: MEMORY_OBJECT_INTRAN
 #endif
+#ifdef	MEMORY_OBJECT_INTRAN_PAYLOAD
+			intranpayload: MEMORY_OBJECT_INTRAN_PAYLOAD
+#endif
 			;
 #if	SEQNOS
 	msgseqno seqno			: mach_port_seqno_t;
@@ -318,6 +328,9 @@ simpleroutine	memory_object_change_completed(
 #ifdef	MEMORY_OBJECT_INTRAN
 			intran: MEMORY_OBJECT_INTRAN
 #endif
+#ifdef	MEMORY_OBJECT_INTRAN_PAYLOAD
+			intranpayload: MEMORY_OBJECT_INTRAN_PAYLOAD
+#endif
 			;
 #if	SEQNOS
 	msgseqno seqno			: mach_port_seqno_t;
diff --git a/include/mach/message.h b/include/mach/message.h
index f78e978..0a7297e 100644
--- a/include/mach/message.h
+++ b/include/mach/message.h
@@ -136,7 +136,10 @@ typedef	struct {
     mach_msg_bits_t	msgh_bits;
     mach_msg_size_t	msgh_size;
     mach_port_t		msgh_remote_port;
-    mach_port_t		msgh_local_port;
+    union {
+        mach_port_t	msgh_local_port;
+        unsigned long	msgh_protected_payload;
+    };
     mach_port_seqno_t	msgh_seqno;
     mach_msg_id_t	msgh_id;
 } mach_msg_header_t;
@@ -253,7 +256,9 @@ typedef	struct	{
 #define MACH_MSG_TYPE_PORT_SEND		MACH_MSG_TYPE_MOVE_SEND
 #define MACH_MSG_TYPE_PORT_SEND_ONCE	MACH_MSG_TYPE_MOVE_SEND_ONCE
 
-#define MACH_MSG_TYPE_LAST		22		/* Last assigned */
+#define MACH_MSG_TYPE_PROTECTED_PAYLOAD	23
+
+#define MACH_MSG_TYPE_LAST		23		/* Last assigned */
 
 /*
  *  A dummy value.  Mostly used to indicate that the actual value
diff --git a/include/mach/notify.defs b/include/mach/notify.defs
index e06f6b4..37229a4 100644
--- a/include/mach/notify.defs
+++ b/include/mach/notify.defs
@@ -28,6 +28,10 @@ subsystem notify 64;
 
 #include <mach/std_types.defs>
 
+#ifdef NOTIFY_IMPORTS
+NOTIFY_IMPORTS
+#endif
+
 #if	SEQNOS
 serverprefix do_seqnos_;
 serverdemux seqnos_notify_server;
@@ -37,7 +41,20 @@ serverdemux notify_server;
 #endif	SEQNOS
 
 type notify_port_t = MACH_MSG_TYPE_MOVE_SEND_ONCE
-	ctype: mach_port_t;
+	ctype: mach_port_t
+#ifdef	NOTIFY_INTRAN
+	intran: NOTIFY_INTRAN
+#endif
+#ifdef	NOTIFY_INTRAN_PAYLOAD
+	intranpayload: NOTIFY_INTRAN_PAYLOAD
+#endif
+#ifdef	NOTIFY_OUTTRAN
+	outtran: NOTIFY_OUTTRAN
+#endif
+#ifdef	NOTIFY_DESTRUCTOR
+	destructor: NOTIFY_DESTRUCTOR
+#endif
+;
 
 /* MACH_NOTIFY_FIRST: 0100 */
 skip;
diff --git a/ipc/ipc_kmsg.c b/ipc/ipc_kmsg.c
index 06cec72..71a0d74 100644
--- a/ipc/ipc_kmsg.c
+++ b/ipc/ipc_kmsg.c
@@ -1799,9 +1799,17 @@ ipc_kmsg_copyout_header(
 		} else
 			ip_unlock(dest);
 
-		msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
-				  MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND));
-		msg->msgh_local_port = dest_name;
+		if (! ipc_port_flag_protected_payload(dest)) {
+			msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
+				MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND));
+			msg->msgh_local_port = dest_name;
+		} else {
+			msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
+				MACH_MSGH_BITS(
+					0, MACH_MSG_TYPE_PROTECTED_PAYLOAD));
+			msg->msgh_protected_payload =
+				dest->ip_protected_payload;
+		}
 		msg->msgh_remote_port = MACH_PORT_NULL;
 		return MACH_MSG_SUCCESS;
 	    }
@@ -1897,10 +1905,18 @@ ipc_kmsg_copyout_header(
 		} else
 			ip_unlock(dest);
 
-		msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
-				  MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE,
-						 MACH_MSG_TYPE_PORT_SEND));
-		msg->msgh_local_port = dest_name;
+		if (! ipc_port_flag_protected_payload(dest)) {
+			msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
+				MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE,
+					       MACH_MSG_TYPE_PORT_SEND));
+			msg->msgh_local_port = dest_name;
+		} else {
+			msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
+				MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE,
+					MACH_MSG_TYPE_PROTECTED_PAYLOAD));
+			msg->msgh_protected_payload =
+				dest->ip_protected_payload;
+		}
 		msg->msgh_remote_port = reply_name;
 		return MACH_MSG_SUCCESS;
 	    }
@@ -1932,9 +1948,18 @@ ipc_kmsg_copyout_header(
 			dest_name = MACH_PORT_NULL;
 		}
 
-		msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
-			MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND_ONCE));
-		msg->msgh_local_port = dest_name;
+		if (! ipc_port_flag_protected_payload(dest)) {
+			msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
+				MACH_MSGH_BITS(0,
+					MACH_MSG_TYPE_PORT_SEND_ONCE));
+			msg->msgh_local_port = dest_name;
+		} else {
+			msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
+				MACH_MSGH_BITS(0,
+					MACH_MSG_TYPE_PROTECTED_PAYLOAD));
+			msg->msgh_protected_payload =
+				dest->ip_protected_payload;
+		}
 		msg->msgh_remote_port = MACH_PORT_NULL;
 		return MACH_MSG_SUCCESS;
 	    }
@@ -2224,9 +2249,16 @@ ipc_kmsg_copyout_header(
 	if (IP_VALID(reply))
 		ipc_port_release(reply);
 
-	msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
-			  MACH_MSGH_BITS(reply_type, dest_type));
-	msg->msgh_local_port = dest_name;
+	if (! ipc_port_flag_protected_payload(dest)) {
+		msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
+				  MACH_MSGH_BITS(reply_type, dest_type));
+		msg->msgh_local_port = dest_name;
+	} else {
+		msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
+				  MACH_MSGH_BITS(reply_type,
+					MACH_MSG_TYPE_PROTECTED_PAYLOAD));
+		msg->msgh_protected_payload = dest->ip_protected_payload;
+	}
 	msg->msgh_remote_port = reply_name;
     }
 
diff --git a/ipc/ipc_object.c b/ipc/ipc_object.c
index 982bd4e..db6ef01 100644
--- a/ipc/ipc_object.c
+++ b/ipc/ipc_object.c
@@ -481,6 +481,7 @@ ipc_object_copyin_from_kernel(
 
 		port->ip_receiver_name = MACH_PORT_NULL;
 		port->ip_destination = IP_NULL;
+		ipc_port_flag_protected_payload_clear(port);
 		ip_unlock(port);
 		break;
 	    }
diff --git a/ipc/ipc_object.h b/ipc/ipc_object.h
index adf5bca..b83bb5a 100644
--- a/ipc/ipc_object.h
+++ b/ipc/ipc_object.h
@@ -57,7 +57,9 @@ typedef struct ipc_object {
 #define	IO_VALID(io)		(((io) != IO_NULL) && ((io) != IO_DEAD))
 
 #define	IO_BITS_KOTYPE		0x0000ffff	/* used by the object */
-#define IO_BITS_OTYPE		0x7fff0000 	/* determines a cache */
+#define IO_BITS_OTYPE		0x3fff0000 	/* determines a cache */
+/* The following masks are used to store attributes of ipc ports.  */
+#define	IO_BITS_PROTECTED_PAYLOAD	0x40000000	/* pp set? */
 #define	IO_BITS_ACTIVE		0x80000000U	/* is object alive? */
 
 #define	io_active(io)		((int)(io)->io_bits < 0)	/* hack */
diff --git a/ipc/ipc_port.c b/ipc/ipc_port.c
index 78211e6..89a5d67 100644
--- a/ipc/ipc_port.c
+++ b/ipc/ipc_port.c
@@ -423,6 +423,44 @@ ipc_port_set_seqno(
 }
 
 /*
+ *	Routine:	ipc_port_set_protected_payload
+ *	Purpose:
+ *		Changes a port's protected payload.
+ *	Conditions:
+ *		The port is locked and active.
+ */
+
+void
+ipc_port_set_protected_payload(ipc_port_t port, unsigned long payload)
+{
+	ipc_mqueue_t mqueue;
+
+	mqueue = ipc_port_lock_mqueue(port);
+	port->ip_protected_payload = payload;
+	ipc_port_flag_protected_payload_set(port);
+	imq_unlock(mqueue);
+}
+
+/*
+ *	Routine:	ipc_port_clear_protected_payload
+ *	Purpose:
+ *		Clear a port's protected payload.
+ *	Conditions:
+ *		The port is locked and active.
+ */
+
+void
+ipc_port_clear_protected_payload(ipc_port_t port)
+{
+	ipc_mqueue_t mqueue;
+
+	mqueue = ipc_port_lock_mqueue(port);
+	ipc_port_flag_protected_payload_clear(port);
+	imq_unlock(mqueue);
+}
+
+
+/*
  *	Routine:	ipc_port_clear_receiver
  *	Purpose:
  *		Prepares a receive right for transmission/destruction.
@@ -491,6 +529,8 @@ ipc_port_init(
 	port->ip_seqno = 0;
 	port->ip_msgcount = 0;
 	port->ip_qlimit = MACH_PORT_QLIMIT_DEFAULT;
+	ipc_port_flag_protected_payload_clear(port);
+	port->ip_protected_payload = 0;
 
 	ipc_mqueue_init(&port->ip_messages);
 	ipc_thread_queue_init(&port->ip_blocked);
@@ -613,6 +653,7 @@ ipc_port_destroy(
 		/* make port be in limbo */
 		port->ip_receiver_name = MACH_PORT_NULL;
 		port->ip_destination = IP_NULL;
+		ipc_port_flag_protected_payload_clear(port);
 		ip_unlock(port);
 
 		if (!ipc_port_check_circularity(port, pdrequest)) {
@@ -1215,6 +1256,11 @@ ipc_port_print(port)
 
 	indent += 2;
 
+	iprintf("flags ");
+	printf("has_protected_payload=%d",
+	       ipc_port_flag_protected_payload(port));
+	printf("\n");
+
 	ipc_object_print(&port->ip_object);
 	iprintf("receiver=0x%x", port->ip_receiver);
 	printf(", receiver_name=0x%x\n", port->ip_receiver_name);
@@ -1237,6 +1283,8 @@ ipc_port_print(port)
 	printf(", sndrs=0x%x", port->ip_blocked.ithq_base);
 	printf(", kobj=0x%x\n", port->ip_kobject);
 
+	iprintf("protected_payload=%p\n", (void *) port->ip_protected_payload);
+
 	indent -= 2;
 }
 
diff --git a/ipc/ipc_port.h b/ipc/ipc_port.h
index 27d2e49..125fefc 100644
--- a/ipc/ipc_port.h
+++ b/ipc/ipc_port.h
@@ -48,6 +48,7 @@
 #include <ipc/ipc_mqueue.h>
 #include <ipc/ipc_table.h>
 #include <ipc/ipc_thread.h>
+#include <ipc/ipc_object.h>
 #include "ipc_target.h"
 #include <mach/rpc.h>
 
@@ -96,6 +97,7 @@ struct ipc_port {
 	mach_port_msgcount_t ip_msgcount;
 	mach_port_msgcount_t ip_qlimit;
 	struct ipc_thread_queue ip_blocked;
+	unsigned long ip_protected_payload;
 };
 
 #define ip_object		ip_target.ipt_object
@@ -262,6 +264,12 @@ extern void
 ipc_port_set_seqno(ipc_port_t, mach_port_seqno_t);
 
 extern void
+ipc_port_set_protected_payload(ipc_port_t, unsigned long);
+
+extern void
+ipc_port_clear_protected_payload(ipc_port_t);
+
+extern void
 ipc_port_clear_receiver(ipc_port_t);
 
 extern void
@@ -325,4 +333,23 @@ ipc_port_dealloc_special(ipc_port_t, ipc_space_t);
 #define	ipc_port_release(port)		\
 		ipc_object_release(&(port)->ip_object)
 
+extern inline boolean_t
+ipc_port_flag_protected_payload(const struct ipc_port *port)
+{
+	return !! (port->ip_target.ipt_object.io_bits
+		   & IO_BITS_PROTECTED_PAYLOAD);
+}
+
+extern inline void
+ipc_port_flag_protected_payload_set(struct ipc_port *port)
+{
+	port->ip_target.ipt_object.io_bits |= IO_BITS_PROTECTED_PAYLOAD;
+}
+
+extern inline void
+ipc_port_flag_protected_payload_clear(struct ipc_port *port)
+{
+	port->ip_target.ipt_object.io_bits &= ~IO_BITS_PROTECTED_PAYLOAD;
+}
+
 #endif	/* _IPC_IPC_PORT_H_ */
diff --git a/ipc/ipc_right.c b/ipc/ipc_right.c
index 77a68ce..503eb1f 100644
--- a/ipc/ipc_right.c
+++ b/ipc/ipc_right.c
@@ -1432,6 +1432,12 @@ ipc_right_copyin(
 
 		port->ip_receiver_name = MACH_PORT_NULL;
 		port->ip_destination = IP_NULL;
+
+		/*
+		 *	Clear the protected payload field to retain
+		 *	the behavior of mach_msg.
+		 */
+		ipc_port_flag_protected_payload_clear(port);
 		ip_unlock(port);
 
 		*objectp = (ipc_object_t) port;
@@ -1932,6 +1938,12 @@ ipc_right_copyout(
 		port->ip_receiver_name = name;
 		port->ip_receiver = space;
 
+		/*
+		 *	Clear the protected payload field to retain
+		 *	the behavior of mach_msg.
+		 */
+		ipc_port_flag_protected_payload_clear(port);
+
 		assert((bits & MACH_PORT_TYPE_RECEIVE) == 0);
 
 		if (bits & MACH_PORT_TYPE_SEND) {
diff --git a/ipc/mach_msg.c b/ipc/mach_msg.c
index 01d974b..1e122c7 100644
--- a/ipc/mach_msg.c
+++ b/ipc/mach_msg.c
@@ -1132,11 +1132,19 @@ mach_msg_trap(
 			} else
 				ip_unlock(dest_port);
 
-			kmsg->ikm_header.msgh_bits =
-				MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE,
-					       MACH_MSG_TYPE_PORT_SEND);
+			if (! ipc_port_flag_protected_payload(dest_port)) {
+				kmsg->ikm_header.msgh_bits = MACH_MSGH_BITS(
+					MACH_MSG_TYPE_PORT_SEND_ONCE,
+					MACH_MSG_TYPE_PORT_SEND);
+				kmsg->ikm_header.msgh_local_port = dest_name;
+			} else {
+				kmsg->ikm_header.msgh_bits = MACH_MSGH_BITS(
+					MACH_MSG_TYPE_PORT_SEND_ONCE,
+					MACH_MSG_TYPE_PROTECTED_PAYLOAD);
+				kmsg->ikm_header.msgh_protected_payload =
+					dest_port->ip_protected_payload;
+			}
 			kmsg->ikm_header.msgh_remote_port = reply_name;
-			kmsg->ikm_header.msgh_local_port = dest_name;
 			goto fast_put;
 
 		    abort_request_copyout:
@@ -1170,11 +1178,19 @@ mach_msg_trap(
 				dest_name = MACH_PORT_NULL;
 			}
 
-			kmsg->ikm_header.msgh_bits =
-				MACH_MSGH_BITS(0,
-					       MACH_MSG_TYPE_PORT_SEND_ONCE);
+			if (! ipc_port_flag_protected_payload(dest_port)) {
+				kmsg->ikm_header.msgh_bits = MACH_MSGH_BITS(
+					0,
+					MACH_MSG_TYPE_PORT_SEND_ONCE);
+				kmsg->ikm_header.msgh_local_port = dest_name;
+			} else {
+				kmsg->ikm_header.msgh_bits = MACH_MSGH_BITS(
+					0,
+					MACH_MSG_TYPE_PROTECTED_PAYLOAD);
+				kmsg->ikm_header.msgh_protected_payload =
+					dest_port->ip_protected_payload;
+			}
 			kmsg->ikm_header.msgh_remote_port = MACH_PORT_NULL;
-			kmsg->ikm_header.msgh_local_port = dest_name;
 			goto fast_put;
 		    }
 
@@ -1204,12 +1220,23 @@ mach_msg_trap(
 				dest_name = MACH_PORT_NULL;
 			}
 
-			kmsg->ikm_header.msgh_bits =
-				MACH_MSGH_BITS_COMPLEX |
-				MACH_MSGH_BITS(0,
-					       MACH_MSG_TYPE_PORT_SEND_ONCE);
+			if (! ipc_port_flag_protected_payload(dest_port)) {
+				kmsg->ikm_header.msgh_bits =
+					MACH_MSGH_BITS_COMPLEX
+					| MACH_MSGH_BITS(
+						0,
+						MACH_MSG_TYPE_PORT_SEND_ONCE);
+				kmsg->ikm_header.msgh_local_port = dest_name;
+			} else {
+				kmsg->ikm_header.msgh_bits =
+					MACH_MSGH_BITS_COMPLEX
+					| MACH_MSGH_BITS(
+					    0,
+					    MACH_MSG_TYPE_PROTECTED_PAYLOAD);
+				kmsg->ikm_header.msgh_protected_payload =
+					dest_port->ip_protected_payload;
+			}
 			kmsg->ikm_header.msgh_remote_port = MACH_PORT_NULL;
-			kmsg->ikm_header.msgh_local_port = dest_name;
 
 			mr = ipc_kmsg_copyout_body(
 				(vm_offset_t) (&kmsg->ikm_header + 1),
diff --git a/ipc/mach_port.c b/ipc/mach_port.c
index 4a4efcc..4ff39f2 100644
--- a/ipc/mach_port.c
+++ b/ipc/mach_port.c
@@ -1564,3 +1564,76 @@ mach_port_set_syscall_right(
 }
 #endif
 #endif /* MIGRATING_THREADS */
+
+/*
+ *	Routine:	mach_port_set_protected_payload [kernel call]
+ *	Purpose:
+ *		Changes a receive right's protected payload.
+ *	Conditions:
+ *		Nothing locked.
+ *	Returns:
+ *		KERN_SUCCESS		Set protected payload.
+ *		KERN_INVALID_TASK	The space is null.
+ *		KERN_INVALID_TASK	The space is dead.
+ *		KERN_INVALID_NAME	The name doesn't denote a right.
+ *		KERN_INVALID_RIGHT	Name doesn't denote receive rights.
+ */
+
+kern_return_t
+mach_port_set_protected_payload(
+	ipc_space_t		space,
+	mach_port_t		name,
+	unsigned long		payload)
+{
+	ipc_port_t port;
+	kern_return_t kr;
+
+	if (space == IS_NULL)
+		return KERN_INVALID_TASK;
+
+	kr = ipc_port_translate_receive(space, name, &port);
+	if (kr != KERN_SUCCESS)
+		return kr;
+	/* port is locked and active */
+
+	ipc_port_set_protected_payload(port, payload);
+
+	ip_unlock(port);
+	return KERN_SUCCESS;
+}
+
+/*
+ *	Routine:	mach_port_clear_protected_payload [kernel call]
+ *	Purpose:
+ *		Clears a receive right's protected payload.
+ *	Conditions:
+ *		Nothing locked.
+ *	Returns:
+ *		KERN_SUCCESS		Clear protected payload.
+ *		KERN_INVALID_TASK	The space is null.
+ *		KERN_INVALID_TASK	The space is dead.
+ *		KERN_INVALID_NAME	The name doesn't denote a right.
+ *		KERN_INVALID_RIGHT	Name doesn't denote receive rights.
+ */
+
+kern_return_t
+mach_port_clear_protected_payload(
+	ipc_space_t		space,
+	mach_port_t		name)
+{
+	ipc_port_t port;
+	kern_return_t kr;
+
+	if (space == IS_NULL)
+		return KERN_INVALID_TASK;
+
+	kr = ipc_port_translate_receive(space, name, &port);
+	if (kr != KERN_SUCCESS)
+		return kr;
+	/* port is locked and active */
+
+	ipc_port_clear_protected_payload(port);
+
+	ip_unlock(port);
+	return KERN_SUCCESS;
+}