-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsrc.asm
More file actions
231 lines (188 loc) · 4.3 KB
/
Copy pathsrc.asm
File metadata and controls
231 lines (188 loc) · 4.3 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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
.intel_syntax noprefix
.globl _start
_start:
# --- socket(AF_INET=2, SOCK_STREAM=1, 0)
mov rdi, 2
mov rsi, 1
xor rdx, rdx
mov rax, 41
syscall
mov r12, rax # listenfd
# --- bind(listenfd, &sockaddr, 16)
mov rdi, r12
lea rsi, [rip + sockaddr]
mov rdx, 16
mov rax, 49
syscall
# --- listen(listenfd, backlog=16)
mov rdi, r12
mov rsi, 16
mov rax, 50
syscall
accept_loop:
# --- accept(listenfd, NULL, NULL)
mov rdi, r12
xor rsi, rsi
xor rdx, rdx
mov rax, 43
syscall
mov r13, rax # connfd
# --- fork()
mov rax, 57
syscall
test rax, rax
jz child_process
parent_process:
# parent closes connfd and loops back to accept again
mov rdi, r13
mov rax, 3 # close
syscall
jmp accept_loop
child_process:
# child closes listenfd
mov rdi, r12
mov rax, 3 # close
syscall
# reserve stack buffer for request
sub rsp, 4096
mov rbx, rsp # buf_start
# --- read(connfd, buf, 4096)
xor rax, rax # read
mov rdi, r13
mov rsi, rbx
mov rdx, 4096
syscall
mov r15, rax # bytes_read
cmp r15, 0
jle send_400_and_exit
lea r10, [rbx]
# --- find first space after method
find_method_sp:
mov al, byte ptr [r10]
cmp al, ' '
je method_sp_found
inc r10
jmp find_method_sp
method_sp_found:
inc r10 # now at start of path
# strip leading '/' so open() isn't absolute path, otherwise it would be a massive security issue
mov al, byte ptr [r10]
cmp al, '/'
jne path_start_ok
inc r10
path_start_ok:
mov r11, r10
find_path_sp:
mov al, byte ptr [r11]
cmp al, ' '
je path_sp_found
inc r11
jmp find_path_sp
path_sp_found:
mov byte ptr [r11], 0 # NUL-terminate path
# minimal traversal protection: reject ".." anywhere in path
mov r8, r10 # scan = path_start
scan_dotdot:
mov al, byte ptr [r8]
test al, al
je dotdot_ok
cmp al, '.'
jne dotdot_next
mov dl, byte ptr [r8 + 1]
cmp dl, '.'
je send_400_and_exit
dotdot_next:
inc r8
jmp scan_dotdot
dotdot_ok:
# --- find end of headers: "\r\n\r\n"
lea r14, [rbx]
find_hdr_end:
mov al, byte ptr [r14]
cmp al, 13 # \r
jne hdr_inc
mov al, byte ptr [r14 + 1]
cmp al, 10 # \n
jne hdr_inc
mov al, byte ptr [r14 + 2]
cmp al, 13 # \r
jne hdr_inc
mov al, byte ptr [r14 + 3]
cmp al, 10 # \n
jne hdr_inc
jmp hdr_end_found
hdr_inc:
inc r14
jmp find_hdr_end
hdr_end_found:
add r14, 4 # payload_start = header_end + 4
# payload_len = bytes_read - (payload_start - buf_start)
mov rdx, r15 # rdx = bytes_read
mov rcx, r14 # rcx = payload_start
sub rcx, rbx # rcx = payload_start - buf_start
sub rdx, rcx # rdx = payload_len
jl send_400_and_exit # malformed if negative
# --- open(path, O_WRONLY|O_CREAT|O_TRUNC, 0777)
mov rdi, r10 # filename
mov rsi, 1 # O_WRONLY
or rsi, 0x40 # O_CREAT
or rsi, 0x200 # O_TRUNC
mov rdx, 0777
mov rax, 2 # open
syscall
cmp rax, 0
jl send_500_and_exit
mov r12, rax # filefd (reuse r12 in child)
# --- write(filefd, payload_start, payload_len)
mov rdi, r12
mov rsi, r14
# rdx already payload_len
mov rax, 1
syscall
# close(filefd)
mov rdi, r12
mov rax, 3
syscall
# --- write(connfd, "HTTP/1.0 200 OK\r\n\r\n", 19)
mov rdi, r13
lea rsi, [rip + http_ok]
mov rdx, 19
mov rax, 1
syscall
jmp child_exit
send_400_and_exit:
mov rdi, r13
lea rsi, [rip + http_400]
mov rdx, http_400_len
mov rax, 1
syscall
jmp child_exit
send_500_and_exit:
mov rdi, r13
lea rsi, [rip + http_500]
mov rdx, http_500_len
mov rax, 1
syscall
jmp child_exit
child_exit:
# close(connfd)
mov rdi, r13
mov rax, 3
syscall
mov rax, 60 # exit(0)
xor rdi, rdi
syscall
.section .data
sockaddr:
.word 2 # AF_INET
.word 0x5000 # port 80 in network byte order (htons(80))
.long 0 # INADDR_ANY
.quad 0
http_ok:
.ascii "HTTP/1.0 200 OK\r\n\r\n"
http_400:
.ascii "HTTP/1.0 400 Bad Request\r\n\r\n"
.set http_400_len, . - http_400
http_500:
.ascii "HTTP/1.0 500 Internal Server Error\r\n\r\n"
.set http_500_len, . - http_500