kernel: Allow kernel calls to return ENOTREADY.
This is required to avoid races with safecopy() at live update time. Change-Id: I1f3e22d40f22d94bd2b850915f9b8163a08b5616
This commit is contained in:
		
							parent
							
								
									c8a9900b0c
								
							
						
					
					
						commit
						9e6b1315c3
					
				| @ -87,7 +87,8 @@ void cpf_reload(void); | |||||||
| /* Set a process' grant table location and size (in-kernel only). */ | /* Set a process' grant table location and size (in-kernel only). */ | ||||||
| #define _K_SET_GRANT_TABLE(rp, ptr, entries)	\ | #define _K_SET_GRANT_TABLE(rp, ptr, entries)	\ | ||||||
| 	priv(rp)->s_grant_table= (ptr);		\ | 	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 */ | #endif	/* _MINIX_SAFECOPIES_H */ | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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; |   vir_bytes count = m_ptr->m_lsys_krn_sys_sdevio.vec_size; | ||||||
|   long port = m_ptr->m_lsys_krn_sys_sdevio.port; |   long port = m_ptr->m_lsys_krn_sys_sdevio.port; | ||||||
|   phys_bytes vir_buf; |   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 priv *privp; | ||||||
|   struct io_range *iorp; |   struct io_range *iorp; | ||||||
|   struct proc *destproc; |   struct proc *destproc; | ||||||
| @ -67,11 +67,12 @@ int do_sdevio(struct proc * caller, message *m_ptr) | |||||||
|   /* Check for 'safe' variants. */ |   /* Check for 'safe' variants. */ | ||||||
|   if((m_ptr->m_lsys_krn_sys_sdevio.request & _DIO_SAFEMASK) == _DIO_SAFE) { |   if((m_ptr->m_lsys_krn_sys_sdevio.request & _DIO_SAFEMASK) == _DIO_SAFE) { | ||||||
|      /* Map grant address to physical address. */ |      /* 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, | 		m_ptr->m_lsys_krn_sys_sdevio.vec_addr, count, | ||||||
| 		req_dir == _DIO_INPUT ? CPF_WRITE : CPF_READ, | 		req_dir == _DIO_INPUT ? CPF_WRITE : CPF_READ, | ||||||
| 		m_ptr->m_lsys_krn_sys_sdevio.offset, &newoffset, &newep, | 		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"); | 	printf("do_sdevio: verify_grant failed\n"); | ||||||
| 	return EPERM; | 	return EPERM; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -60,6 +60,7 @@ struct priv { | |||||||
|   int s_irq_tab[NR_IRQ]; |   int s_irq_tab[NR_IRQ]; | ||||||
|   vir_bytes s_grant_table;	/* grant table address of process, or 0 */ |   vir_bytes s_grant_table;	/* grant table address of process, or 0 */ | ||||||
|   int s_grant_entries;		/* no. of entries, 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 */ |   vir_bytes s_state_table;	/* state table address of process, or 0 */ | ||||||
|   int s_state_entries;		/* no. of entries, or 0 */ |   int s_state_entries;		/* no. of entries, or 0 */ | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -156,6 +156,7 @@ int do_privctl(struct proc * caller, message * m_ptr) | |||||||
| 	priv(rp)->s_nr_irq= 0; | 	priv(rp)->s_nr_irq= 0; | ||||||
| 	priv(rp)->s_grant_table= 0; | 	priv(rp)->s_grant_table= 0; | ||||||
| 	priv(rp)->s_grant_entries= 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_table= 0; | ||||||
| 	priv(rp)->s_state_entries= 0; | 	priv(rp)->s_state_entries= 0; | ||||||
| 	priv(rp)->s_ipcf= 0; | 	priv(rp)->s_ipcf= 0; | ||||||
|  | |||||||
| @ -64,6 +64,23 @@ u32_t *flags;			/* CPF_* */ | |||||||
| 		} | 		} | ||||||
| 		granter_proc = proc_addr(proc_nr); | 		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
 | 		/* If there is no priv. structure, or no grant table in the
 | ||||||
| 		 * priv. structure, or the grant table in the priv. structure | 		 * priv. structure, or the grant table in the priv. structure | ||||||
| 		 * is too small for the grant, return EPERM. | 		 * 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; | 		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. */ | 	/* Decide who is src and who is dst. */ | ||||||
| 	if(access & CPF_READ) { | 	if(access & CPF_READ) { | ||||||
| 		src = &granter; | 		src = &granter; | ||||||
| @ -275,6 +284,7 @@ int access;			/* CPF_READ for a copy from granter to grantee, CPF_WRITE | |||||||
| 	/* Verify permission exists. */ | 	/* Verify permission exists. */ | ||||||
| 	if((r=verify_grant(granter, grantee, grantid, bytes, access, | 	if((r=verify_grant(granter, grantee, grantid, bytes, access, | ||||||
| 	    g_offset, &v_offset, &new_granter, &flags)) != OK) { | 	    g_offset, &v_offset, &new_granter, &flags)) != OK) { | ||||||
|  | 		if(r == ENOTREADY) return r; | ||||||
| 			printf( | 			printf( | ||||||
| 		"grant %d verify to copy %d->%d by %d failed: err %d\n", | 		"grant %d verify to copy %d->%d by %d failed: err %d\n", | ||||||
| 				grantid, *src, *dst, grantee, r); | 				grantid, *src, *dst, grantee, r); | ||||||
|  | |||||||
| @ -1,9 +1,22 @@ | |||||||
|  | #define _SYSTEM 1 | ||||||
|  | 
 | ||||||
| #include <lib.h> | #include <lib.h> | ||||||
| #include <minix/syslib.h> | #include <minix/syslib.h> | ||||||
|  | #include <minix/sysutil.h> | ||||||
| 
 | 
 | ||||||
| int _kernel_call(int syscallnr, message *msgptr) | int _kernel_call(int syscallnr, message *msgptr) | ||||||
| { | { | ||||||
|   msgptr->m_type = syscallnr; |   int t, r; | ||||||
|   do_kernel_call(msgptr); |   t = 1; | ||||||
|   return(msgptr->m_type); |   while(1) { | ||||||
|  |       msgptr->m_type = syscallnr; | ||||||
|  |       do_kernel_call(msgptr); | ||||||
|  |       r = msgptr->m_type; | ||||||
|  |       if(r != ENOTREADY) { | ||||||
|  |           break; | ||||||
|  |       } | ||||||
|  |       tickdelay(t++); | ||||||
|  |   } | ||||||
|  |   return r; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Cristiano Giuffrida
						Cristiano Giuffrida