Linux kernel that runs python file for init - linux

Would it be possible and not incredibly difficult to build a linux kernel, with a python interpreter built in or accessible from the kernel, that could run a python file as it's init process?

Can't you just replace /sbin/init or provide an init=... option to the boot loader? Just make sure you put python + libs on the root filesystem.
edit I didn't feel like thrashing a system, so it is untested, but looking at linux/init/main.c:
static void run_init_process(char *init_filename)
{
argv_init[0] = init_filename;
kernel_execve(init_filename, argv_init, envp_init);
}
I see no reason why a (python) script cannot replace the init process; execve is the same call that fires any normal process. And I think stdin and stdout are just connected to /dev/console, for init=/bin/sh also works. (but why on earth would you?!)

I don't think init needs to be a C binary; it can be a script with a #! at the beginning; if that is the case, then you can have it be a python program with little effort.
Having said that, it is pretty trivial to write an inittab where init just runs a single program once (Although it's usually more useful to do other stuff too).
Given that you will probably want to do some things on your system which can't easily be done with python (for example, try mounting filesystems without a "mount" binary), you will probably need a busybox (for example) anyway; adding "init" to a busybox binary increases its size very little.

Related

determine how a linux process was invoked

Is there a way in linux, to determine how a process was invoked?
I know, that ps displays the startup parameters, but I'm interested how the process start was executed.
Was it a init.d script, a cron job or manual invocation via cli.
Right now I am looking through all configs/commands manually, is there an easy way I am overlooking?
(I also know, that the presence of systemd etc. is distro related which helps to priorize a little bit.)
In most cases, for a process of pid 1234, you can get valuable information about it thru /proc/1234/ (see proc(5) for details)
See also credentials(7) and Advanced Linux Programming and Linux From Scratch
For exemple, try ps $$ then cat /proc/$$/status then cat /proc/$$/maps then cat /proc/$$/comm in your terminal (running probably the GNU bash shell, or zsh)
Consider writing your C program doing appropriate syscalls(2) (with perhaps opendir(3) and readdir(3)...) to query that information from /proc/ ....
Remember to read errno(3). A lot of functions (like open(2), read(2), getpwnam(3) ....) can fail.
Download, then study for inspiration the source code of the GNU bash shell (or even of the Linux kernel), it is free software.

How do I determine the commands being issued when I use a GUI?

I am working on a Linux machine (running openSUSE 13.1 w/ KDE, specifically) and I would like to determine what commands are actually being issued in the background when I do something with an application's GUI.
My question is very similar to the following one which has received no answer:
https://stackoverflow.com/questions/20930239/how-can-i-see-the-commands-being-passed-in-backend-of-a-gui-application
If it helps at all, the specific task I am trying to accomplish is figuring out what the command line-equivalent is for sending a file to the Trash in KDE's Dolphin utility. I would like to make an alias for this functionality in my .bashrc so that I have a "gentler" alternative to rm. But I would rather know the answer to my more general question so that I can do similar things in the future.
My naive guess was that a log file might exist somewhere. Then I could do a task with a GUI and just tail that log file afterward to see what the underlying commands were for what I just did in the GUI. As far as I can tell, however, no such log exists.
To move a file foo to your trash bin, try
mv foo $HOME/Trash/
so you could make that a shell function in your .bashrc
function movetotrash() {
mv $* $HOME/Trash/
}
AFAIK, most GUI applications don't have log files. They are generally free software (and using free software libraries), so you could study their source code and improve it. Try to interact with their communities (and use strace as I commented)
BTW, not every GUI application is using commands. Some are (e.g. IDE are indeed forking commands like gcc) but others just do directly syscalls (probably a file manager won't fork an mv but just would copy contents or call the rename(2) syscall).

TCL, Linux, and FLOCK

So I am working with a program written in TCL that uses the FLOCK function to lock files. I am testing it on a newer version of Linux than the one it currently runs on and I found that when the newer machine runs the script, it uses FLOCK from /usr/bin/flock, which differs from the TCL version of FLOCK. The TCL version uses -read -write and such, while the Linux version uses completely different options.
In short, the program stops working and errors out when it gets to any FLOCK call. If I change the options to fit the Linux version, it breaks the program on the other machines.
Is there a way to make it use the TCL version as opposed to the Linux one?
Tcl itself does not come with a flock command, though you might be seeing it automatically trying to use the system command if you're testing interactively. Such automated use of system commands is not done in scripts (that would be hellishly prone to instability due to varying PATHs) so when writing a script you should be explicit as to what you mean.
If you want to use the system command (itself non-portable, especially to non-Linux systems) then just do:
exec flock $options...
Be aware that Tcl uses a different form of argument quoting to the shell. This can sometimes catch people out when writing exec calls.
Alternatively, use the flock Tcl command that is in the TclX package. The syntax is a little different to that of the Linux system utility, in large part because it's a bit lower-level. In its favor, it is rather more portable.

trigger alert when a specified command executes in linux

I have 3 samba shares mounted in my system, but suddenly, one of them gets umounted without my permision. Maybe one of houndreds of scripts which run in my crontab, but i dont know which one.
I've reviewed all /var/log directory looking for umount word without success, then i want to log when command umount is executed and which process is running it.
Maybe with syslog, maybe with another log, maybe a mail to my box....
Thanks a lot.
I have this software:
mount: mount-2.12q
mount.cifs version: 1.14-3.5.4
Unmounting does not only happen by calling the umount binary, many programs might do it. See the manual page (man syscalls) and search for umount. This said, you would have to hook the corresponding syscall and see who invokes it. I'm not sure, but most probably it's possible to disconnect inside the kernel by calling the corresponding method directly, so functionality might bypass the syscall interface which is mainly required for userspace interaction. In this case you would have to use some debugging technique on the kernel itself, which maybe is a little much for finding your problem!
You may have success using strace on an already running process (man strace), for example smbd, and see if this process invokes umount, which is quite possible.
Anyways, if you can recompile your kernel from source, you might add some printk message inside the function that is used to unmount a device to see which process did it (this would be my approach for cases where nothing else, including strace, helps).
Since the mount is a change in the filesystem, maybe the inode-observer incron is a solution for you. Another option might be the auditd.

Is there a way to change the environment variables of another process in Unix?

On Unix, is there any way that one process can change another's environment variables (assuming they're all being run by the same user)? A general solution would be best, but if not, what about the specific case where one is a child of the other?
Edit: How about via gdb?
Via gdb:
(gdb) attach process_id
(gdb) call putenv ("env_var_name=env_var_value")
(gdb) detach
This is quite a nasty hack and should only be done in the context of a debugging scenario, of course.
You probably can do it technically (see other answers), but it might not help you.
Most programs will expect that env vars cannot be changed from the outside after startup, hence most will probably just read the vars they are interested in at startup and initialize based on that. So changing them afterwards will not make a difference, since the program will never re-read them.
If you posted this as a concrete problem, you should probably take a different approach. If it was just out of curiosity: Nice question :-).
Substantially, no. If you had sufficient privileges (root, or thereabouts) and poked around /dev/kmem (kernel memory), and you made changes to the process's environment, and if the process actually re-referenced the environment variable afterwards (that is, the process had not already taken a copy of the env var and was not using just that copy), then maybe, if you were lucky and clever, and the wind was blowing in the right direction, and the phase of the moon was correct, perhaps, you might achieve something.
Quoting Jerry Peek:
You can't teach an old dog new tricks.
The only thing you can do is to change the environment variable of the child process before starting it: it gets the copy of the parent environment, sorry.
See http://www.unix.com.ua/orelly/unix/upt/ch06_02.htm for details.
Just a comment on the answer about using /proc. Under linux /proc is supported but, it does not work, you cannot change the /proc/${pid}/environ file, even if you are root: it is absolutely read-only.
I could think of the rather contrived way to do that, and it will not work for arbitrary processes.
Suppose that you write your own shared library which implements 'char *getenv'. Then, you set up 'LD_PRELOAD' or 'LD_LIBRARY_PATH' env. vars so that both your processes are run with your shared library preloaded.
This way, you will essentially have a control over the code of the 'getenv' function. Then, you could do all sorts of nasty tricks. Your 'getenv' could consult external config file or SHM segment for alternate values of env vars. Or you could do regexp search/replace on the requested values. Or ...
I can't think of an easy way to do that for arbitrary running processes (even if you are root), short of rewriting dynamic linker (ld-linux.so).
Or get your process to update a config file for the new process and then either:
perform a kill -HUP on the new process to reread the updated config file, or
have the process check the config file for updates every now and then. If changes are found, then reread the config file.
It seems that putenv doesn't work now, but setenv does.
I was testing the accepted answer while trying to set the variable in the current shell with no success
$] sudo gdb -p $$
(gdb) call putenv("TEST=1234")
$1 = 0
(gdb) call (char*) getenv("TEST")
$2 = 0x0
(gdb) detach
(gdb) quit
$] echo "TEST=$TEST"
TEST=
and the variant how it works:
$] sudo gdb -p $$
(gdb) call (int) setenv("TEST", "1234", 1)
$1 = 0
(gdb) call (char*) getenv("TEST")
$2 = 0x55f19ff5edc0 "1234"
(gdb) detach
(gdb) quit
$] echo "TEST=$TEST"
TEST=1234
Not as far as I know. Really you're trying to communicate from one process to another which calls for one of the IPC methods (shared memory, semaphores, sockets, etc.). Having received data by one of these methods you could then set environment variables or perform other actions more directly.
If your unix supports the /proc filesystem, then it's trivial to READ the env - you can read the environment, commandline, and many other attributes of any process you own that way. Changing it... Well, I can think of a way, but it's a BAD idea.
The more general case... I don't know, but I doubt there's a portable answer.
(Edited: my original answer assumed the OP wanted to READ the env, not change it)
UNIX is full of Inter-process communication. Check if your target instance has some. Dbus is becoming a standard in "desktop" IPC.
I change environment variables inside of Awesome window manager using awesome-client with is a Dbus "sender" of lua code.
Not a direct answer but... Raymond Chen had a [Windows-based] rationale around this only the other day :-
... Although there are certainly unsupported ways of doing it or ways that work with the assistance of a debugger, there’s nothing that is supported for programmatic access to another process’s command line, at least nothing provided by the kernel. ...
That there isn’t is a consequence of the principle of not keeping track of information which you don’t need. The kernel has no need to obtain the command line of another process. It takes the command line passed to the CreateProcess function and copies it into the address space of the process being launched, in a location where the GetCommandLine function can retrieve it. Once the process can access its own command line, the kernel’s responsibilities are done.
Since the command line is copied into the process’s address space, the process might even write to the memory that holds the command line and modify it. If that happens, then the original command line is lost forever; the only known copy got overwritten.
In other words, any such kernel facilities would be
difficult to implement
potentially a security concern
However the most likely reason is simply that there's limited use cases for such a facility.
Yes, you can, but it doesn't make sense. To do that you should invade into a running process and change its memory.
Environment variables are the part of the running process, that also means env vars are copied and stored to the memory of a process when it started, and only the process itself owns it.
If you change evn vars when the process is trying to read them it could be corrupted, but you still can change them if you attach a debugger to the process, because it has access to the memory of the attached process.

Resources