beta-tester / RPi-PXE-Server

setup a Raspberry Pi as an PXE-Server
307 stars 63 forks source link

install-pxe-server_pass2.sh -- unlikely, but possibility of deleting / recursively, as root! #36

Closed jake5253 closed 3 years ago

jake5253 commented 3 years ago

https://github.com/beta-tester/RPi-PXE-Server/blob/9d15bd097ed724d54bb84d31167fa8f76b3f2293/install-pxe-server_pass2.sh#L650 https://github.com/beta-tester/RPi-PXE-Server/blob/9d15bd097ed724d54bb84d31167fa8f76b3f2293/install-pxe-server_pass2.sh#L755 https://github.com/beta-tester/RPi-PXE-Server/blob/9d15bd097ed724d54bb84d31167fa8f76b3f2293/install-pxe-server_pass2.sh#L915 https://github.com/beta-tester/RPi-PXE-Server/blob/9d15bd097ed724d54bb84d31167fa8f76b3f2293/install-pxe-server_pass2.sh#L922 https://github.com/beta-tester/RPi-PXE-Server/blob/9d15bd097ed724d54bb84d31167fa8f76b3f2293/install-pxe-server_pass2.sh#L966 https://github.com/beta-tester/RPi-PXE-Server/blob/9d15bd097ed724d54bb84d31167fa8f76b3f2293/install-pxe-server_pass2.sh#L968

If, by some unfortunate miracle of chance, $DST_NFS_ETH0 were to become unset, these lines (particularly 650 and 755) could erase someones entire system, including any and all attached media, possibly even mounted network shares. Worse yet, this script is being run as root. I see there is a check to make sure _unhandle_iso and _unhandlekernel is not called with a blank $1, but theres still a chance someone could pass a character that does not resolve to $1_ == __, but overall would still resolve to sudo rm -rf /.

For example, calling _unhandle_kernel * would end up as rm -rf /* and passes the check.

Should change to: sudo rm -rf $DST_NFS_ETH0:?

I realize this is an extremely unlikely chance, but never underestimate people's ability to shoot themself in the foot and claim it was your fault because you let them chew bubblegum that one day back in '88.

beta-tester commented 3 years ago

thank you for your hint.

you mean ... sudo rm -rf "${DST_NFS_ETH0:?}/${NAME:?}"; and sudo rm -rf "${DST_BOOT:?}"/*; and sudo rm -rf "${DST_NFS_ROOT:?}"/;

i would do a dump bulk replacing of all $VAR to "${VAR:?}" everywhere in my script, not only for rm. bulk replacing would be the quickest way to me to cover the command rm and maybe other commands with dangerous side effects. performance drops og my script, because of the extra conditions, does not matter i think. and with quotes around the variables, i would cover *, coming from the variables... but there are still possibilities to run into dangerous situations when variables contains ..

jake5253 commented 3 years ago

Sorry that is what I meant. It was getting late and I'd been staring at screens too long at that point last night.

I think the lines I listed are the only ones that contained -rf. Without the recursion, I wouldn't worry much about it. Someone could lose a handful of documents or photos of their dogs wedding, sure, that would be unfortunate, but it's not as bad as wiping your drive plus writable mounted shares. Lines 755 and 650 are straight-shots. The others would require someone to be trying to maliciously attack a system. The DST_BOOT was a variable merged with a coded "-boot" so even passing it tricky characters, it would end up trying to delete something like /-boot. And the others, the function would never get to rm -rf /, there would be other errors before that point, if I remember correctly.

beta-tester commented 3 years ago

at the moment i did only a dump replacement for the variables from $VAR to "${VAR:?}". there are now test for unset variables i hope it will be catched early before it goes evil.

jake5253 commented 3 years ago

I was trying to think of a solution, ideally, SELinux contexts would be about the best unfortunately Raspbian has no plans to implement it by default, last time I looked into it. Aside from that, the next best solution might be creating a group "pxe" or similar, who has wrx permission granted only for pxe files, and the ability to mount/dismount ISOs. Elevation to sudo would only need to be done for initial setup. That would prevent the accidentally nuking of important things. Caveat being adding checks to make sure they've executed scripts as that user, but I suppose a function to do that could be implemented, and/or a function that causes an immediate bail-out if select variables aren't set.

I'm just not sure what would be most effective, or easiest to implement. I'll keep thinking and I'll let you know if I come up with anything good. I need to push to my fork, I've been tweaking a lot of things on a local branch. Perhaps I'll branch again and try implementing the above ideas.

beta-tester commented 3 years ago

in the last commit i changed alot. also the p2-include-handle.sh is now totally in-compatible with the previous version. but it looks much cleaner now to me.

jake5253 commented 3 years ago

Cool! I'll check it out later today when I return to my workstation.

Unrelated almost entirely, I'm curious what version(s) RPi do you use? I have a 2B which recently has a constant lightning bolt in the top right corner. Everything I've found on the Raspbian forums say it's starving for power, but according to my USB tester, even under full load it's only using about 1.3amps to 1.5amp when connected to a 3amp source, and voltage stays perfectly steady at 5.16v. It seems that when it detects an "under-powered" state, it enables cpu throttling which results in I/O throttling, and even ethernet throttling. I was curious if you've ever run into any false power detections/false reporting events?I'm thinking it might be time to get one of those pretty new 8gb pi 4's.

beta-tester commented 3 years ago

i have now a RPi4B with 4GB. before i was running my project on my RPi3B+, RPi3B, RPi2B. i am not sure if i was running it on my RPi1B as well. when came the RPi2 across - when i started my RPiPXE-Server project?

i am very happy with the RPi4 with its "real" built-in 1Gb/s ethernet interface - still not as good performance as a real PC network interface but way better than all RPi's before. i have it running mostely permanently 24/7 attached to my TV, to surf in the internet and test things when ever i want, without having to boot up my loud and slow starting heavy PCs.

the only thing with the RPi4 i don't understand is the SWAP file usage. i mean the RPi4 has plenty of RAM but in some situations the swap runs quickly up to 100% swap usage but the RAM is not fully used, mostely 2/3'th was free at those situations. no reason to fill up the swap at all...

i changed the swap settings from the default 100MB to 256MB, i tried to change the stress parameters to keep things in RAM as long as possible, nothing helped. when the swap runs full and keeps that full for ever, it happens, that the user interface get non-responsive or it kiils its process and you are logged off from the graphical user interface. so i came up with cleaning the swap from time to time, when i see it is running full.

cleaning the swap:

sync ; \
sudo systemctl restart dphys-swapfile.service ; \
sudo sysctl -w vm.drop_caches=1 ;

collect information of swap/memory usage befor cleaning the swap:

sudo cat /proc/sys/vm/stat_refresh /proc/meminfo ; \
sudo free -wlt ; \
sudo vmstat -awtn ; \
sudo vmstat -awtnm ; \
sudo vmstat -awtnd ; \
sudo top -b -n 1 -w 512 ; \
sudo sysctl -a | grep ^vm. ;

... i could not identify a process that caused the swap using.

i only know that it must be related with network processes. i have conky running, what displays me the memory and swap usage. the swap starts running full, when i transfer lots of data with samba. then i do parallel other data transfere e.g. pxe boot PCs, then the swap runs full even quicker.

do i need SWAP on RPi4 with 4GB?

oh, and the other annoing thing with the RPi4 is the huge heat generation and poor head dissipation, do not buy the old closed standard plastic case for the RPi4. buy one with built-in (passive) heat sinking functionality

beta-tester commented 3 years ago

i spyed to your fork of the project. i like the split of for the customization and the descriptions in there. can i copy that to my project?

jake5253 commented 3 years ago

Yeah, absolutely! I haven't pushed my most recent changes yet; I'm still working out some bugs caused by 3am-sleep-deprived coding errors, but I will push it through soon. You're welcome to use the current stuff though -- I don't think I changed much of anything between what's on my fork vs my local working directory. Do note, however, that the "is_local" (ISOs that are already on the system, but not originally downloaded by this) only handle_iso is implemented at this time. handle_kernel and handle_zip weren't needed when I added it to handle_iso so I didn't continue adding it. Also, if you see anything that could/should be fixed, by all means do so. This is by far the most Bash I've ever worked with so I'm sure some of my methods and (dis)logic are less-than-ideal or perhaps just plain wrong.

That swap usage sounds weird to me. I only have RPi 2B so 1GB of RAM. Currently, I'm using almost no physical memory and my swap file is empty:

pi@raspberrypi:~ $ free
              total        used        free      shared  buff/cache   available
Mem:         946400       51332      725744       12684      169324      827816
Swap:        102396           0      102396

I have recently restarted it (last night sometime) but I think i have not run any network intensive programs since then. You could, just to test it, do swapoff -a and see if you run into any out-of-memory problems. Alternatively, but perhaps a bit drastic would be to install a different kernel. rpi-update will grab 5.10.x (maybe 5.11 now?) sources from their repo and build a fresh bleeding edge kernel.
I'm currently using a bleeding edge with no additional problems. I upgraded from the "stock" kernel to this trying to see if that would solve my "undervoltage" problem... no effect. My current kernel reports:

Linux raspberrypi 5.10.10-v7+ #1397 SMP Mon Jan 25 18:38:45 GMT 2021 armv7l GNU/Linux
beta-tester commented 3 years ago

ok, i pushed a new commit with renaming and splitting scripts. and adding custom scripts with some of the templates / descriptions you made.

now there is a run.sh script that automatically switches to the different passes (install, setup, update). only the run.sh can be executed directly.

EDIT: when you run the script on a systen, where you already have installed a previous version of PXE server, you should run: bash run.sh update otherwise it will try to start with install all the packages again, because it assumes it is a clean system, when there is no .run_last file exist in the script folder with the last action in it,

jake5253 commented 3 years ago

Awesome! To further push the "runnables" vs "don't run this directly" scripts, leave the ones meant to be executed as .sh and change the others to no extension, or .inc for includes, or something like that. It could automatically detect if it's fresh or an update by checking what pkgs are installed. It's probably safe enough to assume that if, for instance, dnsmasq and/or nfs-kernel-server isn't installed that it's fresh.

Looking great!! I see you added ipxe's additional DHCP options in dnsmasq Added hostapd, too?! Nice!

beta-tester commented 3 years ago

i keeped the extension .sh, to have syntax highlighting in the editor... but yes, an other extension of those scripts would people stop from trying executing them directly. EDIT: i just realized, that my editor is smart enough to show script highlighting even the file has no extension.

no, hostapd is not executed in the master branch. hostapd found its way to master to make maintaining master and testing branch bit easier to me. it will not add the package for it in the master branch. i have no strategy what i will do with it in the master branch.

ipxe is only a simple menu i greated and found good enough for people who want to play with it. but its menu is fixed - it does not follow dynamically the installed images like the lpxelinux menu and i added only the most important images to it..

for some reason the ipxe of VirtualBox is not able to boot the images, but i can chainload the actual ipxe bootloader.

ipxe has the big downside that it currently has not been signed for UEFI + SebureBoot. as soon they publish a signed ipxe bootloader i maybe will switch to ipxe completely and drop lpxelinux... but i don't see this happen in the next 1-2 years...

beta-tester commented 3 years ago

ok, i think i am done for the moment - all changes implemented, i want wanted to implement for now. my last commit added chainloading iPXE from within PXE-Linux menu (for that i had to disable graphical userinterface and enabled text mode menu) i will close this issue. thank you for the kick in my ass ;-)