File: insn_queue.h

package info (click to toggle)
libpulp 0.3.16-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,976 kB
  • sloc: ansic: 11,792; python: 1,216; sh: 881; makefile: 871; cpp: 582; asm: 387
file content (150 lines) | stat: -rw-r--r-- 3,772 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*
 *  libpulp - User-space Livepatching Library
 *
 *  Copyright (C) 2023 SUSE Software Solutions GmbH
 *
 *  This file is part of libpulp.
 *
 *  libpulp is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  libpulp is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with libpulp.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef INSNQ_H
#define INSNQ_H

#include <stdbool.h>
#include <stdint.h>

/** Define a 2Mb buffer for holding the instructions list.  */
#define INSN_BUFFER_MAX (2 * 1024 * 1024)

/** Define the current version of the instruction queue.  */
#define INSNQ_CURR_VERSION 1

/** The ULP instruction queue.  This works as follows:
 * 1- Libpulp write instructions that should be executed on the `ulp` tool
 * side. The main reason why this exists is because some processes are launched
 * with systemd memory protection mechanism, and a way to circunvent that is to
 * ptrace from an external process.
 *
 * 2- the `ulp` tool interpret the instructions after libpulp finishes
 * executing the function from its side (__ulp_apply_patch, for example).
 */
struct insn_queue
{
  /** Version of the queue running.  */
  int version;

  /** Number of instructions in this queue.  */
  int num_insns;

  /** Size in bytes of content.  Must not be larger than INSN_BUFFER_MAX.  */
  int size;

  /** Here to force 8-byte alignment on the buffer.*/
  int _align;

  /** Buffer holding the instructions.  */
  char buffer[INSN_BUFFER_MAX];
};

/** Shorthand for the instruction queue object.  */
typedef struct insn_queue insn_queue_t;

extern insn_queue_t __ulp_insn_queue;

/** Type of instructions.  */
enum __attribute__((__packed__)) ulp_insn_type
{
  /** NOP instruction.  Nothing is done.  */
  ULP_INSN_NOP = 0,

  /** Print a message.  */
  ULP_INSN_PRINT = 1,

  /** Write into target process.  */
  ULP_INSN_WRITE,

  ULP_NUM_INSNS,
};

/** Common instruction object.  Holds the type as well the size of the
    instruction in bytes.  */
struct ulp_insn
{
  /** Type of instruction.  */
  enum ulp_insn_type type;

  /** Size of instruction.  Max size is 24 bits to fit into 4 bytes.  */
  int size : 24;
};

/** A print instruction.  Print the content hold in `bytes`.  */
struct ulp_insn_print
{
  /** Base object.  */
  struct ulp_insn base;

  /** Bytes holding the string.  */
  char bytes[];
};

/** A write instruction.  Writes into the address the amout of `n` bytes given
    in bytes into the target process.  */
struct ulp_insn_write
{
  /** Base object.  */
  struct ulp_insn base;

  /** Number of bytes.  */
  uint32_t n;

  /** Address to patch.  */
  uintptr_t address;

  /** Content.  */
  unsigned char bytes[];
};

/** @brief Check if instruction is valid.
 *
 * This function will check if given instruction is valid.
 *
 * @param insn     Instruction to check.
 * @return         true if valid, false otherwise.
 */
static inline bool
ulp_insn_valid(struct ulp_insn *insn)
{
  switch (insn->type) {
    case ULP_INSN_NOP:
    case ULP_INSN_PRINT:
    case ULP_INSN_WRITE:
      return true;
      break;

    default:
      return false;
  }
}


/** @brief Interpret the instructions in queue.
 *
 * Interpret all instructions inserted into the queue object.
 *
 * @param queue
 */
int insnq_interpret(insn_queue_t *queue);

#endif /* INSNQ_H */