forked from mirrors/linux
		
	scm: Capture the full credentials of the scm sender.
Start capturing not only the userspace pid, uid and gid values of the sending process but also the struct pid and struct cred of the sending process as well. This is in preparation for properly supporting SCM_CREDENTIALS for sockets that have different uid and/or pid namespaces at the different ends. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Acked-by: Serge E. Hallyn <serge@hallyn.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									b47030c71d
								
							
						
					
					
						commit
						257b5358b3
					
				
					 2 changed files with 48 additions and 4 deletions
				
			
		|  | @ -19,6 +19,8 @@ struct scm_fp_list { | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct scm_cookie { | struct scm_cookie { | ||||||
|  | 	struct pid		*pid;		/* Skb credentials */ | ||||||
|  | 	const struct cred	*cred; | ||||||
| 	struct scm_fp_list	*fp;		/* Passed files		*/ | 	struct scm_fp_list	*fp;		/* Passed files		*/ | ||||||
| 	struct ucred		creds;		/* Skb credentials	*/ | 	struct ucred		creds;		/* Skb credentials	*/ | ||||||
| #ifdef CONFIG_SECURITY_NETWORK | #ifdef CONFIG_SECURITY_NETWORK | ||||||
|  | @ -42,8 +44,27 @@ static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_co | ||||||
| { } | { } | ||||||
| #endif /* CONFIG_SECURITY_NETWORK */ | #endif /* CONFIG_SECURITY_NETWORK */ | ||||||
| 
 | 
 | ||||||
|  | static __inline__ void scm_set_cred(struct scm_cookie *scm, | ||||||
|  | 				    struct pid *pid, const struct cred *cred) | ||||||
|  | { | ||||||
|  | 	scm->pid  = get_pid(pid); | ||||||
|  | 	scm->cred = get_cred(cred); | ||||||
|  | 	cred_to_ucred(pid, cred, &scm->creds); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static __inline__ void scm_destroy_cred(struct scm_cookie *scm) | ||||||
|  | { | ||||||
|  | 	put_pid(scm->pid); | ||||||
|  | 	scm->pid  = NULL; | ||||||
|  | 
 | ||||||
|  | 	if (scm->cred) | ||||||
|  | 		put_cred(scm->cred); | ||||||
|  | 	scm->cred = NULL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static __inline__ void scm_destroy(struct scm_cookie *scm) | static __inline__ void scm_destroy(struct scm_cookie *scm) | ||||||
| { | { | ||||||
|  | 	scm_destroy_cred(scm); | ||||||
| 	if (scm && scm->fp) | 	if (scm && scm->fp) | ||||||
| 		__scm_destroy(scm); | 		__scm_destroy(scm); | ||||||
| } | } | ||||||
|  | @ -51,10 +72,7 @@ static __inline__ void scm_destroy(struct scm_cookie *scm) | ||||||
| static __inline__ int scm_send(struct socket *sock, struct msghdr *msg, | static __inline__ int scm_send(struct socket *sock, struct msghdr *msg, | ||||||
| 			       struct scm_cookie *scm) | 			       struct scm_cookie *scm) | ||||||
| { | { | ||||||
| 	struct task_struct *p = current; | 	scm_set_cred(scm, task_tgid(current), current_cred()); | ||||||
| 	scm->creds.uid = current_uid(); |  | ||||||
| 	scm->creds.gid = current_gid(); |  | ||||||
| 	scm->creds.pid = task_tgid_vnr(p); |  | ||||||
| 	scm->fp = NULL; | 	scm->fp = NULL; | ||||||
| 	unix_get_peersec_dgram(sock, scm); | 	unix_get_peersec_dgram(sock, scm); | ||||||
| 	if (msg->msg_controllen <= 0) | 	if (msg->msg_controllen <= 0) | ||||||
|  | @ -96,6 +114,8 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg, | ||||||
| 	if (test_bit(SOCK_PASSCRED, &sock->flags)) | 	if (test_bit(SOCK_PASSCRED, &sock->flags)) | ||||||
| 		put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(scm->creds), &scm->creds); | 		put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(scm->creds), &scm->creds); | ||||||
| 
 | 
 | ||||||
|  | 	scm_destroy_cred(scm); | ||||||
|  | 
 | ||||||
| 	scm_passec(sock, msg, scm); | 	scm_passec(sock, msg, scm); | ||||||
| 
 | 
 | ||||||
| 	if (!scm->fp) | 	if (!scm->fp) | ||||||
|  |  | ||||||
|  | @ -170,6 +170,30 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p) | ||||||
| 			err = scm_check_creds(&p->creds); | 			err = scm_check_creds(&p->creds); | ||||||
| 			if (err) | 			if (err) | ||||||
| 				goto error; | 				goto error; | ||||||
|  | 
 | ||||||
|  | 			if (pid_vnr(p->pid) != p->creds.pid) { | ||||||
|  | 				struct pid *pid; | ||||||
|  | 				err = -ESRCH; | ||||||
|  | 				pid = find_get_pid(p->creds.pid); | ||||||
|  | 				if (!pid) | ||||||
|  | 					goto error; | ||||||
|  | 				put_pid(p->pid); | ||||||
|  | 				p->pid = pid; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if ((p->cred->euid != p->creds.uid) || | ||||||
|  | 				(p->cred->egid != p->creds.gid)) { | ||||||
|  | 				struct cred *cred; | ||||||
|  | 				err = -ENOMEM; | ||||||
|  | 				cred = prepare_creds(); | ||||||
|  | 				if (!cred) | ||||||
|  | 					goto error; | ||||||
|  | 
 | ||||||
|  | 				cred->uid = cred->euid = p->creds.uid; | ||||||
|  | 				cred->gid = cred->egid = p->creds.uid; | ||||||
|  | 				put_cred(p->cred); | ||||||
|  | 				p->cred = cred; | ||||||
|  | 			} | ||||||
| 			break; | 			break; | ||||||
| 		default: | 		default: | ||||||
| 			goto error; | 			goto error; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Eric W. Biederman
						Eric W. Biederman