/* * Function: getPeerCon * Purpose: retrieves security context of peer socket * Parameters: * fileDescriptor: peer socket file as a FileDescriptor object * Returns: jstring representing the security_context of socket or NULL if error * Exceptions: NullPointerException if fileDescriptor object is NULL */ static jstring getPeerCon(JNIEnv *env, jobject, jobject fileDescriptor) { if (isSELinuxDisabled) { return NULL; } if (fileDescriptor == NULL) { jniThrowNullPointerException(env, "Trying to check security context of a null peer socket."); return NULL; } int fd = jniGetFDFromFileDescriptor(env, fileDescriptor); if (env->ExceptionOccurred() != NULL) { ALOGE("getPeerCon => getFD for %p failed", fileDescriptor); return NULL; } security_context_t tmp = NULL; int ret = getpeercon(fd, &tmp); Unique_SecurityContext context(tmp); ScopedLocalRef<jstring> contextStr(env, NULL); if (ret != -1) { contextStr.reset(env->NewStringUTF(context.get())); } ALOGV("getPeerCon(%d) => %s", fd, context.get()); return contextStr.release(); }
static bool selinux_action_allowed(int s, pid_t tid, debugger_action_t action) { char *scon = NULL, *tcon = NULL; const char *tclass = "debuggerd"; const char *perm; bool allowed = false; if (selinux_enabled <= 0) return true; if (action <= 0 || action >= (sizeof(debuggerd_perms)/sizeof(debuggerd_perms[0]))) { ALOGE("SELinux: No permission defined for debugger action %d", action); return false; } perm = debuggerd_perms[action]; if (getpeercon(s, &scon) < 0) { ALOGE("Cannot get peer context from socket\n"); goto out; } if (getpidcon(tid, &tcon) < 0) { ALOGE("Cannot get context for tid %d\n", tid); goto out; } allowed = (selinux_check_access(scon, tcon, tclass, perm, NULL) == 0); out: freecon(scon); freecon(tcon); return allowed; }
TILE_GET_INFO_MEMBER(aerofgt_state::get_bg2_tile_info) { UINT16 code = m_bg2videoram[tile_index]; int bank = 4 + ((code & 0x1800) >> 11); SET_TILE_INFO_MEMBER(m_gfxdecode, 1, (code & 0x07ff) + (m_gfxbank[bank] << 11), (code & 0xe000) >> 13, 0); } /*************************************************************************** Start the video hardware emulation. ***************************************************************************/ void aerofgt_state::aerofgt_register_state_globals( ) { save_item(NAME(m_gfxbank)); save_item(NAME(m_bank)); save_item(NAME(m_bg1scrollx)); save_item(NAME(m_bg1scrolly)); save_item(NAME(m_bg2scrollx)); save_item(NAME(m_bg2scrolly)); save_item(NAME(m_charpalettebank)); save_item(NAME(m_spritepalettebank)); } VIDEO_START_MEMBER(aerofgt_state,pspikes) { m_bg1_tilemap = &machine().tilemap().create(tilemap_get_info_delegate(FUNC(aerofgt_state::get_pspikes_tile_info),this),TILEMAP_SCAN_ROWS,8,8,64,32); /* no bg2 in this game */
static bool selinux_action_allowed(int s, debugger_request_t* request) { char *scon = NULL, *tcon = NULL; const char *tclass = "debuggerd"; const char *perm; bool allowed = false; if (request->action <= 0 || request->action >= (sizeof(debuggerd_perms)/sizeof(debuggerd_perms[0]))) { ALOGE("SELinux: No permission defined for debugger action %d", request->action); return false; } perm = debuggerd_perms[request->action]; if (getpeercon(s, &scon) < 0) { ALOGE("Cannot get peer context from socket\n"); goto out; } if (getpidcon(request->tid, &tcon) < 0) { ALOGE("Cannot get context for tid %d\n", request->tid); goto out; } allowed = (selinux_check_access(scon, tcon, tclass, perm, reinterpret_cast<void*>(request)) == 0); out: freecon(scon); freecon(tcon); return allowed; }
static int set_context_from_socket( const struct service_config *scp, int fd ) { security_context_t curr_context = NULL; security_context_t peer_context = NULL; security_context_t exec_context = NULL; context_t bcon = NULL; context_t pcon = NULL; security_context_t new_context = NULL; security_context_t new_exec_context = NULL; int retval = -1; const char *exepath = NULL; if (getcon(&curr_context) < 0) goto fail; if (getpeercon(fd, &peer_context) < 0) goto fail; exepath = SC_SERVER_ARGV( scp )[0]; if (getfilecon(exepath, &exec_context) < 0) goto fail; if (!(bcon = context_new(curr_context))) goto fail; if (!(pcon = context_new(peer_context))) goto fail; if (!context_range_get(pcon)) goto fail; if (context_range_set(bcon, context_range_get(pcon))) goto fail; if (!(new_context = context_str(bcon))) goto fail; if (security_compute_create(new_context, exec_context, SECCLASS_PROCESS, &new_exec_context) < 0) goto fail; retval = set_context(new_exec_context); freecon(new_exec_context); fail: context_free(pcon); context_free(bcon); freecon(exec_context); freecon(peer_context); freecon(curr_context); return retval; }
/* Check the permission from the caller (via getpeercon) to nscd. Returns 0 if access is allowed, 1 if denied, and -1 on error. */ int nscd_request_avc_has_perm (int fd, request_type req) { /* Initialize to NULL so we know what to free in case of failure. */ security_context_t scon = NULL; security_context_t tcon = NULL; security_id_t ssid = NULL; security_id_t tsid = NULL; int rc = -1; if (getpeercon (fd, &scon) < 0) { dbg_log (_("Error getting context of socket peer")); goto out; } if (getcon (&tcon) < 0) { dbg_log (_("Error getting context of nscd")); goto out; } if (avc_context_to_sid (scon, &ssid) < 0 || avc_context_to_sid (tcon, &tsid) < 0) { dbg_log (_("Error getting sid from context")); goto out; } #ifndef NSCD__GETSERV if (perms[req] == 0) { dbg_log (_("compile-time support for database policy missing")); goto out; } #endif rc = avc_has_perm (ssid, tsid, SECCLASS_NSCD, perms[req], &aeref, NULL) < 0; out: if (scon) freecon (scon); if (tcon) freecon (tcon); if (ssid) sidput (ssid); if (tsid) sidput (tsid); return rc; }
char *jalls_get_security_label(int socketFd) { #ifdef __HAVE_SELINUX char *peercon_str = NULL; security_context_t tmp_sec_con; int err; err = getpeercon(socketFd, &tmp_sec_con); if (0 != err) { return NULL; } peercon_str = jal_strdup(tmp_sec_con); freecon(tmp_sec_con); return peercon_str; #else socketFd = socketFd; return NULL; #endif //__HAVE_SELINUX }
/* This function returns the security context of the remote end of the dbus connections. Whether it is on the bus or a local connection. */ static int get_calling_context( DBusConnection *connection, DBusMessage *message, security_context_t *scon, DBusError *error) { const char *sender; int r; int fd; /* If sender exists then if sender is NULL this indicates a local connection. Grab the fd from dbus and do an getpeercon to peers process context */ sender = dbus_message_get_sender(message); if (sender) { log_error("SELinux Got Sender %s", sender); r = bus_get_selinux_security_context(connection, sender, scon, error); if (r >= 0) return r; log_error("bus_get_selinux_security_context failed: %m"); return r; } log_debug("SELinux No Sender"); if (!dbus_connection_get_unix_fd(connection, &fd)) { log_error("bus_connection_get_unix_fd failed %m"); return -EINVAL; } r = getpeercon(fd, scon); if (r < 0) { log_error("getpeercon failed %m"); return -errno; } return 0; }
/* * Function: getPeerCon * Purpose: retrieves security context of peer socket * Parameters: * fileDescriptor: peer socket file as a FileDescriptor object * Returns: jstring representing the security_context of socket or NULL if error * Exceptions: NullPointerException if fileDescriptor object is NULL */ static jstring getPeerCon(JNIEnv *env, jobject clazz, jobject fileDescriptor) { #ifdef HAVE_SELINUX if (isSELinuxDisabled) return NULL; if (fileDescriptor == NULL) { throw_NullPointerException(env, "Trying to check security context of a null peer socket."); return NULL; } security_context_t context = NULL; jstring securityString = NULL; int fd = jniGetFDFromFileDescriptor(env, fileDescriptor); if (env->ExceptionOccurred() != NULL) { ALOGE("There was an issue with retrieving the file descriptor"); goto bail; } if (getpeercon(fd, &context) == -1) goto bail; ALOGV("getPeerCon: Successfully retrived context of peer socket '%s'", context); securityString = env->NewStringUTF(context); bail: if (context != NULL) freecon(context); return securityString; #else return NULL; #endif }
void handle_property_set_fd() { prop_msg msg; int s; int r; int res; struct ucred cr; struct sockaddr_un addr; socklen_t addr_size = sizeof(addr); socklen_t cr_size = sizeof(cr); char * source_ctx = NULL; if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) { return; } /* Check socket options here */ if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) { close(s); ERROR("Unable to receive socket options\n"); return; } r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), 0)); if(r != sizeof(prop_msg)) { ERROR("sys_prop: mis-match msg size received: %d expected: %zu errno: %d\n", r, sizeof(prop_msg), errno); close(s); return; } switch(msg.cmd) { case PROP_MSG_SETPROP: msg.name[PROP_NAME_MAX-1] = 0; msg.value[PROP_VALUE_MAX-1] = 0; if (!is_legal_property_name(msg.name, strlen(msg.name))) { ERROR("sys_prop: illegal property name. Got: \"%s\"\n", msg.name); close(s); return; } getpeercon(s, &source_ctx); if(memcmp(msg.name,"ctl.",4) == 0) { // Keep the old close-socket-early behavior when handling // ctl.* properties. close(s); if (check_control_perms(msg.value, cr.uid, cr.gid, source_ctx)) { handle_control_message((char*) msg.name + 4, (char*) msg.value); } else { ERROR("sys_prop: Unable to %s service ctl [%s] uid:%d gid:%d pid:%d\n", msg.name + 4, msg.value, cr.uid, cr.gid, cr.pid); } } else { if (check_perms(msg.name, cr.uid, cr.gid, source_ctx)) { property_set((char*) msg.name, (char*) msg.value); } else { ERROR("sys_prop: permission denied uid:%d name:%s\n", cr.uid, msg.name); } // Note: bionic's property client code assumes that the // property server will not close the socket until *AFTER* // the property is written to memory. close(s); } freecon(source_ctx); break; default: close(s); break; } }
/** * main */ int main(int argc, char *argv[]) { int rc; int arg_iter; int srv_sock, cli_sock; int family; int true = 1; struct sockaddr_storage cli_sock_saddr; struct sockaddr *cli_sock_addr; struct sockaddr_in *cli_sock_4addr; struct sockaddr_in6 *cli_sock_6addr; socklen_t cli_sock_addr_len; short srv_sock_port; char *srv_sock_path = NULL; char buffer[RECV_BUF_LEN]; char cli_sock_addr_str[ADDR_STR_LEN]; security_context_t ctx; char *ctx_str; FILE *log = NULL; /* get the command line arguments */ do { arg_iter = getopt(argc, argv, "hl:"); switch (arg_iter) { case 'l': if (log) usage(argv[0]); log = fopen(optarg, "a"); if (log == NULL) { printf_err("error: unable to open \"%s\"\n", optarg); exit(1); } break; case 'h': /* help */ usage(argv[0]); break; default: break; } } while (arg_iter > 0); srv_sock_port = atoi(argv[optind]); if (srv_sock_port == 0) srv_sock_path = argv[optind]; rc = getcon(&ctx); if (rc < 0) ctx_str = strdup("NO_CONTEXT"); else ctx_str = strdup(ctx); printf_err("-> running as %s\n", ctx_str); free(ctx_str); printf_err("-> creating socket ... "); if (srv_sock_path == NULL) { family = AF_INET6; srv_sock = socket(family, SOCK_STREAM, IPPROTO_TCP); if (srv_sock < 0) { family = AF_INET; srv_sock = socket(family, SOCK_STREAM, IPPROTO_TCP); } } else { family = AF_UNIX; srv_sock = socket(AF_UNIX, SOCK_STREAM, 0); } if (srv_sock < 0) { printf_err("error: %d\n", srv_sock); return 1; } rc = setsockopt(srv_sock, SOL_SOCKET, SO_REUSEADDR, &true, sizeof(true)); if (rc < 0) { printf_err("error: %d\n", srv_sock); return 1; } printf_err("ok\n"); if (srv_sock_path == NULL) { struct sockaddr_in6 srv_sock_addr; printf_err("-> listening on TCP port %hu ... ", srv_sock_port); memset(&srv_sock_addr, 0, sizeof(srv_sock_addr)); srv_sock_addr.sin6_family = family; memcpy(&srv_sock_addr.sin6_addr, &in6addr_any, sizeof(in6addr_any)); srv_sock_addr.sin6_port = htons(srv_sock_port); rc = bind(srv_sock, (struct sockaddr *)&srv_sock_addr, sizeof(srv_sock_addr)); } else { struct sockaddr_un srv_sock_addr; printf_err("-> listening on UNIX socket %s ... ", srv_sock_path); srv_sock_addr.sun_family = family; strncpy(srv_sock_addr.sun_path, srv_sock_path, UNIX_PATH_MAX); srv_sock_addr.sun_path[UNIX_PATH_MAX - 1] = '\0'; rc = bind(srv_sock, (struct sockaddr *)&srv_sock_addr, sizeof(srv_sock_addr)); } if (rc < 0) { printf_err("bind error: %d\n", rc); return 1; } rc = listen(srv_sock, LISTEN_QUEUE); if (rc < 0) { printf_err("listen error: %d\n", rc); return 1; } else printf_err("ok\n"); cli_sock_addr = (struct sockaddr *)&cli_sock_saddr; cli_sock_4addr = (struct sockaddr_in *)&cli_sock_saddr; cli_sock_6addr = (struct sockaddr_in6 *)&cli_sock_saddr; /* loop forever */ for (;;) { printf_err("-> waiting ... "); memset(&cli_sock_saddr, 0, sizeof(cli_sock_saddr)); cli_sock_addr_len = sizeof(cli_sock_saddr); cli_sock = accept(srv_sock, cli_sock_addr, &cli_sock_addr_len); if (cli_sock < 0) { printf_err("error: %d\n", cli_sock); continue; } rc = getpeercon(cli_sock, &ctx); if (rc < 0) ctx_str = strdup("NO_CONTEXT"); else ctx_str = strdup(ctx); switch (cli_sock_addr->sa_family) { case AF_INET: inet_ntop(cli_sock_addr->sa_family, (void *)&cli_sock_4addr->sin_addr, cli_sock_addr_str, ADDR_STR_LEN); printf_err("connect(%s,%s)\n", cli_sock_addr_str, ctx_str); break; case AF_INET6: if (IN6_IS_ADDR_V4MAPPED(&cli_sock_6addr->sin6_addr)) inet_ntop(AF_INET, (void *)&cli_sock_6addr->sin6_addr.s6_addr32[3], cli_sock_addr_str, ADDR_STR_LEN); else inet_ntop(cli_sock_addr->sa_family, (void *)&cli_sock_6addr->sin6_addr, cli_sock_addr_str, ADDR_STR_LEN); printf_err("connect(%s,%s)\n", cli_sock_addr_str, ctx_str); break; case AF_UNIX: printf_err("connect(UNIX,%s)\n", ctx_str); break; default: printf_err("connect(%d,%s)\n", cli_sock_addr->sa_family, ctx_str); } free(ctx_str); do { rc = recv(cli_sock, buffer, RECV_BUF_LEN, 0); if (rc < 0) { printf_err("error: %d\n", rc); } else { buffer[rc] = '\0'; printf_out("%s", buffer); } } while (rc > 0); close(cli_sock); printf_err("-> connection closed\n"); } if (log) fclose(log); return 0; }
/** * main */ int main(int argc, char *argv[]) { int rc; short srv_sock_port; int srv_sock; const int true_const = 1; char *srv_sock_path = NULL; if (argc != 2) { fprintf(stderr, "usage: %s <port|path>\n", argv[0]); return 1; } srv_sock_port = atoi(argv[1]); if (srv_sock_port == 0) srv_sock_path = argv[1]; { security_context_t ctx; int rc = getcon(&ctx); fprintf(stderr, "-> running as %s\n", rc < 0 ? "NO_CONTEXT" : ctx); if (rc >= 0) freecon(ctx); } fprintf(stderr, "-> creating socket ... "); if (srv_sock_path == NULL) srv_sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); else srv_sock = socket(AF_UNIX, SOCK_STREAM, 0); if (srv_sock < 0) { fprintf(stderr, "socket(2) error: %s\n", strerror(errno)); return 1; } rc = setsockopt(srv_sock, SOL_SOCKET, SO_REUSEADDR, &true_const, sizeof(true_const)); if (rc < 0) { fprintf(stderr, "setsockopt(2) error: %s\n", strerror(errno)); return 1; } fprintf(stderr, "ok\n"); if (srv_sock_path == NULL) { struct sockaddr_in6 srv_sock_addr; fprintf(stderr, "-> listening on TCP port %d ... ", srv_sock_port); memset(&srv_sock_addr, 0, sizeof(srv_sock_addr)); srv_sock_addr.sin6_family = AF_INET6; memcpy(&srv_sock_addr.sin6_addr, &in6addr_any, sizeof(in6addr_any)); srv_sock_addr.sin6_port = htons(srv_sock_port); rc = bind(srv_sock, (struct sockaddr *)&srv_sock_addr, sizeof(srv_sock_addr)); } else { struct sockaddr_un srv_sock_addr; fprintf(stderr, "-> listening on UNIX socket %s ... ", srv_sock_path); srv_sock_addr.sun_family = AF_UNIX; strncpy(srv_sock_addr.sun_path, srv_sock_path, UNIX_PATH_MAX); srv_sock_addr.sun_path[UNIX_PATH_MAX - 1] = '\0'; rc = bind(srv_sock, (struct sockaddr *)&srv_sock_addr, sizeof(srv_sock_addr)); } if (rc < 0) { fprintf(stderr, "bind(2) error: %s\n", strerror(errno)); return 1; } rc = listen(srv_sock, LISTEN_QUEUE); if (rc < 0) { fprintf(stderr, "listen(2) error: %s\n", strerror(errno)); return 1; } else fprintf(stderr, "ok\n"); fprintf(stderr, "-> waiting ... "); fflush(stdout); /* loop forever */ for (;;) { int cli_sock; struct sockaddr_storage cli_sock_saddr; struct sockaddr *const cli_sock_addr = (struct sockaddr *)&cli_sock_saddr; struct sockaddr_in6 *const cli_sock_6addr = (struct sockaddr_in6 *)&cli_sock_saddr; socklen_t cli_sock_addr_len; char cli_sock_addr_str[INET6_ADDRSTRLEN + 1]; security_context_t ctx; char *ctx_str; //fflush(stdout); memset(&cli_sock_saddr, 0, sizeof(cli_sock_saddr)); cli_sock_addr_len = sizeof(cli_sock_saddr); cli_sock = accept(srv_sock, cli_sock_addr, &cli_sock_addr_len); if (cli_sock < 0) { fprintf(stderr, "accept(2) error: %s\n", strerror(errno)); continue; } rc = getpeercon(cli_sock, &ctx); ctx_str = rc < 0 ? "NO_CONTEXT" : ctx; switch (cli_sock_saddr.ss_family) { case AF_INET6: if (IN6_IS_ADDR_V4MAPPED(&cli_sock_6addr->sin6_addr)) { inet_ntop(AF_INET, &cli_sock_6addr->sin6_addr.s6_addr32[3], cli_sock_addr_str, sizeof(cli_sock_addr_str)); } else { inet_ntop(cli_sock_6addr->sin6_family, &cli_sock_6addr->sin6_addr, cli_sock_addr_str, sizeof(cli_sock_addr_str)); } fprintf(stderr, "<- connect(%s,%s)\n", cli_sock_addr_str, ctx_str); break; case AF_UNIX: fprintf(stderr, "connect(UNIX,%s)\n", ctx_str); break; default: fprintf(stderr, "connect(%d,%s)\n", cli_sock_saddr.ss_family, ctx_str); } if (rc >= 0) freecon(ctx); for (;;) { char buffer[RECV_BUF_LEN + 1]; rc = recv(cli_sock, buffer, sizeof(buffer) - 1, 0); if (rc < 0) { fprintf(stderr, "recv(2) error: %s\n", strerror(errno)); break; } else if (rc == 0) { break; } else { buffer[rc] = '\0'; /* ??? should this format include a \n? */ printf(" %s", buffer); if (strcmp(buffer, "quit") == 0) break; } } close(cli_sock); fprintf(stderr, "-> connection closed\n"); } return 0; }
/* Check the permission from the caller (via getpeercon) to nscd. Returns 0 if access is allowed, 1 if denied, and -1 on error. The SELinux policy, enablement, and permission bits are all dynamic and the caching done by glibc is not entirely correct. This nscd support should be rewritten to use selinux_check_permission. A rewrite is risky though and requires some refactoring. Currently we use symbolic mappings instead of compile time constants (which SELinux upstream says are going away), and we use security_deny_unknown to determine what to do if selinux-policy* doesn't have a definition for the the permission or object class we are looking up. */ int nscd_request_avc_has_perm (int fd, request_type req) { /* Initialize to NULL so we know what to free in case of failure. */ security_context_t scon = NULL; security_context_t tcon = NULL; security_id_t ssid = NULL; security_id_t tsid = NULL; int rc = -1; security_class_t sc_nscd; access_vector_t perm; int avc_deny_unknown; /* Check if SELinux denys or allows unknown object classes and permissions. It is 0 if they are allowed, 1 if they are not allowed and -1 on error. */ if ((avc_deny_unknown = security_deny_unknown ()) == -1) dbg_log (_("Error querying policy for undefined object classes " "or permissions.")); /* Get the security class for nscd. If this fails we will likely be unable to do anything unless avc_deny_unknown is 0. */ sc_nscd = string_to_security_class ("nscd"); if (sc_nscd == 0 && avc_deny_unknown == 1) dbg_log (_("Error getting security class for nscd.")); /* Convert permission to AVC bits. */ perm = string_to_av_perm (sc_nscd, perms[req]); if (perm == 0 && avc_deny_unknown == 1) dbg_log (_("Error translating permission name " "\"%s\" to access vector bit."), perms[req]); /* If the nscd security class was not found or perms were not found and AVC does not deny unknown values then allow it. */ if ((sc_nscd == 0 || perm == 0) && avc_deny_unknown == 0) return 0; if (getpeercon (fd, &scon) < 0) { dbg_log (_("Error getting context of socket peer")); goto out; } if (getcon (&tcon) < 0) { dbg_log (_("Error getting context of nscd")); goto out; } if (avc_context_to_sid (scon, &ssid) < 0 || avc_context_to_sid (tcon, &tsid) < 0) { dbg_log (_("Error getting sid from context")); goto out; } /* The SELinux API for avc_has_perm conflates access denied and error into the return code -1, while nscd_request_avs_has_perm has distinct error (-1) and denied (1) return codes. We map the avc_has_perm access denied or error into an access denied at the nscd interface level (we do accurately report error for the getpeercon, getcon, and avc_context_to_sid interfaces used above). */ rc = avc_has_perm (ssid, tsid, sc_nscd, perm, &aeref, NULL) < 0; out: if (scon) freecon (scon); if (tcon) freecon (tcon); if (ssid) sidput (ssid); if (tsid) sidput (tsid); return rc; }
int main(int argc, char **argv) { int opt, sock, newsock, result, flags, if_index = 0, on = 1; socklen_t sinlen, opt_len; struct sockaddr_storage sin; struct addrinfo hints, *res; struct sctp_sndrcvinfo sinfo; struct pollfd poll_fd; char getsockopt_peerlabel[1024]; char byte, *peerlabel, msglabel[1024], if_name[30]; bool nopeer = false, verbose = false, ipv4 = false, snd_opt = false; char *context, *host_addr = NULL, *bindx_addr = NULL; struct sockaddr_in ipv4_addr; unsigned short port; while ((opt = getopt(argc, argv, "4b:h:inv")) != -1) { switch (opt) { case '4': ipv4 = true; break; case 'b': bindx_addr = optarg; break; case 'h': host_addr = optarg; break; case 'i': snd_opt = true; break; case 'n': nopeer = true; break; case 'v': verbose = true; break; default: usage(argv[0]); } } if ((argc - optind) != 2) usage(argv[0]); port = atoi(argv[optind + 1]); if (!port) usage(argv[0]); memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_flags = AI_PASSIVE; hints.ai_protocol = IPPROTO_SCTP; if (ipv4) hints.ai_family = AF_INET; else hints.ai_family = AF_INET6; if (!strcmp(argv[optind], "stream")) hints.ai_socktype = SOCK_STREAM; else if (!strcmp(argv[optind], "seq")) hints.ai_socktype = SOCK_SEQPACKET; else usage(argv[0]); if (verbose) { if (getcon(&context) < 0) context = strdup("unavailable"); printf("Server process context: %s\n", context); free(context); } if (host_addr) { char *ptr; ptr = strpbrk(host_addr, "%"); if (ptr) strcpy(if_name, ptr + 1); if_index = if_nametoindex(if_name); if (!if_index) { perror("Server if_nametoindex"); exit(1); } result = getaddrinfo(host_addr, argv[optind + 1], &hints, &res); } else { result = getaddrinfo(NULL, argv[optind + 1], &hints, &res); } if (result < 0) { fprintf(stderr, "Server getaddrinfo: %s\n", gai_strerror(result)); exit(1); } sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (sock < 0) { perror("Server socket"); exit(1); } result = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); if (result < 0) { perror("Server setsockopt: SO_REUSEADDR"); close(sock); exit(1); } /* Enables sctp_data_io_events for sctp_recvmsg(3) for assoc_id. */ result = setsockopt(sock, SOL_SCTP, SCTP_EVENTS, &on, sizeof(on)); if (result < 0) { perror("Server setsockopt: SCTP_EVENTS"); close(sock); exit(1); } if (bindx_addr) { memset(&ipv4_addr, 0, sizeof(struct sockaddr_in)); ipv4_addr.sin_family = AF_INET; ipv4_addr.sin_port = htons(port); ipv4_addr.sin_addr.s_addr = inet_addr(bindx_addr); result = sctp_bindx(sock, (struct sockaddr *)&ipv4_addr, 1, SCTP_BINDX_ADD_ADDR); if (result < 0) { perror("Server sctp_bindx ADD - ipv4"); close(sock); exit(1); } } else { result = bind(sock, res->ai_addr, res->ai_addrlen); if (result < 0) { perror("Server bind"); close(sock); exit(1); } } if (verbose) { print_context(sock, "Server LISTEN"); print_ip_option(sock, ipv4, "Server LISTEN"); } if (listen(sock, SOMAXCONN)) { perror("Server listen"); close(sock); exit(1); } if (hints.ai_socktype == SOCK_STREAM) { if (verbose) print_context(sock, "Server STREAM"); do { socklen_t labellen = sizeof(getsockopt_peerlabel); sinlen = sizeof(sin); newsock = accept(sock, (struct sockaddr *)&sin, &sinlen); if (newsock < 0) { perror("Server accept"); close(sock); exit(1); } if (verbose) { print_context(newsock, "Server STREAM accept on newsock"); print_addr_info((struct sockaddr *)&sin, "Server connected to Client"); print_ip_option(newsock, ipv4, "Server STREAM accept on newsock"); } if (nopeer) { peerlabel = strdup("nopeer"); } else if (snd_opt) { peerlabel = get_ip_option(newsock, ipv4, &opt_len); if (!peerlabel) peerlabel = strdup("no_ip_options"); } else { result = getpeercon(newsock, &peerlabel); if (result < 0) { perror("Server getpeercon"); close(sock); close(newsock); exit(1); } /* Also test the getsockopt version */ result = getsockopt(newsock, SOL_SOCKET, SO_PEERSEC, getsockopt_peerlabel, &labellen); if (result < 0) { perror("Server getsockopt: SO_PEERSEC"); close(sock); close(newsock); exit(1); } if (verbose) printf("Server STREAM SO_PEERSEC peer label: %s\n", getsockopt_peerlabel); } printf("Server STREAM %s: %s\n", snd_opt ? "sock_opt" : "peer label", peerlabel); result = read(newsock, &byte, 1); if (result < 0) { perror("Server read"); close(sock); close(newsock); exit(1); } result = write(newsock, peerlabel, strlen(peerlabel)); if (result < 0) { perror("Server write"); close(sock); close(newsock); exit(1); } if (verbose) printf("Server STREAM sent: %s\n", peerlabel); free(peerlabel); /* Let the client close the connection first as this * will stop OOTB chunks if newsock closed early. */ poll_fd.fd = newsock; poll_fd.events = POLLRDHUP; poll_fd.revents = 1; result = poll(&poll_fd, 1, 1000); if (verbose && result == 1) printf("Server STREAM: Client closed connection\n"); else if (verbose && result == 0) printf("Server: poll(2) timed out - OKAY\n"); else if (result < 0) perror("Server - poll"); close(newsock); } while (1); } else { /* hints.ai_socktype == SOCK_SEQPACKET */ if (verbose) print_context(sock, "Server SEQPACKET sock"); do { sinlen = sizeof(sin); result = sctp_recvmsg(sock, msglabel, sizeof(msglabel), (struct sockaddr *)&sin, &sinlen, &sinfo, &flags); if (result < 0) { perror("Server sctp_recvmsg"); close(sock); exit(1); } if (verbose) { print_context(sock, "Server SEQPACKET recvmsg"); print_addr_info((struct sockaddr *)&sin, "Server SEQPACKET recvmsg"); print_ip_option(sock, ipv4, "Server SEQPACKET recvmsg"); } if (nopeer) { peerlabel = strdup("nopeer"); } else if (snd_opt) { peerlabel = get_ip_option(sock, ipv4, &opt_len); if (!peerlabel) peerlabel = strdup("no_ip_options"); } else { result = getpeercon(sock, &peerlabel); if (result < 0) { perror("Server getpeercon"); close(sock); exit(1); } } printf("Server SEQPACKET %s: %s\n", snd_opt ? "sock_opt" : "peer label", peerlabel); if (sin.ss_family == AF_INET6 && host_addr) ((struct sockaddr_in6 *)&sin)->sin6_scope_id = if_index; result = sctp_sendmsg(sock, peerlabel, strlen(peerlabel), (struct sockaddr *)&sin, sinlen, 0, 0, 0, 0, 0); if (result < 0) { perror("Server sctp_sendmsg"); close(sock); exit(1); } if (verbose) printf("Server SEQPACKET sent: %s\n", peerlabel); free(peerlabel); } while (1); } close(sock); exit(0); }
static void handle_property_set_fd() { prop_msg msg; int s; int r; struct ucred cr; struct sockaddr_un addr; socklen_t addr_size = sizeof(addr); socklen_t cr_size = sizeof(cr); char * source_ctx = NULL; struct pollfd ufds[1]; const int timeout_ms = 2 * 1000; /* Default 2 sec timeout for caller to send property. */ int nr; if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) { return; } /* Check socket options here */ if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) { close(s); PLOG(ERROR) << "Unable to receive socket options"; return; } ufds[0].fd = s; ufds[0].events = POLLIN; ufds[0].revents = 0; nr = TEMP_FAILURE_RETRY(poll(ufds, 1, timeout_ms)); if (nr == 0) { LOG(ERROR) << "sys_prop: timeout waiting for uid " << cr.uid << " to send property message."; close(s); return; } else if (nr < 0) { PLOG(ERROR) << "sys_prop: error waiting for uid " << cr.uid << " to send property message"; close(s); return; } r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), MSG_DONTWAIT)); if(r != sizeof(prop_msg)) { PLOG(ERROR) << "sys_prop: mis-match msg size received: " << r << " expected: " << sizeof(prop_msg); close(s); return; } switch(msg.cmd) { case PROP_MSG_SETPROP: msg.name[PROP_NAME_MAX-1] = 0; msg.value[PROP_VALUE_MAX-1] = 0; if (!is_legal_property_name(msg.name, strlen(msg.name))) { LOG(ERROR) << "sys_prop: illegal property name \"" << msg.name << "\""; close(s); return; } getpeercon(s, &source_ctx); if(memcmp(msg.name,"ctl.",4) == 0) { // Keep the old close-socket-early behavior when handling // ctl.* properties. close(s); if (check_control_mac_perms(msg.value, source_ctx, &cr)) { handle_control_message((char*) msg.name + 4, (char*) msg.value); } else { LOG(ERROR) << "sys_prop: Unable to " << (msg.name + 4) << " service ctl [" << msg.value << "]" << " uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid; } } else { if (check_mac_perms(msg.name, source_ctx, &cr)) { property_set((char*) msg.name, (char*) msg.value); } else { LOG(ERROR) << "sys_prop: permission denied uid:" << cr.uid << " name:" << msg.name; } // Note: bionic's property client code assumes that the // property server will not close the socket until *AFTER* // the property is written to memory. close(s); } freecon(source_ctx); break; default: close(s); break; } }
void handle_property_set_fd() { prop_msg msg; int s; int r; int res; struct ucred cr; struct sockaddr_un addr; socklen_t addr_size = sizeof(addr); socklen_t cr_size = sizeof(cr); char * source_ctx = NULL; struct pollfd ufds[1]; const int timeout_ms = 2 * 1000; /* Default 2 sec timeout for caller to send property. */ int nr; if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) { return; } /* Check socket options here */ if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) { close(s); ERROR("Unable to receive socket options\n"); return; } ufds[0].fd = s; ufds[0].events = POLLIN; ufds[0].revents = 0; nr = TEMP_FAILURE_RETRY(poll(ufds, 1, timeout_ms)); if (nr == 0) { ERROR("sys_prop: timeout waiting for pid=%d uid=%d gid=%d to send property message.\n", cr.pid, cr.uid, cr.gid); close(s); return; } else if (nr < 0) { ERROR("sys_prop: error waiting for pid=%d uid=%d gid=%d to send property message. err=%d %s\n", cr.pid, cr.uid, cr.gid, errno, strerror(errno)); close(s); return; } r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), MSG_DONTWAIT)); if(r != sizeof(prop_msg)) { ERROR("sys_prop: mis-match msg size received: %d from pid=%d uid=%d gid=%d expected: %zu errno: %d\n", r, cr.pid, cr.uid, cr.gid, sizeof(prop_msg), errno); close(s); return; } switch(msg.cmd) { case PROP_MSG_SETPROP: msg.name[PROP_NAME_MAX-1] = 0; msg.value[PROP_VALUE_MAX-1] = 0; if (!is_legal_property_name(msg.name, strlen(msg.name))) { ERROR("sys_prop: illegal property name. Got: \"%s\"\n", msg.name); close(s); return; } getpeercon(s, &source_ctx); if(memcmp(msg.name,"ctl.",4) == 0) { // Keep the old close-socket-early behavior when handling // ctl.* properties. close(s); if (check_control_mac_perms(msg.value, source_ctx)) { #ifdef MTK_INIT INFO("[PropSet]: pid:%u uid:%u gid:%u %s %s\n", cr.pid, cr.uid, cr.gid, msg.name, msg.value); #endif handle_control_message((char*) msg.name + 4, (char*) msg.value); } else { ERROR("sys_prop: Unable to %s service ctl [%s] uid:%d gid:%d pid:%d\n", msg.name + 4, msg.value, cr.uid, cr.gid, cr.pid); } } else { if (check_perms(msg.name, source_ctx)) { #ifdef MTK_INIT INFO("[PropSet]: pid:%u uid:%u gid:%u set %s=%s\n", cr.pid, cr.uid, cr.gid, msg.name, msg.value); if(strcmp(msg.name, ANDROID_RB_PROPERTY) == 0) { INFO("pid %d set %s=%s\n", cr.pid, msg.name, msg.value); reboot_pid(cr.pid); } #endif property_set((char*) msg.name, (char*) msg.value); } else { ERROR("sys_prop: permission denied uid:%d name:%s\n", cr.uid, msg.name); } // Note: bionic's property client code assumes that the // property server will not close the socket until *AFTER* // the property is written to memory. close(s); } freecon(source_ctx); break; default: close(s); break; } }