static int getqctrl(caddr_t data) { au_kcontext_t *kctx = GET_KCTX_PZ; STRUCT_DECL(au_qctrl, qctrl); STRUCT_INIT(qctrl, get_udatamodel()); mutex_enter(&(kctx->auk_queue.lock)); STRUCT_FSET(qctrl, aq_hiwater, kctx->auk_queue.hiwater); STRUCT_FSET(qctrl, aq_lowater, kctx->auk_queue.lowater); STRUCT_FSET(qctrl, aq_bufsz, kctx->auk_queue.bufsz); STRUCT_FSET(qctrl, aq_delay, kctx->auk_queue.delay); mutex_exit(&(kctx->auk_queue.lock)); if (copyout(STRUCT_BUF(qctrl), data, STRUCT_SIZE(qctrl))) return (EFAULT); return (0); }
/* ARGSUSED */ static int get_soft_list(dev_t dev, caddr_t arg, int mode, int *rval) { STRUCT_DECL(crypto_get_soft_list, soft_list); char *names; size_t len; uint_t count; STRUCT_INIT(soft_list, mode); if (copyin(arg, STRUCT_BUF(soft_list), STRUCT_SIZE(soft_list)) != 0) return (EFAULT); /* get the list from the core module */ if (crypto_get_soft_list(&count, &names, &len) != 0) { STRUCT_FSET(soft_list, sl_return_value, CRYPTO_FAILED); if (copyout(STRUCT_BUF(soft_list), arg, STRUCT_SIZE(soft_list)) != 0) { return (EFAULT); } return (0); } /* check if buffer is too small */ if (len > STRUCT_FGET(soft_list, sl_soft_len)) { STRUCT_FSET(soft_list, sl_soft_count, count); STRUCT_FSET(soft_list, sl_soft_len, len); STRUCT_FSET(soft_list, sl_return_value, CRYPTO_BUFFER_TOO_SMALL); kmem_free(names, len); if (copyout(STRUCT_BUF(soft_list), arg, STRUCT_SIZE(soft_list)) != 0) { return (EFAULT); } return (0); } STRUCT_FSET(soft_list, sl_soft_count, count); STRUCT_FSET(soft_list, sl_soft_len, len); STRUCT_FSET(soft_list, sl_return_value, CRYPTO_SUCCESS); if (count > 0 && copyout(names, STRUCT_FGETP(soft_list, sl_soft_names), len) != 0) { kmem_free(names, len); return (EFAULT); } kmem_free(names, len); if (copyout(STRUCT_BUF(soft_list), arg, STRUCT_SIZE(soft_list)) != 0) { return (EFAULT); } return (0); }
/*ARGSUSED*/ static int cpuid_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval) { char areq[16]; void *ustr; switch (cmd) { case CPUID_GET_HWCAP: { STRUCT_DECL(cpuid_get_hwcap, h); STRUCT_INIT(h, mode); if (ddi_copyin((void *)arg, STRUCT_BUF(h), STRUCT_SIZE(h), mode)) return (EFAULT); if ((ustr = STRUCT_FGETP(h, cgh_archname)) != NULL && copyinstr(ustr, areq, sizeof (areq), NULL) != 0) return (EFAULT); areq[sizeof (areq) - 1] = '\0'; if (strcmp(areq, architecture) == 0) STRUCT_FSET(h, cgh_hwcap, auxv_hwcap); #if defined(_SYSCALL32_IMPL) else if (strcmp(areq, architecture_32) == 0) STRUCT_FSET(h, cgh_hwcap, auxv_hwcap32); #endif else STRUCT_FSET(h, cgh_hwcap, 0); if (ddi_copyout(STRUCT_BUF(h), (void *)arg, STRUCT_SIZE(h), mode)) return (EFAULT); return (0); } default: return (ENOTTY); } }
/* * Get the audit state information from the current process. * Return EFAULT if copyout fails. */ int getaudit(caddr_t info_p) { STRUCT_DECL(auditinfo, info); const auditinfo_addr_t *ainfo; model_t model; if (secpolicy_audit_getattr(CRED(), B_FALSE) != 0) return (EPERM); model = get_udatamodel(); STRUCT_INIT(info, model); ainfo = crgetauinfo(CRED()); if (ainfo == NULL) return (EINVAL); /* trying to read a process with an IPv6 address? */ if (ainfo->ai_termid.at_type == AU_IPv6) return (EOVERFLOW); STRUCT_FSET(info, ai_auid, ainfo->ai_auid); STRUCT_FSET(info, ai_mask, ainfo->ai_mask); #ifdef _LP64 if (model == DATAMODEL_ILP32) { dev32_t dev; /* convert internal 64 bit form to 32 bit version */ if (cmpldev(&dev, ainfo->ai_termid.at_port) == 0) { return (EOVERFLOW); } STRUCT_FSET(info, ai_termid.port, dev); } else STRUCT_FSET(info, ai_termid.port, ainfo->ai_termid.at_port); #else STRUCT_FSET(info, ai_termid.port, ainfo->ai_termid.at_port); #endif STRUCT_FSET(info, ai_termid.machine, ainfo->ai_termid.at_addr[0]); STRUCT_FSET(info, ai_asid, ainfo->ai_asid); if (copyout(STRUCT_BUF(info), info_p, STRUCT_SIZE(info))) return (EFAULT); return (0); }
static int getkaudit(caddr_t info_p, int len) { STRUCT_DECL(auditinfo_addr, info); model_t model; au_kcontext_t *kctx = GET_KCTX_PZ; model = get_udatamodel(); STRUCT_INIT(info, model); if (len < STRUCT_SIZE(info)) return (EOVERFLOW); STRUCT_FSET(info, ai_auid, kctx->auk_info.ai_auid); STRUCT_FSET(info, ai_mask, kctx->auk_info.ai_namask); #ifdef _LP64 if (model == DATAMODEL_ILP32) { dev32_t dev; /* convert internal 64 bit form to 32 bit version */ if (cmpldev(&dev, kctx->auk_info.ai_termid.at_port) == 0) { return (EOVERFLOW); } STRUCT_FSET(info, ai_termid.at_port, dev); } else { STRUCT_FSET(info, ai_termid.at_port, kctx->auk_info.ai_termid.at_port); } #else STRUCT_FSET(info, ai_termid.at_port, kctx->auk_info.ai_termid.at_port); #endif STRUCT_FSET(info, ai_termid.at_type, kctx->auk_info.ai_termid.at_type); STRUCT_FSET(info, ai_termid.at_addr[0], kctx->auk_info.ai_termid.at_addr[0]); STRUCT_FSET(info, ai_termid.at_addr[1], kctx->auk_info.ai_termid.at_addr[1]); STRUCT_FSET(info, ai_termid.at_addr[2], kctx->auk_info.ai_termid.at_addr[2]); STRUCT_FSET(info, ai_termid.at_addr[3], kctx->auk_info.ai_termid.at_addr[3]); STRUCT_FSET(info, ai_asid, kctx->auk_info.ai_asid); if (copyout(STRUCT_BUF(info), info_p, STRUCT_SIZE(info))) return (EFAULT); return (0); }
static int getpinfo_addr(caddr_t data, int len) { STRUCT_DECL(auditpinfo_addr, apinfo); proc_t *proc; const auditinfo_addr_t *ainfo; model_t model; cred_t *cr, *newcred; model = get_udatamodel(); STRUCT_INIT(apinfo, model); if (len < STRUCT_SIZE(apinfo)) return (EOVERFLOW); if (copyin(data, STRUCT_BUF(apinfo), STRUCT_SIZE(apinfo))) return (EFAULT); newcred = cralloc(); mutex_enter(&pidlock); if ((proc = prfind(STRUCT_FGET(apinfo, ap_pid))) == NULL) { mutex_exit(&pidlock); crfree(newcred); return (ESRCH); } mutex_enter(&proc->p_lock); /* so process doesn't go away */ mutex_exit(&pidlock); audit_update_context(proc, newcred); /* make sure it's up-to-date */ mutex_enter(&proc->p_crlock); crhold(cr = proc->p_cred); mutex_exit(&proc->p_crlock); mutex_exit(&proc->p_lock); ainfo = crgetauinfo(cr); if (ainfo == NULL) { crfree(cr); return (EINVAL); } STRUCT_FSET(apinfo, ap_auid, ainfo->ai_auid); STRUCT_FSET(apinfo, ap_asid, ainfo->ai_asid); #ifdef _LP64 if (model == DATAMODEL_ILP32) { dev32_t dev; /* convert internal 64 bit form to 32 bit version */ if (cmpldev(&dev, ainfo->ai_termid.at_port) == 0) { crfree(cr); return (EOVERFLOW); } STRUCT_FSET(apinfo, ap_termid.at_port, dev); } else STRUCT_FSET(apinfo, ap_termid.at_port, ainfo->ai_termid.at_port); #else STRUCT_FSET(apinfo, ap_termid.at_port, ainfo->ai_termid.at_port); #endif STRUCT_FSET(apinfo, ap_termid.at_type, ainfo->ai_termid.at_type); STRUCT_FSET(apinfo, ap_termid.at_addr[0], ainfo->ai_termid.at_addr[0]); STRUCT_FSET(apinfo, ap_termid.at_addr[1], ainfo->ai_termid.at_addr[1]); STRUCT_FSET(apinfo, ap_termid.at_addr[2], ainfo->ai_termid.at_addr[2]); STRUCT_FSET(apinfo, ap_termid.at_addr[3], ainfo->ai_termid.at_addr[3]); STRUCT_FSET(apinfo, ap_mask, ainfo->ai_mask); crfree(cr); if (copyout(STRUCT_BUF(apinfo), data, STRUCT_SIZE(apinfo))) return (EFAULT); return (0); }
/* * msgctl system call. * * gets q lock (via ipc_lookup), releases before return. * may call users of msg_lock */ static int msgctl(int msgid, int cmd, void *arg) { STRUCT_DECL(msqid_ds, ds); /* SVR4 queue work area */ kmsqid_t *qp; /* ptr to associated q */ int error; struct cred *cr; model_t mdl = get_udatamodel(); struct msqid_ds64 ds64; kmutex_t *lock; proc_t *pp = curproc; STRUCT_INIT(ds, mdl); cr = CRED(); /* * Perform pre- or non-lookup actions (e.g. copyins, RMID). */ switch (cmd) { case IPC_SET: if (copyin(arg, STRUCT_BUF(ds), STRUCT_SIZE(ds))) return (set_errno(EFAULT)); break; case IPC_SET64: if (copyin(arg, &ds64, sizeof (struct msqid_ds64))) return (set_errno(EFAULT)); break; case IPC_RMID: if (error = ipc_rmid(msq_svc, msgid, cr)) return (set_errno(error)); return (0); } /* * get msqid_ds for this msgid */ if ((lock = ipc_lookup(msq_svc, msgid, (kipc_perm_t **)&qp)) == NULL) return (set_errno(EINVAL)); switch (cmd) { case IPC_SET: if (STRUCT_FGET(ds, msg_qbytes) > qp->msg_qbytes && secpolicy_ipc_config(cr) != 0) { mutex_exit(lock); return (set_errno(EPERM)); } if (error = ipcperm_set(msq_svc, cr, &qp->msg_perm, &STRUCT_BUF(ds)->msg_perm, mdl)) { mutex_exit(lock); return (set_errno(error)); } qp->msg_qbytes = STRUCT_FGET(ds, msg_qbytes); qp->msg_ctime = gethrestime_sec(); break; case IPC_STAT: if (error = ipcperm_access(&qp->msg_perm, MSG_R, cr)) { mutex_exit(lock); return (set_errno(error)); } if (qp->msg_rcv_cnt) qp->msg_perm.ipc_mode |= MSG_RWAIT; if (qp->msg_snd_cnt) qp->msg_perm.ipc_mode |= MSG_WWAIT; ipcperm_stat(&STRUCT_BUF(ds)->msg_perm, &qp->msg_perm, mdl); qp->msg_perm.ipc_mode &= ~(MSG_RWAIT|MSG_WWAIT); STRUCT_FSETP(ds, msg_first, NULL); /* kernel addr */ STRUCT_FSETP(ds, msg_last, NULL); STRUCT_FSET(ds, msg_cbytes, qp->msg_cbytes); STRUCT_FSET(ds, msg_qnum, qp->msg_qnum); STRUCT_FSET(ds, msg_qbytes, qp->msg_qbytes); STRUCT_FSET(ds, msg_lspid, qp->msg_lspid); STRUCT_FSET(ds, msg_lrpid, qp->msg_lrpid); STRUCT_FSET(ds, msg_stime, qp->msg_stime); STRUCT_FSET(ds, msg_rtime, qp->msg_rtime); STRUCT_FSET(ds, msg_ctime, qp->msg_ctime); break; case IPC_SET64: mutex_enter(&pp->p_lock); if ((ds64.msgx_qbytes > qp->msg_qbytes) && secpolicy_ipc_config(cr) != 0 && rctl_test(rc_process_msgmnb, pp->p_rctls, pp, ds64.msgx_qbytes, RCA_SAFE) & RCT_DENY) { mutex_exit(&pp->p_lock); mutex_exit(lock); return (set_errno(EPERM)); } mutex_exit(&pp->p_lock); if (error = ipcperm_set64(msq_svc, cr, &qp->msg_perm, &ds64.msgx_perm)) { mutex_exit(lock); return (set_errno(error)); } qp->msg_qbytes = ds64.msgx_qbytes; qp->msg_ctime = gethrestime_sec(); break; case IPC_STAT64: if (qp->msg_rcv_cnt) qp->msg_perm.ipc_mode |= MSG_RWAIT; if (qp->msg_snd_cnt) qp->msg_perm.ipc_mode |= MSG_WWAIT; ipcperm_stat64(&ds64.msgx_perm, &qp->msg_perm); qp->msg_perm.ipc_mode &= ~(MSG_RWAIT|MSG_WWAIT); ds64.msgx_cbytes = qp->msg_cbytes; ds64.msgx_qnum = qp->msg_qnum; ds64.msgx_qbytes = qp->msg_qbytes; ds64.msgx_lspid = qp->msg_lspid; ds64.msgx_lrpid = qp->msg_lrpid; ds64.msgx_stime = qp->msg_stime; ds64.msgx_rtime = qp->msg_rtime; ds64.msgx_ctime = qp->msg_ctime; break; default: mutex_exit(lock); return (set_errno(EINVAL)); } mutex_exit(lock); /* * Do copyout last (after releasing mutex). */ switch (cmd) { case IPC_STAT: if (copyout(STRUCT_BUF(ds), arg, STRUCT_SIZE(ds))) return (set_errno(EFAULT)); break; case IPC_STAT64: if (copyout(&ds64, arg, sizeof (struct msqid_ds64))) return (set_errno(EFAULT)); break; } return (0); }
/* * semctl - Semctl system call. */ static int semctl(int semid, uint_t semnum, int cmd, uintptr_t arg) { ksemid_t *sp; /* ptr to semaphore header */ struct sem *p; /* ptr to semaphore */ unsigned int i; /* loop control */ ushort_t *vals, *vp; size_t vsize = 0; int error = 0; int retval = 0; struct cred *cr; kmutex_t *lock; model_t mdl = get_udatamodel(); STRUCT_DECL(semid_ds, sid); struct semid_ds64 ds64; STRUCT_INIT(sid, mdl); cr = CRED(); /* * Perform pre- or non-lookup actions (e.g. copyins, RMID). */ switch (cmd) { case IPC_SET: if (copyin((void *)arg, STRUCT_BUF(sid), STRUCT_SIZE(sid))) return (set_errno(EFAULT)); break; case IPC_SET64: if (copyin((void *)arg, &ds64, sizeof (struct semid_ds64))) return (set_errno(EFAULT)); break; case SETALL: if ((lock = ipc_lookup(sem_svc, semid, (kipc_perm_t **)&sp)) == NULL) return (set_errno(EINVAL)); vsize = sp->sem_nsems * sizeof (*vals); mutex_exit(lock); /* allocate space to hold all semaphore values */ vals = kmem_alloc(vsize, KM_SLEEP); if (copyin((void *)arg, vals, vsize)) { kmem_free(vals, vsize); return (set_errno(EFAULT)); } break; case IPC_RMID: if (error = ipc_rmid(sem_svc, semid, cr)) return (set_errno(error)); return (0); } if ((lock = ipc_lookup(sem_svc, semid, (kipc_perm_t **)&sp)) == NULL) { if (vsize != 0) kmem_free(vals, vsize); return (set_errno(EINVAL)); } switch (cmd) { /* Set ownership and permissions. */ case IPC_SET: if (error = ipcperm_set(sem_svc, cr, &sp->sem_perm, &STRUCT_BUF(sid)->sem_perm, mdl)) { mutex_exit(lock); return (set_errno(error)); } sp->sem_ctime = gethrestime_sec(); mutex_exit(lock); return (0); /* Get semaphore data structure. */ case IPC_STAT: if (error = ipcperm_access(&sp->sem_perm, SEM_R, cr)) { mutex_exit(lock); return (set_errno(error)); } ipcperm_stat(&STRUCT_BUF(sid)->sem_perm, &sp->sem_perm, mdl); STRUCT_FSETP(sid, sem_base, NULL); /* kernel addr */ STRUCT_FSET(sid, sem_nsems, sp->sem_nsems); STRUCT_FSET(sid, sem_otime, sp->sem_otime); STRUCT_FSET(sid, sem_ctime, sp->sem_ctime); STRUCT_FSET(sid, sem_binary, sp->sem_binary); mutex_exit(lock); if (copyout(STRUCT_BUF(sid), (void *)arg, STRUCT_SIZE(sid))) return (set_errno(EFAULT)); return (0); case IPC_SET64: if (error = ipcperm_set64(sem_svc, cr, &sp->sem_perm, &ds64.semx_perm)) { mutex_exit(lock); return (set_errno(error)); } sp->sem_ctime = gethrestime_sec(); mutex_exit(lock); return (0); case IPC_STAT64: ipcperm_stat64(&ds64.semx_perm, &sp->sem_perm); ds64.semx_nsems = sp->sem_nsems; ds64.semx_otime = sp->sem_otime; ds64.semx_ctime = sp->sem_ctime; mutex_exit(lock); if (copyout(&ds64, (void *)arg, sizeof (struct semid_ds64))) return (set_errno(EFAULT)); return (0); /* Get # of processes sleeping for greater semval. */ case GETNCNT: if (error = ipcperm_access(&sp->sem_perm, SEM_R, cr)) { mutex_exit(lock); return (set_errno(error)); } if (semnum >= sp->sem_nsems) { mutex_exit(lock); return (set_errno(EINVAL)); } retval = sp->sem_base[semnum].semncnt; mutex_exit(lock); return (retval); /* Get pid of last process to operate on semaphore. */ case GETPID: if (error = ipcperm_access(&sp->sem_perm, SEM_R, cr)) { mutex_exit(lock); return (set_errno(error)); } if (semnum >= sp->sem_nsems) { mutex_exit(lock); return (set_errno(EINVAL)); } retval = sp->sem_base[semnum].sempid; mutex_exit(lock); return (retval); /* Get semval of one semaphore. */ case GETVAL: if (error = ipcperm_access(&sp->sem_perm, SEM_R, cr)) { mutex_exit(lock); return (set_errno(error)); } if (semnum >= sp->sem_nsems) { mutex_exit(lock); return (set_errno(EINVAL)); } retval = sp->sem_base[semnum].semval; mutex_exit(lock); return (retval); /* Get all semvals in set. */ case GETALL: if (error = ipcperm_access(&sp->sem_perm, SEM_R, cr)) { mutex_exit(lock); return (set_errno(error)); } /* allocate space to hold all semaphore values */ vsize = sp->sem_nsems * sizeof (*vals); vals = vp = kmem_alloc(vsize, KM_SLEEP); for (i = sp->sem_nsems, p = sp->sem_base; i--; p++, vp++) bcopy(&p->semval, vp, sizeof (p->semval)); mutex_exit(lock); if (copyout((void *)vals, (void *)arg, vsize)) { kmem_free(vals, vsize); return (set_errno(EFAULT)); } kmem_free(vals, vsize); return (0); /* Get # of processes sleeping for semval to become zero. */ case GETZCNT: if (error = ipcperm_access(&sp->sem_perm, SEM_R, cr)) { mutex_exit(lock); return (set_errno(error)); } if (semnum >= sp->sem_nsems) { mutex_exit(lock); return (set_errno(EINVAL)); } retval = sp->sem_base[semnum].semzcnt; mutex_exit(lock); return (retval); /* Set semval of one semaphore. */ case SETVAL: if (error = ipcperm_access(&sp->sem_perm, SEM_A, cr)) { mutex_exit(lock); return (set_errno(error)); } if (semnum >= sp->sem_nsems) { mutex_exit(lock); return (set_errno(EINVAL)); } if ((uint_t)arg > USHRT_MAX) { mutex_exit(lock); return (set_errno(ERANGE)); } p = &sp->sem_base[semnum]; if ((p->semval = (ushort_t)arg) != 0) { if (p->semncnt) { cv_broadcast(&p->semncnt_cv); } } else if (p->semzcnt) { cv_broadcast(&p->semzcnt_cv); } p->sempid = curproc->p_pid; sem_undo_clear(sp, (ushort_t)semnum, (ushort_t)semnum); mutex_exit(lock); return (0); /* Set semvals of all semaphores in set. */ case SETALL: /* Check if semaphore set has been deleted and reallocated. */ if (sp->sem_nsems * sizeof (*vals) != vsize) { error = set_errno(EINVAL); goto seterr; } if (error = ipcperm_access(&sp->sem_perm, SEM_A, cr)) { error = set_errno(error); goto seterr; } sem_undo_clear(sp, 0, sp->sem_nsems - 1); for (i = 0, p = sp->sem_base; i < sp->sem_nsems; (p++)->sempid = curproc->p_pid) { if ((p->semval = vals[i++]) != 0) { if (p->semncnt) { cv_broadcast(&p->semncnt_cv); } } else if (p->semzcnt) { cv_broadcast(&p->semzcnt_cv); } } seterr: mutex_exit(lock); kmem_free(vals, vsize); return (error); default: mutex_exit(lock); return (set_errno(EINVAL)); } /* NOTREACHED */ }
/* * Get the audit state information from the current process. * Return EFAULT if copyout fails. */ static int getaudit_addr(caddr_t info_p, int len) { STRUCT_DECL(auditinfo_addr, info); const auditinfo_addr_t *ainfo; model_t model; if (secpolicy_audit_getattr(CRED()) != 0) return (EPERM); model = get_udatamodel(); STRUCT_INIT(info, model); if (len < STRUCT_SIZE(info)) return (EOVERFLOW); ainfo = crgetauinfo(CRED()); if (ainfo == NULL) return (EINVAL); STRUCT_FSET(info, ai_auid, ainfo->ai_auid); STRUCT_FSET(info, ai_mask, ainfo->ai_mask); #ifdef _LP64 if (model == DATAMODEL_ILP32) { dev32_t dev; /* convert internal 64 bit form to 32 bit version */ if (cmpldev(&dev, ainfo->ai_termid.at_port) == 0) { return (EOVERFLOW); } STRUCT_FSET(info, ai_termid.at_port, dev); } else STRUCT_FSET(info, ai_termid.at_port, ainfo->ai_termid.at_port); #else STRUCT_FSET(info, ai_termid.at_port, ainfo->ai_termid.at_port); #endif STRUCT_FSET(info, ai_termid.at_type, ainfo->ai_termid.at_type); STRUCT_FSET(info, ai_termid.at_addr[0], ainfo->ai_termid.at_addr[0]); STRUCT_FSET(info, ai_termid.at_addr[1], ainfo->ai_termid.at_addr[1]); STRUCT_FSET(info, ai_termid.at_addr[2], ainfo->ai_termid.at_addr[2]); STRUCT_FSET(info, ai_termid.at_addr[3], ainfo->ai_termid.at_addr[3]); STRUCT_FSET(info, ai_asid, ainfo->ai_asid); if (copyout(STRUCT_BUF(info), info_p, STRUCT_SIZE(info))) return (EFAULT); return (0); }