LCOV - code coverage report
Current view: top level - include/linux - sockptr.h (source / functions) Hit Total Coverage
Test: landlock.info Lines: 9 26 34.6 %
Date: 2021-04-22 12:43:58 Functions: 1 3 33.3 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: GPL-2.0-only */
       2             : /*
       3             :  * Copyright (c) 2020 Christoph Hellwig.
       4             :  *
       5             :  * Support for "universal" pointers that can point to either kernel or userspace
       6             :  * memory.
       7             :  */
       8             : #ifndef _LINUX_SOCKPTR_H
       9             : #define _LINUX_SOCKPTR_H
      10             : 
      11             : #include <linux/slab.h>
      12             : #include <linux/uaccess.h>
      13             : 
      14             : typedef struct {
      15             :         union {
      16             :                 void            *kernel;
      17             :                 void __user     *user;
      18             :         };
      19             :         bool            is_kernel : 1;
      20             : } sockptr_t;
      21             : 
      22         396 : static inline bool sockptr_is_kernel(sockptr_t sockptr)
      23             : {
      24         396 :         return sockptr.is_kernel;
      25             : }
      26             : 
      27           0 : static inline sockptr_t KERNEL_SOCKPTR(void *p)
      28             : {
      29           0 :         return (sockptr_t) { .kernel = p, .is_kernel = true };
      30             : }
      31             : 
      32         370 : static inline sockptr_t USER_SOCKPTR(void __user *p)
      33             : {
      34         370 :         return (sockptr_t) { .user = p };
      35             : }
      36             : 
      37             : static inline bool sockptr_is_null(sockptr_t sockptr)
      38             : {
      39             :         if (sockptr_is_kernel(sockptr))
      40             :                 return !sockptr.kernel;
      41             :         return !sockptr.user;
      42             : }
      43             : 
      44         396 : static inline int copy_from_sockptr_offset(void *dst, sockptr_t src,
      45             :                 size_t offset, size_t size)
      46             : {
      47         396 :         if (!sockptr_is_kernel(src))
      48         792 :                 return copy_from_user(dst, src.user + offset, size);
      49           0 :         memcpy(dst, src.kernel + offset, size);
      50           0 :         return 0;
      51             : }
      52             : 
      53         396 : static inline int copy_from_sockptr(void *dst, sockptr_t src, size_t size)
      54             : {
      55         396 :         return copy_from_sockptr_offset(dst, src, 0, size);
      56             : }
      57             : 
      58             : static inline int copy_to_sockptr_offset(sockptr_t dst, size_t offset,
      59             :                 const void *src, size_t size)
      60             : {
      61             :         if (!sockptr_is_kernel(dst))
      62             :                 return copy_to_user(dst.user + offset, src, size);
      63             :         memcpy(dst.kernel + offset, src, size);
      64             :         return 0;
      65             : }
      66             : 
      67           0 : static inline void *memdup_sockptr(sockptr_t src, size_t len)
      68             : {
      69           0 :         void *p = kmalloc_track_caller(len, GFP_USER | __GFP_NOWARN);
      70             : 
      71           0 :         if (!p)
      72           0 :                 return ERR_PTR(-ENOMEM);
      73           0 :         if (copy_from_sockptr(p, src, len)) {
      74           0 :                 kfree(p);
      75           0 :                 return ERR_PTR(-EFAULT);
      76             :         }
      77             :         return p;
      78             : }
      79             : 
      80             : static inline void *memdup_sockptr_nul(sockptr_t src, size_t len)
      81             : {
      82             :         char *p = kmalloc_track_caller(len + 1, GFP_KERNEL);
      83             : 
      84             :         if (!p)
      85             :                 return ERR_PTR(-ENOMEM);
      86             :         if (copy_from_sockptr(p, src, len)) {
      87             :                 kfree(p);
      88             :                 return ERR_PTR(-EFAULT);
      89             :         }
      90             :         p[len] = '\0';
      91             :         return p;
      92             : }
      93             : 
      94           0 : static inline long strncpy_from_sockptr(char *dst, sockptr_t src, size_t count)
      95             : {
      96           0 :         if (sockptr_is_kernel(src)) {
      97           0 :                 size_t len = min(strnlen(src.kernel, count - 1) + 1, count);
      98             : 
      99           0 :                 memcpy(dst, src.kernel, len);
     100           0 :                 return len;
     101             :         }
     102           0 :         return strncpy_from_user(dst, src.user, count);
     103             : }
     104             : 
     105             : #endif /* _LINUX_SOCKPTR_H */

Generated by: LCOV version 1.14