18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#ifndef __LINUX_NET_SCM_H
38c2ecf20Sopenharmony_ci#define __LINUX_NET_SCM_H
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#include <linux/limits.h>
68c2ecf20Sopenharmony_ci#include <linux/net.h>
78c2ecf20Sopenharmony_ci#include <linux/cred.h>
88c2ecf20Sopenharmony_ci#include <linux/security.h>
98c2ecf20Sopenharmony_ci#include <linux/pid.h>
108c2ecf20Sopenharmony_ci#include <linux/nsproxy.h>
118c2ecf20Sopenharmony_ci#include <linux/sched/signal.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci/* Well, we should have at least one descriptor open
148c2ecf20Sopenharmony_ci * to accept passed FDs 8)
158c2ecf20Sopenharmony_ci */
168c2ecf20Sopenharmony_ci#define SCM_MAX_FD	253
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistruct scm_creds {
198c2ecf20Sopenharmony_ci	u32	pid;
208c2ecf20Sopenharmony_ci	kuid_t	uid;
218c2ecf20Sopenharmony_ci	kgid_t	gid;
228c2ecf20Sopenharmony_ci};
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistruct scm_fp_list {
258c2ecf20Sopenharmony_ci	short			count;
268c2ecf20Sopenharmony_ci	short			max;
278c2ecf20Sopenharmony_ci	struct user_struct	*user;
288c2ecf20Sopenharmony_ci	struct file		*fp[SCM_MAX_FD];
298c2ecf20Sopenharmony_ci};
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistruct scm_cookie {
328c2ecf20Sopenharmony_ci	struct pid		*pid;		/* Skb credentials */
338c2ecf20Sopenharmony_ci	struct scm_fp_list	*fp;		/* Passed files		*/
348c2ecf20Sopenharmony_ci	struct scm_creds	creds;		/* Skb credentials	*/
358c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_NETWORK
368c2ecf20Sopenharmony_ci	u32			secid;		/* Passed security ID 	*/
378c2ecf20Sopenharmony_ci#endif
388c2ecf20Sopenharmony_ci};
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_civoid scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm);
418c2ecf20Sopenharmony_civoid scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm);
428c2ecf20Sopenharmony_ciint __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm);
438c2ecf20Sopenharmony_civoid __scm_destroy(struct scm_cookie *scm);
448c2ecf20Sopenharmony_cistruct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl);
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_NETWORK
478c2ecf20Sopenharmony_cistatic __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_cookie *scm)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	security_socket_getpeersec_dgram(sock, NULL, &scm->secid);
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ci#else
528c2ecf20Sopenharmony_cistatic __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_cookie *scm)
538c2ecf20Sopenharmony_ci{ }
548c2ecf20Sopenharmony_ci#endif /* CONFIG_SECURITY_NETWORK */
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic __inline__ void scm_set_cred(struct scm_cookie *scm,
578c2ecf20Sopenharmony_ci				    struct pid *pid, kuid_t uid, kgid_t gid)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	scm->pid  = get_pid(pid);
608c2ecf20Sopenharmony_ci	scm->creds.pid = pid_vnr(pid);
618c2ecf20Sopenharmony_ci	scm->creds.uid = uid;
628c2ecf20Sopenharmony_ci	scm->creds.gid = gid;
638c2ecf20Sopenharmony_ci}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic __inline__ void scm_destroy_cred(struct scm_cookie *scm)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	put_pid(scm->pid);
688c2ecf20Sopenharmony_ci	scm->pid  = NULL;
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistatic __inline__ void scm_destroy(struct scm_cookie *scm)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	scm_destroy_cred(scm);
748c2ecf20Sopenharmony_ci	if (scm->fp)
758c2ecf20Sopenharmony_ci		__scm_destroy(scm);
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistatic __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
798c2ecf20Sopenharmony_ci			       struct scm_cookie *scm, bool forcecreds)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	memset(scm, 0, sizeof(*scm));
828c2ecf20Sopenharmony_ci	scm->creds.uid = INVALID_UID;
838c2ecf20Sopenharmony_ci	scm->creds.gid = INVALID_GID;
848c2ecf20Sopenharmony_ci	if (forcecreds)
858c2ecf20Sopenharmony_ci		scm_set_cred(scm, task_tgid(current), current_uid(), current_gid());
868c2ecf20Sopenharmony_ci	unix_get_peersec_dgram(sock, scm);
878c2ecf20Sopenharmony_ci	if (msg->msg_controllen <= 0)
888c2ecf20Sopenharmony_ci		return 0;
898c2ecf20Sopenharmony_ci	return __scm_send(sock, msg, scm);
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_NETWORK
938c2ecf20Sopenharmony_cistatic inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	char *secdata;
968c2ecf20Sopenharmony_ci	u32 seclen;
978c2ecf20Sopenharmony_ci	int err;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	if (test_bit(SOCK_PASSSEC, &sock->flags)) {
1008c2ecf20Sopenharmony_ci		err = security_secid_to_secctx(scm->secid, &secdata, &seclen);
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci		if (!err) {
1038c2ecf20Sopenharmony_ci			put_cmsg(msg, SOL_SOCKET, SCM_SECURITY, seclen, secdata);
1048c2ecf20Sopenharmony_ci			security_release_secctx(secdata, seclen);
1058c2ecf20Sopenharmony_ci		}
1068c2ecf20Sopenharmony_ci	}
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic inline bool scm_has_secdata(struct socket *sock)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	return test_bit(SOCK_PASSSEC, &sock->flags);
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci#else
1148c2ecf20Sopenharmony_cistatic inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm)
1158c2ecf20Sopenharmony_ci{ }
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cistatic inline bool scm_has_secdata(struct socket *sock)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	return false;
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci#endif /* CONFIG_SECURITY_NETWORK */
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic __inline__ void scm_recv(struct socket *sock, struct msghdr *msg,
1248c2ecf20Sopenharmony_ci				struct scm_cookie *scm, int flags)
1258c2ecf20Sopenharmony_ci{
1268c2ecf20Sopenharmony_ci	if (!msg->msg_control) {
1278c2ecf20Sopenharmony_ci		if (test_bit(SOCK_PASSCRED, &sock->flags) || scm->fp ||
1288c2ecf20Sopenharmony_ci		    scm_has_secdata(sock))
1298c2ecf20Sopenharmony_ci			msg->msg_flags |= MSG_CTRUNC;
1308c2ecf20Sopenharmony_ci		scm_destroy(scm);
1318c2ecf20Sopenharmony_ci		return;
1328c2ecf20Sopenharmony_ci	}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	if (test_bit(SOCK_PASSCRED, &sock->flags)) {
1358c2ecf20Sopenharmony_ci		struct user_namespace *current_ns = current_user_ns();
1368c2ecf20Sopenharmony_ci		struct ucred ucreds = {
1378c2ecf20Sopenharmony_ci			.pid = scm->creds.pid,
1388c2ecf20Sopenharmony_ci			.uid = from_kuid_munged(current_ns, scm->creds.uid),
1398c2ecf20Sopenharmony_ci			.gid = from_kgid_munged(current_ns, scm->creds.gid),
1408c2ecf20Sopenharmony_ci		};
1418c2ecf20Sopenharmony_ci		put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(ucreds), &ucreds);
1428c2ecf20Sopenharmony_ci	}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	scm_destroy_cred(scm);
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	scm_passec(sock, msg, scm);
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	if (!scm->fp)
1498c2ecf20Sopenharmony_ci		return;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	scm_detach_fds(msg, scm);
1528c2ecf20Sopenharmony_ci}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci#endif /* __LINUX_NET_SCM_H */
1568c2ecf20Sopenharmony_ci
157