Skip to content

Commit

Permalink
injector: Prototype patchspec implementation
Browse files Browse the repository at this point in the history
Patch specification is read from `bakatsugi` section of patchlib elf
file. A patchlib is a normal shared library with the extra section
containing patch metadata. A helper C header is included in
`c/bakatsugi.h`
  • Loading branch information
sammko committed Mar 5, 2022
1 parent 7ba109b commit 70d548a
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 7 deletions.
79 changes: 72 additions & 7 deletions bakatsugi-injector/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
use std::{
ffi::{c_void, CStr},
fs::{self, File},
io::{IoSlice, Write},
io::{IoSlice, Read, Seek, Write},
mem,
net::Shutdown,
os::unix::{
Expand All @@ -15,6 +15,7 @@ use std::{
prelude::{AsRawFd, FromRawFd, RawFd},
},
path::{Path, PathBuf},
str,
};

use anyhow::{bail, Context, Result};
Expand Down Expand Up @@ -153,14 +154,68 @@ fn send_fd(fd: i32, sock: &UnixStream) -> Result<()> {
Ok(())
}

#[derive(Debug)]
enum PatchSpec<'a> {
Own { old: &'a str, new: &'a str },
Lib { old: &'a str, new: &'a str },
}

fn parse_patchspec(patchlib: &[u8]) -> Result<Vec<PatchSpec>> {
let elf = Elf::parse(patchlib)?;
let mut r = Vec::new();
let mut section = None;
for shdr in &elf.section_headers {
if elf.shdr_strtab.get_at(shdr.sh_name) == Some("bakatsugi") {
section = Some(shdr);
}
}
let Some(section) = section else { bail!("Could not find metadata section in patch lib") };
let range = section
.file_range()
.context("Section has no range in file")?;
let section_data = &patchlib[range];
if section_data[section_data.len() - 1] != 0 {
bail!("Not null terminated");
}
let section_data = &section_data[..section_data.len() - 1];
for line in section_data.split(|&b| b == b'\n') {
if line.is_empty() {
continue;
}
r.push(match line[0] {
flag @ (b'O' | b'L') => {
if let [l, r] = &str::from_utf8(&line[1..])?
.split('.')
.collect::<Vec<&str>>()[..]
{
match flag {
b'O' => PatchSpec::Own { old: l, new: r },
b'L' => PatchSpec::Lib { old: l, new: r },
_ => unreachable!(),
}
} else {
bail!("Malformed line in patchspec")
}
}
_ => bail!("Bad flag in patchspec: {:x}", line[0]),
});
}
Ok(r)
}

fn handle_stage2(socket: &mut UnixStream, patchlib: &Path, debugelf: Option<&Path>) -> Result<()> {
let mut patchfd = fs::File::open(patchlib).context("Could not open patchlib")?;
let mut patchelf = Vec::new();
patchfd
.read_to_end(&mut patchelf)
.context("Could not read patchlib")?;
patchfd.rewind().context("Could not rewind patchlib")?;
let patches = parse_patchspec(&patchelf).context("Could not parse patchspec")?;

MessageItoT::Ping(33).send(socket)?;
let MessageTtoI::Pong(33) = MessageTtoI::recv(socket)? else { bail!("BAD") };

// MessageItoT::OpenDSO(32, PathBuf::from("/tmp/libx.so")).send(socket)?;
MessageItoT::RecvDSO(1).send(socket)?;

let patchfd = fs::File::open(patchlib)?;
send_fd(patchfd.as_raw_fd(), socket)?;
drop(patchfd);

Expand All @@ -175,9 +230,19 @@ fn handle_stage2(socket: &mut UnixStream, patchlib: &Path, debugelf: Option<&Pat
let MessageTtoI::Ok = MessageTtoI::recv(socket)? else { bail!("BAD") };
}

// MessageItoT::PatchLib("write".to_string(), 1, "b".to_string()).send(socket)?;
MessageItoT::PatchOwn("volam".to_string(), 1, "b".to_string()).send(socket)?;
let MessageTtoI::Ok = MessageTtoI::recv(socket)? else { bail!("BAD") };
for patch in patches {
println!("Patch: {:?}", patch);
match patch {
PatchSpec::Own { old, new } => {
MessageItoT::PatchOwn(old.to_string(), 1, new.to_string())
}
PatchSpec::Lib { old, new } => {
MessageItoT::PatchLib(old.to_string(), 1, new.to_string())
}
}
.send(socket)?;
let MessageTtoI::Ok = MessageTtoI::recv(socket)? else { bail!("BAD") };
}

MessageItoT::Quit.send(socket)?;

Expand Down
6 changes: 6 additions & 0 deletions c/bakatsugi.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef BAKATSUGI_H
#define BAKATSUGI_H
#define BAKATSUGI(__X) const char __bakatsugi_patches[] __attribute__((section("bakatsugi"))) = __X;
#define PATCH_OWN(orig, replace) "O" #orig "." #replace "\n"
#define PATCH_LIB(orig, replace) "L" #orig "." #replace "\n"
#endif

0 comments on commit 70d548a

Please sign in to comment.