cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sockptr.h (2279B)


      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
     14typedef struct {
     15	union {
     16		void		*kernel;
     17		void __user	*user;
     18	};
     19	bool		is_kernel : 1;
     20} sockptr_t;
     21
     22static inline bool sockptr_is_kernel(sockptr_t sockptr)
     23{
     24	return sockptr.is_kernel;
     25}
     26
     27static inline sockptr_t KERNEL_SOCKPTR(void *p)
     28{
     29	return (sockptr_t) { .kernel = p, .is_kernel = true };
     30}
     31
     32static inline sockptr_t USER_SOCKPTR(void __user *p)
     33{
     34	return (sockptr_t) { .user = p };
     35}
     36
     37static 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
     44static inline int copy_from_sockptr_offset(void *dst, sockptr_t src,
     45		size_t offset, size_t size)
     46{
     47	if (!sockptr_is_kernel(src))
     48		return copy_from_user(dst, src.user + offset, size);
     49	memcpy(dst, src.kernel + offset, size);
     50	return 0;
     51}
     52
     53static inline int copy_from_sockptr(void *dst, sockptr_t src, size_t size)
     54{
     55	return copy_from_sockptr_offset(dst, src, 0, size);
     56}
     57
     58static 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
     67static inline void *memdup_sockptr(sockptr_t src, size_t len)
     68{
     69	void *p = kmalloc_track_caller(len, GFP_USER | __GFP_NOWARN);
     70
     71	if (!p)
     72		return ERR_PTR(-ENOMEM);
     73	if (copy_from_sockptr(p, src, len)) {
     74		kfree(p);
     75		return ERR_PTR(-EFAULT);
     76	}
     77	return p;
     78}
     79
     80static 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
     94static inline long strncpy_from_sockptr(char *dst, sockptr_t src, size_t count)
     95{
     96	if (sockptr_is_kernel(src)) {
     97		size_t len = min(strnlen(src.kernel, count - 1) + 1, count);
     98
     99		memcpy(dst, src.kernel, len);
    100		return len;
    101	}
    102	return strncpy_from_user(dst, src.user, count);
    103}
    104
    105#endif /* _LINUX_SOCKPTR_H */