I'm trying to create a POSIX message queue from a privileged process (waiting for later read), then open this message queue from an unprivileged process (to send message), and the later mq_open() returned: EACCES.
If the create process and open process are both privileged or both unprivileged, mq_open will success.
I checked the mq_open manual, it says EACCES means the caller does not have permission to open it in the specified mode, but I'm not sure what is 'specified mode'...
Create success in privileged process:
struct mq_attr attr;
attr.mq_flags = O_RDONLY;
attr.mq_maxmsg = 10;
attr.mq_msgsize = 1024;
attr.mq_curmsgs = 0;
mq_open("/myMq", (O_RDONLY| O_CREAT), (S_IRWXU | S_IRWXG | S_IRWXO) /* 777 */, &attr);
Open failed in unprivileged process:
mqd_t mqd;
mqd = mq_open("/myMq", (O_WRONLY|O_NONBLOCK));
if ((mqd_t)-1 == mqd) {
printf("mq_open %d %s\n", errno, strerror(errno)); }
It gives the error: mq_open 13 Permission denied
I'm using CentOS 6.5 64-bit
uname -r
2.6.32-431.el6.x86_64
Can you help me to figure out what the problem is. Thanks in advance.
In this case, you're being stung by the umask of the creating process.
The permissions settings are masked against the process umask.
You can use:
mode_t omask;
omask = umask(0);
mq_open("/myMq", (O_RDONLY| O_CREAT), (S_IRWXU | S_IRWXG | S_IRWXO) /* 777 */, &attr);
umask(omask);
but beware of umask-dependent race conditions if you're running in a multi-threaded process.
Related
When I run my code:
int i = fork();
if (!i){
int id = open("shared.txt", 0600 | O_WRONLY);
if(flock(id, LOCK_EX) == 0)
printf("child\n");
close(id);
}
else {
int id = open("shared.txt", 0600 | O_WRONLY);
if(flock(id, LOCK_EX) == 0)
printf("parent\n");
close(id);
}
wait(NULL);
I expect that one process will block my file and the other process will not send my a message, because flock() returns -1. But either first and second flock() works with different file descriptors.
I expect that one process will block my file and the other process will not send my a message
No, not at all.
Let's say one of the processes locks the file and the other tries to lock it. flock doesn't return. flock blocks until the file becomes unlocked. The process with the lock will output its message and exit, which releases the lock. The other process will now unblock, output its message and exit. Both processes will always output their messages (eventually).
There is a flag that will cause flock to return immediately if the file is locked: LOCK_NB. But even if you used LOCK_NB, this wouldn't guarantee that only one of the processes would output a message.
Let's say one of the processes locks the file, prints its message and exits before the other process even attempts to lock the file. Easily possible with the program you provided. The other process will have no problem obtaining a lock and thus output its message and exit. It's possible for both processes to output their messages.
flock() returns -1
This does not indicate that the file is already locked; this indicates something went wrong.[1] Perhaps the open failed, so you provided an invalid file descriptor to flock. Both open and flock set errno on error, which you output using perror.
int fd = open( ... );
if ( fd == -1 ) {
// Error!
perror( "open" );
exit( 1 );
}
if ( flock( fd, LOCK_EX ) == -1 )
// Error!
perror( "flock" );
exit( 1 );
}
...
close( fd );
It can indicate the file is already locked when LOCK_NB is used. errno == EWOULDBLOCK if that's the case. But you didn't use LOCK_NB.
I have the following C script running in linux (Ubuntu 12.0.4) as a set root UID script (chmod 4755)
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
void main()
{ int fd;
/* Assume that /etc/zzz is an important system file,
* and it is owned by root with permission 0644.
* Before running this program, you should create
* the file /etc/zzz first. */
fd = open("/etc/zzz", O_RDWR | O_APPEND);
if (fd == -1) {
printf("Cannot open /etc/zzz\n");
exit(0);
}
/* Simulate the tasks conducted by the program */
sleep(1);
/* After the task, the root privileges are no longer needed, it’s time to relinquish the root privileges
permanently. */
setgroups(0, NULL);
setregid(getgid());
setreuid(getuid()); /* getuid() returns the real uid */
if(setregid(getgid()) == 0){
printf("Still root GID!\n");
exit(0);
} if(setreuid(getuid()) ==0){
printf("Still root UID\n");
exit(0);
if (fork()) { /* In the parent process */
close (fd);
exit(0);
} else { /* in the child process */
/* Now, assume that the child process is compromised,
malicious attackers have injected the following
statements into this process */
write (fd, "Malicious Data\n", 15);
close (fd);
}
}
As far as I can see, it should be setting the permissions back to the real user (ID 1000) but I am getting the "Still root" errors.
I have tried inserting setuid(1000) and setuid(0) just about the setgroups to remove any saved UID issues, but that just allows it to bypass the if statements, but still allows the "Malicious Data" to be written.
I have also tried closing the file close(fd) before dropping permissions, as I was unsure if you'd be unable to edit permissions whilst a file opened as root was still open. But I was still having the same issue
Any ideas as to what I am doing wrong here? And why it isn't working?
I assume you run the program with sudo. In that case, getuid will return 0.
You'd have to explicitly call set the uid to the desired (e.g. 1000) uid.
Also, "Malicious Data\n" will be written because the fd was already opened when the process had elevated permissions, and you can still write there even if your process lost permissions. The process now cannot open the file again.
Everything is according to spec: if you want to disallow the process from writing to the file, make sure to close it before dropping permissions.
I have successfully created a C program which runs an infinite loop waiting for a connecting through sockets.
I would like to make it a daemon and be able to start and stop it. How can I do it? What changes should I do to my code to run in the background?
The classic tasks required to become a daemon are:
Change the working directory to the root, so that your daemon does not pin another mount;
Call fork() and have the parent exit, so that the process is not a process group leader;
Redirect standard input, standard output and standard error to /dev/null;
Call setsid() to make the process a session group leader of a new session with no controlling terminal.
Without error-checking:
chdir("/);
if (fork() > 0)
_exit();
close(0);
close(1);
close(2);
open("/dev/null", O_RDWR);
dup(0);
dup(0);
setsid();
On Linux, glibc provides a daemon() helper function to do these tasks.
To run a c program as daemon you need to do the following steps.
// Create child process
process_id = fork();
//unmask the file mode
umask(0);
//change the directory as your home directory
strcpy(home,"HOME");
home=getenv(home);
chdir(home) ;
//set new session
sid = setsid();
close(STDIN_FILENO); open("/dev/null", O_RDWR);
close(STDOUT_FILENO); open("/dev/null", O_RDWR);
close(STDERR_FILENO); open("/dev/null", O_RDWR);
If I have a message queue
mqd_t m;
m = mq_open(NAME,O_CREAT | O_RDWR, 0666, NULL);
Is it possible to send a message on it and the same process to perform a receive on the
same message ?
Thank you!
Why not? It could. See the official mannual here: http://man7.org/linux/man-pages/man3/mq_open.3.html
The argument O_RDWR means:
O_RDWR Open the queue to both send and receive messages.
Like a file object, you could read and write it in one process.
I am programming a small web server in C that is supposed to serve multiple client requests using a process pool. The process pool was working fine, before adding a shared memory component to store the number of traffic sent by the server. All requests were handled by different processes before. Now they are all handled by the same process. I haven't changed the code to fork() the child-processes, which is what baffles me..
typedef struct {
long int traffic;
pthread_mutex_t muxlock;
} shmem;
/*Creating the shared memory and,setting its size, closing | Initializing the mutex*/
shm_unlink("/sum_traffic");
int shmfd = shm_open("/sum_traffic", O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); //Creates the shared memory
ftruncate(shmfd,sizeof(int)*8+sizeof(shmem)); //Sets the size of the shared memory
shmem *memptr = mmap(NULL, (sizeof(int)*8+sizeof(shmem)), PROT_READ | PROT_WRITE, MAP_SHARED, shmfd,0); //Maps a pointer for us to work with
pthread_mutex_init(&(*memval).muxlock,NULL); //Initialize the mutex lock
//Forking 10 worker processes
int i;
for(i=0; i<11;i++){
if(pid>0){
pid=fork();
}
}
if(pid < 0){
fprintf(stderr, "Error forking, error: %d\n",errno);
exit(EXIT_FAILURE);
}
//Worker-processes
while(1)
if(pid == 0){
//Accept connection on list_s
if((conn_s = accept(list_s, NULL, NULL)) < 0){
fprintf(stderr , "Error calling accept \n");
exit(EXIT_FAILURE);
}
httpRequest request;
request = parseRequest(getMessage(conn_s)); //Parses the http GET request
headertraffic=selectHeader(conn_s,request.returncode); //Selects a Header file to send
currenttraffic=printFile(conn_s,request.filename); //Serves the requested file
pthread_mutex_lock(&(*memval).muxlock); //Lock the mutex to write to shared memory
(*memval).traffic=((*memval).traffic+currentdata+headerdata);
pthread_mutex_unlock(&(*memval).muxlock); // Unlock mutex
printf("PID: %d\n",getpid());
(void)close(conn_s);
}
Help is much appreciated!
Not sure if this is your real code but some error checking would be helpful.
This may not be your problem but a contributing factor is that you haven't set the mutex to be shared by multiple processes. You can't take the default attributes in pthread_mutex_init(). You have to initialize a mutex attribute with pthread_mutexattr_init()and then callpthread_mutexattr_setpshared()and then callpthread_mutex_init()`.