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