Exemplo 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);
}
Exemplo n.º 2
0
/*
 * semget - Semget system call.
 */
static int
semget(key_t key, int nsems, int semflg)
{
    ksemid_t	*sp;
    kmutex_t	*lock;
    int		id, error;
    proc_t		*pp = curproc;

top:
    if (error = ipc_get(sem_svc, key, semflg, (kipc_perm_t **)&sp, &lock))
        return (set_errno(error));

    if (!IPC_FREE(&sp->sem_perm)) {
        /*
         * A semaphore with the requested key exists.
         */
        if (!((nsems >= 0) && (nsems <= sp->sem_nsems))) {
            mutex_exit(lock);
            return (set_errno(EINVAL));
        }
    } else {
        /*
         * This is a new semaphore set.  Finish initialization.
         */
        if (nsems <= 0 || (rctl_test(rc_process_semmsl, pp->p_rctls, pp,
                                     nsems, RCA_SAFE) & RCT_DENY)) {
            mutex_exit(lock);
            mutex_exit(&pp->p_lock);
            ipc_cleanup(sem_svc, (kipc_perm_t *)sp);
            return (set_errno(EINVAL));
        }
        mutex_exit(lock);
        mutex_exit(&pp->p_lock);

        /*
         * We round the allocation up to coherency granularity
         * so that multiple semaphore allocations won't result
         * in the false sharing of their sem structures.
         */
        sp->sem_base =
            kmem_zalloc(P2ROUNDUP(nsems * sizeof (struct sem), 64),
                        KM_SLEEP);
        sp->sem_binary = (nsems == 1);
        sp->sem_nsems = (ushort_t)nsems;
        sp->sem_ctime = gethrestime_sec();
        sp->sem_otime = 0;
        list_create(&sp->sem_undos, sizeof (struct sem_undo),
                    offsetof(struct sem_undo, un_list));

        if (error = ipc_commit_begin(sem_svc, key, semflg,
                                     (kipc_perm_t *)sp)) {
            if (error == EAGAIN)
                goto top;
            return (set_errno(error));
        }
        sp->sem_maxops =
            rctl_enforced_value(rc_process_semopm, pp->p_rctls, pp);
        if (rctl_test(rc_process_semmsl, pp->p_rctls, pp, nsems,
                      RCA_SAFE) & RCT_DENY) {
            ipc_cleanup(sem_svc, (kipc_perm_t *)sp);
            return (set_errno(EINVAL));
        }
        lock = ipc_commit_end(sem_svc, &sp->sem_perm);
    }
    if (audit_active)
        audit_ipcget(AT_IPC_SEM, (void *)sp);
    id = sp->sem_perm.ipc_id;
    mutex_exit(lock);
    return (id);
}