Skip to content

Commit d6b2bb7

Browse files
Start proving client serialization safety
1 parent 5016936 commit d6b2bb7

File tree

7 files changed

+196
-101
lines changed

7 files changed

+196
-101
lines changed

theories/Client.v

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Open Scope sint63_scope.
1313
(**
1414
The internal loop of our client sending thread
1515
*)
16-
Definition client_send_thread (uname_sockfd : username * file_descr) : optionE unit :=
16+
Definition client_send_thread (uname_sockfd : username * file_descr) : result unit :=
1717
let '(uname, sockfd) := uname_sockfd in
1818
repeat_until_timeout max_int (fun _ =>
1919
let* _ <= print_string ">>> " #;
@@ -46,18 +46,18 @@ Definition client_send_thread (uname_sockfd : username * file_descr) : optionE u
4646
send_message sockfd (serialize_client_message
4747
(MESG msg))
4848
else
49-
SomeE tt)) with
50-
| SomeE _ => SomeE Recurse
51-
| NoneE s =>
49+
Ok tt)) with
50+
| Ok _ => Ok Recurse
51+
| Error s =>
5252
let* _ <= log Log_Error s #;
53-
SomeE Recurse
53+
Ok Recurse
5454
end
5555
).
5656

5757
(**
5858
The internal loop of our client receiving thread
5959
*)
60-
Definition client_recv_thread (sockfd : file_descr) : optionE unit :=
60+
Definition client_recv_thread (sockfd : file_descr) : result unit :=
6161
repeat_until_timeout max_int (fun _ =>
6262
server_msg <- recv_server_message sockfd ;;
6363
let* _ <= (match server_msg with
@@ -70,13 +70,13 @@ Definition client_recv_thread (sockfd : file_descr) : optionE unit :=
7070
print_string ">>> "
7171
| _ => tt
7272
end) #;
73-
SomeE Recurse
73+
Ok Recurse
7474
).
7575

7676
(**
7777
Wraps up all client logic: port binding, threading, etc.
7878
*)
79-
Definition client (host : string) (portno : port) : optionE unit :=
79+
Definition client (host : string) (portno : port) : result unit :=
8080
(* Obtain username from user *)
8181
let* _ <= print_endline "Please enter a username (length 1-32, no spaces)" #;
8282
username_string <- read_line tt ;;
@@ -101,9 +101,9 @@ Definition client (host : string) (portno : port) : optionE unit :=
101101
(* Display chatroom information to user output *)
102102
let* _ <= log Log_Info ("Total users: " ++ (string_of_int num_users)) #;
103103
(* Get user input *)
104-
input_thread <- create (username *file_descr) (optionE unit) client_send_thread (uname, socket_fd) ;;
104+
input_thread <- create (username *file_descr) (result unit) client_send_thread (uname, socket_fd) ;;
105105
(* Display server messages *)
106-
recv_thread <- create file_descr (optionE unit) client_recv_thread socket_fd ;;
106+
recv_thread <- create file_descr (result unit) client_recv_thread socket_fd ;;
107107
let* _ <= join input_thread #;
108108
(* let* _ <= join recv_thread #; *)
109109
let* _ <= log Log_Info "Closing connection to server" #;

theories/Messages.v

Lines changed: 111 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ Open Scope Z_scope.
1717
Open Scope sint63_scope.
1818
Open Scope list_scope.
1919
Open Scope monad_scope.
20-
2120
(** ** Usernames
2221
2322
Usernames have specific properties per the project requirements. This
2423
section implements a dependently-typed Record type for usernames and some
2524
automation to create them at will.
25+
2626
*)
2727

2828
(**
@@ -34,6 +34,8 @@ Record username : Type := {
3434
(1 <= to_Z (int_len_string Uname) <= 32)%Z
3535
; NoSpaces :
3636
~ InString space Uname
37+
; NoNulls :
38+
~ InString (ascii_of_byte "000"%byte) Uname
3739
}.
3840

3941
(**
@@ -49,7 +51,7 @@ Record username : Type := {
4951
*)
5052
Definition validate_username (name : string) : bool :=
5153
((1 <=? int_len_string name) && (int_len_string name <=? 32))
52-
&& (no_spaces name).
54+
&& (no_spaces name) && (no_nulls name).
5355

5456
(**
5557
Ensure that [validate_username] provides
@@ -60,45 +62,58 @@ Theorem validate_username_correct :
6062
forall (name : string)
6163
(VALID : validate_username name = true),
6264
(1 <= to_Z (int_len_string name) <= 32)%Z /\
63-
~ InString space name.
65+
~ InString space name /\ ~ InString (ascii_of_byte "000"%byte) name.
6466
Proof.
6567
intros. unfold validate_username in VALID.
66-
apply andb_true_iff in VALID.
67-
destruct VALID as [Length NoSpaces].
68-
apply andb_true_iff in Length.
69-
destruct Length as [NonEmpty Le32].
68+
rewrite andb_true_iff in VALID.
69+
destruct VALID as (VALID & NoNulls).
70+
rewrite andb_true_iff in VALID.
71+
destruct VALID as (VALID & NoSpaces).
72+
rewrite andb_true_iff in VALID.
73+
destruct VALID as (NonEmpty & Le32).
7074
apply leb_spec in NonEmpty, Le32.
7175
split.
72-
- change 1%Z with (to_Z 1). now split.
76+
change 1%Z with (to_Z 1). now split.
77+
split.
7378
- clear - NoSpaces. induction name as [| a name']. auto.
7479
simpl. simpl in NoSpaces.
7580
destruct (ascii_dec a space) as [a_space|a_space].
7681
-- inversion NoSpaces.
7782
-- intro Contra. destruct Contra.
7883
+ now apply a_space.
7984
+ now apply IHname'.
85+
- clear - NoNulls. induction name as [| a name']. auto.
86+
simpl. simpl in NoNulls.
87+
destruct (ascii_dec a (ascii_of_byte "000"%byte)) as [a_null|a_null].
88+
-- inversion NoNulls.
89+
-- intro Contra. destruct Contra.
90+
+ now apply a_null.
91+
+ now apply IHname'.
8092
Qed.
8193

8294
(**
8395
Instantiate a username object if it
8496
passes [validate_username], or return
8597
[None]
8698
*)
87-
Definition new_username (s : string) : optionE username.
99+
Definition new_username (s : string) : result username.
88100
destruct (validate_username s) eqn:E.
89101
- apply validate_username_correct in E.
90-
destruct E.
91-
exact (SomeE {|
102+
destruct E, H0.
103+
exact (Ok {|
92104
Uname := s;
93105
ValidLength := H;
94-
NoSpaces := H0
106+
NoSpaces := H0;
107+
NoNulls := H1
95108
|}).
96109
- destruct (no_spaces s).
97-
-- (* No Spaces *)
98-
exact (NoneE
110+
-- (* No Spaces *)
111+
destruct (no_nulls s).
112+
exact (Error ("Username cannot contain nulls")).
113+
exact (Error
99114
("Username length must be in range [1..32]: '" ++ s ++ "'")).
100115
-- (* Spaces *)
101-
exact (NoneE ("Username cannot contain spaces: '" ++ s ++ "'")).
116+
exact (Error ("Username cannot contain spaces: '" ++ s ++ "'")).
102117
Defined.
103118

104119
(** A placeholder username *)
@@ -107,7 +122,9 @@ Definition dummy_username : username.
107122
(split; unfold to_Z, Uint63.to_Z; simpl; lia).
108123
assert (~ InString space "X") by
109124
(intro; destruct H0; [discriminate | auto]).
110-
exact {|Uname := "X"; ValidLength := H; NoSpaces := H0|}.
125+
assert (~ InString (ascii_of_byte "000"%byte) "X") by
126+
(intro; destruct H1; [discriminate | auto]).
127+
exact {|Uname := "X"; ValidLength := H; NoSpaces := H0; NoNulls := H1|}.
111128
Defined.
112129

113130
(** Username equality *)
@@ -183,7 +200,7 @@ Definition serialize_client_message (cm : client_message) : bytes :=
183200
end.
184201

185202
(** Convert a list of [byte]s into a [client_message] *)
186-
Definition deserialize_client_message (b : bytes) : optionE client_message :=
203+
Definition deserialize_client_message (b : bytes) : result client_message :=
187204
match b with
188205
| x00 :: t =>
189206
uname <- new_username (trim_null t) ;;
@@ -197,9 +214,65 @@ Definition deserialize_client_message (b : bytes) : optionE client_message :=
197214
| x03 :: t =>
198215
uname <- new_username (trim_null t) ;;
199216
return (EXIT uname)
200-
| _ => NoneE ("Client message code not recognized: " ++ (string_of_bytes b))
217+
| _ => Error ("Client message code not recognized: " ++ (string_of_bytes b))
201218
end.
202219

220+
Lemma create_null_list_forall : forall n,
221+
Forall (fun b0 : byte => b0 = "000"%byte) (create_list_nat "000"%byte n).
222+
Proof.
223+
induction n.
224+
apply Forall_nil.
225+
apply Forall_cons. reflexivity.
226+
apply IHn.
227+
Qed.
228+
229+
Lemma trim_null_app : forall n l,
230+
trim_null (l ++ create_list_nat "000"%byte n) = trim_null l.
231+
Proof.
232+
intros. pose proof (create_null_list_forall n).
233+
remember (create_list_nat _ _).
234+
clear Heql0.
235+
induction l.
236+
Admitted.
237+
238+
Lemma trim_null_pad_r : forall (s : string) (p : int),
239+
trim_null (bytes_of_string (pad_string_r s "000" p)) = trim_null (bytes_of_string s).
240+
Proof.
241+
intros. unfold pad_string_r. rewrite bytes_of_string_app, bytes_of_string_of_bytes.
242+
unfold create_list. apply trim_null_app.
243+
Qed.
244+
245+
Lemma not_instring_inv : forall c a s,
246+
~ InString c (String a s) -> c <> a /\ ~ InString c s.
247+
Proof.
248+
intros. split.
249+
intro. apply H. subst. unfold InString. now left.
250+
intro. apply H. unfold InString. right. apply H0.
251+
Qed.
252+
253+
Lemma trim_null_uname : forall uname,
254+
trim_null (bytes_of_string (Uname uname)) = Uname uname.
255+
Proof.
256+
intros. pose proof (NoNulls uname). induction (Uname uname).
257+
reflexivity.
258+
apply not_instring_inv in H. destruct H.
259+
Admitted.
260+
261+
Lemma new_username_clean : forall (name : username),
262+
new_username (trim_null (bytes_of_string (pad_string_r (Uname name) "000" 32))) = Ok name.
263+
Proof.
264+
intros. rewrite trim_null_pad_r, trim_null_uname.
265+
enough (validate_username (Uname name) = true).
266+
Admitted.
267+
268+
Theorem serialize_client_message_safe :
269+
forall (cm : client_message),
270+
deserialize_client_message (serialize_client_message cm) = Ok cm.
271+
Proof.
272+
intros. destruct cm.
273+
- simpl. unfold serialize_username. now rewrite new_username_clean.
274+
Admitted.
275+
203276
Theorem serialize_username_len : forall (u : username),
204277
int_len_list (serialize_username u) = 32.
205278
Proof.
@@ -308,7 +381,7 @@ Definition serialize_server_message (sm : server_message) : bytes :=
308381
end.
309382

310383
(** Convert a list of [byte]s into a [server_message] *)
311-
Definition deserialize_server_message (b : bytes) : optionE server_message :=
384+
Definition deserialize_server_message (b : bytes) : result server_message :=
312385
match b with
313386
(** This case isn't helpful... why should we deserialize
314387
something when we don't even know how many bytes to pull?
@@ -346,7 +419,7 @@ Function resend
346419
(sockfd : file_descr) (message : bytes)
347420
(len_msg : int)
348421
{measure (fun x => (Z.to_nat (to_Z x))) fuel}
349-
: optionE unit :=
422+
: result unit :=
350423
if sub1_no_underflow fuel then
351424
let send_result := n_sent + send sockfd message n_sent (len_msg - n_sent) [] in
352425
(* If uncommented, the extractor will call [send] twice, because it tries
@@ -355,45 +428,45 @@ Function resend
355428
if send_result <? len_msg then
356429
resend (fuel - 1) send_result sockfd message len_msg
357430
else
358-
SomeE tt
431+
Ok tt
359432
else
360-
NoneE ("Timed out while sending message '" ++ (string_of_bytes message) ++ "'").
433+
Error ("Timed out while sending message '" ++ (string_of_bytes message) ++ "'").
361434
prove_sub1.
362435
Defined.
363436

364437
(** Wrapper for [resend] *)
365-
Definition send_message (sockfd : file_descr) (message : bytes) : optionE unit :=
438+
Definition send_message (sockfd : file_descr) (message : bytes) : result unit :=
366439
resend 100 0 sockfd message (int_len_list message).
367440

368441
(** Receives a message from a socket *)
369-
Definition recv_message (sockfd : file_descr) (len : int) : optionE bytes :=
442+
Definition recv_message (sockfd : file_descr) (len : int) : result bytes :=
370443
match recv sockfd 0 len [] with
371-
| (_, out) => SomeE out
444+
| (_, out) => Ok out
372445
end.
373446

374447
(** Receives a message from a socket and deserializes it as a client message *)
375-
(* Definition recv_client_message (sockfd : file_descr) : optionE client_message :=
448+
(* Definition recv_client_message (sockfd : file_descr) : result client_message :=
376449
msg_bytes <- recv_message sockfd max_message_len ;;
377450
deserialize_client_message msg_bytes. *)
378451

379452
(** Receives an int from a socket *)
380-
Definition recv_int (sockfd : file_descr) : optionE int :=
453+
Definition recv_int (sockfd : file_descr) : result int :=
381454
n_bytes <- recv_message sockfd 8 ;;
382455
return bytes_to_int63 (n_bytes).
383456

384457
(** Receives a string from a socket *)
385-
Definition recv_string (sockfd : file_descr) : optionE string :=
458+
Definition recv_string (sockfd : file_descr) : result string :=
386459
str_len <- recv_int sockfd ;;
387460
str_bytes <- recv_message sockfd str_len ;;
388461
return string_of_bytes (str_bytes).
389462

390-
Definition recv_username (sockfd : file_descr) : optionE username :=
463+
Definition recv_username (sockfd : file_descr) : result username :=
391464
username_bytes <- recv_message sockfd 32 ;;
392465
uname <- new_username (string_of_bytes username_bytes) ;;
393466
return uname.
394467

395468
(** Receives an ACK message *)
396-
Definition recv_server_ACK (sockfd : file_descr) : optionE server_message :=
469+
Definition recv_server_ACK (sockfd : file_descr) : result server_message :=
397470
(* Receive a serialized int63 detailing number of connected users *)
398471
num_users <- recv_int sockfd ;;
399472
usernames_bytes <- recv_message sockfd (num_users * 32) ;;
@@ -404,18 +477,18 @@ Definition recv_server_ACK (sockfd : file_descr) : optionE server_message :=
404477
return ACK num_users usernames.
405478

406479
(** Receives a server MSG message *)
407-
Definition recv_server_MSG (sockfd : file_descr) : optionE server_message :=
480+
Definition recv_server_MSG (sockfd : file_descr) : result server_message :=
408481
username <- recv_username sockfd ;;
409482
msg <- recv_string sockfd ;;
410483
return MSG username msg.
411484

412-
Definition recv_server_ERR (sockfd : file_descr) : optionE server_message :=
485+
Definition recv_server_ERR (sockfd : file_descr) : result server_message :=
413486
err_code <- recv_int sockfd ;;
414487
return ERR (error_of_int err_code).
415488

416489
(** Consumes the message code and dispatches to specific receiver functions to
417490
deserialize and parse a server message*)
418-
Definition recv_server_message (sockfd : file_descr) : optionE server_message :=
491+
Definition recv_server_message (sockfd : file_descr) : result server_message :=
419492
code <- recv_message sockfd 1 ;;
420493
match code with
421494
| [x00] => recv_server_ACK sockfd
@@ -424,24 +497,24 @@ Definition recv_server_message (sockfd : file_descr) : optionE server_message :=
424497
| _ => fail ("Failed to receieve server message with opcode " ++ (string_of_bytes code))
425498
end.
426499

427-
Definition recv_client_REG (sockfd : file_descr) : optionE client_message :=
500+
Definition recv_client_REG (sockfd : file_descr) : result client_message :=
428501
uname <- recv_username sockfd ;;
429502
return REG uname.
430503

431-
Definition recv_client_MESG (sockfd : file_descr) : optionE client_message :=
504+
Definition recv_client_MESG (sockfd : file_descr) : result client_message :=
432505
msg <- recv_string sockfd ;;
433506
return MESG msg.
434507

435-
Definition recv_client_PMSG (sockfd : file_descr) : optionE client_message :=
508+
Definition recv_client_PMSG (sockfd : file_descr) : result client_message :=
436509
uname <- recv_username sockfd ;;
437510
msg <- recv_string sockfd ;;
438511
return PMSG msg uname.
439512

440-
Definition recv_client_EXIT (sockfd : file_descr) : optionE client_message :=
513+
Definition recv_client_EXIT (sockfd : file_descr) : result client_message :=
441514
uname <- recv_username sockfd ;;
442515
return EXIT uname.
443516

444-
Definition recv_client_message (sockfd : file_descr) : optionE client_message :=
517+
Definition recv_client_message (sockfd : file_descr) : result client_message :=
445518
code <- recv_message sockfd 1 ;;
446519
match code with
447520
| [x00] => recv_client_REG sockfd

0 commit comments

Comments
 (0)