1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0 */
2*4882a593Smuzhiyun #ifndef __LINUX_NET_SCM_H
3*4882a593Smuzhiyun #define __LINUX_NET_SCM_H
4*4882a593Smuzhiyun
5*4882a593Smuzhiyun #include <linux/limits.h>
6*4882a593Smuzhiyun #include <linux/net.h>
7*4882a593Smuzhiyun #include <linux/cred.h>
8*4882a593Smuzhiyun #include <linux/security.h>
9*4882a593Smuzhiyun #include <linux/pid.h>
10*4882a593Smuzhiyun #include <linux/nsproxy.h>
11*4882a593Smuzhiyun #include <linux/sched/signal.h>
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun /* Well, we should have at least one descriptor open
14*4882a593Smuzhiyun * to accept passed FDs 8)
15*4882a593Smuzhiyun */
16*4882a593Smuzhiyun #define SCM_MAX_FD 253
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun struct scm_creds {
19*4882a593Smuzhiyun u32 pid;
20*4882a593Smuzhiyun kuid_t uid;
21*4882a593Smuzhiyun kgid_t gid;
22*4882a593Smuzhiyun };
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun struct scm_fp_list {
25*4882a593Smuzhiyun short count;
26*4882a593Smuzhiyun short max;
27*4882a593Smuzhiyun struct user_struct *user;
28*4882a593Smuzhiyun struct file *fp[SCM_MAX_FD];
29*4882a593Smuzhiyun };
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun struct scm_cookie {
32*4882a593Smuzhiyun struct pid *pid; /* Skb credentials */
33*4882a593Smuzhiyun struct scm_fp_list *fp; /* Passed files */
34*4882a593Smuzhiyun struct scm_creds creds; /* Skb credentials */
35*4882a593Smuzhiyun #ifdef CONFIG_SECURITY_NETWORK
36*4882a593Smuzhiyun u32 secid; /* Passed security ID */
37*4882a593Smuzhiyun #endif
38*4882a593Smuzhiyun };
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm);
41*4882a593Smuzhiyun void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm);
42*4882a593Smuzhiyun int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm);
43*4882a593Smuzhiyun void __scm_destroy(struct scm_cookie *scm);
44*4882a593Smuzhiyun struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl);
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun #ifdef CONFIG_SECURITY_NETWORK
unix_get_peersec_dgram(struct socket * sock,struct scm_cookie * scm)47*4882a593Smuzhiyun static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_cookie *scm)
48*4882a593Smuzhiyun {
49*4882a593Smuzhiyun security_socket_getpeersec_dgram(sock, NULL, &scm->secid);
50*4882a593Smuzhiyun }
51*4882a593Smuzhiyun #else
unix_get_peersec_dgram(struct socket * sock,struct scm_cookie * scm)52*4882a593Smuzhiyun static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_cookie *scm)
53*4882a593Smuzhiyun { }
54*4882a593Smuzhiyun #endif /* CONFIG_SECURITY_NETWORK */
55*4882a593Smuzhiyun
scm_set_cred(struct scm_cookie * scm,struct pid * pid,kuid_t uid,kgid_t gid)56*4882a593Smuzhiyun static __inline__ void scm_set_cred(struct scm_cookie *scm,
57*4882a593Smuzhiyun struct pid *pid, kuid_t uid, kgid_t gid)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun scm->pid = get_pid(pid);
60*4882a593Smuzhiyun scm->creds.pid = pid_vnr(pid);
61*4882a593Smuzhiyun scm->creds.uid = uid;
62*4882a593Smuzhiyun scm->creds.gid = gid;
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun
scm_destroy_cred(struct scm_cookie * scm)65*4882a593Smuzhiyun static __inline__ void scm_destroy_cred(struct scm_cookie *scm)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun put_pid(scm->pid);
68*4882a593Smuzhiyun scm->pid = NULL;
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun
scm_destroy(struct scm_cookie * scm)71*4882a593Smuzhiyun static __inline__ void scm_destroy(struct scm_cookie *scm)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun scm_destroy_cred(scm);
74*4882a593Smuzhiyun if (scm->fp)
75*4882a593Smuzhiyun __scm_destroy(scm);
76*4882a593Smuzhiyun }
77*4882a593Smuzhiyun
scm_send(struct socket * sock,struct msghdr * msg,struct scm_cookie * scm,bool forcecreds)78*4882a593Smuzhiyun static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
79*4882a593Smuzhiyun struct scm_cookie *scm, bool forcecreds)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun memset(scm, 0, sizeof(*scm));
82*4882a593Smuzhiyun scm->creds.uid = INVALID_UID;
83*4882a593Smuzhiyun scm->creds.gid = INVALID_GID;
84*4882a593Smuzhiyun if (forcecreds)
85*4882a593Smuzhiyun scm_set_cred(scm, task_tgid(current), current_uid(), current_gid());
86*4882a593Smuzhiyun unix_get_peersec_dgram(sock, scm);
87*4882a593Smuzhiyun if (msg->msg_controllen <= 0)
88*4882a593Smuzhiyun return 0;
89*4882a593Smuzhiyun return __scm_send(sock, msg, scm);
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun #ifdef CONFIG_SECURITY_NETWORK
scm_passec(struct socket * sock,struct msghdr * msg,struct scm_cookie * scm)93*4882a593Smuzhiyun static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun char *secdata;
96*4882a593Smuzhiyun u32 seclen;
97*4882a593Smuzhiyun int err;
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun if (test_bit(SOCK_PASSSEC, &sock->flags)) {
100*4882a593Smuzhiyun err = security_secid_to_secctx(scm->secid, &secdata, &seclen);
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun if (!err) {
103*4882a593Smuzhiyun put_cmsg(msg, SOL_SOCKET, SCM_SECURITY, seclen, secdata);
104*4882a593Smuzhiyun security_release_secctx(secdata, seclen);
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun #else
scm_passec(struct socket * sock,struct msghdr * msg,struct scm_cookie * scm)109*4882a593Smuzhiyun static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm)
110*4882a593Smuzhiyun { }
111*4882a593Smuzhiyun #endif /* CONFIG_SECURITY_NETWORK */
112*4882a593Smuzhiyun
scm_recv(struct socket * sock,struct msghdr * msg,struct scm_cookie * scm,int flags)113*4882a593Smuzhiyun static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg,
114*4882a593Smuzhiyun struct scm_cookie *scm, int flags)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun if (!msg->msg_control) {
117*4882a593Smuzhiyun if (test_bit(SOCK_PASSCRED, &sock->flags) || scm->fp)
118*4882a593Smuzhiyun msg->msg_flags |= MSG_CTRUNC;
119*4882a593Smuzhiyun scm_destroy(scm);
120*4882a593Smuzhiyun return;
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun if (test_bit(SOCK_PASSCRED, &sock->flags)) {
124*4882a593Smuzhiyun struct user_namespace *current_ns = current_user_ns();
125*4882a593Smuzhiyun struct ucred ucreds = {
126*4882a593Smuzhiyun .pid = scm->creds.pid,
127*4882a593Smuzhiyun .uid = from_kuid_munged(current_ns, scm->creds.uid),
128*4882a593Smuzhiyun .gid = from_kgid_munged(current_ns, scm->creds.gid),
129*4882a593Smuzhiyun };
130*4882a593Smuzhiyun put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(ucreds), &ucreds);
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun scm_destroy_cred(scm);
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun scm_passec(sock, msg, scm);
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun if (!scm->fp)
138*4882a593Smuzhiyun return;
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun scm_detach_fds(msg, scm);
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun #endif /* __LINUX_NET_SCM_H */
145*4882a593Smuzhiyun
146