/*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)); }
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); }
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); }
/* * 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); }
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); }