/*
 * 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;
}
Example #3
0
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;
}
Example #5
0
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;
}
Example #6
0
/* 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;
}
Example #7
0
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
}
Example #8
0
/*
   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
  }
Example #10
0
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;
}
Example #12
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;
}
Example #13
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;
}
Example #14
0
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;
    }
}
Example #16
0
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;
    }
}