Hello OpenBSD developers!

I have a suggestion on how to get the current executable path in OpenBSD that 
might be reliable enough and not too costly that it might be accepted for a 
future OpenBSD version.

Even if it won't be accepted, I need a little help completing the solution I 
have in mind.

The current solution relies on $PWD, $PATH, and argv[0] to guess the 
most-likely executable path if $PWD, $PATH, or arv[0] were not modified from 
their original values.

The code that does this i originally wrote in C++, I found someone else wrote a 
C solution which does the same thing, and I helped them by adding the $PWD code 
logic as a replacement for the cwd.

The code is here:
https://github.com/time-killer-games/getexecname/blob/patch-1/getexecname.c

Due to the use of realpath() if the exe is not found, an empty string or NULL 
can be returned. However, I want to take it a step further in terms of error 
codes if an existing executable is in fact found, though it does not point to 
the same executable that actually spawned the current process. For example: 
Running firefox but argv[0] was modified to look like it was actually chromium 
that was running when it isn't chromium. Just an example of that.

This doesn't solve the issue of multiple hard links to the executable, which is 
unlikely to happen enough I'm not worried about it all that much. Maybe an 
error code could be done in the case of multiple executable hard links which 
the number of hard links could be retrieved from the stat structure. Which 
leads to how my other error codes will be returned:

Here's my thoughts on the matter as discussed on implementing this feature for 
the OpenBSD version of the fish shell:


The issue: linking errors and not knowing what libraries to link (documentation 
on the function I use seem incomplete):
https://github.com/fish-shell/fish-shell/issues/9086#issuecomment-1194464329

"I've come up with a means to get a proper error code if the executable path 
returns a path to the wrong file. Basically if meams getting the vnode from the 
current process id, get the stat struct from the vnode, the compare a few stat 
structure members with the stat structure returned by opening the path the 
function guessed points to the current executable. It involves working with a 
lot of kernel functions which do have documentation but for one reason or 
another I can't get any of it to compile because linking errors, and the docs 
don't say anything about what libraries I should be linking to. It will take a 
while, but this is a lot better."

The implementation I am using explained, which is currently incomplete:
https://github.com/fish-shell/fish-shell/issues/9086#issuecomment-1194504685

Note: This code won't be implemented in fish shell as the idea was rejected by 
them, however I'd like to use this code for my own libraries once it is 
finished.

"To expand on my previous comment, here's some general notes from my research 
yesterday.

<snip>

To get the vnode from a process id, you must get the struct process * from the 
process id using the function struct process *prfind(pid_t) declared in 
sys/proc.h. Then from that struct process * there is the member of the struct 
called struct vnode *ps_textvp which according to the code comment and other 
research is in fact the struct vnode * of the process's executable file. The 
struct process * structure is defined in sys/proc.h. The _KERNEL and 
__need_process macros need to be defined before including the sys/proc.h header 
otherwise the struct process * will not be defined. Defining _KERNEL before 
including sys/proc.h must be done, however it breaks my code if I define that 
macro before including sys/vnode.h, which is required for the int 
VOP_GETATTR(struct vnode *, struct vattr *, struct ucred *, struct proc *) 
function among other things we need, like the struct vattr * structure, which 
holds the information necessary to get a proper struct stat * from the struct 
vnode *. To actually get the struct stat * from the struct vnode *, we call int 
vn_stat(struct vnode *, struct stat *, struct proc *) which also relies on 
another structure we need to magically get from the current process id, struct 
proc *. I'm not sure if that parameter can be null or not, or if that would 
cause issues. MAXCPUS is a macro which needs to be defined, and I'm not sure 
what header is the right one to include for it, but it depends on the 
architecture when done incorrectly because each architecture of binary has its 
own definition of its macro in a different folder in the source tree named 
after the architecture. For example, if you are building for amd64, it will be 
in a folder named amd64, etc. Despute having all the right includes and 
defining that MAXCPUS macro on my own as 64, it still gives me undefined 
references when building. According to the multiple sources I've found, 
comparing the ino_t, dev_t, (and possible filesize, modified timestamp) members 
of struct stat is good enough to know it is the correct file on the file 
system, the only issue one would run into is hard links of the executable, 
which have wrong locations, though it would be very unlikely to return them 
from the current argv[0]."

My question is, what linker flags for which libraries do I need, and how do I 
get the struct proc * structure from the current process id? Are these things 
even needed to do what I'm after, or is does the issue lie elsewhere?

Thank you so very much!!
Samuel
  • [no subject] Samuel Venable
    • Re: Theo de Raadt
    • Re: Stuart Henderson
      • Re: Samuel Venable

Reply via email to