From 9e6b1315c3aa89badd9faa3be96f699fdeee0b16 Mon Sep 17 00:00:00 2001 From: Cristiano Giuffrida Date: Tue, 11 Mar 2014 17:47:40 +0100 Subject: [PATCH] kernel: Allow kernel calls to return ENOTREADY. This is required to avoid races with safecopy() at live update time. Change-Id: I1f3e22d40f22d94bd2b850915f9b8163a08b5616 --- minix/include/minix/safecopies.h | 3 ++- minix/kernel/arch/i386/do_sdevio.c | 7 ++++--- minix/kernel/priv.h | 1 + minix/kernel/system/do_privctl.c | 1 + minix/kernel/system/do_safecopy.c | 26 ++++++++++++++++++-------- minix/lib/libsys/kernel_call.c | 19 ++++++++++++++++--- 6 files changed, 42 insertions(+), 15 deletions(-) diff --git a/minix/include/minix/safecopies.h b/minix/include/minix/safecopies.h index 4d9b4e2e8..3f875614b 100644 --- a/minix/include/minix/safecopies.h +++ b/minix/include/minix/safecopies.h @@ -87,7 +87,8 @@ void cpf_reload(void); /* Set a process' grant table location and size (in-kernel only). */ #define _K_SET_GRANT_TABLE(rp, ptr, entries) \ priv(rp)->s_grant_table= (ptr); \ - priv(rp)->s_grant_entries= (entries); + priv(rp)->s_grant_entries= (entries); \ + priv(rp)->s_grant_endpoint= (rp)->p_endpoint; #endif /* _MINIX_SAFECOPIES_H */ diff --git a/minix/kernel/arch/i386/do_sdevio.c b/minix/kernel/arch/i386/do_sdevio.c index 28558672a..add9f2adf 100644 --- a/minix/kernel/arch/i386/do_sdevio.c +++ b/minix/kernel/arch/i386/do_sdevio.c @@ -30,7 +30,7 @@ int do_sdevio(struct proc * caller, message *m_ptr) vir_bytes count = m_ptr->m_lsys_krn_sys_sdevio.vec_size; long port = m_ptr->m_lsys_krn_sys_sdevio.port; phys_bytes vir_buf; - int i, req_type, req_dir, size, nr_io_range; + int i, r, req_type, req_dir, size, nr_io_range; struct priv *privp; struct io_range *iorp; struct proc *destproc; @@ -67,11 +67,12 @@ int do_sdevio(struct proc * caller, message *m_ptr) /* Check for 'safe' variants. */ if((m_ptr->m_lsys_krn_sys_sdevio.request & _DIO_SAFEMASK) == _DIO_SAFE) { /* Map grant address to physical address. */ - if(verify_grant(proc_nr_e, caller->p_endpoint, + if((r=verify_grant(proc_nr_e, caller->p_endpoint, m_ptr->m_lsys_krn_sys_sdevio.vec_addr, count, req_dir == _DIO_INPUT ? CPF_WRITE : CPF_READ, m_ptr->m_lsys_krn_sys_sdevio.offset, &newoffset, &newep, - NULL) != OK) { + NULL)) != OK) { + if(r == ENOTREADY) return r; printf("do_sdevio: verify_grant failed\n"); return EPERM; } diff --git a/minix/kernel/priv.h b/minix/kernel/priv.h index 06e4c091e..4efd9e877 100644 --- a/minix/kernel/priv.h +++ b/minix/kernel/priv.h @@ -60,6 +60,7 @@ struct priv { int s_irq_tab[NR_IRQ]; vir_bytes s_grant_table; /* grant table address of process, or 0 */ int s_grant_entries; /* no. of entries, or 0 */ + endpoint_t s_grant_endpoint; /* the endpoint the grant table belongs to */ vir_bytes s_state_table; /* state table address of process, or 0 */ int s_state_entries; /* no. of entries, or 0 */ }; diff --git a/minix/kernel/system/do_privctl.c b/minix/kernel/system/do_privctl.c index 41eee88c7..0fc6c3118 100644 --- a/minix/kernel/system/do_privctl.c +++ b/minix/kernel/system/do_privctl.c @@ -156,6 +156,7 @@ int do_privctl(struct proc * caller, message * m_ptr) priv(rp)->s_nr_irq= 0; priv(rp)->s_grant_table= 0; priv(rp)->s_grant_entries= 0; + priv(rp)->s_grant_endpoint = rp->p_endpoint; priv(rp)->s_state_table= 0; priv(rp)->s_state_entries= 0; priv(rp)->s_ipcf= 0; diff --git a/minix/kernel/system/do_safecopy.c b/minix/kernel/system/do_safecopy.c index 382068269..ce3ef9630 100644 --- a/minix/kernel/system/do_safecopy.c +++ b/minix/kernel/system/do_safecopy.c @@ -64,6 +64,23 @@ u32_t *flags; /* CPF_* */ } granter_proc = proc_addr(proc_nr); + /* If the granter has a temporary grant table, always allow + * requests with unspecified access and return ENOTREADY if + * no grant table is present or if the grantee's endpoint is not + * the endpoint the table belongs to. When ENOTREADY is returned + * the same verify_grant() request will be replayed again in a + * while until the grant table is final. This is necessary to + * avoid races at live update time. + */ + if(priv(granter_proc)->s_grant_endpoint != granter_proc->p_endpoint) { + if(!access) { + return OK; + } + else if(!HASGRANTTABLE(granter_proc) || grantee != priv(granter_proc)->s_grant_endpoint) { + return ENOTREADY; + } + } + /* If there is no priv. structure, or no grant table in the * priv. structure, or the grant table in the priv. structure * is too small for the grant, return EPERM. @@ -255,14 +272,6 @@ int access; /* CPF_READ for a copy from granter to grantee, CPF_WRITE return EFAULT; } - /* See if there is a reasonable grant table. */ - if(!(granter_p = endpoint_lookup(granter))) return EINVAL; - if(!HASGRANTTABLE(granter_p)) { - printf( - "safecopy failed: granter %d has no grant table\n", granter); - return(EPERM); - } - /* Decide who is src and who is dst. */ if(access & CPF_READ) { src = &granter; @@ -275,6 +284,7 @@ int access; /* CPF_READ for a copy from granter to grantee, CPF_WRITE /* Verify permission exists. */ if((r=verify_grant(granter, grantee, grantid, bytes, access, g_offset, &v_offset, &new_granter, &flags)) != OK) { + if(r == ENOTREADY) return r; printf( "grant %d verify to copy %d->%d by %d failed: err %d\n", grantid, *src, *dst, grantee, r); diff --git a/minix/lib/libsys/kernel_call.c b/minix/lib/libsys/kernel_call.c index 856e45aa6..ed92b7342 100644 --- a/minix/lib/libsys/kernel_call.c +++ b/minix/lib/libsys/kernel_call.c @@ -1,9 +1,22 @@ +#define _SYSTEM 1 + #include #include +#include int _kernel_call(int syscallnr, message *msgptr) { - msgptr->m_type = syscallnr; - do_kernel_call(msgptr); - return(msgptr->m_type); + int t, r; + t = 1; + while(1) { + msgptr->m_type = syscallnr; + do_kernel_call(msgptr); + r = msgptr->m_type; + if(r != ENOTREADY) { + break; + } + tickdelay(t++); + } + return r; } +