| |
| |
| |
| |
| |
| |
| |
| |
| |
| #include "ftppolicy.h" |
| #include "ptracesandbox.h" |
| #include "tunables.h" |
| #include "session.h" |
| #include "sysutil.h" |
| |
| |
| #include <sys/types.h> |
| #include <sys/socket.h> |
| #include <netinet/in_systm.h> |
| #include <netinet/in.h> |
| #include <netinet/ip.h> |
| #include <netinet/tcp.h> |
| |
| static int socket_validator(struct pt_sandbox* p_sandbox, void* p_arg); |
| static int connect_validator(struct pt_sandbox* p_sandbox, void* p_arg); |
| static int getsockopt_validator(struct pt_sandbox* p_sandbox, void* p_arg); |
| static int setsockopt_validator(struct pt_sandbox* p_sandbox, void* p_arg); |
| |
| void |
| policy_setup(struct pt_sandbox* p_sandbox, const struct vsf_session* p_sess) |
| { |
| int is_anon = p_sess->is_anonymous; |
| |
| ptrace_sandbox_permit_exit(p_sandbox); |
| |
| ptrace_sandbox_permit_mmap(p_sandbox); |
| ptrace_sandbox_permit_mprotect(p_sandbox); |
| ptrace_sandbox_permit_brk(p_sandbox); |
| |
| |
| |
| ptrace_sandbox_permit_read(p_sandbox); |
| ptrace_sandbox_permit_write(p_sandbox); |
| |
| ptrace_sandbox_permit_recv(p_sandbox); |
| |
| |
| |
| ptrace_sandbox_permit_query_time(p_sandbox); |
| |
| |
| |
| |
| |
| ptrace_sandbox_permit_open(p_sandbox, 0); |
| ptrace_sandbox_permit_close(p_sandbox); |
| |
| ptrace_sandbox_permit_file_stats(p_sandbox); |
| ptrace_sandbox_permit_readlink(p_sandbox); |
| |
| ptrace_sandbox_permit_getcwd(p_sandbox); |
| ptrace_sandbox_permit_chdir(p_sandbox); |
| ptrace_sandbox_permit_getdents(p_sandbox); |
| |
| ptrace_sandbox_permit_fd_stats(p_sandbox); |
| ptrace_sandbox_permit_seek(p_sandbox); |
| ptrace_sandbox_permit_shutdown(p_sandbox); |
| ptrace_sandbox_permit_fcntl(p_sandbox); |
| ptrace_sandbox_permit_setsockopt(p_sandbox); |
| ptrace_sandbox_set_setsockopt_validator(p_sandbox, setsockopt_validator, 0); |
| |
| |
| ptrace_sandbox_permit_umask(p_sandbox); |
| |
| ptrace_sandbox_permit_select(p_sandbox); |
| |
| ptrace_sandbox_permit_sigreturn(p_sandbox); |
| |
| ptrace_sandbox_permit_sleep(p_sandbox); |
| |
| ptrace_sandbox_permit_sendfile(p_sandbox); |
| |
| |
| |
| |
| if (tunable_text_userdb_names) |
| { |
| ptrace_sandbox_permit_mremap(p_sandbox); |
| } |
| |
| if (tunable_async_abor_enable || |
| tunable_idle_session_timeout > 0 || |
| tunable_data_connection_timeout > 0) |
| { |
| ptrace_sandbox_permit_sigaction(p_sandbox); |
| } |
| |
| if (tunable_idle_session_timeout > 0 || tunable_data_connection_timeout > 0) |
| { |
| ptrace_sandbox_permit_alarm(p_sandbox); |
| } |
| |
| ptrace_sandbox_permit_socket(p_sandbox); |
| ptrace_sandbox_set_socket_validator(p_sandbox, |
| socket_validator, |
| (void*) p_sess); |
| ptrace_sandbox_permit_bind(p_sandbox); |
| |
| ptrace_sandbox_set_bind_validator(p_sandbox, |
| connect_validator, |
| (void*) p_sess); |
| if (tunable_port_enable) |
| { |
| ptrace_sandbox_permit_connect(p_sandbox); |
| ptrace_sandbox_set_connect_validator(p_sandbox, |
| connect_validator, |
| (void*) p_sess); |
| ptrace_sandbox_permit_getsockopt(p_sandbox); |
| ptrace_sandbox_set_getsockopt_validator(p_sandbox, getsockopt_validator, 0); |
| } |
| if (tunable_pasv_enable) |
| { |
| ptrace_sandbox_permit_listen(p_sandbox); |
| ptrace_sandbox_permit_accept(p_sandbox); |
| } |
| |
| if (tunable_write_enable) |
| { |
| if (!is_anon || tunable_anon_upload_enable) |
| { |
| ptrace_sandbox_permit_open(p_sandbox, 1); |
| } |
| if (!is_anon || tunable_anon_mkdir_write_enable) |
| { |
| ptrace_sandbox_permit_mkdir(p_sandbox); |
| } |
| if (!is_anon || tunable_anon_other_write_enable) |
| { |
| ptrace_sandbox_permit_unlink(p_sandbox); |
| ptrace_sandbox_permit_rmdir(p_sandbox); |
| ptrace_sandbox_permit_rename(p_sandbox); |
| ptrace_sandbox_permit_ftruncate(p_sandbox); |
| if (tunable_mdtm_write) |
| { |
| ptrace_sandbox_permit_utime(p_sandbox); |
| } |
| } |
| if (!is_anon && tunable_chmod_enable) |
| { |
| ptrace_sandbox_permit_chmod(p_sandbox); |
| } |
| if (is_anon && tunable_chown_uploads) |
| { |
| ptrace_sandbox_permit_fchmod(p_sandbox); |
| ptrace_sandbox_permit_fchown(p_sandbox); |
| } |
| } |
| } |
| |
| static int |
| socket_validator(struct pt_sandbox* p_sandbox, void* p_arg) |
| { |
| int ret; |
| struct vsf_session* p_sess = (struct vsf_session*) p_arg; |
| unsigned long arg1; |
| unsigned long arg2; |
| unsigned long expected_family = AF_INET; |
| if (vsf_sysutil_sockaddr_is_ipv6(p_sess->p_local_addr)) |
| { |
| expected_family = AF_INET6; |
| } |
| ret = ptrace_sandbox_get_socketcall_arg(p_sandbox, 0, &arg1); |
| if (ret != 0) |
| { |
| return ret; |
| } |
| ret = ptrace_sandbox_get_socketcall_arg(p_sandbox, 1, &arg2); |
| if (ret != 0) |
| { |
| return ret; |
| } |
| if (arg1 != expected_family || arg2 != SOCK_STREAM) |
| { |
| return -1; |
| } |
| return 0; |
| } |
| |
| static int |
| connect_validator(struct pt_sandbox* p_sandbox, void* p_arg) |
| { |
| int ret; |
| struct vsf_session* p_sess = (struct vsf_session*) p_arg; |
| unsigned long arg2; |
| unsigned long arg3; |
| unsigned long expected_family = AF_INET; |
| unsigned long expected_len = sizeof(struct sockaddr_in); |
| void* p_buf = 0; |
| struct sockaddr* p_sockaddr; |
| static struct vsf_sysutil_sockaddr* p_sockptr; |
| if (vsf_sysutil_sockaddr_is_ipv6(p_sess->p_local_addr)) |
| { |
| expected_family = AF_INET6; |
| expected_len = sizeof(struct sockaddr_in6); |
| } |
| ret = ptrace_sandbox_get_socketcall_arg(p_sandbox, 1, &arg2); |
| if (ret != 0) |
| { |
| return ret; |
| } |
| ret = ptrace_sandbox_get_socketcall_arg(p_sandbox, 2, &arg3); |
| if (ret != 0) |
| { |
| return ret; |
| } |
| if (arg3 != expected_len) |
| { |
| return -1; |
| } |
| p_buf = vsf_sysutil_malloc((int) expected_len); |
| ret = ptrace_sandbox_get_buf(p_sandbox, arg2, expected_len, p_buf); |
| if (ret != 0) |
| { |
| vsf_sysutil_free(p_buf); |
| return -2; |
| } |
| p_sockaddr = (struct sockaddr*) p_buf; |
| if (p_sockaddr->sa_family != expected_family) |
| { |
| vsf_sysutil_free(p_buf); |
| return -3; |
| } |
| if (expected_family == AF_INET) |
| { |
| struct sockaddr_in* p_sockaddr_in = (struct sockaddr_in*) p_sockaddr; |
| vsf_sysutil_sockaddr_alloc_ipv4(&p_sockptr); |
| vsf_sysutil_sockaddr_set_ipv4addr(p_sockptr, |
| (const unsigned char*) |
| &p_sockaddr_in->sin_addr); |
| } |
| else |
| { |
| struct sockaddr_in6* p_sockaddr_in6 = (struct sockaddr_in6*) p_sockaddr; |
| vsf_sysutil_sockaddr_alloc_ipv6(&p_sockptr); |
| vsf_sysutil_sockaddr_set_ipv6addr(p_sockptr, |
| (const unsigned char*) |
| &p_sockaddr_in6->sin6_addr); |
| } |
| if (!vsf_sysutil_sockaddr_addr_equal(p_sess->p_remote_addr, p_sockptr)) |
| { |
| vsf_sysutil_free(p_buf); |
| return -4; |
| } |
| vsf_sysutil_free(p_buf); |
| return 0; |
| } |
| |
| static int |
| getsockopt_validator(struct pt_sandbox* p_sandbox, void* p_arg) |
| { |
| int ret; |
| unsigned long arg2; |
| unsigned long arg3; |
| (void) p_arg; |
| ret = ptrace_sandbox_get_socketcall_arg(p_sandbox, 1, &arg2); |
| if (ret != 0) |
| { |
| return ret; |
| } |
| ret = ptrace_sandbox_get_socketcall_arg(p_sandbox, 2, &arg3); |
| if (ret != 0) |
| { |
| return ret; |
| } |
| if (arg2 != SOL_SOCKET || arg3 != SO_ERROR) |
| { |
| return -1; |
| } |
| return 0; |
| } |
| |
| static int |
| setsockopt_validator(struct pt_sandbox* p_sandbox, void* p_arg) |
| { |
| int ret; |
| unsigned long arg2; |
| unsigned long arg3; |
| (void) p_arg; |
| ret = ptrace_sandbox_get_socketcall_arg(p_sandbox, 1, &arg2); |
| if (ret != 0) |
| { |
| return ret; |
| } |
| ret = ptrace_sandbox_get_socketcall_arg(p_sandbox, 2, &arg3); |
| if (ret != 0) |
| { |
| return ret; |
| } |
| if (arg2 == SOL_SOCKET) |
| { |
| if (arg3 != SO_KEEPALIVE && |
| arg3 != SO_REUSEADDR && |
| arg3 != SO_OOBINLINE && |
| arg3 != SO_LINGER) |
| { |
| return -1; |
| } |
| } |
| else if (arg2 == IPPROTO_TCP) |
| { |
| if (arg3 != TCP_NODELAY) |
| { |
| return -2; |
| } |
| } |
| else if (arg2 == IPPROTO_IP) |
| { |
| if (arg3 != IP_TOS) |
| { |
| return -3; |
| } |
| } |
| else |
| { |
| return -4; |
| } |
| return 0; |
| } |