Nexoniarz is the sole author and SchOS was never published under Apache-2.0, so this is a straight relicence. LICENSE is the FSF GPLv2 text, every first-party SPDX header moves to GPL-2.0-or-later, and NOTICE, README.md, docs/licensing.md and the site say so. projects/schfs-linux follows the rest of the tree. The GPL gives copyleft: a fork has to ship its source. It also lifts the old "Linux drivers, never" rule, since GPL-2.0-only code combines with GPL-2.0-or-later. "Or later" leaves room for GPLv3, but one binary still has to pick one version, so docs/licensing.md now keeps Apache-2.0 and GPLv3 code out of the kernel to keep Linux code possible there. BSD 4-clause code goes from "avoid" to "no", because the advertising clause is GPL-incompatible. LDLS still ships no .ko. That boundary is now project policy rather than a legal requirement, and ldls.md, devices.md and licensing.md section 6 say so. refmod declares license=GPL, and ldls-check passes (27 checks). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
268 lines
10 KiB
C
268 lines
10 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
#pragma once
|
|
|
|
// Loading a relocatable object. docs/architecture/ldls.md, "The loader".
|
|
//
|
|
// A Linux `.ko` is an ordinary ELF64 relocatable object -- the same thing
|
|
// `gcc -c` produces -- and loading one is four steps with no mystery in any of
|
|
// them: index the sections, place the allocatable ones, resolve the undefined
|
|
// symbols against a table, and apply the relocations. There is no licence
|
|
// question anywhere in this file: ELF and the x86-64 relocation set are
|
|
// published specifications, which is the case [../docs/licensing.md] §5
|
|
// describes.
|
|
//
|
|
// **It is freestanding on purpose.** No libc, no allocation, no I/O: the
|
|
// caller hands over the whole image and a buffer, and everything happens in
|
|
// them. That is what lets the same source build as a host tool -- where a test
|
|
// takes a second -- and as the SchOS-side host, which is the discipline
|
|
// `mkschfs` and the kernel already share and the reason SchFS format bugs are
|
|
// found on the host.
|
|
//
|
|
// Types are spelled out rather than taken from a header, because the two sides
|
|
// have different ones and this file has to mean the same thing in both.
|
|
|
|
// The section table is the caller's, not ours.
|
|
//
|
|
// A fixed array needs a limit, and every limit that would fit in a struct is
|
|
// one a real object exceeds: measured over 300 modules the median is 50
|
|
// sections and the 95th percentile is 67, but an object built with
|
|
// -ffunction-sections runs to thousands -- nvidia-modeset has 7,069. Rather
|
|
// than pick a number that is generous until it is not, the caller says how
|
|
// many it is prepared for, and ko_sections_needed() says how many that is.
|
|
//
|
|
// A suggested size for a fixed table on the SchOS side, where allocating is
|
|
// less convenient. It is a caller's choice and not the loader's limit.
|
|
#define KO_SECHINT 128
|
|
|
|
// Undefined symbols the report will hold. Measured over the same corpus the
|
|
// median is 25 and the worst seen is 245, so this is room to spare -- and
|
|
// `undef_lost` says so rather than the list quietly ending.
|
|
#define KO_MAXUNDEF 512
|
|
|
|
// --- ELF64, the relocatable subset ------------------------------------------
|
|
//
|
|
// include/elf.h has `elfhdr` and `proghdr`, which are the ET_EXEC half. None of
|
|
// what a relocatable object needs is there, so it is here.
|
|
|
|
struct ko_ehdr {
|
|
unsigned char e_ident[16];
|
|
unsigned short e_type;
|
|
unsigned short e_machine;
|
|
unsigned int e_version;
|
|
unsigned long long e_entry;
|
|
unsigned long long e_phoff;
|
|
unsigned long long e_shoff;
|
|
unsigned int e_flags;
|
|
unsigned short e_ehsize;
|
|
unsigned short e_phentsize;
|
|
unsigned short e_phnum;
|
|
unsigned short e_shentsize;
|
|
unsigned short e_shnum;
|
|
unsigned short e_shstrndx;
|
|
};
|
|
|
|
struct ko_shdr {
|
|
unsigned int sh_name;
|
|
unsigned int sh_type;
|
|
unsigned long long sh_flags;
|
|
unsigned long long sh_addr;
|
|
unsigned long long sh_offset;
|
|
unsigned long long sh_size;
|
|
unsigned int sh_link;
|
|
unsigned int sh_info;
|
|
unsigned long long sh_addralign;
|
|
unsigned long long sh_entsize;
|
|
};
|
|
|
|
struct ko_sym {
|
|
unsigned int st_name;
|
|
unsigned char st_info;
|
|
unsigned char st_other;
|
|
unsigned short st_shndx;
|
|
unsigned long long st_value;
|
|
unsigned long long st_size;
|
|
};
|
|
|
|
struct ko_rela {
|
|
unsigned long long r_offset;
|
|
unsigned long long r_info;
|
|
long long r_addend;
|
|
};
|
|
|
|
#define KO_ET_REL 1
|
|
#define KO_EM_X86_64 62
|
|
|
|
#define KO_SHT_PROGBITS 1
|
|
#define KO_SHT_SYMTAB 2
|
|
#define KO_SHT_STRTAB 3
|
|
#define KO_SHT_RELA 4
|
|
#define KO_SHT_NOBITS 8
|
|
|
|
#define KO_SHF_WRITE 0x1
|
|
#define KO_SHF_ALLOC 0x2
|
|
#define KO_SHF_EXECINSTR 0x4
|
|
|
|
#define KO_SHN_UNDEF 0
|
|
#define KO_SHN_ABS 0xfff1
|
|
#define KO_SHN_COMMON 0xfff2
|
|
|
|
#define KO_R_SYM(i) ((unsigned int)((i) >> 32))
|
|
#define KO_R_TYPE(i) ((unsigned int)((i) & 0xffffffffu))
|
|
|
|
// The x86-64 relocations a compiled object actually contains. Anything else is
|
|
// refused by name rather than ignored -- a relocation silently skipped is a
|
|
// wrong address found much later.
|
|
#define KO_R_X86_64_NONE 0
|
|
#define KO_R_X86_64_64 1
|
|
#define KO_R_X86_64_PC32 2
|
|
#define KO_R_X86_64_PLT32 4
|
|
#define KO_R_X86_64_32 10
|
|
#define KO_R_X86_64_32S 11
|
|
#define KO_R_X86_64_PC64 24
|
|
|
|
// --- what the loader knows about a section ----------------------------------
|
|
|
|
struct ko_section {
|
|
const char *name;
|
|
unsigned int type;
|
|
unsigned long long flags;
|
|
unsigned long long size;
|
|
unsigned long long align;
|
|
const unsigned char *data; // 0 for NOBITS
|
|
int alloc; // takes space at run time
|
|
unsigned long long addr; // where it will run, once laid out
|
|
unsigned char *where; // where it is right now, once laid out
|
|
};
|
|
|
|
// Resolving a name to an address. Returns 0 and fills `out` on success, or
|
|
// non-zero to say it does not know it -- which is not an error at L0, it is
|
|
// the answer we are asking for.
|
|
typedef int (*ko_resolver)(void *ctx, const char *name,
|
|
unsigned long long *out);
|
|
|
|
struct ko {
|
|
const unsigned char *img;
|
|
unsigned long long len;
|
|
|
|
const struct ko_ehdr *eh;
|
|
const unsigned char *shtab; // raw, indexed with e_shentsize
|
|
int nsh;
|
|
|
|
const char *shstr; // section name strings
|
|
const struct ko_sym *sym;
|
|
int nsym;
|
|
const char *str; // symbol name strings
|
|
|
|
struct ko_section *sec; // the caller's, nsh entries used
|
|
|
|
const char *undef[KO_MAXUNDEF];
|
|
int nundef;
|
|
int undef_lost; // more than KO_MAXUNDEF of them
|
|
|
|
unsigned long long span; // bytes ko_layout needs
|
|
int laid_out;
|
|
|
|
// How many relocations of each type the object contains, counted by
|
|
// ko_reltypes(). The question "what does the loader actually have to
|
|
// handle" has an exact answer per module, and guessing at it is how a
|
|
// loader ends up refusing a driver on its last relocation.
|
|
unsigned int reltype[64];
|
|
unsigned int reltype_other;
|
|
unsigned int nrel;
|
|
|
|
char err[128];
|
|
};
|
|
|
|
// How many `struct ko_section` this object needs. -1 if it is not an ELF64
|
|
// object at all, which is worth knowing before allocating anything for it.
|
|
int ko_sections_needed(const void *image, unsigned long long len);
|
|
|
|
// Validate and index, using `sec` for the section table. Returns 0, or -1 with
|
|
// ko_err() set -- including when `nsec` is too small, which says how many were
|
|
// needed rather than just refusing.
|
|
int ko_open(struct ko *k, const void *image, unsigned long long len,
|
|
struct ko_section *sec, int nsec);
|
|
|
|
// Bytes ko_layout will need. Valid after ko_open.
|
|
unsigned long long ko_span(const struct ko *k);
|
|
|
|
// Place every allocatable section into `mem`, as if it will run at `base`.
|
|
// The two differ when the object is staged somewhere before being mapped;
|
|
// pass base == (address of mem) when they do not.
|
|
int ko_layout(struct ko *k, void *mem, unsigned long long cap,
|
|
unsigned long long base);
|
|
|
|
// Count the relocations by type, without applying any. Valid after ko_open.
|
|
void ko_reltypes(struct ko *k);
|
|
|
|
// Apply every relocation. Undefined symbols go to `r`; a name it does not know
|
|
// makes this fail, naming the first one.
|
|
int ko_relocate(struct ko *k, ko_resolver r, void *ctx);
|
|
|
|
// Neutralise every `%gs:`-relative load of a named symbol.
|
|
//
|
|
// Linux builds modules with `-mstack-protector-guard-reg=gs`, so the stack
|
|
// canary is fetched through the GS segment:
|
|
//
|
|
// mov %gs:__ref_stack_chk_guard(%rip), %rax (prologue)
|
|
// sub %gs:__ref_stack_chk_guard(%rip), %rax (epilogue, then jne)
|
|
//
|
|
// That is an ABI between the kernel and its own per-CPU area, and a host which
|
|
// is not that kernel cannot provide it. On SchOS the GS base belongs to the
|
|
// kernel, so a user-mode read of it faults on a kernel address -- which is
|
|
// exactly where 8139too's probe stopped the first time it ran there.
|
|
//
|
|
// So the instruction is rewritten to zero the destination register. The canary
|
|
// becomes zero, the check at the end of the function compares zero against
|
|
// zero, and `__stack_chk_fail` is never reached. What is lost is a hardening
|
|
// measure that was never going to work here; what is gained is a driver that
|
|
// runs.
|
|
//
|
|
// Call it **after** ko_relocate(), which will have written a displacement into
|
|
// bytes this then overwrites entirely. Returns how many it patched, or -1 if
|
|
// it found something at that offset it did not recognise -- in which case
|
|
// nothing is modified, because a loader that half-understands an instruction
|
|
// should not be editing it.
|
|
int ko_defuse_gs(struct ko *k, const char *sym);
|
|
|
|
// Turn every *other* `%gs:`-relative reference into an ordinary one.
|
|
//
|
|
// The stack guard is one per-CPU variable; there are others, and `current` is
|
|
// the one every driver touches. `mov %gs:const_current_task(%rip), %r8` reads
|
|
// a pointer out of the kernel's per-CPU area, and a host that is not that
|
|
// kernel has no such area -- so on SchOS it reads a kernel address from user
|
|
// mode and faults.
|
|
//
|
|
// Defusing is not available here: the guard's *value* is arbitrary, so zeroing
|
|
// a register is a correct answer, and `current`'s is not -- the driver will
|
|
// dereference it.
|
|
//
|
|
// What works instead is that **a per-CPU variable in a single-threaded host is
|
|
// just a variable**. Taking the `%gs` off leaves the same instruction reading
|
|
// the same width in the same direction, from storage the embedder supplies for
|
|
// that name. Eight bytes become seven and a nop, and the driver never learns
|
|
// the difference.
|
|
//
|
|
// `percpu` is asked for an address for each name and should return the same
|
|
// one every time it is asked for that name -- and should initialise it, since
|
|
// the driver now reads its *contents*: zero is right for a counter and wrong
|
|
// for `current`. Returning 0 refuses the object.
|
|
//
|
|
// Call after ko_relocate() and after ko_defuse_gs(), for the same reason.
|
|
// Returns how many it rewrote, or -1.
|
|
int ko_fixup_percpu(struct ko *k,
|
|
unsigned long long (*percpu)(void *ctx, const char *name),
|
|
void *ctx);
|
|
|
|
// A value from the `.modinfo` section -- "license", "description", "author",
|
|
// "alias". Returns 0 if the object has no such key.
|
|
//
|
|
// Worth having at L0 rather than later: the first thing anyone should be able
|
|
// to ask about a module is what licence it declares, and that is a string in
|
|
// the file rather than anything that needs loading.
|
|
const char *ko_modinfo(const struct ko *k, const char *key);
|
|
|
|
// The module's own name, from `.gnu.linkonce.this_module`, or 0.
|
|
const char *ko_name(const struct ko *k);
|
|
|
|
const char *ko_err(const struct ko *k);
|