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