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

          Line data    Source code
       1             : /* SPDX-License-Identifier: GPL-2.0-only */
       2             : /*
       3             :  * User-mode machine state access
       4             :  *
       5             :  * Copyright (C) 2007 Red Hat, Inc.  All rights reserved.
       6             :  *
       7             :  * Red Hat Author: Roland McGrath.
       8             :  */
       9             : 
      10             : #ifndef _LINUX_REGSET_H
      11             : #define _LINUX_REGSET_H 1
      12             : 
      13             : #include <linux/compiler.h>
      14             : #include <linux/types.h>
      15             : #include <linux/bug.h>
      16             : #include <linux/uaccess.h>
      17             : struct task_struct;
      18             : struct user_regset;
      19             : 
      20             : struct membuf {
      21             :         void *p;
      22             :         size_t left;
      23             : };
      24             : 
      25             : static inline int membuf_zero(struct membuf *s, size_t size)
      26             : {
      27             :         if (s->left) {
      28             :                 if (size > s->left)
      29             :                         size = s->left;
      30             :                 memset(s->p, 0, size);
      31             :                 s->p += size;
      32             :                 s->left -= size;
      33             :         }
      34             :         return s->left;
      35             : }
      36             : 
      37           0 : static inline int membuf_write(struct membuf *s, const void *v, size_t size)
      38             : {
      39           0 :         if (s->left) {
      40           0 :                 if (size > s->left)
      41             :                         size = s->left;
      42           0 :                 memcpy(s->p, v, size);
      43           0 :                 s->p += size;
      44           0 :                 s->left -= size;
      45             :         }
      46           0 :         return s->left;
      47             : }
      48             : 
      49             : static inline struct membuf membuf_at(const struct membuf *s, size_t offs)
      50             : {
      51             :         struct membuf n = *s;
      52             : 
      53             :         if (offs > n.left)
      54             :                 offs = n.left;
      55             :         n.p += offs;
      56             :         n.left -= offs;
      57             : 
      58             :         return n;
      59             : }
      60             : 
      61             : /* current s->p must be aligned for v; v must be a scalar */
      62             : #define membuf_store(s, v)                              \
      63             : ({                                                      \
      64             :         struct membuf *__s = (s);                       \
      65             :         if (__s->left) {                             \
      66             :                 typeof(v) __v = (v);                    \
      67             :                 size_t __size = sizeof(__v);            \
      68             :                 if (unlikely(__size > __s->left)) {       \
      69             :                         __size = __s->left;          \
      70             :                         memcpy(__s->p, &__v, __size);    \
      71             :                 } else {                                \
      72             :                         *(typeof(__v + 0) *)__s->p = __v;    \
      73             :                 }                                       \
      74             :                 __s->p += __size;                    \
      75             :                 __s->left -= __size;                 \
      76             :         }                                               \
      77             :         __s->left;})
      78             : 
      79             : /**
      80             :  * user_regset_active_fn - type of @active function in &struct user_regset
      81             :  * @target:     thread being examined
      82             :  * @regset:     regset being examined
      83             :  *
      84             :  * Return -%ENODEV if not available on the hardware found.
      85             :  * Return %0 if no interesting state in this thread.
      86             :  * Return >%0 number of @size units of interesting state.
      87             :  * Any get call fetching state beyond that number will
      88             :  * see the default initialization state for this data,
      89             :  * so a caller that knows what the default state is need
      90             :  * not copy it all out.
      91             :  * This call is optional; the pointer is %NULL if there
      92             :  * is no inexpensive check to yield a value < @n.
      93             :  */
      94             : typedef int user_regset_active_fn(struct task_struct *target,
      95             :                                   const struct user_regset *regset);
      96             : 
      97             : typedef int user_regset_get2_fn(struct task_struct *target,
      98             :                                const struct user_regset *regset,
      99             :                                struct membuf to);
     100             : 
     101             : /**
     102             :  * user_regset_set_fn - type of @set function in &struct user_regset
     103             :  * @target:     thread being examined
     104             :  * @regset:     regset being examined
     105             :  * @pos:        offset into the regset data to access, in bytes
     106             :  * @count:      amount of data to copy, in bytes
     107             :  * @kbuf:       if not %NULL, a kernel-space pointer to copy from
     108             :  * @ubuf:       if @kbuf is %NULL, a user-space pointer to copy from
     109             :  *
     110             :  * Store register values.  Return %0 on success; -%EIO or -%ENODEV
     111             :  * are usual failure returns.  The @pos and @count values are in
     112             :  * bytes, but must be properly aligned.  If @kbuf is non-null, that
     113             :  * buffer is used and @ubuf is ignored.  If @kbuf is %NULL, then
     114             :  * ubuf gives a userland pointer to access directly, and an -%EFAULT
     115             :  * return value is possible.
     116             :  */
     117             : typedef int user_regset_set_fn(struct task_struct *target,
     118             :                                const struct user_regset *regset,
     119             :                                unsigned int pos, unsigned int count,
     120             :                                const void *kbuf, const void __user *ubuf);
     121             : 
     122             : /**
     123             :  * user_regset_writeback_fn - type of @writeback function in &struct user_regset
     124             :  * @target:     thread being examined
     125             :  * @regset:     regset being examined
     126             :  * @immediate:  zero if writeback at completion of next context switch is OK
     127             :  *
     128             :  * This call is optional; usually the pointer is %NULL.  When
     129             :  * provided, there is some user memory associated with this regset's
     130             :  * hardware, such as memory backing cached register data on register
     131             :  * window machines; the regset's data controls what user memory is
     132             :  * used (e.g. via the stack pointer value).
     133             :  *
     134             :  * Write register data back to user memory.  If the @immediate flag
     135             :  * is nonzero, it must be written to the user memory so uaccess or
     136             :  * access_process_vm() can see it when this call returns; if zero,
     137             :  * then it must be written back by the time the task completes a
     138             :  * context switch (as synchronized with wait_task_inactive()).
     139             :  * Return %0 on success or if there was nothing to do, -%EFAULT for
     140             :  * a memory problem (bad stack pointer or whatever), or -%EIO for a
     141             :  * hardware problem.
     142             :  */
     143             : typedef int user_regset_writeback_fn(struct task_struct *target,
     144             :                                      const struct user_regset *regset,
     145             :                                      int immediate);
     146             : 
     147             : /**
     148             :  * struct user_regset - accessible thread CPU state
     149             :  * @n:                  Number of slots (registers).
     150             :  * @size:               Size in bytes of a slot (register).
     151             :  * @align:              Required alignment, in bytes.
     152             :  * @bias:               Bias from natural indexing.
     153             :  * @core_note_type:     ELF note @n_type value used in core dumps.
     154             :  * @get:                Function to fetch values.
     155             :  * @set:                Function to store values.
     156             :  * @active:             Function to report if regset is active, or %NULL.
     157             :  * @writeback:          Function to write data back to user memory, or %NULL.
     158             :  *
     159             :  * This data structure describes a machine resource we call a register set.
     160             :  * This is part of the state of an individual thread, not necessarily
     161             :  * actual CPU registers per se.  A register set consists of a number of
     162             :  * similar slots, given by @n.  Each slot is @size bytes, and aligned to
     163             :  * @align bytes (which is at least @size).  For dynamically-sized
     164             :  * regsets, @n must contain the maximum possible number of slots for the
     165             :  * regset.
     166             :  *
     167             :  * For backward compatibility, the @get and @set methods must pad to, or
     168             :  * accept, @n * @size bytes, even if the current regset size is smaller.
     169             :  * The precise semantics of these operations depend on the regset being
     170             :  * accessed.
     171             :  *
     172             :  * The functions to which &struct user_regset members point must be
     173             :  * called only on the current thread or on a thread that is in
     174             :  * %TASK_STOPPED or %TASK_TRACED state, that we are guaranteed will not
     175             :  * be woken up and return to user mode, and that we have called
     176             :  * wait_task_inactive() on.  (The target thread always might wake up for
     177             :  * SIGKILL while these functions are working, in which case that
     178             :  * thread's user_regset state might be scrambled.)
     179             :  *
     180             :  * The @pos argument must be aligned according to @align; the @count
     181             :  * argument must be a multiple of @size.  These functions are not
     182             :  * responsible for checking for invalid arguments.
     183             :  *
     184             :  * When there is a natural value to use as an index, @bias gives the
     185             :  * difference between the natural index and the slot index for the
     186             :  * register set.  For example, x86 GDT segment descriptors form a regset;
     187             :  * the segment selector produces a natural index, but only a subset of
     188             :  * that index space is available as a regset (the TLS slots); subtracting
     189             :  * @bias from a segment selector index value computes the regset slot.
     190             :  *
     191             :  * If nonzero, @core_note_type gives the n_type field (NT_* value)
     192             :  * of the core file note in which this regset's data appears.
     193             :  * NT_PRSTATUS is a special case in that the regset data starts at
     194             :  * offsetof(struct elf_prstatus, pr_reg) into the note data; that is
     195             :  * part of the per-machine ELF formats userland knows about.  In
     196             :  * other cases, the core file note contains exactly the whole regset
     197             :  * (@n * @size) and nothing else.  The core file note is normally
     198             :  * omitted when there is an @active function and it returns zero.
     199             :  */
     200             : struct user_regset {
     201             :         user_regset_get2_fn             *regset_get;
     202             :         user_regset_set_fn              *set;
     203             :         user_regset_active_fn           *active;
     204             :         user_regset_writeback_fn        *writeback;
     205             :         unsigned int                    n;
     206             :         unsigned int                    size;
     207             :         unsigned int                    align;
     208             :         unsigned int                    bias;
     209             :         unsigned int                    core_note_type;
     210             : };
     211             : 
     212             : /**
     213             :  * struct user_regset_view - available regsets
     214             :  * @name:       Identifier, e.g. UTS_MACHINE string.
     215             :  * @regsets:    Array of @n regsets available in this view.
     216             :  * @n:          Number of elements in @regsets.
     217             :  * @e_machine:  ELF header @e_machine %EM_* value written in core dumps.
     218             :  * @e_flags:    ELF header @e_flags value written in core dumps.
     219             :  * @ei_osabi:   ELF header @e_ident[%EI_OSABI] value written in core dumps.
     220             :  *
     221             :  * A regset view is a collection of regsets (&struct user_regset,
     222             :  * above).  This describes all the state of a thread that can be seen
     223             :  * from a given architecture/ABI environment.  More than one view might
     224             :  * refer to the same &struct user_regset, or more than one regset
     225             :  * might refer to the same machine-specific state in the thread.  For
     226             :  * example, a 32-bit thread's state could be examined from the 32-bit
     227             :  * view or from the 64-bit view.  Either method reaches the same thread
     228             :  * register state, doing appropriate widening or truncation.
     229             :  */
     230             : struct user_regset_view {
     231             :         const char *name;
     232             :         const struct user_regset *regsets;
     233             :         unsigned int n;
     234             :         u32 e_flags;
     235             :         u16 e_machine;
     236             :         u8 ei_osabi;
     237             : };
     238             : 
     239             : /*
     240             :  * This is documented here rather than at the definition sites because its
     241             :  * implementation is machine-dependent but its interface is universal.
     242             :  */
     243             : /**
     244             :  * task_user_regset_view - Return the process's native regset view.
     245             :  * @tsk: a thread of the process in question
     246             :  *
     247             :  * Return the &struct user_regset_view that is native for the given process.
     248             :  * For example, what it would access when it called ptrace().
     249             :  * Throughout the life of the process, this only changes at exec.
     250             :  */
     251             : const struct user_regset_view *task_user_regset_view(struct task_struct *tsk);
     252             : 
     253           0 : static inline int user_regset_copyin(unsigned int *pos, unsigned int *count,
     254             :                                      const void **kbuf,
     255             :                                      const void __user **ubuf, void *data,
     256             :                                      const int start_pos, const int end_pos)
     257             : {
     258           0 :         if (*count == 0)
     259             :                 return 0;
     260           0 :         BUG_ON(*pos < start_pos);
     261           0 :         if (end_pos < 0 || *pos < end_pos) {
     262           0 :                 unsigned int copy = (end_pos < 0 ? *count
     263           0 :                                      : min(*count, end_pos - *pos));
     264           0 :                 data += *pos - start_pos;
     265           0 :                 if (*kbuf) {
     266           0 :                         memcpy(data, *kbuf, copy);
     267           0 :                         *kbuf += copy;
     268           0 :                 } else if (__copy_from_user(data, *ubuf, copy))
     269             :                         return -EFAULT;
     270             :                 else
     271           0 :                         *ubuf += copy;
     272           0 :                 *pos += copy;
     273           0 :                 *count -= copy;
     274             :         }
     275             :         return 0;
     276             : }
     277             : 
     278             : static inline int user_regset_copyin_ignore(unsigned int *pos,
     279             :                                             unsigned int *count,
     280             :                                             const void **kbuf,
     281             :                                             const void __user **ubuf,
     282             :                                             const int start_pos,
     283             :                                             const int end_pos)
     284             : {
     285             :         if (*count == 0)
     286             :                 return 0;
     287             :         BUG_ON(*pos < start_pos);
     288             :         if (end_pos < 0 || *pos < end_pos) {
     289             :                 unsigned int copy = (end_pos < 0 ? *count
     290             :                                      : min(*count, end_pos - *pos));
     291             :                 if (*kbuf)
     292             :                         *kbuf += copy;
     293             :                 else
     294             :                         *ubuf += copy;
     295             :                 *pos += copy;
     296             :                 *count -= copy;
     297             :         }
     298             :         return 0;
     299             : }
     300             : 
     301             : extern int regset_get(struct task_struct *target,
     302             :                       const struct user_regset *regset,
     303             :                       unsigned int size, void *data);
     304             : 
     305             : extern int regset_get_alloc(struct task_struct *target,
     306             :                             const struct user_regset *regset,
     307             :                             unsigned int size,
     308             :                             void **data);
     309             : 
     310             : extern int copy_regset_to_user(struct task_struct *target,
     311             :                                const struct user_regset_view *view,
     312             :                                unsigned int setno, unsigned int offset,
     313             :                                unsigned int size, void __user *data);
     314             : 
     315             : /**
     316             :  * copy_regset_from_user - store into thread's user_regset data from user memory
     317             :  * @target:     thread to be examined
     318             :  * @view:       &struct user_regset_view describing user thread machine state
     319             :  * @setno:      index in @view->regsets
     320             :  * @offset:     offset into the regset data, in bytes
     321             :  * @size:       amount of data to copy, in bytes
     322             :  * @data:       user-mode pointer to copy from
     323             :  */
     324           0 : static inline int copy_regset_from_user(struct task_struct *target,
     325             :                                         const struct user_regset_view *view,
     326             :                                         unsigned int setno,
     327             :                                         unsigned int offset, unsigned int size,
     328             :                                         const void __user *data)
     329             : {
     330           0 :         const struct user_regset *regset = &view->regsets[setno];
     331             : 
     332           0 :         if (!regset->set)
     333             :                 return -EOPNOTSUPP;
     334             : 
     335           0 :         if (!access_ok(data, size))
     336             :                 return -EFAULT;
     337             : 
     338           0 :         return regset->set(target, regset, offset, size, NULL, data);
     339             : }
     340             : 
     341             : #endif  /* <linux/regset.h> */

Generated by: LCOV version 1.14