Skip to content

Commit 9692606

Browse files
authored
Extend yaml-specifications to support meta patches and contracts (#98)
* Add support for meta patches update unit tests yaml update unit tests * fixup! support variant for arm achitecture add organization name in yaml remove exclude pattern from meta patches validate yaml and remove exclude from unit tests set spec file path
1 parent 8b22550 commit 9692606

36 files changed

Lines changed: 2167 additions & 637 deletions

docs/GettingStarted/patch_specifications.md

Lines changed: 218 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -34,21 +34,54 @@ Patchestry supports two types of matching:
3434
The patch specification is a YAML file with the following structure:
3535

3636
```yaml
37-
arch: "ARCHITECTURE:ENDIANNESS:BITWIDTH" # Architecture specification
38-
patches:
39-
- name: "PatchName" # Unique identifier for the patch
40-
match: # Match criteria
41-
symbol: "..." # Symbol to match
42-
kind: "..." # Kind of match (function, operation)
43-
# Additional match criteria...
44-
patch: # Patch configuration
45-
mode: "..." # Patch mode (ApplyBefore, ApplyAfter, Replace)
46-
patch_file: "..." # Path to patch implementation file
47-
patch_function: "..." # Function in patch file to call
48-
arguments: # Arguments to pass to patch function
49-
- "..."
50-
exclude: # Exclusion criteria
51-
- "*" # Function name patterns to exclude from matching
37+
apiVersion: patchestry.io/v1 # API version
38+
39+
metadata: # Deployment metadata
40+
name: "deployment-name"
41+
description: "Deployment description"
42+
version: "1.0.0"
43+
author: "Author Name"
44+
created: "YYYY-MM-DD"
45+
organization: "organization-name"
46+
47+
target: # Target binary configuration
48+
binary: "target_binary.bin"
49+
arch: "ARCHITECTURE:ENDIANNESS:BITWIDTH:VARIANT"
50+
51+
libraries: # External patch and contract libraries
52+
patches: "path/to/patches.yaml"
53+
contracts: "path/to/contracts.yaml"
54+
55+
execution_order: # Order of patch/contract execution
56+
- "meta_patches::meta_patch_name"
57+
- "meta_contracts::meta_contract_name"
58+
59+
meta_patches: # Meta-patch configurations
60+
- name: ...
61+
id: "..."
62+
description: "..."
63+
optimization: # Optimization settings
64+
- "inline-patches"
65+
- "inline-contracts"
66+
patch_actions: # Individual patch actions
67+
- id: "PATCH-001"
68+
description: "..."
69+
match: # Match criteria
70+
- symbol: "..."
71+
kind: "..."
72+
# Additional match criteria...
73+
action: # Patch actions
74+
- mode: "..."
75+
patch_id: "..."
76+
description: "..."
77+
arguments: # Patch arguments
78+
- name: "..."
79+
source: "..."
80+
index: "0"
81+
82+
meta_contracts: # Meta-contract configurations
83+
- name: ...
84+
description: "..."
5285
```
5386
5487
## Field Descriptions
@@ -57,18 +90,57 @@ patches:
5790
5891
| Field | Description | Example |
5992
|-------|-------------|---------|
93+
| `apiVersion` | API version for the patch specification | `"patchestry.io/v1"` |
94+
| `metadata` | Deployment metadata container | See metadata fields below |
95+
| `target` | Target binary configuration | See target fields below |
96+
| `libraries` | External patch and contract library references | See library fields below |
97+
| `execution_order` | Order of patch/contract group execution | `- "meta_patches::group_name"` |
98+
| `meta_patches` | Meta-patch group configurations | List of patch groups |
99+
| `meta_contracts` | Meta-contract group configurations | List of contract groups |
100+
101+
### Metadata Fields
102+
103+
| Field | Description | Example |
104+
|-------|-------------|---------|
105+
| `name` | Deployment name identifier | `"usb-security-monitoring"` |
106+
| `description` | Deployment description | `"Deploy USB security monitoring"` |
107+
| `version` | Deployment version | `"1.0.0"` |
108+
| `author` | Author or team name | `"Security Team"` |
109+
| `created` | Creation date | `"2025-01-15"` |
110+
111+
### Target Fields
112+
113+
| Field | Description | Example |
114+
|-------|-------------|---------|
115+
| `binary` | Target binary file name | `"firmware.bin"` |
60116
| `arch` | Target architecture specification in format "ARCH:ENDIANNESS:BITWIDTH" | `"ARM:LE:32"` |
61-
| `patches` | List of patch specifications | `- name: "PatchName"...` |
62117

118+
### Libraries Fields
119+
120+
| Field | Description | Example |
121+
|-------|-------------|---------|
122+
| `patches` | Path to external patch library YAML file | `"patches/security_patches.yaml"` |
123+
| `contracts` | Path to external contract library YAML file | `"contracts/security_contracts.yaml"` |
63124

64-
### Patch Entry Fields
125+
### Meta-Patch Entry Fields
65126

66127
| Field | Description | Example |
67128
|-------|-------------|---------|
68-
| `name` | Unique identifier defining the patch identity | `"CVE-2021-12345"` |
69-
| `match` | Container for match criteria | `symbol: "symbol_name"` |
70-
| `patch` | Container for patch configuration | `mode: "ApplyBefore"` |
71-
| `exclude` | Container for exclusion functions | `- "^func_*"` |
129+
| `name` | Unique identifier for the patch group | `"usb_security_patches"` |
130+
| `id` | Internal identifier for the patch group | `"usb_security_patches"` |
131+
| `description` | Description of the patch group purpose | `"USB security monitoring patches"` |
132+
| `optimization` | List of optimization flags | `["inline-patches", "inline-contracts"]` |
133+
| `patch_actions` | List of individual patch actions | See patch action fields below |
134+
| `exclude` | List of exclusion patterns | `["test_*", "debug_*"]` |
135+
136+
### Patch Action Fields
137+
138+
| Field | Description | Example |
139+
|-------|-------------|---------|
140+
| `id` | Unique identifier for the patch action | `"USB-PATCH-001"` |
141+
| `description` | Description of what the patch does | `"Add USB security validation"` |
142+
| `match` | List of match criteria | See match fields below |
143+
| `action` | List of actions to apply | See action fields below |
72144

73145
### Match Fields
74146

@@ -137,22 +209,25 @@ Common operand patterns:
137209
| `name` | Variable name pattern (supports regex with `/pattern/`) | `"/.*password.*/`, `"secret_key"` |
138210
| `type` | Variable type pattern (optional) | `"!cir.ptr<!cir.int<u, 32>>"` |
139211

140-
### Patch Fields
212+
### Action Fields
141213

142214
| Field | Description | Example |
143215
|-------|-------------|---------|
144-
| `patch.mode` | patching mode to be applied (`ApplyBefore`, `ApplyAfter`, `Replace`) | `"ApplyBefore"` |
145-
| `patch.patch_file` | Path to the C file containing patch code | `"path/to/patch.c"` |
146-
| `patch.patch_function` | Function in patch file to call | `"patch::before::function_name"` |
147-
| `patch.arguments` | List of arguments to pass to patch function | See [Argument Specification](#argument-specification) |
216+
| `mode` | Patching mode to be applied (`apply_before`, `apply_after`, `replace`) | `"apply_before"` |
217+
| `patch_id` | Reference to the patch implementation | `"USB-PATCH-001"` |
218+
| `description` | Description of the action being applied | `"Pre-validation security check"` |
219+
| `arguments` | List of arguments to pass to patch function | See [Argument Specification](#argument-specification) |
148220

149-
### Exclude Fields
221+
### Optimization Flags
150222

151-
Exclude is a top-level field in each patch entry that defines patterns to exclude from matching. It allows more precise control over function where patches should not be applied.
223+
The `optimization` field accepts a list of optimization settings:
152224

153-
| Field | Description | Example |
154-
|-------|-------------|---------|
155-
| `exclude` | List of function name patterns to exclude from matching | `- "^func_*"` |
225+
| Flag | Description | Effect |
226+
|------|-------------|--------|
227+
| `"inline-patches"` | Inline patch function calls | Reduces function call overhead |
228+
| `"inline-contracts"` | Inline contract function calls | Reduces contract validation overhead |
229+
| `"debug-info"` | Preserve debug information | Maintains debugging symbols |
230+
| `"size-optimize"` | Optimize for binary size | Reduces final binary size |
156231

157232
## Argument Specification
158233

@@ -256,41 +331,72 @@ arguments:
256331

257332
## Complete Patch Examples
258333

259-
### Example 1: Function Call Validation with Structured Arguments
334+
### Example 1: USB Security Monitoring Deployment
335+
336+
Based on the actual specification from `bl_usb__send_message_before_patch.yaml`:
260337

261338
```yaml
262-
arch: "ARM:LE:32"
263-
patches:
264-
- name: "validate_memcpy_calls"
265-
match:
266-
symbol: "memcpy"
267-
kind: "function"
268-
argument_matches:
269-
- index: 0
270-
name: "dest"
271-
type: "!cir.ptr<!cir.void>"
272-
- index: 2
273-
name: "size"
274-
type: "!cir.int<u, 32>"
275-
patch:
276-
mode: "ApplyBefore"
277-
patch_file: "patches/bounds_check.c"
278-
patch_function: "validate_memcpy"
279-
arguments:
280-
- name: "dest_ptr"
281-
source: "argument"
282-
index: 0
283-
- name: "copy_size"
284-
source: "argument"
285-
index: 2
286-
- name: "max_allowed"
287-
source: "constant"
288-
value: "4096"
289-
- name: "buffer_limit"
290-
source: "variable"
291-
symbol: "max_buffer_size"
339+
apiVersion: patchestry.io/v1
340+
341+
metadata:
342+
name: "usb-security-monitoring-deployment"
343+
description: "Deploy USB security monitoring for medical device firmware"
344+
version: "1.0.0"
345+
author: "Security Team"
346+
created: "2025-01-15"
347+
348+
target:
349+
binary: "medical_device_firmware.bin"
350+
arch: "ARM:LE:32"
351+
352+
libraries:
353+
patches: "patches/usb_security_patches.yaml"
354+
contracts: "contracts/usb_security_contracts.yaml"
355+
356+
execution_order:
357+
- "meta_patches::usb_security_meta_patches"
358+
- "meta_contracts::usb_security_meta_contracts"
359+
360+
meta_patches:
361+
- name: usb_security_meta_patches
362+
id: "usb_security_meta_patches"
363+
description: "Meta patches for USB security"
364+
optimization:
365+
- "inline-patches"
366+
- "inline-contracts"
367+
368+
patch_actions:
369+
- id: "USB-PATCH-001"
370+
description: "Patch to add USB security validation"
371+
372+
match:
373+
- symbol: "usbd_ep_write_packet"
374+
kind: "function"
375+
function_context:
376+
- name: "bl_usb__send_message"
377+
argument_matches:
378+
- index: 0
379+
name: "usb_g"
380+
381+
action:
382+
- mode: "apply_before"
383+
patch_id: "USB-PATCH-001"
384+
description: "Pre-validation security check"
385+
arguments:
386+
- name: "operand_0"
387+
source: "operand"
388+
index: "0"
389+
- name: "variable_2"
390+
source: "variable"
391+
symbol: "var1"
392+
292393
exclude:
293394
- "test_*"
395+
- "debug_*"
396+
397+
meta_contracts:
398+
- name: usb_security_meta_contracts
399+
description: "Meta contracts for USB security validation"
294400
```
295401

296402
## Operation-Based Matching Examples
@@ -342,46 +448,68 @@ Examples:
342448

343449
The specification supports three patching modes:
344450

345-
- `ApplyBefore`: Apply patch before the matched function or operation
346-
- `ApplyAfter`: Apply patch after the matched function
347-
- `Replace`: Completely replace the matched function
451+
- `apply_before`: Apply patch before the matched function or operation
452+
- `apply_after`: Apply patch after the matched function
453+
- `replace`: Completely replace the matched function
348454

349-
### ApplyBefore Mode
455+
### Apply Before Mode
350456

351-
In `ApplyBefore` mode, the patch is applied before the matched function or operation executes.
457+
In `apply_before` mode, the patch is applied before the matched function or operation executes.
352458
```yaml
353-
patch:
354-
mode: "ApplyBefore"
355-
patch_file: "path/to/patch.c"
356-
target_function: "patch::before::function_name"
357-
arguments:
358-
- "arg1"
359-
- "arg2"
459+
action:
460+
- mode: "apply_before"
461+
patch_id: "SECURITY-001"
462+
description: "Pre-execution validation"
463+
arguments:
464+
- name: "input_param"
465+
source: "operand"
466+
index: "0"
467+
- name: "max_size"
468+
source: "constant"
469+
value: "4096"
360470
```
361471

362-
### ApplyAfter Mode
472+
### Apply After Mode
363473

364-
In `ApplyAfter` mode, the patch is applied after the matched function or operation completes.
474+
In `apply_after` mode, the patch is applied after the matched function or operation completes.
365475

366476
```yaml
367-
patch:
368-
mode: "ApplyAfter"
369-
patch_file: "path/to/patch.c"
370-
target_function: "patch::after::function_name"
371-
arguments:
372-
- "return_value"
477+
action:
478+
- mode: "apply_after"
479+
patch_id: "LOGGING-001"
480+
description: "Post-execution logging"
481+
arguments:
482+
- name: "return_value"
483+
source: "return_value"
484+
- name: "execution_time"
485+
source: "variable"
486+
symbol: "timer_end"
373487
```
374488

375489
### Replace Mode
376490

377-
In `Replace` mode, the matched function or operation is completely replaced by the patch function. The original code is not executed.
491+
In `replace` mode, the matched function or operation is completely replaced by the patch function. The original code is not executed.
378492

379493
```yaml
380-
patch:
381-
mode: "Replace"
382-
patch_file: "path/to/patch.c"
383-
target_function: "patch::replace::function_name"
384-
arguments:
385-
- "arg1"
386-
- "arg2"
494+
action:
495+
- mode: "replace"
496+
patch_id: "SECURE-REPLACEMENT-001"
497+
description: "Secure function replacement"
498+
arguments:
499+
- name: "original_arg1"
500+
source: "operand"
501+
index: "0"
502+
- name: "original_arg2"
503+
source: "operand"
504+
index: "1"
387505
```
506+
507+
## Deployment Architecture
508+
509+
The meta-patch architecture allows for:
510+
511+
1. **Modular Organization**: Group related patches into logical units
512+
2. **External Libraries**: Reference shared patch and contract libraries
513+
3. **Execution Ordering**: Control the order of patch application
514+
4. **Optimization Control**: Fine-tune performance characteristics
515+
5. **Exclusion Patterns**: Exclude specific functions from patching

0 commit comments

Comments
 (0)