Sample Header Ad - 728x90

File acess permissions missing after setuid() system call

3 votes
1 answer
49 views
I have a file access problem in a self developed daemon process after a setuid() system call. I already post this question to SO but the impression is that the problem is not C++ related but Linux related and so maybe there is someone here who could help me solving it. My daemon program cannot access a configuration file after a setuid(iUid) systemcall even though iUid is owner of the configuration file. Why? I am writing a controller daemon in C++ for home automation which finally will run on an raspberry pi with Raspberry Pi OS. It is started with root permissions as after start it should read an SSL certifacate which only root is granted read access. After the SSL certifacte is read the daemon should switch to user 'pvmonitor' as root permissions are no longer needed. This is done by setuid( iUid ); and I have checked with ps that the process runs as user 'pvmonitor'. The configuration file for this daemon is located at /etc/SmartHome/converd.conf and is owned by user pvmonitor. ls -la /etc/SmartHome/ total 24 drwxrwx---+ 2 pvmonitor www-data 4096 Jul 17 20:07 . drwxr-xr-x+ 107 root root 4096 Jul 17 20:07 .. -rw-r-----+ 1 pvmonitor www-data 705 Jul 17 20:07 coverd.conf The raspberry pi is booted from network and the file system is mounted from a NAS which provides an ACL. Also ACL grants access permission to user pvmonitor: getfacl /etc/ getfacl: Removing leading '/' from absolute path names # file: etc/ # owner: root # group: root user::rwx [...] group::--- group:users:rwx #effective:r-x group:www-data:r-x mask::r-x other::r-x [...] getfacl /etc/SmartHome/ getfacl: Removing leading '/' from absolute path names # file: etc/SmartHome/ # owner: pvmonitor # group: www-data user::rwx [...] user:pvmonitor:rwx [...] group::--- [...] group:www-data:r-x mask::rwx other::--- [...] getfacl /etc/SmartHome/coverd.conf getfacl: Removing leading '/' from absolute path names # file: etc/SmartHome/coverd.conf # owner: pvmonitor # group: www-data user::rw- [...] user:pvmonitor:rwx #effective:r-- [...] group::--- [...] group:www-data:r-x #effective:r-- mask::r-- other::--- In addition the output of stat: stat /etc File: /etc Size: 4096 Blocks: 16 IO Block: 4096 directory Device: 0,22 Inode: 74579976 Links: 107 Access: (0755/drwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root) Access: 2024-12-03 22:14:03.809660810 +0100 Modify: 2025-07-17 20:07:13.645754180 +0200 Change: 2025-07-17 20:07:13.645754180 +0200 Birth: - stat /etc/SmartHome/ File: /etc/SmartHome/ Size: 4096 Blocks: 16 IO Block: 4096 directory Device: 0,22 Inode: 74581572 Links: 2 Access: (0770/drwxrwx---) Uid: ( 1004/pvmonitor) Gid: ( 133/www-data) Access: 2025-07-17 20:06:03.525754180 +0200 Modify: 2025-07-17 20:07:08.395754180 +0200 Change: 2025-07-17 20:35:52.235754180 +0200 Birth: - stat /etc/SmartHome/coverd.conf File: /etc/SmartHome/coverd.conf Size: 705 Blocks: 16 IO Block: 131072 regular file Device: 0,22 Inode: 74581810 Links: 1 Access: (0640/-rw-r-----) Uid: ( 1004/pvmonitor) Gid: ( 133/www-data) Access: 2025-07-17 20:07:08.395754180 +0200 Modify: 2025-07-17 20:07:08.395754180 +0200 Change: 2025-07-18 09:33:38.783696180 +0200 Birth: - With sudo -u pvmonitor less /etc/SmartHome/coverd.conf I can read the configuration file without any problem. But when I try to open the configuration file in my daemon process after the setuid(); command I get an "permission denied" error. Here is a minimum reproducable example which is based on excerpts of my daemons code: #include #include #include #include const char *ptConfigFile = "/etc/SmartHome/coverd.conf"; void printConfig( void ) { std::cout << "Try to open file " << ptConfigFile << std::endl; FILE *ptfTest; ptfTest = fopen( ptConfigFile, "r" ); if (ptfTest != nullptr) { char sLine; while (!feof(ptfTest)) { fgets(sLine,1023,ptfTest); std::cout << sLine; } fclose( ptfTest ); } else perror( "Failed to open file" ); } int main(int argc, char **argv ) { int iUid = 1004; std::cout << "User id is now " << getuid() << std::endl; printConfig(); std::cout << "Switch to user id " << iUid << std::endl; if (iUid == 0 || setuid(iUid)== 0) { std::cout << "User id is now " << getuid() << std::endl; printConfig(); return 0; } std::cerr << "Could not switch user id." << std::endl; return -1; } 1004 is the user id of user pvmonitor. The output of this example is: sudo ./test User id is now 0 Try to open file /etc/SmartHome/coverd.conf CERTFILE=[...] [...] Switch to user id 1004 User id is now 1004 Try to open file /etc/SmartHome/coverd.conf Failed to open file: Permission denied In addition here is the output when I run the test program with strace: sudo strace ./test execve("./test", ["./test"], 0x7fc90538b0 /* 13 vars */) = 0 [...] setuid(1004) = 0 getuid() = 1004 write(1, "User id is now 1004\n", 20User id is now 1004 ) = 20 write(1, "Try to open file /etc/SmartHome/"..., 44Try to open file /etc/SmartHome/coverd.conf ) = 44 openat(AT_FDCWD, "/etc/SmartHome/coverd.conf", O_RDONLY) = -1 EACCES (Permission denied) dup(2) = 3 fcntl(3, F_GETFL) = 0x2 (flags O_RDWR) newfstatat(3, "", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0x2), ...}, AT_EMPTY_PATH) = 0 write(3, "Failed to open file: Permission "..., 39Failed to open file: Permission denied ) = 39 close(3) = 0 exit_group(0) = ? What am I doing wrong?
Asked by Holger (33 rep)
Jul 17, 2025, 06:37 PM
Last activity: Jul 18, 2025, 12:24 PM