From aa6ff039c46ffe51f5ceb49a500f07519e6b7f3b Mon Sep 17 00:00:00 2001 From: Joseph Henry Date: Tue, 13 Oct 2015 18:33:56 -0400 Subject: [PATCH] Improved bind() logic, added more error handling to accept() --- netcon/NetconEthernetTap.cpp | 18 ++++++++---- netcon/intercept.c | 53 +++++++++++++++++++++++------------ netcon/libintercept.so.1.0 | Bin 52984 -> 53400 bytes 3 files changed, 48 insertions(+), 23 deletions(-) diff --git a/netcon/NetconEthernetTap.cpp b/netcon/NetconEthernetTap.cpp index f01dcadf9..5ef52b72c 100644 --- a/netcon/NetconEthernetTap.cpp +++ b/netcon/NetconEthernetTap.cpp @@ -490,6 +490,12 @@ int NetconEthernetTap::send_return_value(int fd, int retval, int _errno = 0) * @param error code * @return ERR_OK if everything is ok, -1 otherwise + i := should be implemented in intercept lib + I := is implemented in intercept lib + X := is implemented in service + ? := required treatment Unknown + - := Not needed + [ ] EAGAIN or EWOULDBLOCK - The socket is marked nonblocking and no connections are present to be accepted. POSIX.1-2001 allows either error to be returned for this case, and does not require these constants to have the same value, @@ -499,12 +505,12 @@ int NetconEthernetTap::send_return_value(int fd, int retval, int _errno = 0) [i] EFAULT - The addr argument is not in a writable part of the user address space. [ ] EINTR - The system call was interrupted by a signal that was caught before a valid connection arrived; see signal(7). [ ] EINVAL - Socket is not listening for connections, or addrlen is invalid (e.g., is negative). - [ ] EINVAL - (accept4()) invalid value in flags. + [I] EINVAL - (accept4()) invalid value in flags. [I] EMFILE - The per-process limit of open file descriptors has been reached. [ ] ENFILE - The system limit on the total number of open files has been reached. [ ] ENOBUFS, ENOMEM - Not enough free memory. This often means that the memory allocation is limited by the socket buffer limits, not by the system memory. - [i] ENOTSOCK - The descriptor references a file, not a socket. + [I] ENOTSOCK - The descriptor references a file, not a socket. [I] EOPNOTSUPP - The referenced socket is not of type SOCK_STREAM. [ ] EPROTO - Protocol error. @@ -802,10 +808,12 @@ void NetconEthernetTap::handle_retval(PhySocket *sock, void **uptr, unsigned cha [ ] EACCES - The address is protected, and the user is not the superuser. [X] EADDRINUSE - The given address is already in use. - [X] EBADF - sockfd is not a valid descriptor. + [I] EBADF - sockfd is not a valid descriptor. [X] EINVAL - The socket is already bound to an address. - [i] ENOTSOCK - sockfd is a descriptor for a file, not a socket. - [-] The following errors are specific to UNIX domain (AF_UNIX) sockets: + [I] ENOTSOCK - sockfd is a descriptor for a file, not a socket. + + - The following errors are specific to UNIX domain (AF_UNIX) sockets: + [-] EACCES - Search permission is denied on a component of the path prefix. (See also path_resolution(7).) [-] EADDRNOTAVAIL - A nonexistent interface was requested or the requested address was not local. [-] EFAULT - addr points outside the user's accessible address space. diff --git a/netcon/intercept.c b/netcon/intercept.c index 46f01987a..5060aa2ce 100755 --- a/netcon/intercept.c +++ b/netcon/intercept.c @@ -688,6 +688,21 @@ int poll(POLL_SIG) bind() intercept function */ int bind(BIND_SIG) { +#ifdef CHECKS + /* Check that this is a valid fd */ + if(fcntl(sockfd, F_GETFD) < 0) { + return -1; + errno = EBADF; + } + /* Check that it is a socket */ + int sock_type = -1; + socklen_t sock_type_len = sizeof(sock_type); + if(getsockopt(sockfd, SOL_SOCKET, SO_TYPE, (void *) &sock_type, &sock_type_len) < 0) { + errno = ENOTSOCK; + return -1; + } +#endif + int err; #ifdef DUMMY dwr("bind(%d)\n", sockfd); @@ -697,28 +712,23 @@ int bind(BIND_SIG) if(sockfd == STDIN_FILENO || sockfd == STDOUT_FILENO || sockfd == STDERR_FILENO) return(realbind(sockfd, addr, addrlen)); - int sock_type = -1; - socklen_t sock_type_len = sizeof(sock_type); + /* If local, just use normal syscall */ struct sockaddr_in *connaddr; connaddr = (struct sockaddr_in *) addr; - getsockopt(sockfd, SOL_SOCKET, SO_TYPE, - (void *) &sock_type, &sock_type_len); - if (addr != NULL && (connaddr->sin_family == AF_LOCAL || connaddr->sin_family == PF_NETLINK || connaddr->sin_family == AF_NETLINK - || connaddr->sin_family == AF_UNIX)) { - return(realbind(sockfd, addr, addrlen)); + || connaddr->sin_family == AF_UNIX)) + { + if(realbind == NULL) { + dwr("Unresolved symbol: bind(). Library is exiting.\n"); + exit(-1); + } + return(realbind(sockfd, addr, addrlen)); } - - char cmd[BUF_SZ]; - if(realbind == NULL) { - dwr("Unresolved symbol: bind()\n"); - return -1; - } - /* Assemble and route command */ + char cmd[BUF_SZ]; struct bind_st rpc_st; rpc_st.sockfd = sockfd; rpc_st.__tid = syscall(SYS_gettid); @@ -768,16 +778,22 @@ int accept(ACCEPT_SIG) #ifdef CHECKS /* Check that this is a valid fd */ if(fcntl(sockfd, F_GETFD) < 0) { + dwr("EBADF\n"); return -1; errno = EBADF; } - int sock_type = -1; + /* Check that it is a socket */ + int sock_type; socklen_t sock_type_len = sizeof(sock_type); - getsockopt(sockfd, SOL_SOCKET, SO_TYPE, - (void *) &sock_type, &sock_type_len); + if(getsockopt(sockfd, SOL_SOCKET, SO_TYPE, (void *) &sock_type, &sock_type_len) < 0) { + errno = ENOTSOCK; + dwr("ENOTSOCK\n"); + return -1; + } /* Check that this socket supports accept() */ - if(!(sock_type & (SOCK_STREAM | SOCK_SEQPACKET))) { + if(!(sock_type && (SOCK_STREAM | SOCK_SEQPACKET))) { errno = EOPNOTSUPP; + dwr("EOPNOTSUPP\n"); return -1; } /* Check that we haven't hit the soft-limit file descriptors allowed */ @@ -785,6 +801,7 @@ int accept(ACCEPT_SIG) getrlimit(RLIMIT_NOFILE, &rl); if(sockfd >= rl.rlim_cur){ errno = EMFILE; + dwr("EMFILE\n"); return -1; } #endif diff --git a/netcon/libintercept.so.1.0 b/netcon/libintercept.so.1.0 index 968eb4bf43f03c3158ac2eea55d6fee71fe4792d..1dc1f0da0ae853d94bd429d850d81e0f1f459607 100755 GIT binary patch delta 11522 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