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
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
|
# Mojo "Style" Guide
Mojo is Chrome's new IPC system and provides lots of useful abstractions. These
abstractions can make it easier to write code that makes interprocess calls,
but can also add significant complexity. Below are some recommendation from
Mojo and IPC reviewers for best practices.
For questions, concerns, or suggestions, reach out to
[chromium-mojo@chromium.org](https://groups.google.com/a/chromium.org/forum/#!forum/chromium-mojo).
> For legacy IPC, please see [security tips for IPC][security-tips-for-ipc].
[TOC]
## Simplicity
Strive to write simple interfaces. Minimize the amount of cross-process state
that needs to be maintained in sync.
**_Good_**
```c++
interface TeleporterFactory {
Create(Location start, Location end) => (pending_remote<Teleporter>);
};
interface Teleporter {
TeleportGoat(Goat) = ();
};
```
**_Bad_**
```c++
interface Teleporter {
// Bad: comments will need to explicitly call out that both locations need to
// be bound before calling TeleportGoat()!
//
// In addition, if untrustworthy processes can talk to trustworthy processes,
// the Teleporter implementation will need to also handle the case where the
// Location objects are not yet bound.
SetStart(Location);
SetEnd(Location);
TeleportGoat(Goat) = ();
};
```
Similarly, strive to make methods focused. Do not overuse optional types.
**_Good_**
```c++
struct TeleporterStats {
AnimalStats animal_stats;
FungiStats fungi_stats;
GoatStats goat_stats;
PlantStats plant_stats;
};
interface Teleporter {
TeleportAnimal(Animal) => ();
TeleportFungi(Fungi) => ();
TeleportGoat(Goat) = ();
TeleportPlant(Plant) => ();
// TeleporterStats will be have a value if and only if the call was
// successful.
GetStats() => (TeleporterStats?);
};
```
**_Bad_**
```c++
interface Teleporter {
// The intent of four optional arguments is unclear: can this call teleport
// multiple objects of different types at once, or is the caller only
// supposed to only pass one non-null argument per call?
Teleport(Animal?, Fungi?, Goat?, Plant?) => ();
// Does this return all stats if success is true? Or just the categories that
// the teleporter already has stats for? The intent is uncertain, so wrapping
// the disparate values into a result struct would be cleaner.
GetStats() =>
(bool success, AnimalStats?, FungiStats?, PlantStats?, FungiStats?);
};
```
## Documentation
Mojo structs, interfaces, and methods should all have comments. Make sure the
comments cover the "how" and the "why" of using an interface and its methods,
and not just the "what". Document preconditions, postconditions, and trust: if
an interface is implemented in the browser process and handles requests from
the renderer process, this should be mentioned in the comments. Complex features
should also have an external `README.md` that covers the high-level flow of
information through interfaces and how they interact to implement the feature.
**_Good_**
```c++
// Interface for controlling a teleporter. Lives in the browser process, and
// used to implement the Teleportation over Mojo IPC RFC.
interface Teleporter {
// Teleportation helpers for different taxonomic kingdoms. Teleportation is
// not complete until the reply callback is invoked. The caller must NOT
// release the sender side resources until the reply callback runs; releasing
// the resources early will cause splinching.
TeleportAnimal(Animal) => ();
TeleportFungi(Fungi) => ();
// Goats require a specialized teleportation channel distinct from
// TeleportAnimal to ensure goatiness isolation.
TeleportGoat(Goat) => ();
TeleportPlant(Plant) => ();
// Returns current teleporter stats. On failure (e.g. a teleportation
// operation is currently in progress) a null stats object will be returned.
GetStats() => (TeleporterStats?);
};
```
## Security
Policy should be controlled solely by the browser process. "Policy" can mean
any number of things, such as sizes, addresses, permissions, URLs, origins,
etc. In an ideal world:
1. Unprivileged process asks for a capability from the privileged process that
owns the resource.
1. Privileged process applies policy to find an implementation for the
capability.
1. Unprivileged process performs operations on the capability, constrained in
scope.
The privileged process must own the capability lifecycle.
### Do not trust less privileged processes
This is the overriding principle for all guidelines in this section. When
receiving data from a less trusted process, treat the data as if it were
generated by a malicious adversary. Message handlers cannot assume that offsets
are valid, calculations won't overflow, et cetera.
In general:
* the browser process is the most privileged process type and therefore, must
be maximally suspicious of its IPC inputs
* the renderer and the ARC++ processes are the least privileged and least
trustworthy process types
* other process types, such as GPU and plugin, fall in between
When passing objects up a privilege gradient (from less → more privileged), the
callee must validate the inputs before acting on them. When passing objects
down a privilege gradient, such as from browser → renderer, it is OK for the
callee to trust the caller.
> See also: [Do not Handle Impossible Situations](#Do-not-handle-impossible-situations)
### Do not send unnecessary or privilege-presuming data
> Each `BrowserInterfaceBroker` for frames and workers is strongly associated with an
> origin. Where possible, prefer to use this associated origin rather than
> sending it over IPC. (See <https://crbug.com/734210> and
> <https://crbug.com/775792/>).
For example, the browser process must not (fully) trust the renderer's claims
about origins. The browser process should already know what origin the renderer
is evaluating, and thus should already have this data (for example, see
`RenderFrameHost::GetLastCommittedOrigin()`). Thus, a method that requires
passing an origin from the renderer to the browser process has a conceptual
error, and quite possibly, a vulnerability.
> Note: there are currently subtle races when using `GetLastCommittedOrigin()`
> that will be resolved by fixing <https://crbug.com/729021>.
Similarly, the browser process must not trust the renderer's claims about file
pathnames. It would be unsafe for the browser process to save a downloaded file
to `~/.bashrc` just because the renderer asked. Instead, it would be better for
the browser process to:
1. Kill the renderer if `basename(pathname) != pathname`, since the renderer is
obviously compromised if it makes this mistake.
1. Defang the basename, by removing leading dots, et cetera. Note that the
definition of proper defanging varies per platform.
1. Prepend its own parent directory to the basename, e.g. ~/Downloads.
> TODO(https://crbug.com/779196): Even better would be to implement a C++ type
> performs the appropriate sanitizations and recommend its usage directly here.
### Validate privilege-presuming data received over IPC
If it is not possible to avoid sending privilege-presuming data over IPC (see
the previous section), then such data should be verified before being used.
* Browser process:
- Use `ChildProcessSecurityPolicy`'s methods like
`CanAccessDataForOrigin` or `CanReadFile` to verify IPC messages
received from less privileged processes.
- When verification fails, ignore the IPC and terminate the renderer process
using `mojo::ReportBadMessage` (or using `mojo::GetBadMessageCallback` for
messages handled asynchronously). For legacy IPC, the renderer process
may be terminated by calling the `ReceivedBadMessage` function (separate
implementations exist for `//content`, `//chrome` and other layers).
### Do not define unused or unimplemented things
Mojo interfaces often cross privilege boundaries. Having well-defined interfaces
that don't contain stubbed out methods or unused parameters makes it easier to
understand and evaluate the implications of crossing these boundaries. Several
common areas to watch out for:
#### Do use EnableIf to guard platform-specific constructs
Platform-specific functionality should only be defined on the platforms where
it is implemented. Use the Mojo `EnableIf` annotation to guard definitions that
should only be visible in certain build configurations.
**_Good_**
```c++
// GN file:
mojom("view_bindings") {
// ...
enabled_features = []
if (is_android) {
enabled_features += [ "is_android" ]
}
}
// mojom definition:
interface View {
// ...
[EnableIf=is_android]
UpdateBrowserControlsState(bool enable_hiding, bool enable_showing,
bool animate);
};
// C++ implementation:
class View : public mojom::View {
public:
// ...
#if defined(OS_ANDROID)
void UpdateBrowserControlsState(bool enable_hiding, bool enable_showing,
bool animate);
#endif
};
```
**_Bad_**
```c++
// mojom definition:
interface View {
// ...
UpdateBrowserControlsState(bool enable_hiding, bool enable_showing,
bool animate);
};
// C++ implementation:
class View : public mojom::View {
public:
// ...
#if defined(OS_ANDROID)
void UpdateBrowserControlsState(bool enable_hiding, bool enable_showing,
bool animate) override;
#else
void UpdateBrowserControlsState(bool enable_hiding, bool enable_showing,
bool animate) override {
NOTREACHED();
}
#endif
};
```
The `EnableIf` annotation can be applied to almost anything: imports,
interfaces, methods, arguments, constants, structs, struct members, enums,
enumerator values, et cetera.
#### Do not define unimplemented methods
Reviewing IPC requires reviewing a concrete implementation of the Mojo
interface, to evaluate how the (possibly untrustworthy) inputs are used, what
outputs are produced, et cetera. If a method is not yet implemented, do not
define it in the interface.
**_Bad_**
```c++
// mojom definition:
interface Spaceship {
EnterHyperspace();
ExitHyperspace();
};
// C++ implementation:
class SpaceshipPrototype : public mojom::Spaceship {
void EnterHyperspace() { /* TODO(dcheng): Implement. */ }
void ExitHyperspace() { /* TODO(dcheng): Implement. */ }
};
```
#### Do not define placeholder enumerator values
Do not define placeholder enumerator values like `kLast`, `kMax`, `kCount`, et
cetera. Instead, rely on the autogenerated `kMaxValue` enumerator emitted for
Mojo C++ bindings.
For UMA histograms, logging a Mojo enum is simple: simply use the two argument
version of `UMA_HISTOGRAM_ENUMERATION`:
**_Good_**
```c++
// mojom definition:
enum GoatStatus {
kHappy,
kSad,
kHungry,
kGoaty,
};
// C++:
UMA_HISTOGRAM_ENUMERATION("Goat.Status", status);
```
Using a `kCount` sentinel complicates `switch` statements and makes it harder to
enforce invariants: code needs to actively enforce that the otherwise invalid
`kCount` sentinel value is not incorrectly passed around.
**_Bad_**
```c++
// mojom definition:
enum CatStatus {
kAloof,
kCount,
};
// C++
switch (cat_status) {
case CatStatus::kAloof:
IgnoreHuman();
break;
case CatStatus::kCount:
// this should never happen
}
```
Defining `kLast` manually results in ugly casts to perform arithmetic:
**_Bad_**
```c++
// mojom definition:
enum WhaleStatus {
kFail,
kNotFail,
kLast = kNotFail,
};
// C++:
UMA_HISTOGRAM_ENUMERATION("Whale.Status", status,
static_cast<int>(WhaleStatus::kLast) + 1);
```
For interoperation with legacy IPC, also use `kMaxValue` rather than defining a
custom `kLast`:
**_Good_**
```c++
IPC_ENUM_TRAITS_MAX_VALUE(GoatStatus, GoatStatus::kMaxValue);
```
### Use structured types
Where possible, use structured types: this allows the type system to help
enforce that the input data is valid. Common ones to watch out for:
* Files: use `mojo_base.mojom.File`, not raw descriptor types like `HANDLE`
and `int`.
* File paths: use `mojo_base.mojom.FilePath`, not `string`.
* JSON: use `mojo_base.mojom.Value`, not `string`.
* Mojo interfaces: use `Interface` or `Interface&`, not `handle` or
`handle<message_pipe>`.
* Nonces: use `mojo_base.mojom.UnguessableToken`, not `string`.
* Origins: use `url.mojom.Origin`, not `url.mojom.Url` and certainly not
`string`.
* Time types: use `mojo_base.mojom.TimeDelta` /
`mojo_base.mojom.TimeTicks` / `mojo_base.mojom.Time`, not `int64` /
`uint64` / `double` / et cetera.
* URLs: use `url.mojom.Url`, not `string`.
* `array<uint8>` or `string` and `memcpy()`: use a Mojo struct and statically
define the serialized fields. While `memcpy()` may be tempting for its
simplicity, it can leak info in padding. Even worse, `memcpy()` can easily
copy [undocumented fields][serialize-struct-tm-safely] or newly introduced
fields that were never evaluated for safety by the developer or reviewer.
**_Good_**
```c++
interface ReportingService {
ReportDeprecation(mojo_base.mojom.TimeTicks time,
url.mojom.Url resource,
uint32 line_number);
};
```
**_Bad_**
```c++
interface ReportingService {
// Bad: unclear what units |time| is or what |data| contains.
ReportDeprecation(double time, mojo_base.mojom.Value data);
};
```
Avoid parallel arrays of data that require the receiver to validate that the
arrays have matching lengths. Instead, bundle the data together in a struct so
it is impossible to have a mismatch:
**_Good_**
```c++
struct Pixel {
int8 reds;
int8 greens;
int8 blues;
int8 alphas;
};
struct Bitmap {
// Good: it is impossible for there to be mismatched data.
array<Pixel> pixels;
};
```
**_Bad_**
```c++
// Bad: code using this struct will need to validate that all the arrays have
// matching sizes.
struct Bitmap {
array<int8> reds;
array<int8> greens;
array<int8> blues;
array<int8> alphas;
};
```
### Beware of arithmetic overflow
> TODO(dcheng): Import the guidance from the legacy IPC doc.
Signed overflow is undefined in C++. If unsure about whether or not something
will overflow, use the safe numeric helpers from `//base/numerics`!
**_Good_**
```c++
base::CheckedNumeric<int32_t> size = mojo_rect->width();
size *= mojo_rect.height();
if (!size.IsValid()) {
mojo::ReportBadMessage("Bad size from renderer!");
}
```
**_Bad_**
```c++
// Bad: Signed overflow is undefined in C++!
int32_t size = mojo_rect->width() * mojo_rect.height();
```
Note that even if the types have defined overflow semantics, it is almost always
a good idea to check for overflow.
**_Good_**
```c++
uint32_t alloc_size;
if (!CheckMul(request->elements(), request->element_size())
.AssignIfValid(&alloc_size)) {
// Safe: avoids allocating with a bogus size that overflowed to a smaller than
// expected value.
mojo::ReportBadMessage("Invalid allocation size");
}
Element* array = CreateArray(alloc_size);
for (size_t i = 0; i < request->element_size(); ++i) {
array[i] = PopulateArray(i);
}
```
**_Bad_**
```c++
uint32_t alloc_size = request->elements() * request->element_size();
// Dangerous: alloc_size can overflow so that CreateArray allocates too little
// memory. Subsequent assignments will turn into an out-of-bound write!
Element* array = CreateArray(alloc_size);
for (size_t i = 0; i < request->element_size(); ++i) {
array[i] = PopulateArray(i);
}
```
### All possible message values are semantically valid
When possible, messages should be defined in such a way that all possible values
are semantically valid. As a corollary, avoid having the value of one field
dictate the validity of other fields.
**_Good_**
```c++
union CreateTokenResult {
// Implies success.
string token;
// Implies failure.
string error_message;
};
struct TokenManager {
CreateToken() => (CreateTokenResult result);
};
```
**_Bad_**
```c++
struct TokenManager {
// Requires caller to handle edge case where |success| is set to true, but
// |token| is null.
CreateToken() => (bool success, string? token, string? error_message);
// Requires caller to handle edge case where both |token| and |error_message|
// are set, or both are null.
CreateToken() => (string? token, string? error_message);
};
```
There are some known exceptions to this rule because mojo does not handle
optional primitives.
**_Allowed because mojo has no support for optional primitives_**
```c++
struct Foo {
int32 x;
bool has_x; // does the value of `x` have meaning?
int32 y;
bool has_y; // does the value of `y` have meaning?
};
```
Another common case where we tolerate imperfect message semantics is
with weakly typed integer [bitfields](#handling-bitfields).
### Handling bitfields
Mojom has no native support for bitfields. There are two common approaches: a
type-safe struct of bools which is a bit clunky (preferred) and an integer-based
approach (allowed but not preferred).
**_Type-safe bitfields_**
```c++
struct VehicleBits {
bool has_car;
bool has_bicycle;
bool has_boat;
};
struct Person {
VehicleBits bits;
};
```
**_Integer based approach_**
```c++
struct Person {
const uint64 kHasCar = 1;
const uint64 kHasBicycle = 2;
const uint64 kHasGoat= 4;
uint32 vehicle_bitfield;
};
```
## C++ Best Practices
### Use mojo::WrapCallbackWithDefaultInvokeIfNotRun And mojo::WrapCallbackWithDropHandler sparingly
Mojo provides several convenience helpers to automatically invoke a callback if
the callback has not already been invoked in some other way when the callback is
destroyed, e.g.:
```c++
{
base::OnceCallback<int> cb = mojo::WrapCallbackWithDefaultInvokeIfNotRun(
base::BindOnce([](int) { ... }), -1);
} // |cb| is automatically invoked with an argument of -1.
```
This can be useful for detecting interface errors:
```c++
process->GetMemoryStatistics(
mojo::WrapCallbackWithDefaultInvokeIfNotRun(
base::BindOnce(&MemoryProfiler::OnReplyFromRenderer), <failure args>));
// If the remote process dies, &MemoryProfiler::OnReplyFromRenderer will be
// invoked with <failure args> when Mojo drops outstanding callbacks due to
// a connection error on |process|.
```
However, due to limitations of the current implementation, it's difficult to
tell if a callback object has invoke-on-destroy behavior. In general:
1. Prefer error connection handlers where possible.
1. Only use the callback helpers for detecting interface errors. These
callbacks may be invoked during destruction and must carefully consider
receiver object lifetime. For more information, please see the
[Mojo documentation][mojo-doc-process-crashes].
> Note that using the callback wrappers in the renderer is often unnecessary.
> Message pipes are typically closed as part of a Document shutting down; since
> many Blink objects already inherit `blink::ContextLifecycleObserver`, it is
> usually more idiomatic to use this signal to perform any needed cleanup work.
### Use StructTraits
Creating a typemap and defining a `StructTraits` specialization moves the
complexity of serialization, deserialization, and validation into a central
location. We universally recommend this over defining `TypeConverter`
specializations: when a value fails deserialization, the receiver method will
never even be invoked. As a bonus, it also reduces the number of copies during
serialization and deserialization. 😄
**_Good_**
```c++
// In url_gurl_mojom_traits.h:
template <>
struct StructTraits<url::mojom::UrlDataView, GURL> {
static base::StringPiece url(const GURL& r);
// If Read() returns false, Mojo will discard the message.
static bool Read(url::mojom::UrlDataView data, GURL* out);
};
// In url_gurl_mojom_traits.cc:
// Note that methods that aren't simple getters should be defined
// out-of-line to avoid code bloat.
base::StringPiece StructTraits<url::mojom::UrlDataView, GURL>::url(
const GURL& r) {
if (r.possibly_invalid_spec().length() > url::kMaxURLChars ||
!r.is_valid()) {
return base::StringPiece();
}
return base::StringPiece(r.possibly_invalid_spec().c_str(),
r.possibly_invalid_spec().length());
}
bool StructTraits<url::mojom::UrlDataView, GURL>::Read(
url::mojom::UrlDataView data, GURL* out) {
base::StringPiece url_string;
if (!data.ReadUrl(&url_string))
return false;
if (url_string.length() > url::kMaxURLChars)
return false;
*out = GURL(url_string);
if (!url_string.empty() && !out->is_valid())
return false;
return true;
}
```
**_Bad_**
```c++
template <>
struct TypeConverter<url::mojom::UrlPtr, GURL> {
// Inefficient: this copies data once off the wire to create a
// url.mojom.Url object, then copies it again to create a GURL.
static GURL Convert(const url::mojom::UrlPtr url) {
if (url.url.is_empty()) return GURL();
// Not good: no way to signal errors, so any code that converts the
// Mojo struct to a GURL will somehow need to check for errors…
// but it can't even be distinguished from the empty URL case!
if (url.url.size() > url::kMaxURLChars) return GURL();
return GURL(url.url);
}
};
```
There are also corresponding `EnumTraits` and `UnionTraits` specializations for
mojo enums and unions respectively.
### StructTraits getters should be simple
Where possible, `StructTraits` should be returning const references or simple
read-only views of the data. Having to create temporary data structures during
serialization should be rare, and it should be even rarer to mutate the input
argument.
### Out-of-line complex serialization/deserialization logic
A `StructTraits` specialization is almost always fully specialized. Only define
`StructTraits` methods inline in the header if the method is a simple getter
that returns a reference, pointer, or other simple POD. Define all other
methods out-of-line to avoid code bloat.
### Do not write one-off functions to convert to/from Mojo types
There are some instances where it is simply not possible to define a
`StructTraits` for type mapping: this commonly occurs with Blink IDL and Oilpan
types. In these instances, add a `TypeConverter` specialization rather than
defining a one-off conversion function. This makes it easier to search for and
audit code that does potentially risky type conversions.
> The use of `TypeConverter` should be limited as much as possible: ideally,
> only use it in renderers.
**_Good_**
```c++
template <>
struct TypeConverter<IDLDictionary, mojom::blink::DictionaryPtr> {
static IDLDictionary* Convert(const mojom::blink::DictionaryPtr& in) {
// Note that unlike StructTraits, there is no out-of-band way to signal
// failure.
IDLDictionary* out = new IDLDictionary;
out->int_value = in->int_value;
out->str_value = in->str_value;
return out;
}
};
```
**_Bad_**
```c++
// Using a custom one-off function makes this hard to discover in security
// audits.
IDLDictionary* FromMojo(const mojom::blink::DictionaryPtr& in) {
IDLDictionary* out = new IDLDictionary;
out->int_value = in->int_value;
out->str_value = in->str_value;
return out;
}
```
### Use the proper abstractions
`mojo::ReceiverSet` implies multiple clients may connect. If this actually isn't
the case, please do not use it. For example, if an interface can be rebound,
then use the singular `mojo::Receiver` and simply `reset()` the existing receiver
before reusing it.
### Explicitly reject bad input
While validation should be done inside `StructTraits` specializations when
possible, there are situations where additional checks, e.g. overflow checks,
are needed outside of `StructTraits` specializations. Use
`mojo::ReportBadMessage()` or `mojo::GetBadMessageCallback()` to reject bad
input in these situations. Under the hood, this may record UMAs, kill the
process sending bad input, et cetera.
* `mojo::ReportBadMessage()`: use to report bad IPC input while a message is
being dispatched on the stack.
* `mojo::GetBadMessageCallback()`: use to generate a callback to report bad
IPC input. The callback must be generated while a message is being
dispatched on the stack; however, the returned callback may be invoked be
freely invoked in asynchronously posted callbacks.
## Java Best Practices
Unfortunately, there are no strongly established conventions here. Most code
tends to write manual conversion helpers and throw an exception on conversion
failure. See [NfcTypeConverter.java] as one example of how to write conversion
code.
## General Code Health
### Naming Conventions
Place mojo types in `<top-level namespace>.mojom`. Directories for Mojo traits
should be named `mojom` (preferable) or `ipc`. Legacy names that are also
encountered are `public/interfaces`, `interfaces`, or just `mojo`.
`mojom` is preferred for consistency between the directory name and the nested
namespace name.
### Do not handle impossible situations
Do not clutter the code by handling impossible situations. Omitting it makes
the invariants clear. This takes two different forms:
* A less trustworthy process can be compromised by an adversary and send
arbitrary data. When processing data from a less trustworthy process, do
not attempt to handle this invalid data: just call
`mojo::ReportBadMessage()`. When invoked in the context of processing an
IPC from the renderer, this will kill the renderer process.
* A more trustworthy process must be trusted, by definition. Do not write
code to handle impossible situations "just in case" there's a bug. For
example, the renderer class `content::RenderFrameImpl` must always be
connected to certain control interfaces in the browser. It does not makes
sense to handle a Mojo connection error and try to reconnect: a connection
error signals that the browser process is in the process of deleting the
frame, and any attempt at reconnecting will never succeed.
### Using mojo enums directly when possible
`EnumTraits` generally do not add much value: incoming Mojo enum values are
already validated before typemapping, so it is guaranteed that the input value
to `EnumTraits<T>::FromMojom()` is already a valid enum value, so the method
itself is just a bunch of boilerplate to map between two very similarly named,
yet slightly different, enums.
To avoid this, prefer to use the Mojo enum directly when possible.
### Consider the cost of setting up message pipes
Message pipes are fairly inexpensive, but they are not free either: it takes 6
control messages to establish a message pipe. Keep this in mind: if the
interface is used relatively frequently, connecting once and reusing the
interface pointer is probably a good idea.
## Ensure An Explicit Grant For WebUI Bindings
WebUI renderers sometimes need to call special, powerful IPC endpoints in a
privileged process. It is important to enforce the constraint that the
privileged callee previously created and blessed the calling process as a WebUI
process, and not as a (potentially compromised) web renderer or other
low-privilege process.
* Use the standard pattern for instantiating `MojoWebUIController`. WebUI
Mojo interfaces must only be exposed through a `MojoWebUIController` subclass.
* If there is external functionality that the WebUI needs, make sure to route
it through the Mojo interfaces implemented by the `MojoWebUIController`, to
avoid circumventing access checks.
## Not-Yet-Shipped Features Should Be Feature-Checked On The Privileged Side
Sometimes, there will be powerful new features that are not yet turned on by
default, such as behind a flag, Finch trial, or [origin
trial](https://www.chromium.org/blink/origin-trials). It is not safe to check
for the feature's availability on the renderer side (or in another low-privilege
process type). Instead, ensure that the check is done in the process that has
power to actually enact the feature. Otherwise, a compromised renderer could opt
itself in to the feature! If the feature might not yet be fully developed and
safe, vulnerabilities could arise.
[security-tips-for-ipc]: https://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
[NfcTypeConverter.java]: https://chromium.googlesource.com/chromium/src/+/e97442ee6e8c4cf6bcf7f5623c6fb2cc8cce92ac/services/device/nfc/android/java/src/org/chromium/device/nfc/NfcTypeConverter.java
[mojo-doc-process-crashes]: https://chromium.googlesource.com/chromium/src/+/main/mojo/public/cpp/bindings#Best-practices-for-dealing-with-process-crashes-and-callbacks
[serialize-struct-tm-safely]: https://chromium-review.googlesource.com/c/chromium/src/+/679441
|