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 */
|