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

docs / dangling_ptr.md [blame]

# Dangling Pointer Detector

A pointer is dangling when it references freed memory. Typical examples can be
found [here](https://docs.google.com/document/d/11YYsyPF9rQv_QFf982Khie3YuNPXV0NdhzJPojpZfco/edit?resourcekey=0-h1dr1uDzZGU7YWHth5TRAQ#heading=h.wxt96wl0k0sq).

Dangling pointers are not a problem unless they are subsequently dereferenced
and/or used for other purposes. Proving that pointers are unused has turned out
to be difficult in general, especially in face of future modifications to
the code. Hence, they are a source of UaF bugs and highly discouraged unless
you are able to ensure that they can never be used after the pointed-to objects
are freed.

See also the [Dangling Pointers Guide](./dangling_ptr_guide.md) for how to fix
cases where dangling pointers occur.

Behind build flags, Chrome implements a dangling pointer detector. It causes
Chrome to crash, whenever a raw_ptr becomes dangling:
```cpp
raw_ptr<T> ptr_never_dangling;
```

On the other hand, we cannot simply ban all the usage of dangling pointers
because there are valid use cases. The `DisableDanglingPtrDetection` option can
be used to annotate "intentional-and-safe" dangling pointers. It is meant to be
used as a last resort, only if there is no better way to re-architecture the
code.
```cpp
raw_ptr<T, DisableDanglingPtrDetection> ptr_may_dangle;
```

The `DanglingUntriaged` option has been used to annotate pre-existing dangling
pointers in Chrome:
```cpp
raw_ptr<T, DanglingUntriaged> ptr_dangling_mysteriously;
```
Contrary to `DisableDanglingPtrDetection`, we don't know yet why it dangles. It
is meant to be either refactored to avoid dangling, or turned into
"DisableDanglingPtrDetection" with a comment explaining what happens.

# How to check for dangling pointers?

On **Linux**, it is **enabled by default** on most configurations.
To be precise: (`is_debug` or `dcheck_always_on`) and non `is_official` builds.

For the other operating systems, this is gated by both build and runtime flags:

## Build flags

```bash
gn args ./out/dangling/
```

```gn
use_remoteexec = true
is_debug = false  # Important! (*)
is_component_build = false  # Important! (*)
dcheck_always_on = true
enable_backup_ref_ptr_support = true  # true by default on some platforms
enable_dangling_raw_ptr_checks = true
```

(*) We want to emphasize that setting either `is_debug = false` or
`is_component_build = false` is important. It is a common mistake to set
`is_debug` to `true`, which in turn turns on component builds, which
disables PartitionAlloc-Everywhere. `enable_backup_ref_ptr_support = true` can't
be used without PartitionAlloc-Everywhere, and is silently set to `false`.

## Runtime flags

```bash
./out/dangling/content_shell \
   --enable-features=PartitionAllocBackupRefPtr,PartitionAllocDanglingPtr
```

By default, Chrome will crash on the first dangling raw_ptr detected.

# Runtime flags options:

## Mode parameter

### Crash (default)

```bash
--enable-features=PartitionAllocBackupRefPtr,PartitionAllocDanglingPtr:mode/crash
```

### Record a list of signatures

Example usage:
```bash
./out/dangling/content_shell \
   --enable-features=PartitionAllocBackupRefPtr,PartitionAllocDanglingPtr:mode/log_only \
   |& tee output
```

The logs can be filtered and transformed into a tab separated table:
```bash
cat output \
 | grep "[DanglingSignature]" \
 | cut -f2,3,4,5 \
 | sort \
 | uniq -c \
 | sed -E 's/^ *//; s/ /\t/' \
 | sort -rn
```

This is used to list issues and track progresses.

## Type parameter
### Select all dangling raw_ptr (default)

The option: `type/all` selects every dangling pointer.

Example usage:
```bash
./out/dangling/content_shell \
   --enable-features=PartitionAllocBackupRefPtr,PartitionAllocDanglingPtr:type/all
```

### Select cross tasks dangling raw_ptr

The option: `type/cross_task` selects dangling pointers that are released in a
different task than the one where the memory was freed. Those are more likely to
cause UAF.

Example usage:
```bash
./out/dangling/content_shell \
   --enable-features=PartitionAllocBackupRefPtr,PartitionAllocDanglingPtr:type/cross_task
```

### Combination

Both parameters can be combined, example usage:
```bash
./out/dangling/content_shell \
   --enable-features=PartitionAllocBackupRefPtr,PartitionAllocDanglingPtr:mode/log_only/type/cross_task \
   |& tee output
```

# Alternative dangling pointer detector (experimental)

The dangling pointer detector above works only against certain heap allocated
objects, but there is an alternate form that catches other cases such as
pointers to out-of-scope stack variables or pointers to deallocated shared
memory regions. The GN arguments to enable it are:

```gn
enable_backup_ref_ptr_support=false
is_asan=true
is_component_build=false
use_asan_backup_ref_ptr=false
use_raw_ptr_asan_unowned_impl=true
```

This will crash when the object containing the dangling ptr is destructed,
giving the usual three-stack trace from ASAN showing where the deleted object
was allocated and freed.

When running under this mode, there is no need to specify any --enable-features
flag as above.