int msg_control_read(struct msg_control *msg_ctrl, struct ancillary *data, int minor) { int rc; struct msghdr msghdr; struct cmsghdr *cmsg = NULL; #if DEBUG == 1 static int call_count = 0; printf("(uds) [%d] msg_control_read() call_count=%d\n", minor, ++call_count); #endif data->nfiledes = 0; memset(&msghdr, '\0', sizeof(struct msghdr)); msghdr.msg_control = msg_ctrl->msg_control; msghdr.msg_controllen = msg_ctrl->msg_controllen; for(cmsg = CMSG_FIRSTHDR(&msghdr); cmsg != NULL; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) { if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { int i; int nfds = MIN((cmsg->cmsg_len-CMSG_LEN(0))/sizeof(int), OPEN_MAX); for (i = 0; i < nfds; i++) { if (data->nfiledes == OPEN_MAX) { return EOVERFLOW; } data->fds[data->nfiledes] = ((int *) CMSG_DATA(cmsg))[i]; #if DEBUG == 1 printf("(uds) [%d] fd[%d]=%d\n", minor, data->nfiledes, data->fds[data->nfiledes]); #endif data->nfiledes++; } } } /* obtain this socket's credentials */ rc = getnucred(uds_fd_table[minor].owner, &(data->cred)); if (rc == -1) { return errno; } #if DEBUG == 1 printf("(uds) [%d] cred={%d,%d,%d}\n", minor, data->cred.pid, data->cred.uid, data->cred.gid); #endif return OK; }
int do_getsockopt_peercred_old(message *dev_m_in, message *dev_m_out) { int minor; int peer_minor; int rc; struct ucred cred; struct ucred_old cred_old; #if DEBUG == 1 static int call_count = 0; printf("(uds) [%d] do_getsockopt_peercred() call_count=%d\n", uds_minor(dev_m_in), ++call_count); #endif minor = uds_minor(dev_m_in); if (uds_fd_table[minor].peer == -1) { if (uds_fd_table[minor].err == ECONNRESET) { uds_fd_table[minor].err = 0; return ECONNRESET; } else { return ENOTCONN; } } peer_minor = uds_fd_table[minor].peer; /* obtain the peer's credentials */ rc = getnucred(uds_fd_table[peer_minor].owner, &cred); if (rc == -1) { /* likely error: invalid endpoint / proc doesn't exist */ return errno; } /* copy to old structure */ cred_old.pid = cred.pid; cred_old.uid = (short) cred.uid; cred_old.gid = (char) cred.gid; rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, (vir_bytes) 0, (vir_bytes) &cred_old, sizeof(struct ucred_old), D); return rc ? EIO : OK; }
static int hello_open(message *m) { struct ucred new_owner; // Sanity check: Don't open in Read/Write mode. if (m->COUNT == O_RDWR) { fprintf(stderr, "open() was opened in READ_WRITE mode by UID: %d. Bouncing open() request.\n", new_owner.uid); return EACCES; } // Grab the credentials for the new owner. if (getnucred(m->USER_ENDPT, &new_owner) != 0) { fprintf(stderr, "getnucred failed\n"); return errno; } // If empty... if (owner == -1) { switch (m->COUNT) { // WRITE_ONLY mode on an empty secret. case O_WRONLY: printf("Empty Secret opened in WRITE_ONLY mode by UID: %d\n", new_owner.uid); // Set the owner to be full owner = new_owner.uid; printf("Open file descriptors: %d\n", ++open_file_descriptors); return OK; // READ_ONLY mode on an empty Secret. case O_RDONLY: fprintf(stderr, "UID %d opened an Empty Secret in READ_ONLY mode.\n", new_owner.uid); printf("Open file descriptors: %d\n", ++open_file_descriptors); // do nothing. return OK; // Error state. default: fprintf(stderr, "unknown open() flags: %d", m->COUNT); return -1; } } // If full... else { switch (m->COUNT) { // READ_ONLY mode on a full Secret. case O_RDONLY: // If the Secret is being read by the owner... if (owner == new_owner.uid) { printf("Full Secret opened in READ_ONLY mode by the owner: %d\n", new_owner.uid); // Set the Secret to be empty. owner = -1; // The Secret is now opened for reading secret_opened_for_reading = true; printf("Open file descriptors: %d\n", ++open_file_descriptors); return OK; } // If the Secret is being read by SOMEONE ELSE... else { printf("Can't read someone else's secret: Full Secret opened in READ_ONLY mode by %d, even though the owner was %d\n", new_owner.uid, owner); return -1; } // WRITE_ONLY mode on a full Secret. case O_WRONLY: fprintf(stderr, "No space left on device\n"); return -1; // Error state. default: fprintf(stderr, "unknown open() flags: %d\n", m->COUNT); return -1; } } return OK; }
PUBLIC int uds_open(message *dev_m_in, message *dev_m_out) { message fs_m_in, fs_m_out; struct ucred ucred; int rc, i; int minor; #if DEBUG == 1 static int call_count = 0; printf("(uds) [%d] uds_open() call_count=%d\n", uds_minor(dev_m_in), ++call_count); printf("Endpoint: 0x%x\n", dev_m_in->IO_ENDPT); #endif /* * Find a slot in the descriptor table for the new descriptor. * The index of the descriptor in the table will be returned. * Subsequent calls to read/write/close/ioctl/etc will use this * minor number. The minor number must be different from the * the /dev/uds device's minor number (currently 0). */ minor = -1; /* to trap error */ for (i = 1; i < NR_FDS; i++) { if (uds_fd_table[i].state == UDS_FREE) { minor = i; break; } } if (minor == -1) { /* descriptor table full */ uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT, (cp_grant_id_t) dev_m_in->IO_GRANT, ENFILE); return ENFILE; } /* * We found a slot in uds_fd_table, now initialize the descriptor */ /* mark this one as 'in use' so that it doesn't get assigned to * another socket */ uds_fd_table[minor].state = UDS_INUSE; /* track the system call we are performing in case it gets cancelled */ uds_fd_table[minor].call_nr = dev_m_in->m_type; uds_fd_table[minor].ioctl = 0; uds_fd_table[minor].syscall_done = 0; /* set the socket owner */ uds_fd_table[minor].owner = dev_m_in->IO_ENDPT; uds_fd_table[minor].endpoint = dev_m_in->IO_ENDPT; /* setup select(2) framework */ uds_fd_table[minor].selecting = 0; uds_fd_table[minor].select_proc = 0; uds_fd_table[minor].sel_ops_in = 0; uds_fd_table[minor].sel_ops_out = 0; uds_fd_table[minor].status_updated = 0; /* initialize the data pointer (pos) to the start of the PIPE */ uds_fd_table[minor].pos = 0; /* the PIPE is initially empty */ uds_fd_table[minor].size = 0; /* the default for a new socket is to allow reading and writing. * shutdown(2) will remove one or both flags. */ uds_fd_table[minor].mode = S_IRUSR|S_IWUSR; /* In libc socket(2) sets this to the actual value later with the * NWIOSUDSTYPE ioctl(). */ uds_fd_table[minor].type = -1; /* Clear the backlog by setting each entry to -1 */ for (i = 0; i < UDS_SOMAXCONN; i++) { /* initially no connections are pending */ uds_fd_table[minor].backlog[i] = -1; } memset(&uds_fd_table[minor].ancillary_data, '\0', sizeof(struct ancillary)); for (i = 0; i < OPEN_MAX; i++) { uds_fd_table[minor].ancillary_data.fds[i] = -1; } /* default the size to UDS_SOMAXCONN */ uds_fd_table[minor].backlog_size = UDS_SOMAXCONN; /* the socket isn't listening for incoming connections until * listen(2) is called */ uds_fd_table[minor].listening = 0; /* initially the socket is not connected to a peer */ uds_fd_table[minor].peer = -1; /* there isn't a child waiting to be accept(2)'d */ uds_fd_table[minor].child = -1; /* initially the socket is not bound or listening on an address */ memset(&(uds_fd_table[minor].addr), '\0', sizeof(struct sockaddr_un)); memset(&(uds_fd_table[minor].source), '\0', sizeof(struct sockaddr_un)); memset(&(uds_fd_table[minor].target), '\0', sizeof(struct sockaddr_un)); /* Initially the socket isn't suspended. */ uds_fd_table[minor].suspended = UDS_NOT_SUSPENDED; /* and the socket doesn't have an I/O grant initially */ uds_fd_table[minor].io_gr = (cp_grant_id_t) 0; /* since there is no I/O grant it effectively has no size either */ uds_fd_table[minor].io_gr_size = 0; /* The process isn't suspended so we don't flag it as revivable */ uds_fd_table[minor].ready_to_revive = 0; /* get the effective user id and effective group id from the endpoint */ /* this is needed in the REQ_NEWNODE request to PFS. */ rc = getnucred(uds_fd_table[minor].endpoint, &ucred); if (rc == -1) { /* roll back the changes we made to the descriptor */ memset(&(uds_fd_table[minor]), '\0', sizeof(uds_fd_t)); /* likely error: invalid endpoint / proc doesn't exist */ uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT, (cp_grant_id_t) dev_m_in->IO_GRANT, errno); return errno; } /* Prepare Request to the FS side of PFS */ fs_m_in.m_type = REQ_NEWNODE; fs_m_in.REQ_MODE = I_NAMED_PIPE; fs_m_in.REQ_DEV = NO_DEV; fs_m_in.REQ_UID = ucred.uid; fs_m_in.REQ_GID = ucred.gid; /* Request a new inode on the pipe file system */ rc = fs_newnode(&fs_m_in, &fs_m_out); if (rc != OK) { /* roll back the changes we made to the descriptor */ memset(&(uds_fd_table[minor]), '\0', sizeof(uds_fd_t)); /* likely error: get_block() failed */ uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT, (cp_grant_id_t) dev_m_in->IO_GRANT, errno); return errno; } /* Process the response */ uds_fd_table[minor].inode_nr = fs_m_out.RES_INODE_NR; /* prepare the reply */ uds_fd_table[minor].syscall_done = 1; uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT, (cp_grant_id_t) dev_m_in->IO_GRANT, minor); return minor; }