-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathnull-deref.assura
More file actions
169 lines (144 loc) · 6.1 KB
/
Copy pathnull-deref.assura
File metadata and controls
169 lines (144 loc) · 6.1 KB
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
// ============================================================================
// CVE-2023-25136: OpenSSH Pre-Auth Double-Free / Null Dereference
// CVSS: 6.5
// Root cause: OpenSSH server (sshd) versions 9.1 had a double-free
// vulnerability in the pre-authentication phase. During the SSH handshake,
// a specially crafted packet could trigger a double-free of a buffer in
// the options.kex_algorithms field. On some platforms, this manifested as
// a null pointer dereference when the freed pointer was subsequently
// accessed, crashing sshd and denying service.
//
// Null pointer dereference occurs when code accesses memory through a
// pointer that is NULL (zero). This typically happens when a function
// returns NULL to indicate failure but the caller does not check the
// return value before using the pointer.
//
// Assura prevention: Option types (TYPE.5) replace nullable pointers.
// A value of type Option<T> is either Some(value) or None. The compiler
// requires pattern matching to extract the inner value, making it
// impossible to use a None value as if it were Some. Null dereference
// becomes a compile-time type error.
// ============================================================================
project null_deref_demo {
profile: [core, sec]
}
module sec.null_deref;
// ---------------------------------------------------------------------------
// Contract: SSH algorithm negotiation bounds
//
// During key exchange, the server and client exchange lists of supported
// algorithms. Each list has a maximum length. After validation, the
// list length is proven within bounds.
// ---------------------------------------------------------------------------
contract AlgorithmListBounds {
input(
algorithm_count: Nat,
max_algorithms: Nat
)
requires { algorithm_count > 0 }
requires { max_algorithms > 0 }
requires { algorithm_count <= max_algorithms }
requires { max_algorithms <= 64 }
// PROVEN BY Z3: algorithm count within safe limits
ensures { algorithm_count <= 64 }
ensures { max_algorithms >= algorithm_count }
effects { pure }
}
// ---------------------------------------------------------------------------
// Contract: key exchange buffer bounds
//
// The SSH key exchange message has a maximum size. Before parsing,
// the message length is validated to prevent buffer overruns.
// ---------------------------------------------------------------------------
contract KexMessageBounds {
input(
message: Bytes,
max_message_size: Nat
)
requires { message.length() > 0 }
requires { max_message_size > 0 }
requires { message.length() <= max_message_size }
requires { max_message_size <= 262144 }
// PROVEN BY Z3: message size is within limits
ensures { message.length() <= 262144 }
ensures { max_message_size >= message.length() }
effects { pure }
}
// ---------------------------------------------------------------------------
// Contract: safe string field extraction
//
// When extracting a variable-length string from an SSH message, the
// declared length must fit within the remaining message bytes. This
// prevents reading past the message boundary.
// ---------------------------------------------------------------------------
contract SafeStringExtraction {
input(
remaining_bytes: Nat,
declared_length: Nat
)
// Length prefix is 4 bytes, then the string content
requires { remaining_bytes >= 4 }
requires { declared_length > 0 }
requires { declared_length + 4 <= remaining_bytes }
// PROVEN BY Z3: string fits within remaining message
ensures { declared_length + 4 <= remaining_bytes }
ensures { declared_length <= remaining_bytes - 4 }
effects { pure }
}
// ---------------------------------------------------------------------------
// Contract: session key size validation
//
// The negotiated session key must be exactly the size required by the
// chosen cipher. Mismatched sizes would cause either truncation or
// buffer overflow when the key is copied into the cipher context.
// ---------------------------------------------------------------------------
contract SessionKeySizeValidation {
input(
key_size: Nat,
required_key_size: Nat
)
requires { key_size > 0 }
requires { required_key_size > 0 }
requires { key_size == required_key_size }
requires { required_key_size <= 64 }
// PROVEN BY Z3: key size matches requirement
ensures { key_size == required_key_size }
ensures { key_size <= 64 }
effects { pure }
}
// ---------------------------------------------------------------------------
// Standalone fn: validate banner length
// ---------------------------------------------------------------------------
fn validate_banner_length(
banner_length: Nat,
max_banner_length: Nat
)
requires { banner_length >= 0 }
requires { max_banner_length > 0 }
requires { banner_length <= max_banner_length }
requires { max_banner_length <= 8192 }
ensures { banner_length <= 8192 }
ensures { max_banner_length >= banner_length }
effects { pure }
// ============================================================================
// Summary: What Assura proves at compile time
//
// TYPE.5 (Option types): Nullable pointers are replaced by Option<T>.
// Accessing the inner value requires pattern matching on Some/None.
// Null dereference is a compile-time type error, not a runtime crash.
//
// MEM.1 (Linear types): Buffers freed during key exchange are linear
// resources. The compiler prevents double-free (A05002) and ensures
// freed buffers are never accessed (A05001).
//
// Verified properties:
// 1. AlgorithmListBounds: Algorithm count within safe limits
// 2. KexMessageBounds: Message size within parsing limits
// 3. SafeStringExtraction: String fields fit within message
// 4. SessionKeySizeValidation: Key size matches cipher requirement
// 5. validate_banner_length: Banner length within limits
//
// Result: Null pointer dereference and double-free during SSH key
// exchange are impossible. The OpenSSH pre-auth class of bugs
// cannot exist in Assura.
// ============================================================================