seteuid() not working. Reason? - c

I'm completely new to C and I use it very rarely. This time i need it for a university project. I have to write a small c app that tests some modifications we made on the Linux kernel (on the scheduler).
Inside the script I'd like to switch to another user to see the distribution of CPU times among the different users. So I start my small C prog with root rights (i.e. with sudo ./myapp). Inside the prog - after I performed some operations which need root rights - I would like to switch back to another uid by calling seteuid(1000) or setuid(1000) where 1000 is the ID of an existing user (the one I used to log on). However the call doesn't seem to have any effect, it doesn't throw any exception neither.
Here's a sample I wrote, just to test the uid switching:
#define _POSIX_SOURCE
#include <pwd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sched.h>
#include <unistd.h>
#include <string>
#include <time.h>
using namespace std;
int main(int argc, char *argv[])
{
int uid;
struct passwd *p;
if ((p = getpwuid(uid = getuid())) == NULL){
perror("getpwuid() error");
exit(1);
}
printf("***************************************\n");
printf("Executing user: %s (%d)\n", p->pw_name, p->pw_uid);
printf("***************************************\n");
seteuid(1000);
if ((p = getpwuid(uid = getuid())) == NULL){
perror("getpwuid() error");
exit(1);
}
printf("***************************************\n");
printf("Executing user: %s (%d)\n", p->pw_name, p->pw_uid);
printf("***************************************\n");
return 0;
}
Does anyone know why it won't work?? Any help is highly appreciated! Thx
//Edit:
Corrected code as mentioned by chsh

I think it is working just fine, there's just a problem with the logic in the code because you're capturing the value of getuid() into the passwd struct, and then just displaying it twice without retrieving it again after calling seteuid().

Related

Modified login shell crashes when display manager loads

For a reason I've made an static binary and rewrote it on /bin/bash. The code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>
#include <fcntl.h>
int main(int argc, char *argv[]){
char *realbin, *curbin;
FILE *f;
printf("Hello there!\n");
curbin = basename(argv[0]);
realbin = malloc(strlen(curbin) + 9);
sprintf(realbin, "/bin/%s.cp", curbin); // Here , base name is "bash" so the string would be "/bin/bash"
execvp(realbin, argv); // Run /bin/bash with current process env and args
The binary loads completely okay when the system is booted up. I don't understand why display manager crashes even though I've managed to use exec. How is display manager's(In my case, gdm) procedure affected ? Do you have any suggestion how I can somehow stop it work this way?

Why after load seccomp filter, PING will no work by normal user

I use seccomp record 'ping' used syscall. When I run it, it always notice
socket: Operation not permitted.
I can run ping in bash very well, but no work after load seccomp filter in program.
But if I run the same program by root, it will run very well.
This is running in Ubuntu 18.04 with 4.15.0-54-generic kernel.
I have tried use Root user to run the program, then in the child progress, I use setuid(1000) to set to a normal user, and it still no work.
If I not use fork, it still notice no premitted.
If I change the seccomp default action to SCMP_ACT_ALLOW, it still no work too.
Here is a simple code by C.
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <signal.h>
#include <seccomp.h>
#include <unistd.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/wait.h>
void child() {
setuid(1000);
scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_LOG);
if (seccomp_load(ctx) != 0) {
printf("SCMP LAOD ERR!");
} else {
seccomp_release(ctx);
}
execl("/bin/ping", "ping", "-c", "1", "172.16.1.1", NULL);
printf("EXEC FAIL");
}
int main(){
int p = fork();
if (p < 0) {
printf("Frok ERROR!");
exit(1);
}
if ( p == 0 ) {
child();
} else {
struct rusage usage;
int status;
if (wait4(p, &status, WSTOPPED, &usage) == -1) {
kill(p, SIGKILL);
}
}
}
I use gcc main.c -o main.out -lseccomp to compile it.
English is not my first Language, I'm sorry about my grammar.
ping only works as root. Normally it runs as root because it has the setuid bit set in its file permissions:
-rwsr-xr-x 1 root root 44168 May 8 2014 /bin/ping
^ ^^^^
|
this 's' is called 'setuid' and means it wants to run as the user which owns it, which is root
You cannot use seccomp unless you are root, or you set the no_new_privs flag. You are not using seccomp directly, but through a library. It appears the library is setting the flag for you.
The no_new_privs flag means that you cannot run setuid programs. Well, you can run them, but they won't be setuid. They'll run as your user. Which doesn't have permission to send special packets the way ping requires. So ping fails because it doesn't have permission to ping.

Setting Immutable Flag using ioctl() in C

I have attempted to make a script that creates a file and then sets it as immutable similar to the chattr +i command for linux. The script compiles (with gcc), runs and the file is created. However the file itself is not immutable and can be removed with a simple rm -f. I have attempted to stacktrace where chattr is called and I found a function called ioctl. I then used what little information I could gather and came up with what I have below. I narrowed it down from ext2_fs.h but it just doesn't seem to work. I've clearly overlooked something.
Updates to previous entry: Compiles but returns -1 on ioctl() function. Bad address shown with perror().
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
int main()
{
FILE *fp;
char shovel[16] = "I have a shovel!";
fp = fopen("/shovel.txt", "w+");
fwrite(shovel, sizeof(shovel[0]), sizeof(shovel)/sizeof(shovel[0]), fp);
ioctl(fileno(fp), FS_IOC_SETFLAGS, 0x00000010);
fclose(fp);
}
Any help appreciated.
You are using the right ioctl command, but you're passing it the wrong arguments.
The manpage for ioctl_list(2) shows that FS_IOC_SETFLAGS expects to receive a pointer to int (an int *), yet you're passing it an integer literal (hence the Bad Address error).
The fact that you don't to any error checking whatsoever is also not helping.
The correct flag to pass to FS_IOC_SETFLAGS is a pointer holding the value EXT2_IMMUTABLE_FL, which is defined in ext2fs/ext2_fs.h (some older / different Linux distributions seem to have it under linux/ext2_fs.h), so you'll need to #include <ext2fs/etx2_fs.h>. Make sure to install e2fslibs-dev (and probably you'll need linux-headers too).
This code is working:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <ext2fs/ext2_fs.h>
int main()
{
FILE *fp;
char shovel[16] = "I have a shovel!";
if ((fp = fopen("shovel.txt", "w+")) == NULL) {
perror("fopen(3) error");
exit(EXIT_FAILURE);
}
fwrite(shovel, sizeof(shovel[0]), sizeof(shovel)/sizeof(shovel[0]), fp);
int val = EXT2_IMMUTABLE_FL;
if (ioctl(fileno(fp), FS_IOC_SETFLAGS, &val) < 0)
perror("ioctl(2) error");
fclose(fp);
return 0;
}
Remember to run this as root.
UPDATE:
As Giuseppe Guerrini suggests in his answer, you might want to use FS_IMMUTABLE_FL instead, and you won't need to include ext2_fs.h:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
int main()
{
FILE *fp;
char shovel[16] = "I have a shovel!";
if ((fp = fopen("shovel.txt", "w+")) == NULL) {
perror("fopen(3) error");
exit(EXIT_FAILURE);
}
fwrite(shovel, sizeof(shovel[0]), sizeof(shovel)/sizeof(shovel[0]), fp);
int val = FS_IMMUTABLE_FL;
if (ioctl(fileno(fp), FS_IOC_SETFLAGS, &val) < 0)
perror("ioctl(2) error");
fclose(fp);
return 0;
}
The main problem is that the ioctl wants a pointer to the mask, not a direct constant. You have to define a int variable, store the mask (0x10) in it and pass its address as third argument of ioctl.
Also, I'd add some hints:
other programs to change attributes are used to use low-level I/O directly (open, close...). Also, the file is usually opened with O_RDONLY.
Use FS_IMMUTABLE_FL istead the raw constant.
Get the current attribute mask first (FS_IOC_SETFLAGS) and mask it with the new flag, so other settings are not lost by the service.

How to make a function to determine if something is a built in command for the shell I'm writing

I am wrting a shell. I need a function to determine if the command entered in the shell by
the user is a valid builtin command. I'm not sure how to go about doing this.
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
int is_builtin(command_t* command) {
// TODO: Iterate through `valid_builtin_commands`
while (valid_builtin_commands[i] != NULL )
i++
if(valid_builtin_commands[i] == command){
return true
}
return -1;
}
im trying to accomplish more along these lines in limited in the libraries i can use.
I have a magic crystal ball which says:
int is_builtin(command_t* command) {
return (command->flags & CMD_BUILT_IN) != 0;
}
Try that! You might have to define flags in the command_t structure, and populate that at the time the command_t object is instantiated from parsing the command input. Also, to supply the CMD_BUILT_IN constant in some header file somewhere.

Unix fifo client to server

I want to use a pair of Unix FIFOs in such manner that:
a client sends to a server a file name and
the server returns to the client: the number of words, lines and bytes from the given file.
Could you please help?
client.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int nr,s2c,c2s,c,d,e;
char a[20];
c2s=open("fifo1",O_WRONLY);
s2c=open("fifo2",O_RDONLY);
printf("give file name \n");
scanf("%s",a);
nr=strlen(a);
write(c2s,&nr,sizeof(int));
write(c2s,&a,sizeof(nr));
read(s2c,&c,sizeof(int));
read(s2c,&d,sizeof(int));
read(s2c,&e,sizeof(int));
close(c2s);
close(s2c);
return 0;
}
server.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int nr,s2c,c2s,c,d,e;
char a[20];
FILE* f;
c2s=open("fifo1",O_RDONLY);
s2c=open("fifo2",O_WRONLY);
read(c2s,&nr,sizeof(int));
read(c2s,&a,sizeof(nr));
f=fopen(a,"r");
if(fork()==0)
{
printf("result is: \n");
execl("/usr/bin/wc","wc",c,d,e,NULL);
}
wait(0);
write(s2c,&c,sizeof(int));
write(s2c,&d,sizeof(int));
write(s2c,&e,sizeof(int));
close(c2s);
close(s2c);
printf("\n FINISH \n");
return 0;
}
I have done some improvements but still it doesn't work properly.
In the fork'ed part of the server, redirect the standard input and output of wc with
dup2(c2s, STDIN_FILENO);
dup2(s2c, STDOUT_FILENO);
Then exec it with
execl("/usr/bin/wc", "wc", NULL);
Don't pass the file descriptors as arguments to execl. It expects strings (char const*), not int.
See dup2 in the POSIX standard to understand how this works.
Note that wc writes strings of characters to its output. You are trying to read them as if they are binary numbers. This will lead to confusion - especially as you do not check that the read calls worked correctly.
Actually, general comment - you should check many more of your system calls.
You also have to ensure that your processes do not block when opening the FIFOs. You should be OK; you have the processes open 'fifo1' for reading and writing, and then 'fifo2'. I think that forces a correct order on things.
You only write 4-letter file names correctly on the pipe.

Resources