xref: /openbmc/linux/include/net/scm.h (revision fd2c3ef761fbc5e6c27fa7d40b30cda06bfcd7d8)
11da177e4SLinus Torvalds #ifndef __LINUX_NET_SCM_H
21da177e4SLinus Torvalds #define __LINUX_NET_SCM_H
31da177e4SLinus Torvalds 
41da177e4SLinus Torvalds #include <linux/limits.h>
51da177e4SLinus Torvalds #include <linux/net.h>
6dc49c1f9SCatherine Zhang #include <linux/security.h>
7b488893aSPavel Emelyanov #include <linux/pid.h>
8b488893aSPavel Emelyanov #include <linux/nsproxy.h>
91da177e4SLinus Torvalds 
101da177e4SLinus Torvalds /* Well, we should have at least one descriptor open
111da177e4SLinus Torvalds  * to accept passed FDs 8)
121da177e4SLinus Torvalds  */
13c09edd6eSRoland McGrath #define SCM_MAX_FD	255
141da177e4SLinus Torvalds 
15*fd2c3ef7SEric Dumazet struct scm_fp_list {
16f8d570a4SDavid Miller 	struct list_head	list;
171da177e4SLinus Torvalds 	int			count;
181da177e4SLinus Torvalds 	struct file		*fp[SCM_MAX_FD];
191da177e4SLinus Torvalds };
201da177e4SLinus Torvalds 
21*fd2c3ef7SEric Dumazet struct scm_cookie {
221da177e4SLinus Torvalds 	struct ucred		creds;		/* Skb credentials	*/
231da177e4SLinus Torvalds 	struct scm_fp_list	*fp;		/* Passed files		*/
24877ce7c1SCatherine Zhang #ifdef CONFIG_SECURITY_NETWORK
25dc49c1f9SCatherine Zhang 	u32			secid;		/* Passed security ID 	*/
26877ce7c1SCatherine Zhang #endif
271da177e4SLinus Torvalds };
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds extern void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm);
301da177e4SLinus Torvalds extern void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm);
311da177e4SLinus Torvalds extern int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm);
321da177e4SLinus Torvalds extern void __scm_destroy(struct scm_cookie *scm);
331da177e4SLinus Torvalds extern struct scm_fp_list * scm_fp_dup(struct scm_fp_list *fpl);
341da177e4SLinus Torvalds 
35dc49c1f9SCatherine Zhang #ifdef CONFIG_SECURITY_NETWORK
36dc49c1f9SCatherine Zhang static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_cookie *scm)
37dc49c1f9SCatherine Zhang {
38dc49c1f9SCatherine Zhang 	security_socket_getpeersec_dgram(sock, NULL, &scm->secid);
39dc49c1f9SCatherine Zhang }
40dc49c1f9SCatherine Zhang #else
41dc49c1f9SCatherine Zhang static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_cookie *scm)
42dc49c1f9SCatherine Zhang { }
43dc49c1f9SCatherine Zhang #endif /* CONFIG_SECURITY_NETWORK */
44dc49c1f9SCatherine Zhang 
451da177e4SLinus Torvalds static __inline__ void scm_destroy(struct scm_cookie *scm)
461da177e4SLinus Torvalds {
471da177e4SLinus Torvalds 	if (scm && scm->fp)
481da177e4SLinus Torvalds 		__scm_destroy(scm);
491da177e4SLinus Torvalds }
501da177e4SLinus Torvalds 
511da177e4SLinus Torvalds static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
521da177e4SLinus Torvalds 			       struct scm_cookie *scm)
531da177e4SLinus Torvalds {
541d541dddSBenjamin LaHaise 	struct task_struct *p = current;
558192b0c4SDavid Howells 	scm->creds.uid = current_uid();
568192b0c4SDavid Howells 	scm->creds.gid = current_gid();
57b488893aSPavel Emelyanov 	scm->creds.pid = task_tgid_vnr(p);
581d541dddSBenjamin LaHaise 	scm->fp = NULL;
59dc49c1f9SCatherine Zhang 	unix_get_peersec_dgram(sock, scm);
601da177e4SLinus Torvalds 	if (msg->msg_controllen <= 0)
611da177e4SLinus Torvalds 		return 0;
621da177e4SLinus Torvalds 	return __scm_send(sock, msg, scm);
631da177e4SLinus Torvalds }
641da177e4SLinus Torvalds 
65877ce7c1SCatherine Zhang #ifdef CONFIG_SECURITY_NETWORK
66877ce7c1SCatherine Zhang static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm)
67877ce7c1SCatherine Zhang {
68dc49c1f9SCatherine Zhang 	char *secdata;
69dc49c1f9SCatherine Zhang 	u32 seclen;
70dc49c1f9SCatherine Zhang 	int err;
71dc49c1f9SCatherine Zhang 
72dc49c1f9SCatherine Zhang 	if (test_bit(SOCK_PASSSEC, &sock->flags)) {
73dc49c1f9SCatherine Zhang 		err = security_secid_to_secctx(scm->secid, &secdata, &seclen);
74dc49c1f9SCatherine Zhang 
75dc49c1f9SCatherine Zhang 		if (!err) {
76dc49c1f9SCatherine Zhang 			put_cmsg(msg, SOL_SOCKET, SCM_SECURITY, seclen, secdata);
77dc49c1f9SCatherine Zhang 			security_release_secctx(secdata, seclen);
78dc49c1f9SCatherine Zhang 		}
79dc49c1f9SCatherine Zhang 	}
80877ce7c1SCatherine Zhang }
81877ce7c1SCatherine Zhang #else
82877ce7c1SCatherine Zhang static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm)
83877ce7c1SCatherine Zhang { }
84877ce7c1SCatherine Zhang #endif /* CONFIG_SECURITY_NETWORK */
85877ce7c1SCatherine Zhang 
861da177e4SLinus Torvalds static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg,
871da177e4SLinus Torvalds 				struct scm_cookie *scm, int flags)
881da177e4SLinus Torvalds {
89*fd2c3ef7SEric Dumazet 	if (!msg->msg_control) {
901da177e4SLinus Torvalds 		if (test_bit(SOCK_PASSCRED, &sock->flags) || scm->fp)
911da177e4SLinus Torvalds 			msg->msg_flags |= MSG_CTRUNC;
921da177e4SLinus Torvalds 		scm_destroy(scm);
931da177e4SLinus Torvalds 		return;
941da177e4SLinus Torvalds 	}
951da177e4SLinus Torvalds 
961da177e4SLinus Torvalds 	if (test_bit(SOCK_PASSCRED, &sock->flags))
971da177e4SLinus Torvalds 		put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(scm->creds), &scm->creds);
981da177e4SLinus Torvalds 
99877ce7c1SCatherine Zhang 	scm_passec(sock, msg, scm);
100877ce7c1SCatherine Zhang 
1011da177e4SLinus Torvalds 	if (!scm->fp)
1021da177e4SLinus Torvalds 		return;
1031da177e4SLinus Torvalds 
1041da177e4SLinus Torvalds 	scm_detach_fds(msg, scm);
1051da177e4SLinus Torvalds }
1061da177e4SLinus Torvalds 
1071da177e4SLinus Torvalds 
1081da177e4SLinus Torvalds #endif /* __LINUX_NET_SCM_H */
1091da177e4SLinus Torvalds 
110