Changing capabilities of the process - c

Are there any way that I could run application with a special capabilities?
I'm trying to set capabilities with function "cap_set_flag()", by setting flag "SET_CLEAR", to all "CAP_INHERITABLE" capabilities but it doesn't work. Child application still has all capabilities, but i expect it will have only "cap_dac_override". I also my app with sudo to change capabilities.
My app:
#include <sys/capability.h>
#include <stdio.h>
#include <unistd.h>
cap_value_t newcaps[1] = { CAP_DAC_OVERRIDE, };
cap_value_t cap_list_[33] = {
CAP_CHOWN,
CAP_DAC_READ_SEARCH,
CAP_FOWNER,
CAP_FSETID,
CAP_KILL,
CAP_SETGID,
CAP_SETUID,
CAP_SETPCAP,
CAP_LINUX_IMMUTABLE,
CAP_NET_BIND_SERVICE,
CAP_NET_BROADCAST,
CAP_NET_ADMIN,
CAP_NET_RAW,
CAP_IPC_LOCK,
CAP_IPC_OWNER,
CAP_SYS_MODULE,
CAP_SYS_RAWIO,
CAP_SYS_CHROOT,
CAP_SYS_PTRACE,
CAP_SYS_PACCT,
CAP_SYS_ADMIN,
CAP_SYS_BOOT,
CAP_SYS_NICE,
CAP_SYS_RESOURCE,
CAP_SYS_TIME,
CAP_SYS_TTY_CONFIG,
CAP_MKNOD,
CAP_LEASE,
CAP_AUDIT_WRITE,
CAP_AUDIT_CONTROL,
CAP_SETFCAP,
CAP_MAC_OVERRIDE,
CAP_MAC_ADMIN
};
void test() {
cap_value_t cap_list[35];
const char *cap_name[35] = {
"cap_chown",
"cap_dac_override",
"cap_dac_read_search",
"cap_fowner",
"cap_fsetid",
"cap_kill",
"cap_setgid",
"cap_setuid",
"cap_setpcap",
"cap_linux_immutable",
"cap_net_bind_service",
"cap_net_broadcast",
"cap_net_admin",
"cap_net_raw",
"cap_ipc_lock",
"cap_ipc_owner",
"cap_sys_module",
"cap_sys_rawio",
"cap_sys_chroot",
"cap_sys_ptrace",
"cap_sys_pacct",
"cap_sys_admin",
"cap_sys_boot",
"cap_sys_nice",
"cap_sys_resource",
"cap_sys_time",
"cap_sys_tty_config",
"cap_mknod",
"cap_lease",
"cap_audit_write",
"cap_audit_control",
"cap_setfcap",
"cap_mac_override",
"cap_mac_admin",
"cap_syslog"
};
int i;
pid_t pid = getpid();
cap_t cap = cap_get_pid(pid);
cap_flag_value_t cap_flags_value;
for (i=0; i < 34; i++) {
cap_from_name(cap_name[i], &cap_list[i]);
printf("%-20s %d\t\t", cap_name[i], cap_list[i]);
printf("flags: \t\t");
cap_get_flag(cap, cap_list[i], CAP_EFFECTIVE, &cap_flags_value);
printf(" EFFECTIVE %-4s ", (cap_flags_value == CAP_SET) ? "OK" : "NOK");
cap_get_flag(cap, cap_list[i], CAP_PERMITTED, &cap_flags_value);
printf(" PERMITTED %-4s ", (cap_flags_value == CAP_SET) ? "OK" : "NOK");
cap_get_flag(cap, cap_list[i], CAP_INHERITABLE, &cap_flags_value);
printf(" INHERITABLE %-4s ", (cap_flags_value == CAP_SET) ? "OK" : "NOK");
printf("\n");
}
}
int main(int argc, char **argv[]) {
cap_t caps = cap_get_proc();
printf("Capabilities: %s\n", cap_to_text(caps, NULL));
if (cap_set_flag(caps, CAP_INHERITABLE, 33, cap_list_, CAP_CLEAR)){
printf("ERROR");
return 0;}
if (cap_set_flag(caps, CAP_EFFECTIVE, 33, cap_list_, CAP_CLEAR)){
printf("ERROR");
return 0;}
if (cap_set_flag(caps, CAP_PERMITTED, 33, cap_list_, CAP_CLEAR)){
printf("ERROR");
return 0;}
cap_set_proc(caps);
if(cap_set_flag(caps, CAP_INHERITABLE, 1, newcaps, CAP_SET)){
printf("ERROR2");
return 0;
}
if(cap_set_flag(caps, CAP_INHERITABLE, 1, newcaps, CAP_SET)){
printf("ERROR2");
return 0;
}
if(cap_set_flag(caps, CAP_PERMITTED, 1, newcaps, CAP_SET)){
printf("ERROR2");
return 0;
}
cap_set_proc(caps);
printf("Capabilities: %s\n", cap_to_text(caps, NULL));
cap_free(caps);
printf("====================Cap====================\n");
test();
printf("====================Test====================\n");
return execl("/home/ilya/testSEM/test.o", NULL);
}
My test app:
#include <stdio.h>
#include <sys/capability.h>
int main(int argc, char **argv) {
cap_value_t cap_list[35];
const char *cap_name[35] = {
"cap_chown",
"cap_dac_override",
"cap_dac_read_search",
"cap_fowner",
"cap_fsetid",
"cap_kill",
"cap_setgid",
"cap_setuid",
"cap_setpcap",
"cap_linux_immutable",
"cap_net_bind_service",
"cap_net_broadcast",
"cap_net_admin",
"cap_net_raw",
"cap_ipc_lock",
"cap_ipc_owner",
"cap_sys_module",
"cap_sys_rawio",
"cap_sys_chroot",
"cap_sys_ptrace",
"cap_sys_pacct",
"cap_sys_admin",
"cap_sys_boot",
"cap_sys_nice",
"cap_sys_resource",
"cap_sys_time",
"cap_sys_tty_config",
"cap_mknod",
"cap_lease",
"cap_audit_write",
"cap_audit_control",
"cap_setfcap",
"cap_mac_override",
"cap_mac_admin",
"cap_syslog"
};
int i;
pid_t pid = getpid();
cap_t cap = cap_get_pid(pid);
cap_flag_value_t cap_flags_value;
for (i=0; i < 34 + 1; i++) {
cap_from_name(cap_name[i], &cap_list[i]);
printf("%-20s %d\t\t", cap_name[i], cap_list[i]);
printf("flags: \t\t");
cap_get_flag(cap, cap_list[i], CAP_EFFECTIVE, &cap_flags_value);
printf(" EFFECTIVE %-4s ", (cap_flags_value == CAP_SET) ? "OK" : "NOK");
cap_get_flag(cap, cap_list[i], CAP_PERMITTED, &cap_flags_value);
printf(" PERMITTED %-4s ", (cap_flags_value == CAP_SET) ? "OK" : "NOK");
cap_get_flag(cap, cap_list[i], CAP_INHERITABLE, &cap_flags_value);
printf(" INHERITABLE %-4s ", (cap_flags_value == CAP_SET) ? "OK" : "NOK");
printf("\n");
}
}
My results:
====================Cap====================
cap_chown 0 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK
cap_dac_override 1 flags: EFFECTIVE OK PERMITTED OK INHERITABLE OK
cap_dac_read_search 2 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK
cap_fowner 3 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK
cap_fsetid 4 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK
cap_kill 5 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK
cap_setgid 6 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK
cap_setuid 7 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK
cap_setpcap 8 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK
cap_linux_immutable 9 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK
cap_net_bind_service 10 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK
cap_net_broadcast 11 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK
cap_net_admin 12 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK
cap_net_raw 13 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK
cap_ipc_lock 14 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK
cap_ipc_owner 15 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK
cap_sys_module 16 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK
cap_sys_rawio 17 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK
cap_sys_chroot 18 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK
cap_sys_ptrace 19 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK
cap_sys_pacct 20 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK
cap_sys_admin 21 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK
cap_sys_boot 22 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK
cap_sys_nice 23 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK
cap_sys_resource 24 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK
cap_sys_time 25 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK
cap_sys_tty_config 26 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK
cap_mknod 27 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK
cap_lease 28 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK
cap_audit_write 29 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK
cap_audit_control 30 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK
cap_setfcap 31 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK
cap_mac_override 32 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK
cap_mac_admin 33 flags: EFFECTIVE NOK PERMITTED NOK INHERITABLE NOK
====================Test====================
cap_chown 0 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK
cap_dac_override 1 flags: EFFECTIVE OK PERMITTED OK INHERITABLE OK
cap_dac_read_search 2 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK
cap_fowner 3 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK
cap_fsetid 4 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK
cap_kill 5 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK
cap_setgid 6 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK
cap_setuid 7 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK
cap_setpcap 8 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK
cap_linux_immutable 9 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK
cap_net_bind_service 10 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK
cap_net_broadcast 11 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK
cap_net_admin 12 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK
cap_net_raw 13 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK
cap_ipc_lock 14 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK
cap_ipc_owner 15 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK
cap_sys_module 16 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK
cap_sys_rawio 17 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK
cap_sys_chroot 18 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK
cap_sys_ptrace 19 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK
cap_sys_pacct 20 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK
cap_sys_admin 21 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK
cap_sys_boot 22 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK
cap_sys_nice 23 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK
cap_sys_resource 24 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK
cap_sys_time 25 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK
cap_sys_tty_config 26 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK
cap_mknod 27 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK
cap_lease 28 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK
cap_audit_write 29 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK
cap_audit_control 30 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK
cap_setfcap 31 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK
cap_mac_override 32 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK
cap_mac_admin 33 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK
cap_syslog 34 flags: EFFECTIVE OK PERMITTED OK INHERITABLE NOK

Reading your program over you have two programs: app and test. The app code you provide looks like it is invoking test.o, but I'm going to refer to that program as test in my explanation.
Try doing this:
$ sudo setcap cap_dac_override=ep app
$ sudo setcap cap_dac_override=ei test
If you run ./test (as a regular user and not root) it will be launched with no privilege at all. Confusing, but this is how things work by design.
INHERITABLE file capabilities (=ei) are not privilege, but the potential for inheriting privilege. You can trigger that inheriting effect if you run ./app (as a regular user) it will start with the single cap_dac_override capability in its EFFECTIVE and PERMITTED sets (cap_dac_override=ep). Your app code will raise this single capability in the INHERITABLE process flag as well, to get a process with cap_dac_override=eip.
When app ends by executing ./test, the raised process INHERITABLE flag will combine with the file INHERITABLE flag on the test binary to run your code with privilege. Since it also has the EFFECTIVE file bit, this combination will cause the test program to execute with cap_dac_override=eip. Note, the =ep process capabilities of app are not inherited directly, but only =i bits are passed on through execl() and the rules for capability inheritance convert the file-I and the process-I into a post-execl() process-IP.
For code like this, which knows how to get and set capabilities from code, you don't really need to include the '=e.' part when adding file capabilities. All that is doing is forcing the capabilities to be EFFECTIVE as the program starts running. This feature was included so programs that don't know about capabilities can be made to run with less than full root privilege. It is good practice to use cap_set_flag() and cap_set_proc() to raise the EFFECTIVE capabilities you need only when you need them.

Related

Linux: Why does the FIFO scheduler not work as expected on the 1 core CPU machine?

I am learning about Linux scheduler. Firstly, I want to test the FIFO scheduler. Here is the code I use to test:
#include <sched.h>
#include <stdio.h>
int main(int argc, char **argv)
{
printf("Setting SCHED_FIFO and priority to %d\n",atoi(argv[1]));
struct sched_param param;
param.sched_priority = atoi(argv[1]);
sched_setscheduler(0, SCHED_FIFO, &param);
int n = 0;
while(1) {
n++;
if (!(n % 10000000)) {
printf("%s FIFO Prio %d running (n=%d)\n",argv[2], atoi(argv[1]),n);
}
}
}
I run this program with the priority 1 on 2 terminals: ./main 1. Because my CPU has only 1 core, I expect only the first terminal can run because of the FIFO attribute. However, in the real-test situation: both terminal can run the code.
Here is my CPU information when I run the command lscpu:
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 1
On-line CPU(s) list: 0
Thread(s) per core: 1
Core(s) per socket: 1
Socket(s): 1
NUMA node(s): 1
Vendor ID: GenuineIntel
CPU family: 6
Model: 85
Model name: Intel(R) Xeon(R) Gold 6140 CPU # 2.30GHz
Stepping: 4
CPU MHz: 2294.608
BogoMIPS: 4589.21
Virtualization: VT-x
Hypervisor vendor: KVM
Virtualization type: full
L1d cache: 32K
L1i cache: 32K
L2 cache: 4096K
Please explain for me why.
You should always check the return value of system calls and the corresponding value of errno when that return value is negative. In your case, you are likely not running the program with the right privileges. sched_setscheduler(2) requires CAP_SYS_NICE capability or running as root when you request scheduling policy SCHED_FIFO with priority higher than the soft limit of RLIMIT_RTPRIO, obtainable and settable using ulimit -r. The typical value of this resource limit is 0, which forbids unprivileged processes from requesting the FIFO scheduling policy.
See here for a lot more details and here for the possible error values.

futex man page demo result incorrect

The futex man page provides a simple demo, but I can't get the result as the page described, the result seems to be deadlock on my machine (linux 5.2.1); the parent process isn't awaken by its child. Is the man page wrong?
Example of output on my machine:
[root#archlinux ~]# ./a.out
Child (12877) 0
Parent (12876) 0
Child (12877) 1
// block here
my system:
[root#archlinux ~]# uname -a
Linux archlinux 5.2.1-arch1-1-ARCH #1 SMP PREEMPT Sun Jul 14 14:52:52 UTC 2019 x86_64 GNU/Linux
Indeed the example in the man page is erroneous, at two places the code deviates from the correct depiction in the corresponding comment.
/* Acquire the futex pointed to by 'futexp': wait for its value to
become 1, and then set the value to 0. */
static void
fwait(int *futexp)
{
int s;
/* atomic_compare_exchange_strong(ptr, oldval, newval)
atomically performs the equivalent of:
if (*ptr == *oldval)
*ptr = newval;
It returns true if the test yielded true and *ptr was updated. */
while (1) {
/* Is the futex available? */
const int zero = 0;
if (atomic_compare_exchange_strong(futexp, &zero, 1))
break; /* Yes */
has to be the other way round:
/* Is the futex available? */
if (atomic_compare_exchange_strong(futexp, &(int){1}, 0))
break; /* Yes */
/* Release the futex pointed to by 'futexp': if the futex currently
has the value 0, set its value to 1 and the wake any futex waiters,
so that if the peer is blocked in fpost(), it can proceed. */
static void
fpost(int *futexp)
{
int s;
/* atomic_compare_exchange_strong() was described in comments above */
const int one = 1;
if (atomic_compare_exchange_strong(futexp, &one, 0)) {
…
has to be the other way round:
if (atomic_compare_exchange_strong(futexp, &(int){0}, 1)) {
…

Why do files in /proc/self end up being owned by root if a program has its setuid bit set?

I have this small program:
#define _GNU_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <sys/prctl.h>
extern char **environ;
int main()
{
char * const arglist[] = { "/bin/ls", "-l", "/proc/self/maps", NULL };
uid_t uid, euid, suid;
gid_t gid, egid, sgid;
getresuid(&uid, &euid, &suid);
printf("Before: uid: %u, euid: %u, suid: %u\n", uid, euid, suid);
uid = euid;
setresuid(uid, euid, suid);
getresuid(&uid, &euid, &suid);
printf(" After: uid: %u, euid: %u, suid: %u\n", uid, euid, suid);
getresgid(&gid, &egid, &sgid);
printf("Before: gid: %u, egid: %u, sgid: %u\n", gid, egid, sgid);
gid = egid;
setresuid(gid, egid, sgid);
getresuid(&gid, &egid, &sgid);
printf(" After: gid: %u, egid: %u, sgid: %u\n", gid, egid, sgid);
printf("Get result == %d\n", prctl(PR_GET_DUMPABLE, 0, 0, 0, 0));
printf("Set result == %d\n", prctl(PR_SET_DUMPABLE, 1, 0, 0, 0));
printf("Get result == %d\n", prctl(PR_GET_DUMPABLE, 0, 0, 0, 0));
if (fork())
{
return 0;
}
execve(arglist[0], arglist, environ);
}
I compile this program into an executable named small-test and change it's ownership to a testing user:
[omnifarious#foohost ~]$ ls -l small-test
-rwxrwxr-x. 1 testing testing 8512 Oct 23 12:55 small-test
Then I run the program:
[omnifarious#foohost ~]$ ./small-test
Before: uid: 1001, euid: 1001, suid: 1001
After: uid: 1001, euid: 1001, suid: 1001
Before: gid: 1001, egid: 1001, sgid: 1001
After: gid: 1001, egid: 1001, sgid: 1001
Get result == 1
Set result == 0
Get result == 1
-r--r--r--. 1 hopper hopper 0 Oct 23 14:50 /proc/self/maps
So far, so good. Then I do this:
[omnifarious#foohost ~]$ sudo chmod ug+s ./small-test
[omnifarious#foohost ~]$ ls -l ./small-test
-rwsrwsr-x. 1 testing testing 8512 Oct 23 12:55 ./small-test
[omnifarious#foohost ~]$ ./small-test
Before: uid: 1001, euid: 1002, suid: 1002
After: uid: 1002, euid: 1002, suid: 1002
Before: gid: 1001, egid: 1002, sgid: 1002
After: gid: 1002, egid: 1002, sgid: 1002
Get result == 0
Set result == 0
Get result == 1
-r--r--r--. 1 root root 0 Oct 23 12:59 /proc/self/maps
Why does /proc/self/maps end up being owned by root instead of by testing or omnifarious? Note that the result does not change if I remove the fork.
The reason this is vexing me is that I need create a program that puts itself in a namespace as a user other than the one that executed it. This is so that I don't have access to cgroups and other things owned by the user that started the program. But I'm not being allowed to write to the program's uid_map or gid_map and so I can't set up the namespace properly.
Note: I edited this question to include a call to prctl to set (and read) the DUMPABLE flag as an answer (and the manual) indicated that resetting this should fix the owner on /proc/self/* files. It didn't, as you can see by the new program.
Edit: The above program has a bug in which it is calling setresuid instead of setresgid. This is what caused my problem even after adding the call to prctl. The prctl(PR_SET_DUMPABLE, 1); call has no effect if the real and effective group and user ids of the process are not the same.
Any suid process will default to have its /proc/self directory owned by root for security reasons (to prevent users from inducing a core dump and inspecting its memory for valuable info).
You can set the owner after a suid by manually making the process dumpable with the prctl PR_SET_DUMPABLE.
Here's proc(5), containing a description of what's going on and how to affect it:
/proc/[pid]
There is a numerical subdirectory for each running
process; the subdirectory is named by the process
ID.
Each /proc/[pid] subdirectory contains the pseudo-
files and directories described below. These
files are normally owned by the effective user and
effective group ID of the process. However, as a
security measure, the ownership is made root:root
if the process's "dumpable" attribute is set to a
value other than 1. This attribute may change for
the following reasons:
* The attribute was explicitly set via the
prctl(2) PR_SET_DUMPABLE operation.
* The attribute was reset to the value in the
file /proc/sys/fs/suid_dumpable (described
below), for the reasons described in prctl(2).
Resetting the "dumpable" attribute to 1 reverts
the ownership of the /proc/[pid]/* files to the
process's real UID and real GID.
Below, suid_dumpable has this to say about why the default is what it is:
1 ("debug")
All processes dump core when possible.
(Reasons why a process might nevertheless
not dump core are described in core(5).)
The core dump is owned by the filesystem
user ID of the dumping process and no secu‐
rity is applied. This is intended for sys‐
tem debugging situations only: this mode is
insecure because it allows unprivileged
users to examine the memory contents of
privileged processes.
And as a bonus, prctl(2) lists non-suid circumstances that affect dumpability:
PR_SET_DUMPABLE (since Linux 2.3.20)
(...)
Normally, this flag is set to 1. However, it is
reset to the current value contained in the file
/proc/sys/fs/suid_dumpable (which by default has
the value 0), in the following circumstances:
* The process's effective user or group ID is
changed.
* The process's filesystem user or group ID is
changed (see credentials(7)).
* The process executes (execve(2)) a set-user-ID
or set-group-ID program, resulting in a change
of either the effective user ID or the effec‐
tive group ID.
(...)

System V semget creates semaphore but returns 0

I'm playing with System V semaphores on an Ubuntu 14.04 server. Whenever I make a call to semget(), either to create or access an existing semaphore, a value of zero is returned. Per the man pages of semget, "If successful, the return value will be the semaphore set identifier (a nonnegative integer), otherwise -1 is returned, with errno indicating the error."
I confirm that the sempahore is in fact created by running the ipcs -s command.
------ Semaphore Arrays --------
key semid owner perms nsems
0x00000002 720903 myuser 666 1
So in my case, I believe semget() should have returned 720903 instead of 0.
Here is my code:
static void create_sem(void)
{
int key = 2;
int nsems = 1;
int sem_id;
printf("Attempting to create new semaphore set with %d members\n", nsems);
if(sem_id = semget((key_t)key, nsems, IPC_CREAT|IPC_EXCL|0666) == -1) {
printf("Error creating semaphore\n");
exit(1);
}
printf("Successfully created semaphore %d for key %d\n",
sem_id, key);
if(semctl(sem_id, 0, IPC_RMID, 0) == -1) {
perror("Error destorying semaphore");
exit(1);
}
}
Here's the output
Attempting to create new semaphore set with 1 members
Successfully created semaphore 0 for key 2
Error destroying semaphore: Operation not permitted
Note, if I hardcode the semid I see by issuing ipcs -s, I can successfully remove the semaphore array by using semctl(720903, 0, IPC_RMID, 0).
Why is semget() returning 0 instead of the actual semid?

mq_open() - EACCES, Permission denied

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.

Resources