|  | #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)); | 
|  | } | 
|  |  |