Why can’t other user remove /dev/shm/xxx even with o+rw permissions?

Posted on

Why can’t other user remove /dev/shm/xxx even with o+rw permissions? – A server stack is the collection of software that forms the operational infrastructure on a given machine. In a computing context, a stack is an ordered pile. A server stack is one type of solution stack — an ordered selection of software that makes it possible to complete a particular task. Like in this post about Why can’t other user remove /dev/shm/xxx even with o+rw permissions? was one problem in server stack that need for a solution. Below are some tips in manage your linux server when you find problem about linux, , , , .

I have python scripts that creates shared semaphore /dev/shm/sem.serialize_ld with permissions

$ ll /dev/shm/sem.serialize_ld                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
-rw-rw-rw- 1 buildbot buildbot 32 mar 27 08:36 /dev/shm/sem.serialize_ld

In practice it is always created by user buildbot, but it is not design assumption.
Sometimes problem happens – script is killed by SIGKILL and doesn’t release semaphore. New invocations deadlock on start. To manually fix this situation I want to remove the file and start over. However only buildbot and root users can do this.

Why can’t different user remove this file?

$ rm /dev/shm/sem.serialize_ld                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
rm: cannot remove '/dev/shm/sem.serialize_ld': Operation not permitted

System is Ubuntu 18.04.2 LTS

Script code is:

#!/usr/bin/env python3                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
# -*- coding: utf-8 -*-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            

import posix_ipc                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
import subprocess                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
import sys                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         
import signal                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      

SEM_NAME = '/serialize_ld'                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         
MAX_CONCURRENT = 2                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
PROGRAM = '/usr/bin/ld'                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            


def main():                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
    import os                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
    os.umask(0)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
    sem = posix_ipc.Semaphore(SEM_NAME, posix_ipc.O_CREAT, mode=0o666, initial_value=MAX_CONCURRENT)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
    sem.acquire()                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  

    def release_semaphore(signum, frame):                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
        print("exiting due to signal " + str(signum))                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
        sem.release()                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
        sem.close()                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
        sys.exit(1)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
    signal.signal(signal.SIGTERM | signal.SIGINT, release_semaphore)                                                                                                                                                                                                                                                                                                                                                                                                                                                              

    try:                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
        subprocess.call([PROGRAM, *sys.argv[1:]])                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
    finally:
        sem.release()
        sem.close()


if __name__ == "__main__":
    main()

Your directory /dev/shm/ has the sticky bit t set:

$ ll /dev/shm -d 
drwxrwxrwt 2 root root 60 mar 27 08:36 /dev/shm/

Quote from this answer on askubuntu.com:

So what is the sticky bit?

A sticky bit is a permission bit that is set on a directory that allows only the owner of the file within that directory, the owner of the directory or the root user to delete or rename the file. No other user has the needed privileges to delete the file created by some other user.

This is a security measure to avoid deletion of critical folders and their content (sub-directories and files), though other users have full permissions.

See the answer for more details.

/dev/shm directory has “sticky bit” set (trailing ‘t’) – see man chmod for details/consequences.

Suggested fix: create subdirectory in /dev/shm without sticky bit set and use it for your semaphore files.


man chmod

The letters rwxXst select file mode bits […] restricted deletion flag or sticky bit (t).
[…]
RESTRICTED DELETION FLAG OR STICKY BIT
The restricted deletion flag or sticky bit is a single bit, whose interpretation depends on the file type. For directories, it prevents unprivileged users from removing or renaming a file in the directory unless they own the file or the directory; this is called the restricted deletion flag for the directory, and is commonly found on world-writable directories like /tmp. […]

Leave a Reply

Your email address will not be published. Required fields are marked *