LCOV - code coverage report
Current view: top level - net/unix - scm.c (source / functions) Hit Total Coverage
Test: Real Lines: 45 48 93.8 %
Date: 2020-10-17 15:46:16 Functions: 0 7 0.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : #include <linux/module.h>
       3                 :            : #include <linux/kernel.h>
       4                 :            : #include <linux/string.h>
       5                 :            : #include <linux/socket.h>
       6                 :            : #include <linux/net.h>
       7                 :            : #include <linux/fs.h>
       8                 :            : #include <net/af_unix.h>
       9                 :            : #include <net/scm.h>
      10                 :            : #include <linux/init.h>
      11                 :            : 
      12                 :            : #include "scm.h"
      13                 :            : 
      14                 :            : unsigned int unix_tot_inflight;
      15                 :            : EXPORT_SYMBOL(unix_tot_inflight);
      16                 :            : 
      17                 :            : LIST_HEAD(gc_inflight_list);
      18                 :            : EXPORT_SYMBOL(gc_inflight_list);
      19                 :            : 
      20                 :            : DEFINE_SPINLOCK(unix_gc_lock);
      21                 :            : EXPORT_SYMBOL(unix_gc_lock);
      22                 :            : 
      23                 :          3 : struct sock *unix_get_socket(struct file *filp)
      24                 :            : {
      25                 :            :         struct sock *u_sock = NULL;
      26                 :            :         struct inode *inode = file_inode(filp);
      27                 :            : 
      28                 :            :         /* Socket ? */
      29                 :          3 :         if (S_ISSOCK(inode->i_mode) && !(filp->f_mode & FMODE_PATH)) {
      30                 :            :                 struct socket *sock = SOCKET_I(inode);
      31                 :          3 :                 struct sock *s = sock->sk;
      32                 :            : 
      33                 :            :                 /* PF_UNIX ? */
      34                 :          3 :                 if (s && sock->ops && sock->ops->family == PF_UNIX)
      35                 :            :                         u_sock = s;
      36                 :            :         } else {
      37                 :            :                 /* Could be an io_uring instance */
      38                 :          3 :                 u_sock = io_uring_get_socket(filp);
      39                 :            :         }
      40                 :          3 :         return u_sock;
      41                 :            : }
      42                 :            : EXPORT_SYMBOL(unix_get_socket);
      43                 :            : 
      44                 :            : /* Keep the number of times in flight count for the file
      45                 :            :  * descriptor if it is for an AF_UNIX socket.
      46                 :            :  */
      47                 :          3 : void unix_inflight(struct user_struct *user, struct file *fp)
      48                 :            : {
      49                 :          3 :         struct sock *s = unix_get_socket(fp);
      50                 :            : 
      51                 :            :         spin_lock(&unix_gc_lock);
      52                 :            : 
      53                 :          3 :         if (s) {
      54                 :            :                 struct unix_sock *u = unix_sk(s);
      55                 :            : 
      56                 :          3 :                 if (atomic_long_inc_return(&u->inflight) == 1) {
      57                 :          3 :                         BUG_ON(!list_empty(&u->link));
      58                 :            :                         list_add_tail(&u->link, &gc_inflight_list);
      59                 :            :                 } else {
      60                 :          0 :                         BUG_ON(list_empty(&u->link));
      61                 :            :                 }
      62                 :          3 :                 unix_tot_inflight++;
      63                 :            :         }
      64                 :          3 :         user->unix_inflight++;
      65                 :            :         spin_unlock(&unix_gc_lock);
      66                 :          3 : }
      67                 :            : 
      68                 :          3 : void unix_notinflight(struct user_struct *user, struct file *fp)
      69                 :            : {
      70                 :          3 :         struct sock *s = unix_get_socket(fp);
      71                 :            : 
      72                 :            :         spin_lock(&unix_gc_lock);
      73                 :            : 
      74                 :          3 :         if (s) {
      75                 :            :                 struct unix_sock *u = unix_sk(s);
      76                 :            : 
      77                 :          3 :                 BUG_ON(!atomic_long_read(&u->inflight));
      78                 :          3 :                 BUG_ON(list_empty(&u->link));
      79                 :            : 
      80                 :          3 :                 if (atomic_long_dec_and_test(&u->inflight))
      81                 :            :                         list_del_init(&u->link);
      82                 :          3 :                 unix_tot_inflight--;
      83                 :            :         }
      84                 :          3 :         user->unix_inflight--;
      85                 :            :         spin_unlock(&unix_gc_lock);
      86                 :          3 : }
      87                 :            : 
      88                 :            : /*
      89                 :            :  * The "user->unix_inflight" variable is protected by the garbage
      90                 :            :  * collection lock, and we just read it locklessly here. If you go
      91                 :            :  * over the limit, there might be a tiny race in actually noticing
      92                 :            :  * it across threads. Tough.
      93                 :            :  */
      94                 :          3 : static inline bool too_many_unix_fds(struct task_struct *p)
      95                 :            : {
      96                 :          3 :         struct user_struct *user = current_user();
      97                 :            : 
      98                 :          3 :         if (unlikely(user->unix_inflight > task_rlimit(p, RLIMIT_NOFILE)))
      99                 :          0 :                 return !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN);
     100                 :            :         return false;
     101                 :            : }
     102                 :            : 
     103                 :          3 : int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
     104                 :            : {
     105                 :            :         int i;
     106                 :            : 
     107                 :          3 :         if (too_many_unix_fds(current))
     108                 :            :                 return -ETOOMANYREFS;
     109                 :            : 
     110                 :            :         /*
     111                 :            :          * Need to duplicate file references for the sake of garbage
     112                 :            :          * collection.  Otherwise a socket in the fps might become a
     113                 :            :          * candidate for GC while the skb is not yet queued.
     114                 :            :          */
     115                 :          3 :         UNIXCB(skb).fp = scm_fp_dup(scm->fp);
     116                 :          3 :         if (!UNIXCB(skb).fp)
     117                 :            :                 return -ENOMEM;
     118                 :            : 
     119                 :          3 :         for (i = scm->fp->count - 1; i >= 0; i--)
     120                 :          3 :                 unix_inflight(scm->fp->user, scm->fp->fp[i]);
     121                 :            :         return 0;
     122                 :            : }
     123                 :            : EXPORT_SYMBOL(unix_attach_fds);
     124                 :            : 
     125                 :          3 : void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb)
     126                 :            : {
     127                 :            :         int i;
     128                 :            : 
     129                 :          3 :         scm->fp = UNIXCB(skb).fp;
     130                 :          3 :         UNIXCB(skb).fp = NULL;
     131                 :            : 
     132                 :          3 :         for (i = scm->fp->count-1; i >= 0; i--)
     133                 :          3 :                 unix_notinflight(scm->fp->user, scm->fp->fp[i]);
     134                 :          3 : }
     135                 :            : EXPORT_SYMBOL(unix_detach_fds);
     136                 :            : 
     137                 :          3 : void unix_destruct_scm(struct sk_buff *skb)
     138                 :            : {
     139                 :            :         struct scm_cookie scm;
     140                 :            : 
     141                 :          3 :         memset(&scm, 0, sizeof(scm));
     142                 :          3 :         scm.pid  = UNIXCB(skb).pid;
     143                 :          3 :         if (UNIXCB(skb).fp)
     144                 :          0 :                 unix_detach_fds(&scm, skb);
     145                 :            : 
     146                 :            :         /* Alas, it calls VFS */
     147                 :            :         /* So fscking what? fput() had been SMP-safe since the last Summer */
     148                 :          3 :         scm_destroy(&scm);
     149                 :          3 :         sock_wfree(skb);
     150                 :          3 : }
     151                 :            : EXPORT_SYMBOL(unix_destruct_scm);
    

Generated by: LCOV version 1.14