investigating patchelf for sysexts

investigating patchelf for sysexts
158 Replies
tulip
tulip4mo ago
yeah data from before:
tulip
tulip4mo ago
GitHub
GitHub - NixOS/patchelf: A small utility to modify the dynamic link...
A small utility to modify the dynamic linker and RPATH of ELF executables - NixOS/patchelf
tulip
tulip4mo ago
and this might help prefixing our sysext binaries and libraries by running something like patchelf $MAGIC_FLAGS $LIBRARY_PATH $BINARY readelf exists too and its output is very parseable by any script readelf -d /home/linuxbrew/.linuxbrew/bin/nvim | grep 'R.*PATH' 0x000000000000000f (RPATH) Library rpath: [/home/linuxbrew/.linuxbrew/Cellar/neovim/0.9.5/lib:/home/linuxbrew/.linuxbrew/opt/gcc/lib/gcc/current:/home/linuxbrew/.linuxbrew/opt/icu4c/lib:/home/linuxbrew/.linuxbrew/opt/ncurses/lib:/home/linuxbrew/.linuxbrew/opt/readline/lib:/home/linuxbrew/.linuxbrew/opt/zlib/lib:/home/linuxbrew/.linuxbrew/opt/libxml2/lib:/home/linuxbrew/.linuxbrew/opt/gettext/lib:/home/linuxbrew/.linuxbrew/opt/unibilium/lib:/home/linuxbrew/.linuxbrew/opt/libtermkey/lib:/home/linuxbrew/.linuxbrew/opt/libvterm/lib:/home/linuxbrew/.linuxbrew/opt/luajit/lib:/home/linuxbrew/.linuxbrew/opt/luv/lib:/home/linuxbrew/.linuxbrew/opt/msgpack/lib:/home/linuxbrew/.linuxbrew/opt/tree-sitter/lib:/home/linuxbrew/.linuxbrew/opt/openssl@3/lib:/home/linuxbrew/.linuxbrew/opt/libedit/lib:/home/linuxbrew/.linuxbrew/opt/krb5/lib:/home/linuxbrew/.linuxbrew/opt/libtirpc/lib:/home/linuxbrew/.linuxbrew/opt/libnsl/lib:/home/linuxbrew/.linuxbrew/lib]
bketelsen
bketelsen4mo ago
side note statically linked Go apps don't have any RPATH entries just a "NEEDED" field
tulip
tulip4mo ago
lol interesting
bketelsen
bketelsen4mo ago
readelf -d ~/go/bin/gopls

Dynamic section at offset 0x1479600 contains 19 entries:
Tag Type Name/Value
0x0000000000000004 (HASH) 0x12f7640
0x0000000000000006 (SYMTAB) 0x12f79c0
0x000000000000000b (SYMENT) 24 (bytes)
0x0000000000000005 (STRTAB) 0x12f7720
0x000000000000000a (STRSZ) 669 (bytes)
0x0000000000000007 (RELA) 0x12f7168
0x0000000000000008 (RELASZ) 24 (bytes)
0x0000000000000009 (RELAENT) 24 (bytes)
0x0000000000000003 (PLTGOT) 0x1879740
0x0000000000000015 (DEBUG) 0x0
0x0000000000000001 (NEEDED) Shared library: [libresolv.so.2]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000006ffffffe (VERNEED) 0x12f7580
0x000000006fffffff (VERNEEDNUM) 1
0x000000006ffffff0 (VERSYM) 0x12f75e0
0x0000000000000014 (PLTREL) RELA
0x0000000000000002 (PLTRELSZ) 1008 (bytes)
0x0000000000000017 (JMPREL) 0x12f7180
0x0000000000000000 (NULL) 0x0
readelf -d ~/go/bin/gopls

Dynamic section at offset 0x1479600 contains 19 entries:
Tag Type Name/Value
0x0000000000000004 (HASH) 0x12f7640
0x0000000000000006 (SYMTAB) 0x12f79c0
0x000000000000000b (SYMENT) 24 (bytes)
0x0000000000000005 (STRTAB) 0x12f7720
0x000000000000000a (STRSZ) 669 (bytes)
0x0000000000000007 (RELA) 0x12f7168
0x0000000000000008 (RELASZ) 24 (bytes)
0x0000000000000009 (RELAENT) 24 (bytes)
0x0000000000000003 (PLTGOT) 0x1879740
0x0000000000000015 (DEBUG) 0x0
0x0000000000000001 (NEEDED) Shared library: [libresolv.so.2]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000006ffffffe (VERNEED) 0x12f7580
0x000000006fffffff (VERNEEDNUM) 1
0x000000006ffffff0 (VERSYM) 0x12f75e0
0x0000000000000014 (PLTREL) RELA
0x0000000000000002 (PLTRELSZ) 1008 (bytes)
0x0000000000000017 (JMPREL) 0x12f7180
0x0000000000000000 (NULL) 0x0
needed libc, libresolv
tulip
tulip4mo ago
also brian, apparently bext cannot be statically built with nix :( or at all actually
bketelsen
bketelsen4mo ago
this is fascinating I read a blog post about doing static linking go apps with nix a million years ago
tulip
tulip4mo ago
yeah!!!
bketelsen
bketelsen4mo ago
we'll use goreleaser it'll be fine I have a pro license that's a good $20/mo investment tbh
tulip
tulip4mo ago
its just that like, bext required lvm2, which requires systemdMinimal, which cannot be statically built without very weird binary patching things i tried to build bext with pkgsMusl and it didnt work :(
bketelsen
bketelsen4mo ago
it is what it is
tulip
tulip4mo ago
because -lgpgme and -ldevmapper could not be found by pkg-conf.... its a very interesting rabbit hole but still very sad
bketelsen
bketelsen4mo ago
maybe we break bext into two pieces the developer piece and the user piece
tulip
tulip4mo ago
the nix building thing and the management yeah!
bketelsen
bketelsen4mo ago
the user piece should just need to move things around and enable sysexts the dev piece has all the hard requirements
tulip
tulip4mo ago
i was thinking about doing that with the plugin architecture PR im just doing preparatory work with UX stuff but ill be working on that right after these first PRs yeah!! bext-nix-build bext-oci-sysext bext-melange plugins like that im so excited for all these sysexts and everything that could benefit a lot of people im so happy LOL
bketelsen
bketelsen4mo ago
you're crushing this so hard. keep up the exploring, creating, building!
tulip
tulip4mo ago
hell yeah i will. this is stuff that i really wanna do
tulip
tulip4mo ago
LOL WHAT that will help out a bunch i was thinking we were gonna need a bunch of workarounds in go welp not anymore LOL we can literally just edit the ELF symbols
bketelsen
bketelsen4mo ago
literally open the binary then walk the deps like filepath.Walk
tulip
tulip4mo ago
this is awesome yeah like jesus christ this is amazing
bketelsen
bketelsen4mo ago
well my work here is done i'm going to go feed the baby and go to bed let me know when it all works
tulip
tulip4mo ago
going to try to implement the plugin thing
bketelsen
bketelsen4mo ago
tulip
tulip
tulip4mo ago
then slowly integrate everything with bext hmmm?
bketelsen
bketelsen4mo ago
do a POC on the patchelf as a quick standalone test THEN boil the rest of the ocean
tulip
tulip4mo ago
yeah LOL makes sense
bketelsen
bketelsen4mo ago
unless you have unlimited time and attention in which case, go boil that ocean friend
tulip
tulip4mo ago
hahah yeah i have a bunch of time but not unlimited trying out the POC approach
bketelsen
bketelsen4mo ago
yeah you can just pick any dynamically linked app you already have installed and relocate it plus it's libraries into /opt/tulip without even building a sysext
tulip
tulip4mo ago
yeah!
bketelsen
bketelsen4mo ago
simplest possible proof that this can work then make a sysext then conquer the whole linux world and we'll send @dnkmmr their favorite beverage to celebrate the idea
tulip
tulip4mo ago
hell yeah!!!
bketelsen
bketelsen4mo ago
bonus points if you make a public go package to do this and name it after a carefully chosen elf from LoTR
bketelsen
bketelsen4mo ago
Neo Encyclopedia Wiki
List of Middle-earth Elves
In J. R. R. Tolkien's legendarium, Elves are one of the races that inhabit a fictional Earth, often called Middle-earth, and set in the remote past. They appear in The Hobbit and in The Lord of...
bketelsen
bketelsen4mo ago
is there an elf known for moving things?
tulip
tulip4mo ago
chatgpt had a cool idea
No description
tulip
tulip4mo ago
he is shooting something after all
bketelsen
bketelsen4mo ago
legolas means "greanleaf" just in case it matters
tulip
tulip4mo ago
also
tulip
tulip4mo ago
do you know what the hell is this error
No description
tulip
tulip4mo ago
this is super weird OH i got it nvm LOL i just didnt read the error hmmmmmmmmmmmmmmmmmmm
tulip
tulip4mo ago
reading stuff works
No description
tulip
tulip4mo ago
~/opt/elf-relocator: go run main.go test.elf
selected file doesnt seem to be dynamic linked
~/opt/elf-relocator: go run main.go test.elf
selected file doesnt seem to be dynamic linked
dnkmmr
dnkmmr4mo ago
hey I know what could solve the selinux issues with nix, have it installed as an rpm
tulip
tulip4mo ago
shouldnt be impossible but its not like that would help out :( the issue is that some files inside the sysexts themselves arent properly getting their xattrs
tulip
tulip4mo ago
les goooooo this actually works!
No description
tulip
tulip4mo ago
i got the dependencies!!!!!
bketelsen
bketelsen4mo ago
you're on fire
tulip
tulip4mo ago
found out the library paths
No description
tulip
tulip4mo ago
now i just need to figure out a way to change those to the new ones GOD i just found out that RPATH and RUNPATH arent the same this is SO annoying LOL
~/opt/elf-relocator: go run main.go $env.SHELL
needed deps:
libssl.so.3
libcrypto.so.3
libgcc_s.so.1
libm.so.6
libc.so.6

Library paths:
[/nix/store/h24v1xs4i9l3k18ygxvs62361rl77804-openssl-3.0.13/lib:/nix/store/cyrrf49i2hm1w7vn2j945ic3rrzgxbqs-glibc-2.38-44/lib:/nix/store/1s98ricsglmfjjqkfnpvywnip5z7gp9q-gcc-13.2.0-lib/lib]
~/opt/elf-relocator: go run main.go $env.SHELL
needed deps:
libssl.so.3
libcrypto.so.3
libgcc_s.so.1
libm.so.6
libc.so.6

Library paths:
[/nix/store/h24v1xs4i9l3k18ygxvs62361rl77804-openssl-3.0.13/lib:/nix/store/cyrrf49i2hm1w7vn2j945ic3rrzgxbqs-glibc-2.38-44/lib:/nix/store/1s98ricsglmfjjqkfnpvywnip5z7gp9q-gcc-13.2.0-lib/lib]
now i can get library paths for even nix binaries amazing.
:package:[tulili@bunbun elf-relocator]$ ./reloc free-example.elf
needed deps:
libprocps.so.8
libc.so.6

Library paths:
[/lib/x86_64-linux-gnu/libprocps.so.8 /lib/x86_64-linux-gnu/libc.so.6]
:package:[tulili@bunbun elf-relocator]$ ./reloc free-example.elf
needed deps:
libprocps.so.8
libc.so.6

Library paths:
[/lib/x86_64-linux-gnu/libprocps.so.8 /lib/x86_64-linux-gnu/libc.so.6]
works for dynamic non-nix binaries as well . wonderful.
tulip
tulip4mo ago
No description
tulip
tulip4mo ago
@bketelsen well im going to sleep right now but i managed to make some progress apparently elf files have sections and one of those sections is DT_RUNPATH and i can seek to the section by getting the .dynstr section offset and adding the DT_RUNPATH offset to that by doing that the work is pretty easy jsut cloning the elf file, and writing a new Dynamic64 elf section in its place but sadly there is some sort of issue that is making my program not be able to write to that section properly i feel like its something with the file opening perms or something like that ill post the code to github. since you are quite knowledgeable about golang and all those things, can you help me out? i really cant figure this out!! i think im naming this literally jsut legolas sounds cool rolls of the tongue in a nice way yeeeah legolas it is.
tulip
tulip4mo ago
GitHub
GitHub - tulilirockz/legolas: Go-based utility meant to be a P.O.C....
Go-based utility meant to be a P.O.C. plugin for Bext - alternative to patchelf - tulilirockz/legolas
tulip
tulip4mo ago
@bketelsen i also really dont know how could i write that section without accidentaly overriding another section by accident... this is so tricky ngl
bketelsen
bketelsen4mo ago
I think the go elf package is only for reading get the info you need from that then use exec to drive patchelf maybe? I don't see any way in the debug/elf api to save anything.
tulip
tulip4mo ago
yeah it is but i can copy the file and edit it manually and thats what i wanted to do! i wanted to override the old file's "DT_RUNPATH" section with new values but i havent been able to actually do that :( i think the best way to handle this would be to: - make new ELF file with all ELF parameters and everything - seek over to the dynstr -> DT_RUNPATH (or other) section - override DT_RUNPATH section with zeros, then truncate with length of bytes needed to write the new DT_RUNPATH section - write the new DT_RUNPATH section - Profit! also there is a neovim plugin that makes comparing these binaries a breeze amazing honestly
bketelsen
bketelsen4mo ago
here's my take which almost works
bketelsen
bketelsen4mo ago
GitHub
GitHub - bketelsen/uhaul
Contribute to bketelsen/uhaul development by creating an account on GitHub.
dnkmmr
dnkmmr4mo ago
Could sysext be used to update static bins in ~/?
bketelsen
bketelsen4mo ago
the only error I have is because of a symlink. I need to figure out the right logic for that this is comedic, tbh. I have no idea what I'm doing and i'm just throwing crap at the wall to see what sticks
bketelsen
bketelsen4mo ago
This guy (https://github.com/pothos) from work is going to take a look and tell me what he thinks. He's a dev/maintainer and seems to be way smarter than me lol
GitHub
pothos - Overview
Software developer (Flatcar Container Linux, GNOME Disks, and more), interested in memory safe network stacks. - pothos
bketelsen
bketelsen4mo ago
he asked a bunch of questions that suggested I'm not doing things right with the rpath stuff. FIRST SUCCESS
bketelsen
bketelsen4mo ago
No description
bketelsen
bketelsen4mo ago
neovim (just the binary, no supporting files) as a sysext loaded to /opt/bluefin @j0rge !!
tulip
tulip4mo ago
YO WHAT LETS GOOOOOOOOOOOOO THIS IS GREAT LOL same
bketelsen
bketelsen4mo ago
i used a bunch of your code from legolas after we have a better clue of what we're doing we can merge ideas into one repo if you want
tulip
tulip4mo ago
did you figure out what was wrong? yeah!!!! do you want to merge them into a repo in the ublue-os org?
bketelsen
bketelsen4mo ago
specifically for my first test the nvim binary showed a dependency on brew's ld.so linker but I couldntfigure out why had to change the INTERP of the binary
bketelsen
bketelsen4mo ago
GitHub
uhaul/cmd/root.go at main · bketelsen/uhaul
Contribute to bketelsen/uhaul development by creating an account on GitHub.
tulip
tulip4mo ago
ooooooh but like why changing the interpreter would be necessary?
dnkmmr
dnkmmr4mo ago
could that replace nix for basic package management?
tulip
tulip4mo ago
it should be the same in any distro (even nixos) sadly nah its not the same
bketelsen
bketelsen4mo ago
because the interpreter didn't exist in the sysext
tulip
tulip4mo ago
ooooooh
bketelsen
bketelsen4mo ago
❯ ldd `which nvim`
linux-vdso.so.1 (0x00007ffc3197b000)
libluv.so.1 => /home/linuxbrew/.linuxbrew/opt/luv/lib/libluv.so.1 (0x00007f9fa6fcb000)
libtermkey.so.1 => /home/linuxbrew/.linuxbrew/opt/libtermkey/lib/libtermkey.so.1 (0x00007f9fa6a00000)
libvterm.so.0 => /home/linuxbrew/.linuxbrew/opt/libvterm/lib/libvterm.so.0 (0x00007f9fa7518000)
libmsgpack-c.so.2 => /home/linuxbrew/.linuxbrew/opt/msgpack/lib/libmsgpack-c.so.2 (0x00007f9fa750e000)
libtree-sitter.so.0 => /home/linuxbrew/.linuxbrew/opt/tree-sitter/lib/libtree-sitter.so.0 (0x00007f9fa6f9b000)
libunibilium.so.4 => /home/linuxbrew/.linuxbrew/opt/unibilium/lib/libunibilium.so.4 (0x00007f9fa6f85000)
libluajit-5.1.so.2 => /home/linuxbrew/.linuxbrew/opt/luajit/lib/libluajit-5.1.so.2 (0x00007f9fa6ef6000)
libm.so.6 => /lib64/libm.so.6 (0x00007f9fa6e04000)
libuv.so.1 => /home/linuxbrew/.linuxbrew/lib/libuv.so.1 (0x00007f9fa6dcc000)
libc.so.6 => /lib64/libc.so.6 (0x00007f9fa681e000)
libgcc_s.so.1 => /home/linuxbrew/.linuxbrew/opt/gcc/lib/gcc/current/libgcc_s.so.1 (0x00007f9fa6da5000)
/home/linuxbrew/.linuxbrew/lib/ld.so => /lib64/ld-linux-x86-64.so.2 (0x00007f9fa7531000)
❯ ldd `which nvim`
linux-vdso.so.1 (0x00007ffc3197b000)
libluv.so.1 => /home/linuxbrew/.linuxbrew/opt/luv/lib/libluv.so.1 (0x00007f9fa6fcb000)
libtermkey.so.1 => /home/linuxbrew/.linuxbrew/opt/libtermkey/lib/libtermkey.so.1 (0x00007f9fa6a00000)
libvterm.so.0 => /home/linuxbrew/.linuxbrew/opt/libvterm/lib/libvterm.so.0 (0x00007f9fa7518000)
libmsgpack-c.so.2 => /home/linuxbrew/.linuxbrew/opt/msgpack/lib/libmsgpack-c.so.2 (0x00007f9fa750e000)
libtree-sitter.so.0 => /home/linuxbrew/.linuxbrew/opt/tree-sitter/lib/libtree-sitter.so.0 (0x00007f9fa6f9b000)
libunibilium.so.4 => /home/linuxbrew/.linuxbrew/opt/unibilium/lib/libunibilium.so.4 (0x00007f9fa6f85000)
libluajit-5.1.so.2 => /home/linuxbrew/.linuxbrew/opt/luajit/lib/libluajit-5.1.so.2 (0x00007f9fa6ef6000)
libm.so.6 => /lib64/libm.so.6 (0x00007f9fa6e04000)
libuv.so.1 => /home/linuxbrew/.linuxbrew/lib/libuv.so.1 (0x00007f9fa6dcc000)
libc.so.6 => /lib64/libc.so.6 (0x00007f9fa681e000)
libgcc_s.so.1 => /home/linuxbrew/.linuxbrew/opt/gcc/lib/gcc/current/libgcc_s.so.1 (0x00007f9fa6da5000)
/home/linuxbrew/.linuxbrew/lib/ld.so => /lib64/ld-linux-x86-64.so.2 (0x00007f9fa7531000)
that last line comes from the INTERP section, not an actual dependency even worse it's a symlink to the one in /lib64 so once I fixed that everything started working!
tulip
tulip4mo ago
great!!!! ill test your utility out and send some PRs if necessary legolas was just a POC so whatever idc
bketelsen
bketelsen4mo ago
so steal any bits of that you want if you want to keep pushing legolas no need to abandon yours yet!
tulip
tulip4mo ago
there really is no reason to do so LOL in the end the idea is just to have this working
bketelsen
bketelsen4mo ago
ok well after we get it tight we can put it in ublue. I want to make sure you get credit & ownership.
tulip
tulip4mo ago
yup!!!!
bketelsen
bketelsen4mo ago
next step might be to take an list of binaries instead of just one. Iterate over them and add them to the output dir
tulip
tulip4mo ago
shouldnt be too much of an issue either just looping over the args and everything should suffice
bketelsen
bketelsen4mo ago
no, just looping in the right place but there's a few more issues we need to work through
tulip
tulip4mo ago
what would those be? ill write them as issues in gh just so that we have a nice place to analyze them
bketelsen
bketelsen4mo ago
when I opened neovim in the sysext, the binary had stuff compiled into it with paths
bketelsen
bketelsen4mo ago
No description
tulip
tulip4mo ago
oh.
bketelsen
bketelsen4mo ago
so that's something to figure out. I dont' know how or where, but I'm betting we can figure it out 🙂
tulip
tulip4mo ago
wouldnt that be an issue with where you got the neovim binary itself? try like patching some neovim binary from ubuntu or something yeah!
bketelsen
bketelsen4mo ago
next is: how do you know what else belongs with that binary? Like man pages, etc, supporting files for that I'm wondering if we could be opinionated and use a particular source (say apk, for example) then read the metadata from the package to get the list of extra stuff
tulip
tulip4mo ago
can you run this on your neovim binary? strings $(which nvim) | grep Cellar maybe we could straight up write the correct path into the binary
bketelsen
bketelsen4mo ago
❯ strings $(which nvim) | grep Cellar
/home/linuxbrew/.linuxbrew/Cellar/neovim/0.9.5/share/nvim
/home/linuxbrew/.linuxbrew/Cellar/neovim/0.9.5/lib/nvim
/home/linuxbrew/.linuxbrew/Cellar/neovim/0.9.5/lib:/home/linuxbrew/.linuxbrew/opt/gcc/lib/gcc/current:/home/linuxbrew/.linuxbrew/opt/icu4c/lib:/home/linuxbrew/.linuxbrew/opt/ncurses/lib:/home/linuxbrew/.linuxbrew/opt/readline/lib:/home/linuxbrew/.linuxbrew/opt/zlib/lib:/home/linuxbrew/.linuxbrew/opt/libxml2/lib:/home/linuxbrew/.linuxbrew/opt/gettext/lib:/home/linuxbrew/.linuxbrew/opt/unibilium/lib:/home/linuxbrew/.linuxbrew/opt/libtermkey/lib:/home/linuxbrew/.linuxbrew/opt/libvterm/lib:/home/linuxbrew/.linuxbrew/opt/luajit/lib:/home/linuxbrew/.linuxbrew/opt/luv/lib:/home/linuxbrew/.linuxbrew/opt/msgpack/lib:/home/linuxbrew/.linuxbrew/opt/tree-sitter/lib:/home/linuxbrew/.linuxbrew/opt/openssl@3/lib:/home/linuxbrew/.linuxbrew/opt/libedit/lib:/home/linuxbrew/.linuxbrew/opt/krb5/lib:/home/linuxbrew/.linuxbrew/opt/libtirpc/lib:/home/linuxbrew/.linuxbrew/opt/libnsl/lib:/home/linuxbrew/.linuxbrew/lib
❯ strings $(which nvim) | grep Cellar
/home/linuxbrew/.linuxbrew/Cellar/neovim/0.9.5/share/nvim
/home/linuxbrew/.linuxbrew/Cellar/neovim/0.9.5/lib/nvim
/home/linuxbrew/.linuxbrew/Cellar/neovim/0.9.5/lib:/home/linuxbrew/.linuxbrew/opt/gcc/lib/gcc/current:/home/linuxbrew/.linuxbrew/opt/icu4c/lib:/home/linuxbrew/.linuxbrew/opt/ncurses/lib:/home/linuxbrew/.linuxbrew/opt/readline/lib:/home/linuxbrew/.linuxbrew/opt/zlib/lib:/home/linuxbrew/.linuxbrew/opt/libxml2/lib:/home/linuxbrew/.linuxbrew/opt/gettext/lib:/home/linuxbrew/.linuxbrew/opt/unibilium/lib:/home/linuxbrew/.linuxbrew/opt/libtermkey/lib:/home/linuxbrew/.linuxbrew/opt/libvterm/lib:/home/linuxbrew/.linuxbrew/opt/luajit/lib:/home/linuxbrew/.linuxbrew/opt/luv/lib:/home/linuxbrew/.linuxbrew/opt/msgpack/lib:/home/linuxbrew/.linuxbrew/opt/tree-sitter/lib:/home/linuxbrew/.linuxbrew/opt/openssl@3/lib:/home/linuxbrew/.linuxbrew/opt/libedit/lib:/home/linuxbrew/.linuxbrew/opt/krb5/lib:/home/linuxbrew/.linuxbrew/opt/libtirpc/lib:/home/linuxbrew/.linuxbrew/opt/libnsl/lib:/home/linuxbrew/.linuxbrew/lib
tulip
tulip4mo ago
lol we can literally just straight up patch that
bketelsen
bketelsen4mo ago
the last one is the rpath we CAN?
tulip
tulip4mo ago
yeah hell yeah we can you can use a hex editor to patch that out LOL no need to recompile anything :>
bketelsen
bketelsen4mo ago
ok so if we can patch it, can we figure out what they are with automation? like if it wasn't in a Cellar directory, how would we know they existed?
tulip
tulip4mo ago
i think it would depend on where the binary is from like if the binary has a /usr/VERYCOOLBINARY prefix the user would need to specify that i guess we could search for the string $PREFIX in the binary code, get the entire string from wherever it is, and override it
bketelsen
bketelsen4mo ago
ohh
tulip
tulip4mo ago
pretty sure debug/elf has sooome thing that we could use to search that but for convenience sake we could make the prefix be /usr by default the only issue would be stuff like nix binaries that have very odd prefixes... but any other kind should be fine
bketelsen
bketelsen4mo ago
but we don't want it to be /usr we want it to be the prefix we specify in the app
tulip
tulip4mo ago
nono, its just that the original binary most likely would have a /usr prefix
bketelsen
bketelsen4mo ago
ah ok
tulip
tulip4mo ago
then we can just patch that out to have the /usr/coolbinary prefix and everything
bketelsen
bketelsen4mo ago
so I'd want to figure out what the prefix is, then copy stuff from that prefix into the destination prefix then patch the strings
/home/linuxbrew/.linuxbrew/Cellar/neovim/0.9.5/share/nvim
/home/linuxbrew/.linuxbrew/Cellar/neovim/0.9.5/lib/nvim
/home/linuxbrew/.linuxbrew/Cellar/neovim/0.9.5/share/nvim
/home/linuxbrew/.linuxbrew/Cellar/neovim/0.9.5/lib/nvim
tulip
tulip4mo ago
yup!
bketelsen
bketelsen4mo ago
whatever files are in those need to go in the sysext
tulip
tulip4mo ago
like we could use the binary code itself as a separator like those strings are most likely surrounded by garbled binary instructions we can like search for nvim -> get everything between $BINARY_GARBAGE1 and $BINARY_GARBAGE2 just an idea after all i really dont know if that is gonna work but still
bketelsen
bketelsen4mo ago
who knows! here's the strings for vim that ships with bluefin
❯ strings $(which vim) | grep /usr
/usr/share/vim
.,/usr/include,,
gcc -c -I. -Iproto -DHAVE_CONFIG_H -O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Wno-complain-wrong-lang -Werror=format-security -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -DSYS_VIMRC_FILE=/etc/vimrc -D_REENTRANT -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1
gcc -Wl,--enable-new-dtags -Wl,-z,relro -Wl,--as-needed -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -Wl,--build-id=sha1 -Wl,-z,relro -Wl,--as-needed -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -Wl,--build-id=sha1 -specs=/usr/lib/rpm/redhat/redhat-package-notes -L/usr/local/lib -o vim -lm -lselinux -lncurses -lsodium -lacl -lattr -lgpm
/usr/include/python3.12/cpython/listobject.h
❯ strings $(which vim) | grep /usr
/usr/share/vim
.,/usr/include,,
gcc -c -I. -Iproto -DHAVE_CONFIG_H -O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Wno-complain-wrong-lang -Werror=format-security -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -DSYS_VIMRC_FILE=/etc/vimrc -D_REENTRANT -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1
gcc -Wl,--enable-new-dtags -Wl,-z,relro -Wl,--as-needed -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -Wl,--build-id=sha1 -Wl,-z,relro -Wl,--as-needed -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -Wl,--build-id=sha1 -specs=/usr/lib/rpm/redhat/redhat-package-notes -L/usr/local/lib -o vim -lm -lselinux -lncurses -lsodium -lacl -lattr -lgpm
/usr/include/python3.12/cpython/listobject.h
tulip
tulip4mo ago
wait like arent text strings in binaries stored in the .text section?
bketelsen
bketelsen4mo ago
i'm wondering if we can use {share,lib,...} as the clue to figure out what the prefix is idk
tulip
tulip4mo ago
i think so
bketelsen
bketelsen4mo ago
you tell me lol
tulip
tulip4mo ago
i was watching a video about the elf binary format and that seeemms to be the case when we are making assembly code usually variables and strings are in a separate section like .data or .text
tulip
tulip4mo ago
No description
tulip
tulip4mo ago
here!!!!! section .data!!! that narrows down a lot of stuff :>
bketelsen
bketelsen4mo ago
are you thinking use debug/elf to read the .data section?
tulip
tulip4mo ago
yup! read_elf, err := elf.Open(file) then use read_elf.Section(".data") and walk through it checking out every chunk if the chunk is just binary data we can ignore it if not, we can read the text
bketelsen
bketelsen4mo ago
Section .data found
Section .data size 201361
Section .data found
Section .data size 201361
tulip
tulip4mo ago
sweet!
bketelsen
bketelsen4mo ago
that was vim
tulip
tulip4mo ago
actually maybe its the segments that we need to check out the segments are exclusively used at runtime and they seem to have an effect here oh there is literally an "Open" method in each section cool.
bketelsen
bketelsen4mo ago
yes, but it's binary data so we have to figure out how it is delimited
section := read_elf.Section(".data")
if section != nil {
fmt.Println("Section .data found")
}
bb, err := section.Data()
if err != nil {
return err
}
fmt.Println("Section .data size", len(bb))
section := read_elf.Section(".data")
if section != nil {
fmt.Println("Section .data found")
}
bb, err := section.Data()
if err != nil {
return err
}
fmt.Println("Section .data size", len(bb))
tulip
tulip4mo ago
how does strings even do that jesus christ like reading stuff straight off of xxd results in this:
0010ea90: 2f75 7372 2f73 6861 7265 2f62 6173 6864 /usr/share/bashd
001200a0: 2f62 696e 3a2f 7573 722f 6269 6e3a 2f73 /bin:/usr/bin:/s
001200b0: 6269 6e3a 2f75 7372 2f73 6269 6e3a 2f65 bin:/usr/sbin:/e
00120840: 636f 7065 0000 0000 2f75 7372 2f6c 6f63 cope..../usr/loc
00120850: 616c 2f73 6269 6e3a 2f75 7372 2f6c 6f63 al/sbin:/usr/loc
00120860: 616c 2f62 696e 3a2f 7573 722f 7362 696e al/bin:/usr/sbin
00120870: 3a2f 7573 722f 6269 6e3a 2f73 6269 6e3a :/usr/bin:/sbin:
001228f0: 762d 6578 7061 6e64 0027 2200 2f75 7372 v-expand.'"./usr
00125e80: 746d 7000 2f75 7372 2f74 6d70 0073 6874 tmp./usr/tmp.sht
0010ea90: 2f75 7372 2f73 6861 7265 2f62 6173 6864 /usr/share/bashd
001200a0: 2f62 696e 3a2f 7573 722f 6269 6e3a 2f73 /bin:/usr/bin:/s
001200b0: 6269 6e3a 2f75 7372 2f73 6269 6e3a 2f65 bin:/usr/sbin:/e
00120840: 636f 7065 0000 0000 2f75 7372 2f6c 6f63 cope..../usr/loc
00120850: 616c 2f73 6269 6e3a 2f75 7372 2f6c 6f63 al/sbin:/usr/loc
00120860: 616c 2f62 696e 3a2f 7573 722f 7362 696e al/bin:/usr/sbin
00120870: 3a2f 7573 722f 6269 6e3a 2f73 6269 6e3a :/usr/bin:/sbin:
001228f0: 762d 6578 7061 6e64 0027 2200 2f75 7372 v-expand.'"./usr
00125e80: 746d 7000 2f75 7372 2f74 6d70 0073 6874 tmp./usr/tmp.sht
(this is the bash ubuntu binary) oh! its the rodata section @bketelsen data doesnt have anything that we want rodata has literally everything
tulip
tulip4mo ago
No description
tulip
tulip4mo ago
// Read the data from the .data section
data, err := io.ReadAll(read_elf.Section(".rodata").Open())
if err != nil {
fmt.Println("Error reading .data section:", err)
return
}

characters := make([]rune, len(data))
for i, b := range data {
characters[i] = rune(b)
}

fmt.Printf("Library paths:\n%v\n\n", validPaths)
fmt.Printf("\nRUNPATH library paths:\n%v\n", rpath)
fmt.Printf("Data section: %v", string(characters))
// Read the data from the .data section
data, err := io.ReadAll(read_elf.Section(".rodata").Open())
if err != nil {
fmt.Println("Error reading .data section:", err)
return
}

characters := make([]rune, len(data))
for i, b := range data {
characters[i] = rune(b)
}

fmt.Printf("Library paths:\n%v\n\n", validPaths)
fmt.Printf("\nRUNPATH library paths:\n%v\n", rpath)
fmt.Printf("Data section: %v", string(characters))
brb
bketelsen
bketelsen4mo ago
the prefix isn't listed in .data or .rodata
tulip
tulip4mo ago
weird i wonder where it is being listed
bketelsen
bketelsen4mo ago
idk. back in a bit, meeting time let me know if you find something!
tulip
tulip4mo ago
we could iterate through all sections and check out which one stores the prefix okay!
bketelsen
bketelsen4mo ago
it's definitely .rodata but the strings in there are more than must null character delimited I found "Cellar" in one chunk that had a ton of other crap in it
E197: Cannot set language to "%s"Failed to get master descriptor status flags: %sFailed to make master descriptor non-blocking: %sFailed to set CLOEXEC on ptmx file descriptorE5677: Error writing input to shell-command: %s/home/linuxbrew/.linuxbrew/etc/xdg/:/etc/xdg//home/linuxbrew/.linuxbrew/share/:/usr/local/share/:/usr/share//home/linuxbrew/.linuxbrew/Cellar/neovim/0.9.5/share/nvim8���p���8���p���8���8���8���8���8���8�������8���8���f���8���p���8���8���8���8���8���8���8���8���8���8���8���8�������8���8���*���Ї��!���Ї��Ї��Ї��Ї��Ї��Ї�����Ї��Ї�����Ї�����on_signalsignal_initE79: Cannot expand wildcardsset_duplicating_descriptorinit_childpty_process_spawn��fos_set_cloexecos_env_exists�_(knN���������?%5d FUNCTIONS SORTED ON %s TIME
E197: Cannot set language to "%s"Failed to get master descriptor status flags: %sFailed to make master descriptor non-blocking: %sFailed to set CLOEXEC on ptmx file descriptorE5677: Error writing input to shell-command: %s/home/linuxbrew/.linuxbrew/etc/xdg/:/etc/xdg//home/linuxbrew/.linuxbrew/share/:/usr/local/share/:/usr/share//home/linuxbrew/.linuxbrew/Cellar/neovim/0.9.5/share/nvim8���p���8���p���8���8���8���8���8���8�������8���8���f���8���p���8���8���8���8���8���8���8���8���8���8���8���8�������8���8���*���Ї��!���Ї��Ї��Ї��Ї��Ї��Ї�����Ї��Ї�����Ї�����on_signalsignal_initE79: Cannot expand wildcardsset_duplicating_descriptorinit_childpty_process_spawn��fos_set_cloexecos_env_exists�_(knN���������?%5d FUNCTIONS SORTED ON %s TIME
that's one null delimited string so I figured out why sysexts break "logout, login, shutdown" when they're mounted if you mount something to /usr everything goes read-only check the error:
Feb 28 16:19:24 fedora systemd-userdbd[35229]: /usr/lib/systemd/systemd-userdbd: error while loading shared libraries: libsystemd-shared-254.9-1.fc39.so: cannot open shared object file: Permission denied
Feb 28 16:19:24 fedora systemd-userdbd[35229]: /usr/lib/systemd/systemd-userdbd: error while loading shared libraries: libsystemd-shared-254.9-1.fc39.so: cannot open shared object file: Permission denied
trying to login the user database service tries to open a shared library but can't because it's RO I just can't believe nobody else has hit this problem I know userdbd is relatively new basically if your screen locks you can't log back in like how is this a thing?
j0rge
j0rge4mo ago
I don't think they had desktops in mind when they designed her, chewie.
bketelsen
bketelsen4mo ago
yeah well this is a non-starter we may investigate doing a r/o overlay instead i got pissed because my sysext finally worked, but I left the vm alone for more than 5 minutes and it locked me out so I had to force reboot it then spent 30 minutes trolling through the logs dammit dammit OHH wait a minute i wonder if you can put stuff in /opt/lib/extensions.d instead of /usr nope3 fail fsck
tulip
tulip4mo ago
like does golang have a strings.Find method or something like that? like in JavaScript someone could just "find" the string and then we could get the seek pointer https://pkg.go.dev/golang.org/x/text/search apparently this exists! if we can search for a string, we could get that string, transform it to bytes, search for these specific bytes in order in the rodata section, and seek to the start of the byte thing then override the file from there
bketelsen
bketelsen4mo ago
search bytes directly but it doesn't matter if auth doesn't work on desktop
sects := bytes.Split(bb, []byte("\n"))
for _, s := range sects {
// don't hate me
strData := string(s)
if strings.Contains(strData, "Cellar") {
fmt.Println("------")
fmt.Println(string(s))
fmt.Println("------")
}

}
sects := bytes.Split(bb, []byte("\n"))
for _, s := range sects {
// don't hate me
strData := string(s)
if strings.Contains(strData, "Cellar") {
fmt.Println("------")
fmt.Println(string(s))
fmt.Println("------")
}

}
you can do bytes.Contains() too but you're converting either way if it was performance code I'd care but it's hack code this way allocates memory that doesn't need to be allocated i asked my coworker (who contributed to sysext development) about problems with GUIs and sysexts, will report back when I hear anything
tulip
tulip4mo ago
heyo! alright! im messing around with a dumb little project today but ill be helping out with this asap
bketelsen
bketelsen4mo ago
Hi, it's a recent(?) regression I think, with a mutable upperdir it works (from systemd main branch with extra symlink setup)
dnkmmr
dnkmmr4mo ago
if nix gets an rpm and it is part of the image, that should fix the nix selinux issues (for the service that starts the daemon)
tulip
tulip4mo ago
bro i think you are a bit caught up on nix getting an rpm thing rpms are literally just zip files but with metadata they wont fix any selinux issue we need to figure out ourselves how to make selinux like nix somehow packaging as an RPM will do nothing honestly would be awesome nonetheless, and is not a bad idea, but still
dnkmmr
dnkmmr4mo ago
I prefer /usr be complete,y untouched while /opt would be used instead in my opinion good to know. it has other benefits like being ready right after install, not having it very easily by accidentally typing sudo nix profile remove 0 (which is when nix uninstalls nix) and nix packages could be installed after installation on the first boot to reduce the size of the oci image (for non critical programs like btop)
tulip
tulip4mo ago
honestly that seems like a good idea because it would like make us not require selinux for nix-based sysexts would be awesome
dnkmmr
dnkmmr4mo ago
same
tulip
tulip4mo ago
yeah! it would be sweet
dnkmmr
dnkmmr4mo ago
there is no currently maintained rpm for nix either. the rpm could be built from nixpkgs#nixStatic gotta bring it up with j0rge. I think he would be there to respond quickly because devs don't sleep
tulip
tulip4mo ago
@bketelsen i know this doenst make much sense to do right now, but whenever we build the bext website, this would be super awesome as an element to represent bext (like in place of a logo or something like that) https://ui.aceternity.com/components/evervault-card -> we could write like "bext" in the middle and it would look so awesome
Evervault Card
A cool card with amazing hover effect, reveals encrypted text and a mixed gradient.
tulip
tulip4mo ago
just writing this down so that i wont forget about this
bketelsen
bketelsen4mo ago
neat!
tulip
tulip4mo ago
BRIAN BRIAN OMG I JUST REMEMBERED SOMETHING VERY COOL we can make integration tests with nixos vms like, since we already have a nix package for bext, we can build testing through nixos testing frameworks that people use on nixpkgs
tulip
tulip4mo ago
GitHub
nixpkgs/nixos/tests/podman/default.nix at master · NixOS/nixpkgs
Nix Packages collection & NixOS. Contribute to NixOS/nixpkgs development by creating an account on GitHub.
tulip
tulip4mo ago
@bketelsen
bketelsen
bketelsen4mo ago
i'm not a nix n00b, and it still hurts my head when I look at this tuff
tulip
tulip4mo ago
i mean its really not that hard tho! ive written some on a personal project of mine
tulip
tulip4mo ago
GitHub
GitHub - tulilirockz/clonix: Declaratively manage rsync deployments...
Declaratively manage rsync deployments in NixOS/Home-manager - tulilirockz/clonix