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