Beispiel #1
0
/*PRINTFLIKE2*/
static int
fmd_ckpt_inval(fmd_ckpt_t *ckp, const char *format, ...)
{
	va_list ap;

	va_start(ap, format);
	fmd_verror(EFMD_CKPT_INVAL, format, ap);
	va_end(ap);

	fmd_free(ckp->ckp_buf, ckp->ckp_size);
	return (fmd_set_errno(EFMD_CKPT_INVAL));
}
Beispiel #2
0
static int
fmd_clkmode_set(fmd_conf_param_t *pp, const char *value)
{
	const fmd_timeops_t *ops;

	if (strcasecmp(value, "native") == 0)
		ops = &fmd_timeops_native;
	else if (strcasecmp(value, "simulated") == 0)
		ops = &fmd_timeops_simulated;
	else
		return (fmd_set_errno(EFMD_CONF_INVAL));

	fmd.d_clockops = ops;
	pp->cp_value.cpv_ptr = (void *)ops;
	return (0);
}
Beispiel #3
0
static int
fmd_trmode_set(fmd_conf_param_t *pp, const char *value)
{
	fmd_tracebuf_f *func;

	if (strcasecmp(value, "none") == 0)
		func = fmd_trace_none;
	else if (strcasecmp(value, "lite") == 0)
		func = fmd_trace_lite;
	else if (strcasecmp(value, "full") == 0)
		func = fmd_trace_full;
	else
		return (fmd_set_errno(EFMD_CONF_INVAL));

	fmd.d_thr_trace = (void (*)())func;
	pp->cp_value.cpv_ptr = (void *)func;
	return (0);
}
Beispiel #4
0
/*
 * We use our own private version of svc_create() which registers our services
 * only on loopback transports and enables an option whereby Solaris ucreds
 * are associated with each connection, permitting us to check privilege bits.
 */
static int
fmd_rpc_svc_create_local(void (*disp)(struct svc_req *, SVCXPRT *),
    rpcprog_t prog, rpcvers_t vers, uint_t ssz, uint_t rsz, int force)
{
	struct netconfig *ncp;
	struct netbuf buf;
	SVCXPRT *xprt;
	void *hdl;
	int fd, n = 0;

	char door[PATH_MAX];
	time_t tm;

	if ((hdl = setnetconfig()) == NULL) {
		fmd_error(EFMD_RPC_REG, "failed to iterate over "
		    "netconfig database: %s\n", nc_sperror());
		return (fmd_set_errno(EFMD_RPC_REG));
	}

	if (force)
		svc_unreg(prog, vers); /* clear stale rpcbind registrations */

	buf.buf = alloca(_SS_MAXSIZE);
	buf.maxlen = _SS_MAXSIZE;
	buf.len = 0;

	while ((ncp = getnetconfig(hdl)) != NULL) {
		if (strcmp(ncp->nc_protofmly, NC_LOOPBACK) != 0)
			continue;

		if (!force && rpcb_getaddr(prog, vers, ncp, &buf, HOST_SELF)) {
			(void) endnetconfig(hdl);
			return (fmd_set_errno(EFMD_RPC_BOUND));
		}

		if ((fd = t_open(ncp->nc_device, O_RDWR, NULL)) == -1) {
			fmd_error(EFMD_RPC_REG, "failed to open %s: %s\n",
			    ncp->nc_device, t_strerror(t_errno));
			continue;
		}

		svc_fd_negotiate_ucred(fd); /* enable ucred option on xprt */

		if ((xprt = svc_tli_create(fd, ncp, NULL, ssz, rsz)) == NULL) {
			(void) t_close(fd);
			continue;
		}

		if (svc_reg(xprt, prog, vers, disp, ncp) == FALSE) {
			fmd_error(EFMD_RPC_REG, "failed to register "
			    "rpc service on %s\n", ncp->nc_netid);
			svc_destroy(xprt);
			continue;
		}

		n++;
	}

	(void) endnetconfig(hdl);

	/*
	 * If we failed to register services (n == 0) because rpcbind is down,
	 * then check to see if the RPC door file exists before attempting an
	 * svc_door_create(), which cleverly destroys any existing door file.
	 * The RPC APIs have no stable errnos, so we use rpcb_gettime() as a
	 * hack to determine if rpcbind itself is down.
	 */
	if (!force && n == 0 && rpcb_gettime(HOST_SELF, &tm) == FALSE &&
	    snprintf(door, sizeof (door), RPC_DOOR_RENDEZVOUS,
	    prog, vers) > 0 && access(door, F_OK) == 0)
		return (fmd_set_errno(EFMD_RPC_BOUND));

	/*
	 * Attempt to create a door server for the RPC program as well.  Limit
	 * the maximum request size for the door transport to the receive size.
	 */
	if ((xprt = svc_door_create(disp, prog, vers, ssz)) == NULL) {
		fmd_error(EFMD_RPC_REG, "failed to create door for "
		    "rpc service 0x%lx/0x%lx\n", prog, vers);
	} else {
		(void) svc_control(xprt, SVCSET_CONNMAXREC, &rsz);
		n++;
	}

	return (n);
}
Beispiel #5
0
static int
fmd_ckpt_open(fmd_ckpt_t *ckp, fmd_module_t *mp)
{
	struct stat64 st;
	uint64_t seclen;
	uint_t i;
	int err;

	bzero(ckp, sizeof (fmd_ckpt_t));
	ckp->ckp_mp = mp;

	(void) snprintf(ckp->ckp_src, PATH_MAX, "%s/%s",
	    mp->mod_ckpt, mp->mod_name);

	if ((ckp->ckp_fd = open(ckp->ckp_src, O_RDONLY)) == -1)
		return (-1); /* failed to open checkpoint file */

	if (fstat64(ckp->ckp_fd, &st) == -1) {
		err = errno;
		(void) close(ckp->ckp_fd);
		return (fmd_set_errno(err));
	}

	ckp->ckp_buf = fmd_alloc(st.st_size, FMD_SLEEP);
	ckp->ckp_hdr = (void *)ckp->ckp_buf;
	ckp->ckp_size = read(ckp->ckp_fd, ckp->ckp_buf, st.st_size);

	if (ckp->ckp_size != st.st_size || ckp->ckp_size < sizeof (fcf_hdr_t) ||
	    ckp->ckp_size != ckp->ckp_hdr->fcfh_filesz) {
		err = ckp->ckp_size == (size_t)-1L ? errno : EFMD_CKPT_SHORT;
		fmd_free(ckp->ckp_buf, st.st_size);
		(void) close(ckp->ckp_fd);
		return (fmd_set_errno(err));
	}

	(void) close(ckp->ckp_fd);
	ckp->ckp_fd = -1;

	/*
	 * Once we've read in a consistent copy of the FCF file and we're sure
	 * the header can be accessed, go through it and make sure everything
	 * is valid.  We also check that unused bits are zero so we can expand
	 * to use them safely in the future and support old files if needed.
	 */
	if (bcmp(&ckp->ckp_hdr->fcfh_ident[FCF_ID_MAG0],
	    FCF_MAG_STRING, FCF_MAG_STRLEN) != 0)
		return (fmd_ckpt_inval(ckp, "bad checkpoint magic string\n"));

	if (ckp->ckp_hdr->fcfh_ident[FCF_ID_MODEL] != FCF_MODEL_NATIVE)
		return (fmd_ckpt_inval(ckp, "bad checkpoint data model\n"));

	if (ckp->ckp_hdr->fcfh_ident[FCF_ID_ENCODING] != FCF_ENCODE_NATIVE)
		return (fmd_ckpt_inval(ckp, "bad checkpoint data encoding\n"));

	if (ckp->ckp_hdr->fcfh_ident[FCF_ID_VERSION] != FCF_VERSION_1) {
		return (fmd_ckpt_inval(ckp, "bad checkpoint version %u\n",
		    ckp->ckp_hdr->fcfh_ident[FCF_ID_VERSION]));
	}

	for (i = FCF_ID_PAD; i < FCF_ID_SIZE; i++) {
		if (ckp->ckp_hdr->fcfh_ident[i] != 0) {
			return (fmd_ckpt_inval(ckp,
			    "bad checkpoint padding at id[%d]", i));
		}
	}

	if (ckp->ckp_hdr->fcfh_flags & ~FCF_FL_VALID)
		return (fmd_ckpt_inval(ckp, "bad checkpoint flags\n"));

	if (ckp->ckp_hdr->fcfh_pad != 0)
		return (fmd_ckpt_inval(ckp, "reserved field in use\n"));

	if (ckp->ckp_hdr->fcfh_hdrsize < sizeof (fcf_hdr_t) ||
	    ckp->ckp_hdr->fcfh_secsize < sizeof (fcf_sec_t)) {
		return (fmd_ckpt_inval(ckp,
		    "bad header and/or section size\n"));
	}

	seclen = (uint64_t)ckp->ckp_hdr->fcfh_secnum *
	    (uint64_t)ckp->ckp_hdr->fcfh_secsize;

	if (ckp->ckp_hdr->fcfh_secoff > ckp->ckp_size ||
	    seclen > ckp->ckp_size ||
	    ckp->ckp_hdr->fcfh_secoff + seclen > ckp->ckp_size ||
	    ckp->ckp_hdr->fcfh_secoff + seclen < ckp->ckp_hdr->fcfh_secoff)
		return (fmd_ckpt_inval(ckp, "truncated section headers\n"));

	if (!IS_P2ALIGNED(ckp->ckp_hdr->fcfh_secoff, sizeof (uint64_t)) ||
	    !IS_P2ALIGNED(ckp->ckp_hdr->fcfh_secsize, sizeof (uint64_t)))
		return (fmd_ckpt_inval(ckp, "misaligned section headers\n"));

	/*
	 * Once the header is validated, iterate over the section headers
	 * ensuring that each one is valid w.r.t. offset, alignment, and size.
	 * We also pick up the string table pointer during this pass.
	 */
	ckp->ckp_secp = (void *)(ckp->ckp_buf + ckp->ckp_hdr->fcfh_secoff);
	ckp->ckp_secs = ckp->ckp_hdr->fcfh_secnum;

	for (i = 0; i < ckp->ckp_secs; i++) {
		fcf_sec_t *sp = (void *)(ckp->ckp_buf +
		    ckp->ckp_hdr->fcfh_secoff + ckp->ckp_hdr->fcfh_secsize * i);

		const fmd_ckpt_desc_t *dp = &_fmd_ckpt_sections[sp->fcfs_type];

		if (sp->fcfs_flags != 0) {
			return (fmd_ckpt_inval(ckp, "section %u has invalid "
			    "section flags (0x%x)\n", i, sp->fcfs_flags));
		}

		if (sp->fcfs_align & (sp->fcfs_align - 1)) {
			return (fmd_ckpt_inval(ckp, "section %u has invalid "
			    "alignment (%u)\n", i, sp->fcfs_align));
		}

		if (sp->fcfs_offset & (sp->fcfs_align - 1)) {
			return (fmd_ckpt_inval(ckp, "section %u is not properly"
			    " aligned (offset %llu)\n", i, sp->fcfs_offset));
		}

		if (sp->fcfs_entsize != 0 &&
		    (sp->fcfs_entsize & (sp->fcfs_align - 1)) != 0) {
			return (fmd_ckpt_inval(ckp, "section %u has misaligned "
			    "entsize %u\n", i, sp->fcfs_entsize));
		}

		if (sp->fcfs_offset > ckp->ckp_size ||
		    sp->fcfs_size > ckp->ckp_size ||
		    sp->fcfs_offset + sp->fcfs_size > ckp->ckp_size ||
		    sp->fcfs_offset + sp->fcfs_size < sp->fcfs_offset) {
			return (fmd_ckpt_inval(ckp, "section %u has corrupt "
			    "size or offset\n", i));
		}

		if (sp->fcfs_type >= sizeof (_fmd_ckpt_sections) /
		    sizeof (_fmd_ckpt_sections[0])) {
			return (fmd_ckpt_inval(ckp, "section %u has unknown "
			    "section type %u\n", i, sp->fcfs_type));
		}

		if (sp->fcfs_align != dp->secd_align) {
			return (fmd_ckpt_inval(ckp, "section %u has align %u "
			    "(not %u)\n", i, sp->fcfs_align, dp->secd_align));
		}

		if (sp->fcfs_size < dp->secd_size ||
		    sp->fcfs_entsize < dp->secd_entsize) {
			return (fmd_ckpt_inval(ckp, "section %u has short "
			    "size or entsize\n", i));
		}

		switch (sp->fcfs_type) {
		case FCF_SECT_STRTAB:
			if (ckp->ckp_strs != NULL) {
				return (fmd_ckpt_inval(ckp, "multiple string "
				    "tables are present in checkpoint file\n"));
			}

			ckp->ckp_strs = (char *)ckp->ckp_buf + sp->fcfs_offset;
			ckp->ckp_strn = sp->fcfs_size;

			if (ckp->ckp_strs[ckp->ckp_strn - 1] != '\0') {
				return (fmd_ckpt_inval(ckp, "string table %u "
				    "is missing terminating nul byte\n", i));
			}
			break;

		case FCF_SECT_MODULE:
			if (ckp->ckp_modp != NULL) {
				return (fmd_ckpt_inval(ckp, "multiple module "
				    "sects are present in checkpoint file\n"));
			}
			ckp->ckp_modp = sp;
			break;
		}
	}

	/*
	 * Ensure that the first section is an empty one of type FCF_SECT_NONE.
	 * This is done to ensure that links can use index 0 as a null section.
	 */
	if (ckp->ckp_secs == 0 || ckp->ckp_secp->fcfs_type != FCF_SECT_NONE ||
	    ckp->ckp_secp->fcfs_entsize != 0 || ckp->ckp_secp->fcfs_size != 0) {
		return (fmd_ckpt_inval(ckp, "section 0 is not of the "
		    "appropriate size and/or attributes (SECT_NONE)\n"));
	}

	if (ckp->ckp_modp == NULL) {
		return (fmd_ckpt_inval(ckp,
		    "no module section found in file\n"));
	}

	return (0);
}