Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 894e091

Browse files
committed
Day 39
1 parent d0e1d2d commit 894e091

File tree

1 file changed

+107
-0
lines changed

1 file changed

+107
-0
lines changed
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
Originally from: [tweet](https://twitter.com/samokhvalov/status/1720734029207732456), [LinkedIn post]().
2+
3+
---
4+
5+
# How to break a database, Part 1: How to corrupt
6+
7+
> I post a new PostgreSQL "howto" article every day. Join me in this
8+
> journey – [subscribe](https://twitter.com/samokhvalov/), provide feedback, share!
9+
10+
Sometimes, you might want to damage a database – for educational purposes, to simulate failures, learn how to deal with
11+
them, to test mitigation procedures.
12+
13+
Let's discuss some ways to break things.
14+
15+
<span style="padding: 1ex; background-color: yellow">
16+
⚠️ Don't do it in production unless you're a chaos engineer ⚠️
17+
</span>
18+
19+
## Corruption
20+
21+
There are many types of corruption and there are very simple ways to get a corrupted database, for example:
22+
23+
👉 **Modifying system catalogs directly:**
24+
25+
```sql
26+
nik=# create table t1(id int8 primary key, val text);
27+
CREATE TABLE
28+
29+
nik=# delete from pg_attribute where attrelid = 't1'::regclass and attname = 'val';
30+
DELETE 1
31+
32+
nik=# table t1;
33+
ERROR: pg_attribute catalog is missing 1 attribute(s) for relation OID 107006
34+
LINE 1: table t1;
35+
^
36+
```
37+
38+
More ways can be found in this article:
39+
[How to corrupt your PostgreSQL database](https://cybertec-postgresql.com/en/how-to-corrupt-your-postgresql-database/).
40+
A couple of interesting methods from there:
41+
42+
- `fsync=off` + `kill -9` to Postgres (or `pg_ctl stop -m immediate`)
43+
- `kill -9` + `pg_resetwal -f`
44+
45+
One useful method is to use `dd` to write to a data file directly. This can be used to simulate a corruption that can be
46+
detected by checksum verification
47+
([Day 37: How to enable data checksums without downtime](0037_how_to_enable_data_checksums_without_downtime.md)). This
48+
is also demonstrated in this article:
49+
[pg_healer: repairing Postgres problems automatically](https://endpointdev.com/blog/2016/09/pghealer-repairing-postgres-problems/).
50+
51+
First, create a table and see where its data file is located:
52+
53+
```sql
54+
nik=# show data_checksums;
55+
data_checksums
56+
----------------
57+
on
58+
(1 row)
59+
60+
nik=# create table t1 as select i from generate_series(1, 10000) i;
61+
SELECT 10000
62+
63+
nik=# select count(*) from t1;
64+
count
65+
-------
66+
10000
67+
(1 row)
68+
69+
nik=# select format('%s/%s',
70+
current_setting('data_directory'),
71+
pg_relation_filepath('t1'));
72+
format
73+
---------------------------------------------------
74+
/opt/homebrew/var/postgresql@15/base/16384/123388
75+
(1 row)
76+
```
77+
78+
Now, let's write some garbage to this file directly, using `dd` (note that here we use a macOS version, where `dd` has
79+
the option `oseek` – on Linux, it's `seek_bytes`), and then restart Postgres to make sure the table is not present in
80+
the buffer pool anymore:
81+
82+
```bash
83+
echo -n "BOOoo" \
84+
| dd conv=notrunc bs=1 \
85+
oseek=4000 count=1 \
86+
of=/opt/homebrew/var/postgresql@15/base/16384/123388
87+
1+0 records in
88+
1+0 records out
89+
1 bytes transferred in 0.000240 secs (4167 bytes/sec)
90+
91+
❯ brew services stop postgresql@15
92+
Stopping `postgresql@15`... (might take a while)
93+
==> Successfully stopped `postgresql@15` (label: homebrew.mxcl.postgresql@15)
94+
95+
❯ brew services start postgresql@15
96+
==> Successfully started `postgresql@15` (label: homebrew.mxcl.postgresql@15)
97+
```
98+
99+
Successfully corrupted – the data checksums mechanism complains about it:
100+
101+
```sql
102+
nik=# table t1;
103+
WARNING: page verification failed, calculated checksum 52379 but expected 35499
104+
ERROR: invalid page in block 0 of relation base/16384/123388
105+
```
106+
107+
**🔜 To be continued ...**

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /