Server/driver protocols: no longer allow third-party copies.

Before safecopies, the IO_ENDPT and DL_ENDPT message fields were needed
to know which actual process to copy data from/to, as that process may
not always be the caller. Now that we have full safecopy support, these
fields have become useless for that purpose: the owner of the grant is
*always* the caller. Allowing the caller to supply another endpoint is
in fact dangerous, because the callee may then end up using a grant
from a third party. One could call this a variant of the confused
deputy problem.

From now on, safecopy calls should always use the caller's endpoint as
grant owner. This fully obsoletes the DL_ENDPT field in the
inet/ethernet protocol. IO_ENDPT has other uses besides identifying the
grant owner though. This patch renames IO_ENDPT to USER_ENDPT, not only
because that is a more fitting name (it should never be used for I/O
after all), but also in order to intentionally break any old system
source code outside the base system. If this patch breaks your code,
fixing it is fairly simple:

- DL_ENDPT should be replaced with m_source;
- IO_ENDPT should be replaced with m_source when used for safecopies;
- IO_ENDPT should be replaced with USER_ENDPT for any other use, e.g.
  when setting REP_ENDPT, matching requests in CANCEL calls, getting
  DEV_SELECT flags, and retrieving of the real user process's endpoint
  in DEV_OPEN.

The changes in this patch are binary backward compatible.
This commit is contained in:
David van Moolenbroek
2011-04-11 17:35:05 +00:00
parent 4e86b0d53f
commit c51cd5fe91
52 changed files with 351 additions and 343 deletions

View File

@@ -8,7 +8,7 @@
*
* The driver supports the following operations:
*
* m_type DEVICE IO_ENDPT COUNT POSITION ADRRESS
* m_type DEVICE USER_ENDPT COUNT POSITION ADRRESS
* -----------------------------------------------------------------
* | DEV_OPEN | device | proc nr | | | |
* |-------------+---------+---------+---------+---------+---------|
@@ -122,7 +122,7 @@ PUBLIC int main(int argc, char *argv[])
/* open the special file ( = parameter) */
r = msg_open(mess.DEVICE);
repl_mess.m_type = DEV_REVIVE;
repl_mess.REP_ENDPT = mess.IO_ENDPT;
repl_mess.REP_ENDPT = mess.USER_ENDPT;
repl_mess.REP_STATUS = r;
send(caller, &repl_mess);
@@ -132,7 +132,7 @@ PUBLIC int main(int argc, char *argv[])
/* close the special file ( = parameter) */
r = msg_close(mess.DEVICE);
repl_mess.m_type = DEV_CLOSE_REPL;
repl_mess.REP_ENDPT = mess.IO_ENDPT;
repl_mess.REP_ENDPT = mess.USER_ENDPT;
repl_mess.REP_STATUS = r;
send(caller, &repl_mess);
@@ -144,7 +144,7 @@ PUBLIC int main(int argc, char *argv[])
if (r != SUSPEND)
{
repl_mess.m_type = DEV_REVIVE;
repl_mess.REP_ENDPT = mess.IO_ENDPT;
repl_mess.REP_ENDPT = mess.USER_ENDPT;
repl_mess.REP_IO_GRANT =
(unsigned)mess.IO_GRANT;
repl_mess.REP_STATUS = r;
@@ -162,7 +162,7 @@ PUBLIC int main(int argc, char *argv[])
/* reopen the special file ( = parameter) */
r = msg_open(mess.DEVICE);
repl_mess.m_type = DEV_REOPEN_REPL;
repl_mess.REP_ENDPT = mess.IO_ENDPT;
repl_mess.REP_ENDPT = mess.USER_ENDPT;
repl_mess.REP_STATUS = r;
send(caller, &repl_mess);
continue;
@@ -479,7 +479,7 @@ PRIVATE int msg_ioctl(const message *m_ptr)
if (m_ptr->REQUEST & _IOC_IN) { /* if there is data for us, copy it */
len = io_ctl_length(m_ptr->REQUEST);
if(sys_safecopyfrom(m_ptr->IO_ENDPT,
if(sys_safecopyfrom(m_ptr->m_source,
(vir_bytes)m_ptr->ADDRESS, 0,
(vir_bytes)io_ctl_buf, len, D) != OK) {
printf("%s:%d: safecopyfrom failed\n", __FILE__, __LINE__);
@@ -493,7 +493,7 @@ PRIVATE int msg_ioctl(const message *m_ptr)
if (status == OK && m_ptr->REQUEST & _IOC_OUT) {
/* copy result back to user */
if(sys_safecopyto(m_ptr->IO_ENDPT, (vir_bytes)m_ptr->ADDRESS, 0,
if(sys_safecopyto(m_ptr->m_source, (vir_bytes)m_ptr->ADDRESS, 0,
(vir_bytes)io_ctl_buf, len, D) != OK) {
printf("%s:%d: safecopyto failed\n", __FILE__, __LINE__);
}
@@ -515,7 +515,7 @@ PRIVATE void msg_write(const message *m_ptr)
if (chan == NO_CHANNEL) {
error("%s: No write channel specified!\n", drv.DriverName);
reply(DEV_REVIVE, m_ptr->m_source, m_ptr->IO_ENDPT, EIO);
reply(DEV_REVIVE, m_ptr->m_source, m_ptr->USER_ENDPT, EIO);
return;
}
/* get pointer to sub device data */
@@ -529,20 +529,20 @@ PRIVATE void msg_write(const message *m_ptr)
}
if(m_ptr->COUNT != sub_dev_ptr->FragSize) {
error("Fragment size does not match user's buffer length\n");
reply(DEV_REVIVE, m_ptr->m_source, m_ptr->IO_ENDPT, EINVAL);
reply(DEV_REVIVE, m_ptr->m_source, m_ptr->USER_ENDPT, EINVAL);
return;
}
/* if we are busy with something else than writing, return EBUSY */
if(sub_dev_ptr->DmaBusy && sub_dev_ptr->DmaMode != DEV_WRITE_S) {
error("Already busy with something else then writing\n");
reply(DEV_REVIVE, m_ptr->m_source, m_ptr->IO_ENDPT, EBUSY);
reply(DEV_REVIVE, m_ptr->m_source, m_ptr->USER_ENDPT, EBUSY);
return;
}
sub_dev_ptr->RevivePending = TRUE;
sub_dev_ptr->ReviveProcNr = m_ptr->IO_ENDPT;
sub_dev_ptr->ReviveProcNr = m_ptr->USER_ENDPT;
sub_dev_ptr->ReviveGrant = (cp_grant_id_t) m_ptr->ADDRESS;
sub_dev_ptr->NotifyProcNr = m_ptr->m_source;
sub_dev_ptr->SourceProcNr = m_ptr->m_source;
data_from_user(sub_dev_ptr);
@@ -566,7 +566,7 @@ PRIVATE void msg_read(message *m_ptr)
if (chan == NO_CHANNEL) {
error("%s: No read channel specified!\n", drv.DriverName);
reply(DEV_REVIVE, m_ptr->m_source, m_ptr->IO_ENDPT, EIO);
reply(DEV_REVIVE, m_ptr->m_source, m_ptr->USER_ENDPT, EIO);
return;
}
/* get pointer to sub device data */
@@ -575,25 +575,26 @@ PRIVATE void msg_read(message *m_ptr)
if (!sub_dev_ptr->DmaBusy) { /* get fragment size on first read */
if (drv_get_frag_size(&(sub_dev_ptr->FragSize), sub_dev_ptr->Nr) != OK){
error("%s: Could not retrieve fragment size!\n", drv.DriverName);
reply(DEV_REVIVE, m_ptr->m_source, m_ptr->IO_ENDPT, EIO);
reply(DEV_REVIVE, m_ptr->m_source, m_ptr->USER_ENDPT,
EIO);
return;
}
}
if(m_ptr->COUNT != sub_dev_ptr->FragSize) {
reply(DEV_REVIVE, m_ptr->m_source, m_ptr->IO_ENDPT, EINVAL);
reply(DEV_REVIVE, m_ptr->m_source, m_ptr->USER_ENDPT, EINVAL);
error("fragment size does not match message size\n");
return;
}
/* if we are busy with something else than reading, reply EBUSY */
if(sub_dev_ptr->DmaBusy && sub_dev_ptr->DmaMode != DEV_READ_S) {
reply(DEV_REVIVE, m_ptr->m_source, m_ptr->IO_ENDPT, EBUSY);
reply(DEV_REVIVE, m_ptr->m_source, m_ptr->USER_ENDPT, EBUSY);
return;
}
sub_dev_ptr->RevivePending = TRUE;
sub_dev_ptr->ReviveProcNr = m_ptr->IO_ENDPT;
sub_dev_ptr->ReviveProcNr = m_ptr->USER_ENDPT;
sub_dev_ptr->ReviveGrant = (cp_grant_id_t) m_ptr->ADDRESS;
sub_dev_ptr->NotifyProcNr = m_ptr->m_source;
sub_dev_ptr->SourceProcNr = m_ptr->m_source;
if(!sub_dev_ptr->DmaBusy) { /* Dma tranfer not yet started */
get_started(sub_dev_ptr);
@@ -814,7 +815,7 @@ PRIVATE void data_from_user(sub_dev_t *subdev)
if (subdev->DmaLength < subdev->NrOfDmaFragments) { /* room in dma buf */
sys_safecopyfrom(subdev->ReviveProcNr,
sys_safecopyfrom(subdev->SourceProcNr,
(vir_bytes)subdev->ReviveGrant, 0,
(vir_bytes)subdev->DmaPtr +
subdev->DmaFillNext * subdev->FragSize,
@@ -828,7 +829,7 @@ PRIVATE void data_from_user(sub_dev_t *subdev)
} else { /* room in extra buf */
sys_safecopyfrom(subdev->ReviveProcNr,
sys_safecopyfrom(subdev->SourceProcNr,
(vir_bytes)subdev->ReviveGrant, 0,
(vir_bytes)subdev->ExtraBuf +
subdev->BufFillNext * subdev->FragSize,
@@ -858,11 +859,11 @@ PRIVATE void data_from_user(sub_dev_t *subdev)
m.REP_ENDPT = subdev->ReviveProcNr;
m.REP_IO_GRANT = subdev->ReviveGrant;
m.REP_STATUS = subdev->ReviveStatus;
r= send(subdev->NotifyProcNr, &m); /* send the message */
r= send(subdev->SourceProcNr, &m); /* send the message */
if (r != OK)
{
printf("audio_fw: send to %d failed: %d\n",
subdev->NotifyProcNr, r);
subdev->SourceProcNr, r);
}
/* reset variables */
@@ -883,7 +884,7 @@ PRIVATE void data_to_user(sub_dev_t *sub_dev_ptr)
if(sub_dev_ptr->BufLength != 0) { /* data in extra buffer available */
sys_safecopyto(sub_dev_ptr->ReviveProcNr,
sys_safecopyto(sub_dev_ptr->SourceProcNr,
(vir_bytes)sub_dev_ptr->ReviveGrant,
0, (vir_bytes)sub_dev_ptr->ExtraBuf +
sub_dev_ptr->BufReadNext * sub_dev_ptr->FragSize,
@@ -898,7 +899,7 @@ PRIVATE void data_to_user(sub_dev_t *sub_dev_ptr)
} else { /* extra buf empty, but data in dma buf*/
sys_safecopyto(
sub_dev_ptr->ReviveProcNr,
sub_dev_ptr->SourceProcNr,
(vir_bytes)sub_dev_ptr->ReviveGrant, 0,
(vir_bytes)sub_dev_ptr->DmaPtr +
sub_dev_ptr->DmaReadNext * sub_dev_ptr->FragSize,
@@ -920,11 +921,11 @@ PRIVATE void data_to_user(sub_dev_t *sub_dev_ptr)
m.REP_ENDPT = sub_dev_ptr->ReviveProcNr;
m.REP_IO_GRANT = sub_dev_ptr->ReviveGrant;
m.REP_STATUS = sub_dev_ptr->ReviveStatus;
r= send(sub_dev_ptr->NotifyProcNr, &m); /* send the message */
r= send(sub_dev_ptr->SourceProcNr, &m); /* send the message */
if (r != OK)
{
printf("audio_fw: send to %d failed: %d\n",
sub_dev_ptr->NotifyProcNr, r);
sub_dev_ptr->SourceProcNr, r);
}
/* reset variables */

View File

@@ -9,7 +9,7 @@
*
* The drivers support the following operations (using message format m2):
*
* m_type DEVICE IO_ENDPT COUNT POSITION HIGHPOS IO_GRANT
* m_type DEVICE USER_ENDPT COUNT POSITION HIGHPOS IO_GRANT
* ----------------------------------------------------------------------------
* | DEV_OPEN | device | proc nr | | | | |
* |---------------+--------+---------+---------+--------+--------+-----------|
@@ -53,7 +53,7 @@ FORWARD _PROTOTYPE( void clear_open_devs, (void) );
FORWARD _PROTOTYPE( int is_open_dev, (int device) );
FORWARD _PROTOTYPE( void set_open_dev, (int device) );
FORWARD _PROTOTYPE( void asyn_reply, (message *mess, int proc_nr, int r) );
FORWARD _PROTOTYPE( void asyn_reply, (message *mess, int r) );
FORWARD _PROTOTYPE( int driver_reply, (endpoint_t caller_e, int caller_status,
message *m_ptr) );
FORWARD _PROTOTYPE( int driver_spurious_reply, (endpoint_t caller_e,
@@ -61,7 +61,8 @@ FORWARD _PROTOTYPE( int driver_spurious_reply, (endpoint_t caller_e,
FORWARD _PROTOTYPE( int do_rdwt, (struct driver *dr, message *mp) );
FORWARD _PROTOTYPE( int do_vrdwt, (struct driver *dr, message *mp) );
int device_caller;
PRIVATE endpoint_t device_caller;
PUBLIC endpoint_t device_endpt; /* used externally by log driver */
PRIVATE mq_t *queue_head = NULL;
PRIVATE int open_devs[MAX_NR_OPEN_DEVICES];
PRIVATE int next_open_devs_slot = 0;
@@ -108,9 +109,8 @@ PRIVATE void set_open_dev(int device)
/*===========================================================================*
* asyn_reply *
*===========================================================================*/
PRIVATE void asyn_reply(mess, proc_nr, r)
PRIVATE void asyn_reply(mess, r)
message *mess;
int proc_nr;
int r;
{
/* Send a reply using the new asynchronous character device protocol.
@@ -120,13 +120,13 @@ int r;
switch (mess->m_type) {
case DEV_OPEN:
reply_mess.m_type = DEV_REVIVE;
reply_mess.REP_ENDPT = proc_nr;
reply_mess.REP_ENDPT = device_endpt;
reply_mess.REP_STATUS = r;
break;
case DEV_CLOSE:
reply_mess.m_type = DEV_CLOSE_REPL;
reply_mess.REP_ENDPT = proc_nr;
reply_mess.REP_ENDPT = device_endpt;
reply_mess.REP_STATUS = r;
break;
@@ -134,10 +134,11 @@ int r;
case DEV_WRITE_S:
case DEV_IOCTL_S:
if (r == SUSPEND)
printf("driver_task: reviving %d with SUSPEND\n", proc_nr);
printf("driver_task: reviving %d (%d) with SUSPEND\n",
device_caller, device_endpt);
reply_mess.m_type = DEV_REVIVE;
reply_mess.REP_ENDPT = proc_nr;
reply_mess.REP_ENDPT = device_endpt;
reply_mess.REP_IO_GRANT = (cp_grant_id_t) mess->IO_GRANT;
reply_mess.REP_STATUS = r;
break;
@@ -154,7 +155,7 @@ int r;
default:
reply_mess.m_type = TASK_REPLY;
reply_mess.REP_ENDPT = proc_nr;
reply_mess.REP_ENDPT = device_endpt;
/* Status is # of bytes transferred or error code. */
reply_mess.REP_STATUS = r;
break;
@@ -202,7 +203,7 @@ message *m_ptr;
int r;
m_ptr->m_type = TASK_REPLY;
m_ptr->REP_ENDPT = m_ptr->IO_ENDPT;
m_ptr->REP_ENDPT = m_ptr->USER_ENDPT;
m_ptr->REP_STATUS = ERESTART;
r = driver_reply(caller_e, caller_status, m_ptr);
@@ -346,7 +347,7 @@ int type; /* Driver type (DRIVER_STD or DRIVER_ASYN) */
{
/* Main program of any device driver task. */
int r, proc_nr, ipc_status;
int r, ipc_status;
message mess;
driver_running = TRUE;
@@ -371,10 +372,10 @@ int type; /* Driver type (DRIVER_STD or DRIVER_ASYN) */
message *m_ptr; /* Pointer to message to handle */
int ipc_status;
{
int r, proc_nr;
int r;
device_caller = m_ptr->m_source;
proc_nr = m_ptr->IO_ENDPT;
device_endpt = m_ptr->USER_ENDPT;
if (is_ipc_notify(ipc_status)) {
switch (_ENDPOINT_P(m_ptr->m_source)) {
case HARDWARE:
@@ -425,7 +426,7 @@ send_reply:
switch (type) {
case DRIVER_STD:
m_ptr->m_type = TASK_REPLY;
m_ptr->REP_ENDPT = proc_nr;
m_ptr->REP_ENDPT = device_endpt;
/* Status is # of bytes transferred or error code. */
m_ptr->REP_STATUS = r;
@@ -439,7 +440,7 @@ send_reply:
break;
case DRIVER_ASYN:
asyn_reply(m_ptr, proc_nr, r);
asyn_reply(m_ptr, r);
break;
@@ -495,7 +496,7 @@ message *mp; /* pointer to read or write message */
/* Transfer bytes from/to the device. */
position= make64(mp->POSITION, mp->HIGHPOS);
r = (*dp->dr_transfer)(mp->IO_ENDPT, opcode, position, &iovec1, 1);
r = (*dp->dr_transfer)(mp->m_source, opcode, position, &iovec1, 1);
/* Return the number of bytes transferred or an error code. */
return(r == OK ? (mp->COUNT - iovec1.iov_size) : r);
@@ -536,7 +537,7 @@ message *mp; /* pointer to read or write message */
/* Transfer bytes from/to the device. */
opcode = mp->m_type;
position= make64(mp->POSITION, mp->HIGHPOS);
r = (*dp->dr_transfer)(mp->IO_ENDPT, opcode, position, iovec, nr_req);
r = (*dp->dr_transfer)(mp->m_source, opcode, position, iovec, nr_req);
/* Copy the I/O vector back to the caller. */
if (OK != sys_safecopyto(mp->m_source, (vir_bytes) mp->IO_GRANT,
@@ -659,7 +660,7 @@ message *mp; /* pointer to ioctl request */
if (mp->REQUEST == DIOCSETP) {
/* Copy just this one partition table entry. */
s=sys_safecopyfrom(mp->IO_ENDPT, (vir_bytes) mp->IO_GRANT,
s=sys_safecopyfrom(mp->m_source, (vir_bytes) mp->IO_GRANT,
0, (vir_bytes) &entry, sizeof(entry), D);
if(s != OK)
return s;
@@ -670,7 +671,7 @@ message *mp; /* pointer to ioctl request */
entry.base = dv->dv_base;
entry.size = dv->dv_size;
(*dp->dr_geometry)(&entry);
s=sys_safecopyto(mp->IO_ENDPT, (vir_bytes) mp->IO_GRANT,
s=sys_safecopyto(mp->m_source, (vir_bytes) mp->IO_GRANT,
0, (vir_bytes) &entry, sizeof(entry), D);
if (OK != s)
return s;

View File

@@ -7,7 +7,7 @@ PUBLIC int sys_enable_iop(proc_ep)
endpoint_t proc_ep; /* number of process to allow I/O */
{
message m_iop;
m_iop.IO_ENDPT = proc_ep;
m_iop.IOP_ENDPT = proc_ep;
return _kernel_call(SYS_IOPENABLE, &m_iop);
}