blob: 73b9b1a956dd24f3d49dd8279e39d8b992767bf1 [file] [log] [blame]
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <malloc.h>
#include <termios.h>
#include <strings.h>
#include "syscall_server.h"
#define debug(...) printf(__VA_ARGS__)
int main()
{
run_server();
return 0;
}
// Poll for incoming messages and send responses.
void run_server()
{
// Struct for reading the syscall over the channel
syscall_req_t syscall_req;
syscall_rsp_t syscall_rsp;
int fd_read, fd_write;
int ret = init_syscall_server(&fd_read, &fd_write);
if(ret < 0)
error(ret, "Could not open file desciptors for communication\n");
printf("Server started....");
// Continuously read in data from the channel socket
while(1) {
syscall_req.payload_len = 0;
syscall_req.payload = NULL;
syscall_rsp.payload_len = 0;
syscall_rsp.payload = NULL;
debug("\nWaiting for syscall...\n");
read_syscall_req(fd_read, &syscall_req);
debug("Processing syscall: %d\n", syscall_req.header.id);
handle_syscall(&syscall_req, &syscall_rsp);
debug("Writing response: %d\n", syscall_req.header.id);
write_syscall_rsp(fd_write, &syscall_rsp);
if(syscall_req.payload != NULL)
free(syscall_req.payload);
if(syscall_rsp.payload != NULL)
free(syscall_rsp.payload);
}
}
void read_syscall_req(int fd, syscall_req_t* req)
{
read_syscall_req_header(fd, req);
set_syscall_req_payload_len(req);
read_syscall_req_payload(fd, req);
}
void set_syscall_req_payload_len(syscall_req_t* req)
{
switch(req->header.id) {
case OPEN_ID:
req->payload_len = req->header.subheader.open.len;
break;
case WRITE_ID:
req->payload_len = req->header.subheader.write.len;
break;
case LINK_ID:
req->payload_len = req->header.subheader.link.old_len
+ req->header.subheader.link.new_len;
break;
case UNLINK_ID:
req->payload_len = req->header.subheader.unlink.len;
break;
case STAT_ID:
req->payload_len = req->header.subheader.stat.len;
break;
}
}
void read_syscall_req_header(int fd, syscall_req_t* req)
{
// Try to read the syscall id from the socket.
// If no data available, spin until there is
int bytes_read = 0;
bytes_read = read_from_channel(fd, &req->header, sizeof(req->header.id), 0);
// If no data, or the ID we got is bad, terminate process.
uint32_t id = req->header.id;
if ((bytes_read < 0) || (id < 0) || (id > NUM_SYSCALLS)) {
perror("Problems reading the id from the channel...");
}
// Otherwise, start grabbing the rest of the data
bytes_read = read_from_channel(fd, &req->header.subheader,
sizeof(req->header.subheader) , 0);
if(bytes_read < 0)
error(fd, "Problems reading header from the channel...");
}
void read_syscall_req_payload(int fd, syscall_req_t* req) {
if (req->payload_len == 0)
return;
req->payload = malloc(req->payload_len);
if (req->payload == NULL)
error(fd, "No free memory!");
int bytes_read = read_from_channel(fd, req->payload, req->payload_len, 0);
if (bytes_read < 0)
error(fd, "Problems reading payload from channel");
}
// Read len bytes from the given socket to the buffer.
// If peek is 0, will wait indefinitely until that much data is read.
// If peek is 1, if no data is available, will return immediately.
int read_from_channel(int fd, void* buf, int len, int peek)
{
int total_read = 0;
int just_read = read_syscall_server(fd, buf, len);
if (just_read < 0) return just_read;
if (just_read == 0 && peek) return just_read;
total_read += just_read;
while (total_read != len) {
just_read = read_syscall_server(fd, buf + total_read, len - total_read);
if (just_read < 0) return just_read;
total_read += just_read;
}
return total_read;
}
// Send CONNECTION_TERMINATED over the FD (if possible)
void error(int fd, const char* s)
{
fprintf(stderr, "Error: FD: %i\n",fd);
perror(s);
fprintf(stderr, "Sending CONNECTION_TERMINATED.... \n");
close(fd);
exit(-1);
}
void handle_syscall(syscall_req_t* req, syscall_rsp_t* rsp)
{
switch (req->header.id) {
case OPEN_ID:
handle_open(req, rsp);
break;
case CLOSE_ID:
handle_close(req, rsp);
break;
case READ_ID:
handle_read(req, rsp);
break;
case WRITE_ID:
handle_write(req, rsp);
break;
case LINK_ID:
handle_link(req, rsp);
break;
case UNLINK_ID:
handle_unlink(req, rsp);
break;
case LSEEK_ID:
handle_lseek(req, rsp);
break;
case FSTAT_ID:
handle_fstat(req, rsp);
break;
case ISATTY_ID:
handle_isatty(req, rsp);
break;
case STAT_ID:
handle_stat(req, rsp);
break;
default:
error(-1, "Illegal syscall, should never be here...");
}
rsp->header.return_errno = errno;
}
void write_syscall_rsp(int fd, syscall_rsp_t* rsp)
{
write_syscall_rsp_header(fd, rsp);
write_syscall_rsp_payload(fd, rsp);
}
void write_syscall_rsp_header(int fd, syscall_rsp_t* rsp)
{
int written = write_syscall_server(fd, (char*)&rsp->header,
sizeof(syscall_rsp_header_t), rsp->payload_len);
if (written < 0)
error(fd, "Problems writing the syscall response header...");
}
void write_syscall_rsp_payload(int fd, syscall_rsp_t* rsp)
{
if(rsp->payload_len == 0)
return;
int written = write_syscall_server(fd, rsp->payload, rsp->payload_len, 0);
if (written < 0)
error(fd, "Problems writing the syscall response payload...");
if (written < rsp->payload_len)
error(fd, "Problems writing all bytes in the response payload...");
}
char* sandbox_file_name(char* name, uint32_t len) {
char* new_name = malloc(len + sizeof(SANDBOX_DIR) - 1);
if (new_name == NULL)
perror("No free memory!");
sprintf(new_name, "%s%s", SANDBOX_DIR, name);
printf("%s\n", new_name);
return new_name;
}
void handle_open(syscall_req_t* req, syscall_rsp_t* rsp)
{
char* name = sandbox_file_name(req->payload, req->payload_len);
open_subheader_t* o = &req->header.subheader.open;
int native_flags = translate_flags(o->flags);
int native_mode = translate_mode(o->mode);
rsp->header.return_val = open(name, native_flags, native_mode);
free(name);
}
void handle_close(syscall_req_t* req, syscall_rsp_t* rsp)
{
close_subheader_t* c = &req->header.subheader.close;
rsp->header.return_val = close(c->fd);
}
void handle_read(syscall_req_t* req, syscall_rsp_t* rsp)
{
read_subheader_t* r = &req->header.subheader.read;
rsp->payload = malloc(r->len);
if (rsp->payload == NULL)
perror("No free memory!");
rsp->header.return_val = read(r->fd, rsp->payload, r->len);
if(rsp->header.return_val >= 0)
rsp->payload_len = rsp->header.return_val;
}
void handle_write(syscall_req_t* req, syscall_rsp_t* rsp)
{
write_subheader_t* w = &req->header.subheader.write;
rsp->header.return_val = write(w->fd, req->payload, w->len);
}
void handle_link(syscall_req_t* req, syscall_rsp_t* rsp)
{
link_subheader_t* l = &req->header.subheader.link;
char* old_name = sandbox_file_name(req->payload, l->old_len);
char* new_name = sandbox_file_name(req->payload + l->old_len, l->new_len);
rsp->header.return_val = link(old_name, new_name);
free(old_name);
free(new_name);
}
void handle_unlink(syscall_req_t* req, syscall_rsp_t* rsp)
{
char* name = sandbox_file_name(req->payload, req->payload_len);
rsp->header.return_val = unlink(name);
free(name);
}
void handle_lseek(syscall_req_t* req, syscall_rsp_t* rsp)
{
lseek_subheader_t* l = &req->header.subheader.lseek;
int native_whence = translate_whence(l->dir);
rsp->header.return_val = lseek(l->fd, l->ptr, native_whence);
}
void handle_fstat(syscall_req_t* req, syscall_rsp_t* rsp)
{
struct stat native_struct;
fstat_subheader_t* f = &req->header.subheader.fstat;
rsp->payload = malloc(sizeof(newlib_stat_t));
if (rsp->payload == NULL)
perror("No free memory!");
rsp->header.return_val = fstat(f->fd, &native_struct);
if(rsp->header.return_val >= 0)
rsp->payload_len = sizeof(newlib_stat_t);
translate_stat(&native_struct, (newlib_stat_t*)(rsp->payload));
}
void handle_isatty(syscall_req_t* req, syscall_rsp_t* rsp)
{
isatty_subheader_t* i = &req->header.subheader.isatty;
rsp->header.return_val = isatty(i->fd);
}
void handle_stat(syscall_req_t* req, syscall_rsp_t* rsp)
{
struct stat native_struct;
rsp->payload = malloc(sizeof(newlib_stat_t));
if (rsp->payload == NULL)
perror("No free memory!");
rsp->header.return_val = stat(req->payload, &native_struct);
if(rsp->header.return_val >= 0)
rsp->payload_len = sizeof(newlib_stat_t);
translate_stat(&native_struct, (newlib_stat_t*)(rsp->payload));
}