I'm having trouble running some C code before launching an app from Spotlight or the Applications folder. I figured I should just be able to create an executable with my code where after all the computations are done I make a execvp() call to run the original app's executable, which will then replace the current process.
I compiled the .c file and gave it the original app's executable name (in my case clion) and then executed it from Terminal.. great, it works!.. Until I tried to open the app bundle from spotlight (or Finder)
For some reason the execvp() call fails and the original program continues, but my custom executable is indeed called by spotlight! Not even making a child process with fork() will work, neither a system() call. What could be the problem here?
Contents folder of CLion: clion is my executable, clion-real is the original executable
-rwxr-xr-x 1 marc admin 8700 22 Mai 10:35 clion
-rw-r--r-- 1 marc admin 550 22 Mai 10:35 clion-fake.c
-rwxr-xr-x# 1 marc admin 128353 21 Mai 12:56 clion-real
clion-fake.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char** argv) {
system("say 'called'");
char* args[] = {"./clion-real", NULL};
int status = execvp(args[0], args);
system("say 'failed'");
return 0;
}
When calling ./clion from terminal it works as intended, the system says called and the app opens, but when opening the .app from Spotlight it says both called and failed, which means that the execvp() call failed.
Errno 2 is ENOENT, aka "no such file or directory".
You need to make sure that the current working directoy for the execution of your clion binary is actually set to the directory where your binaries live in, otherwise relative paths like ./clion-real won't work.
Related
I am trying to debug a C program using GDB. But when I try to run it from inside gdb I get the following error :
note: the FATAL error line is user defined
gdb-peda$ run
Starting program: /home/masterdungeon/HTAOEBookPrograms/0x200/0x280/0x287/GameOfChance
**************** WELCOME to the GAME OF CHANCE *****************
This game will essentially tell you how lucky you are today ;)
---- New player ----
Please enter your name : user_gdb
[!!!] Fatal Error in register_user() while opening DATAFILE
: Permission denied
[Inferior 1 (process 10636) exited with code 0377]
Warning: not running
gdb-peda$
This program is actually a command line game named "GameOfChance" (from the book HTAOE). Whenever a user runs the program, the program first checks its UserID to see whether the user is already registered as a player in the DATAFILE. If there is no entry of that UID in the DATAFILE(i.e player not registered already), then the program allows to create a new player and accept a username, thus registering as a player with that UID and accepted username. But I think GDB does not have a UID since there is no entry of gdb in /etc/passwd. How do I make the program run while debugging and register GDB as a new player? Is it even possible ?
The code looks like this :
12 #define DATAFILE "/var/gameofchance.data" // File to store user data
46 int main(){
//lines of code
53 uid = getuid(); // get current user_id i.e player_id
54 player_exists = get_player_data(uid); // returns -1 if player does not exist
55 //otherwise returns 0 and puts all player data into struct player
56
57 if(player_exists == -1) {
58 register_player(uid);
59 }
//lines of code
148 return 0;
149 } //end main()
314 void register_player(int uid){
//lines of code
327 fd = open(DATAFILE, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR);
329
330 if(fd==-1){
331 fatal(" in register_user() while opening DATAFILE\n");
332 }
//lines of code
344 } //end register_player
the permissions for DATAFILE are :
-rw------- 1 root masterdungeon 240 Apr 19 13:54 gameofchance.data
the permissions for executable game GameOfChance are :
-rwsrwxr-x 1 root root 29064 Jan 4 19:45 GameOfChance
Another thing I couldn't understand is when I set a breakpoint at line 54 and check for value of uid I get 1000 as UID of GDB.
Breakpoint 16, main () at gameofchance.c:54
54 player_exists = get_player_data(uid); // returns -1 if player does not exist
gdb-peda$ x/wd &uid
0x7ffd4ed4aee8: 1000
How's it possible that GDB has userid of 1000 ? as there is no entry of gdb in /etc/passwd. 1000 is userid of masterdungeon.
Okay so it works when gdb is run using sudo gdb. But why do I have to run it as root to get it run nicely in GDB ?
Otherwise in BASH the program runs successfully as user masterdungeon. Only in GDB it require to be run as root
Does GDB have a userid?
Yes. Every process that runs, including GDB processes, has both an effective UID and a real UID. Often these are the same. But you seem to have a misunderstanding. These do not describe the process itself. Rather they describe the user on whose behalf the process is running.
How's it possible that GDB has userid of 1000 ? as there is no entry of gdb in /etc/passwd. 1000 is userid of masterdungeon.
Because you're running gdb as user "masterdungeon", or as another user with the same UID number.
Okay so it works when gdb is run using sudo gdb. But why do I have to run it as root to get it run nicely in GDB ?
Your data file is accessible only to root:
-rw------- 1 root masterdungeon 240 Apr 19 13:54 gameofchance.data
. When run directly, the program accommodates that by being root-owned and having its SUID bit set:
-rwsrwxr-x 1 root root 29064 Jan 4 19:45 GameOfChance
(note the "s" in the first triad of permission bits). That causes the program, when run directly, to run with the effective UID of root, even though root did not actually launch it. This is one of the cases where the effective and real UIDs differ. It is also a very poor use case for SUID, because SUID root programs present an existential security risk to the host system, and that risk is not justified for a game.
The risk would be much worse if the SUID bit were honored when the program is running under control of a debugger. A debugger can make arbitrary changes to program data and even binary code while the program is running, and that would present an easy vector for privilege escalation if SUID were honored in such contexts. Accordingly, the SUID bit on an executable has no effect when the program is run in a debugger. (See also Can gdb debug suid root programs?)
Thus, if you debug the program as a user other than root, it will not be able to open the data file, but if you use sudo to run the debugger then you obtain the needed privelege to access the data file through sudo, and the fact that the SUID bit on the executable is not honored is irrelevant.
The best way to debug the program is in its build environment, before installation, such that it is owned by you and does not need (or have) its SUID bit set. This may require some manipulation of where or how it looks for its data file, which should also be owned by you.
As for how the program is installed, you have a tension between priorities:
Programs available for all users to run should be owned by root and writable only by root, to make it difficult for other users to modify them or substitute different program for them, both of which could lead to data breach and (further) privilege escalation.
You apparently require that users running the game program be able to write to a shared data file. It's unclear what this file contains, but a shared high score list might be an example.
But you do not (presumably) want to allow users to manipulate the data file arbitrarily, under their own authority, lest they cheat in some way, or worse.
The easiest approach would be to give each user their own, unshared data file, created at need by the program within the user's home directory, and accessible to that user. Then you don't need to mess with SUID / SGID, nor do you need to have any concern about users interfering with each other. Sure, they may be able to cheat, but it will affect only them. And you will be able to debug the program with GDB.
If it is essential that the data file be both shared among program users and writable (via the program) to all of them, then a better approach than making the program SUID-root would be to make it SGID-some_group_not_root, and make the data file writable by that group. Better still, avoid the SGID bit, and just require users to be members of the chosen group in order to use the program. Do note that SGID is not honored when debugging, either.
This is a repost after being referred to "Calling a script from a setuid root C program - script does not run as root" for a solution
My problem is different in that I do not want to run the C program (and c-shell script called inside) as root. Rather, I want to run as the owner of the c program file.
Also, I tried with "setuid(0)" as this was the solution in the referenced post. This is reflected in the edited code below. Same results.
Also, I opened permissions up all the way this time with "chmod 7775" (just in case it was a permissions problem)
Here's the original note with edits to reflect the change to "setuid(0)"
I'm having a problem implementing an simple example that would demonstrate how setuid can be made to run a binary with the uid of the file owner of the binary. What I would eventually like to do is run a c-shell script using this technique.
I read that this will not work for shell scripts but also heard of a work-around using a C program to run a system() call that'll run the c-shell script ( e.g. system("source my.csh") ). I wrote a C program that attempts this, plus simply reports the current uid. This is what I tried...
From my current shell, I did a "su katman" to become the user of the binary I want to run as user katman.
I created a C program try.c. ...
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
setuid(0);
printf("In try.c ... sourcing katwhoami.csh...\n");
system( "source /home/me/su_experiments/katwhoami.csh");
printf("In try.c ... using straight system call...\n");
system("whoami");
return 0;
}
I "setuid(0)" as recommended by a reference to a different note. But earlier, I tried setting it to the uid of the C program's owner as obtained with "id -u".
The katwhoami.csh shell script is simply...
date
echo "In katwhoami.csh, I am "`whoami`
echo "In katwhoami.csh, I am "$USER
exit
Then I compiled the C program and set the bit...
% gcc -o try try.c
% chmod 7775 try
% ls -l try
-rwsrwsr-x 1 katman design 6784 Mar 1 11:59 try
And then I test it...
% try
In try.c ... sourcing katwhoami.csh...
Thu Mar 1 12:28:28 EST 2018
In katwhoami.csh, I am ktadmin
In katwhoami.csh, I am ktadmin
In try.c ... using straight system call...
ktadmin
...which is what I expected.
I exit to get back to the shell I started from, hoping that if I run try there, it'll tell me I'm "katman"....
% exit
% whoami
daveg
% try
In try.c ... sourcing katwhoami.csh...
Thu Mar 1 12:30:04 EST 2018
In katwhoami.csh, I am daveg
In katwhoami.csh, I am daveg
In try.c ... using straight system call...
daveg
... which is not what I was hoping for :-(
As you can probably tell, I'm new at using this.
Any help would be appreciated !
Update....
I tried a new sample program, a.c...
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fh;
setuid(1234);
system("whoami");
fh=fopen("test.file","w");
fprintf(fh,"Here I am\n");
fclose(fh);
return 0;
}
I compiled and set the bit
gcc -o a a.c
chmod 4775 a
Then I exited the "su" and ran as a user that is NOT the owner of the binary. Same result as before with regard to reported uid (the current uid), BUT, the owner of the file that the C program created ion this version was the owner of the C program !!! So that worked.
Is there something fishy about the "whoami" command? system() call ?
If I do a "system("source some.csh") does it create a new shell which assumes the original uid (not the owner of the C binary) ? Something like that ?
I really need the new uid to "stick" as far as child processes.
I have this C file:
#include <stdio.h>
#include <unistd.h>
int main(void)
{
printf("%s\n", getlogin());
printf("%i\n", getuid());
}
I compile it, set the UID and GID both to root and set the setuid bit, so that it looks like this:
-rwsrwsr-x 1 root root 8735 Apr 8 19:51 a.out
However when I call $ ./a.out I still get:
user
1000
What am I doing wrong?
The real user ID is still the user that called the program, but the effective user ID is root. In a setuid program, they are not the same.
To get the effective user ID, call geteuid(). You can also use cuserid() to get the name associated with the effective user ID.
Your program has got only the permission to change its uid. To actually switch to root you have to call setuid(0) in it.
Please have a look here
... I'm new to C programming on Ubuntu, so please bear with me if i'm being too much of a noob.
I have a C file that when compiled, is allocated to a particular user (testUser) and is run as they log in as their shell. The user doesn't have sudo rights to the system in question. Basically this shell permits the user to update a file (/var/wwww/testfile) upon login and then reboots the system. Of course, it's the reboot which is giving me some issues, as they don't have superuser rights.
//file: testShell.c
#include <unistd.h>
//#include <linux/reboot.h>
int main(void)
{
execl("/usr/bin/nano", "nano", "/var/www/testfile", NULL);
execl("/usr/bin/shutdown", "shutdown", "-h 0", NULL);
//reboot(LINUX_REBOOT_CMD_RESTART);
return 0;
}
The file compiles just fine to testShell
I chown root:root testShell
Grant SetUID using chmod u+s testShell
Copy the file cp testShell /bin
Update the users account to use the shell chsh -s /bin/testShell testUser
I've read the man pages on shutdown and tried within the program itself using reboot (you can see in this particular version of the file, I've commented out the header file and call) but I still can't get this user to be able to reboot the system (Ubuntu 12.04 presently). I've even tried the "init 6" system call that was posted here, but all to no avail. I've also read that using the system() call isn't a particularly good idea: I've tried it none-the-less and still no joy.
It was my understanding that if I allocate the permissions correctly and then SetUID the file, anyone running that file would implicitly be running it under the owners rights, root in this case. In fact, the /var/www/testfile that the testUser is updating, is owned by root, so something's working correctly.
Any ideas where I'm going wrong?
It is really simple : you use directly execl to start nano and ... never return from it if it correctly works !
You should use a fork - exec- wait.
You will find a complete example on this other post from SO https://stackoverflow.com/a/19099707/3545273
How do I know the difference in the 'execution env' of a process in two different contexts?
To articulate the question properly, I have plan9port installed in /opt/plan9/ and when I run the fortune program from /opt/plan9/bin/fortune it works fine. (reads the list of fortunes from /opt/plan9/lib/fortune and /opt/plan9/lib/fortune.index ). When I call it from inside of a c code (test.c) with
char* opts[] = {"fortune"};
execve("/opt/plan9/bin/fortune", opts, NULL);
It doesn't read the fortune list. I used strace to see what is the difference when I call these two binaries.
strace -f -eopen ./test
open("/usr/local/plan9/lib/fortunes", O_RDONLY) = -1 ENOENT (No such file or directory)
Misfortune!
+++ exited with 1 +++
Gives out the default message "Misfortune".
strace -f -eopen fortune
open("/opt/plan9/lib/fortunes", O_RDONLY) = 3
Snob intellectual bachelors can't have fun in San Antonio. -Ted Nelson
+++ exited with 0 +++
which works perfectly fine.
How do I change ./test read fortunes file. It must have something to do with the exec environment, from where the binary reads the libraries from.
When you call execve(), you are explicitly setting up a NULL environment. So the fortune program is probably depending on some environment variable to find /opt/plan9/.... Type env at a shell prompt to find out which environment variables are set.