Esempio n. 1
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);
}
Esempio n. 2
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 */
}