123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296 |
- unshare system call:
- --------------------
- This document describes the new system call, unshare. The document
- provides an overview of the feature, why it is needed, how it can
- be used, its interface specification, design, implementation and
- how it can be tested.
- Change Log:
- -----------
- version 0.1 Initial document, Janak Desai (janak@us.ibm.com), Jan 11, 2006
- Contents:
- ---------
- 1) Overview
- 2) Benefits
- 3) Cost
- 4) Requirements
- 5) Functional Specification
- 6) High Level Design
- 7) Low Level Design
- 8) Test Specification
- 9) Future Work
- 1) Overview
- -----------
- Most legacy operating system kernels support an abstraction of threads
- as multiple execution contexts within a process. These kernels provide
- special resources and mechanisms to maintain these "threads". The Linux
- kernel, in a clever and simple manner, does not make distinction
- between processes and "threads". The kernel allows processes to share
- resources and thus they can achieve legacy "threads" behavior without
- requiring additional data structures and mechanisms in the kernel. The
- power of implementing threads in this manner comes not only from
- its simplicity but also from allowing application programmers to work
- outside the confinement of all-or-nothing shared resources of legacy
- threads. On Linux, at the time of thread creation using the clone system
- call, applications can selectively choose which resources to share
- between threads.
- unshare system call adds a primitive to the Linux thread model that
- allows threads to selectively 'unshare' any resources that were being
- shared at the time of their creation. unshare was conceptualized by
- Al Viro in the August of 2000, on the Linux-Kernel mailing list, as part
- of the discussion on POSIX threads on Linux. unshare augments the
- usefulness of Linux threads for applications that would like to control
- shared resources without creating a new process. unshare is a natural
- addition to the set of available primitives on Linux that implement
- the concept of process/thread as a virtual machine.
- 2) Benefits
- -----------
- unshare would be useful to large application frameworks such as PAM
- where creating a new process to control sharing/unsharing of process
- resources is not possible. Since namespaces are shared by default
- when creating a new process using fork or clone, unshare can benefit
- even non-threaded applications if they have a need to disassociate
- from default shared namespace. The following lists two use-cases
- where unshare can be used.
- 2.1 Per-security context namespaces
- -----------------------------------
- unshare can be used to implement polyinstantiated directories using
- the kernel's per-process namespace mechanism. Polyinstantiated directories,
- such as per-user and/or per-security context instance of /tmp, /var/tmp or
- per-security context instance of a user's home directory, isolate user
- processes when working with these directories. Using unshare, a PAM
- module can easily setup a private namespace for a user at login.
- Polyinstantiated directories are required for Common Criteria certification
- with Labeled System Protection Profile, however, with the availability
- of shared-tree feature in the Linux kernel, even regular Linux systems
- can benefit from setting up private namespaces at login and
- polyinstantiating /tmp, /var/tmp and other directories deemed
- appropriate by system administrators.
- 2.2 unsharing of virtual memory and/or open files
- -------------------------------------------------
- Consider a client/server application where the server is processing
- client requests by creating processes that share resources such as
- virtual memory and open files. Without unshare, the server has to
- decide what needs to be shared at the time of creating the process
- which services the request. unshare allows the server an ability to
- disassociate parts of the context during the servicing of the
- request. For large and complex middleware application frameworks, this
- ability to unshare after the process was created can be very
- useful.
- 3) Cost
- -------
- In order to not duplicate code and to handle the fact that unshare
- works on an active task (as opposed to clone/fork working on a newly
- allocated inactive task) unshare had to make minor reorganizational
- changes to copy_* functions utilized by clone/fork system call.
- There is a cost associated with altering existing, well tested and
- stable code to implement a new feature that may not get exercised
- extensively in the beginning. However, with proper design and code
- review of the changes and creation of an unshare test for the LTP
- the benefits of this new feature can exceed its cost.
- 4) Requirements
- ---------------
- unshare reverses sharing that was done using clone(2) system call,
- so unshare should have a similar interface as clone(2). That is,
- since flags in clone(int flags, void *stack) specifies what should
- be shared, similar flags in unshare(int flags) should specify
- what should be unshared. Unfortunately, this may appear to invert
- the meaning of the flags from the way they are used in clone(2).
- However, there was no easy solution that was less confusing and that
- allowed incremental context unsharing in future without an ABI change.
- unshare interface should accommodate possible future addition of
- new context flags without requiring a rebuild of old applications.
- If and when new context flags are added, unshare design should allow
- incremental unsharing of those resources on an as needed basis.
- 5) Functional Specification
- ---------------------------
- NAME
- unshare - disassociate parts of the process execution context
- SYNOPSIS
- #include <sched.h>
- int unshare(int flags);
- DESCRIPTION
- unshare allows a process to disassociate parts of its execution
- context that are currently being shared with other processes. Part
- of execution context, such as the namespace, is shared by default
- when a new process is created using fork(2), while other parts,
- such as the virtual memory, open file descriptors, etc, may be
- shared by explicit request to share them when creating a process
- using clone(2).
- The main use of unshare is to allow a process to control its
- shared execution context without creating a new process.
- The flags argument specifies one or bitwise-or'ed of several of
- the following constants.
- CLONE_FS
- If CLONE_FS is set, file system information of the caller
- is disassociated from the shared file system information.
- CLONE_FILES
- If CLONE_FILES is set, the file descriptor table of the
- caller is disassociated from the shared file descriptor
- table.
- CLONE_NEWNS
- If CLONE_NEWNS is set, the namespace of the caller is
- disassociated from the shared namespace.
- CLONE_VM
- If CLONE_VM is set, the virtual memory of the caller is
- disassociated from the shared virtual memory.
- RETURN VALUE
- On success, zero returned. On failure, -1 is returned and errno is
- ERRORS
- EPERM CLONE_NEWNS was specified by a non-root process (process
- without CAP_SYS_ADMIN).
- ENOMEM Cannot allocate sufficient memory to copy parts of caller's
- context that need to be unshared.
- EINVAL Invalid flag was specified as an argument.
- CONFORMING TO
- The unshare() call is Linux-specific and should not be used
- in programs intended to be portable.
- SEE ALSO
- clone(2), fork(2)
- 6) High Level Design
- --------------------
- Depending on the flags argument, the unshare system call allocates
- appropriate process context structures, populates it with values from
- the current shared version, associates newly duplicated structures
- with the current task structure and releases corresponding shared
- versions. Helper functions of clone (copy_*) could not be used
- directly by unshare because of the following two reasons.
- 1) clone operates on a newly allocated not-yet-active task
- structure, where as unshare operates on the current active
- task. Therefore unshare has to take appropriate task_lock()
- before associating newly duplicated context structures
- 2) unshare has to allocate and duplicate all context structures
- that are being unshared, before associating them with the
- current task and releasing older shared structures. Failure
- do so will create race conditions and/or oops when trying
- to backout due to an error. Consider the case of unsharing
- both virtual memory and namespace. After successfully unsharing
- vm, if the system call encounters an error while allocating
- new namespace structure, the error return code will have to
- reverse the unsharing of vm. As part of the reversal the
- system call will have to go back to older, shared, vm
- structure, which may not exist anymore.
- Therefore code from copy_* functions that allocated and duplicated
- current context structure was moved into new dup_* functions. Now,
- copy_* functions call dup_* functions to allocate and duplicate
- appropriate context structures and then associate them with the
- task structure that is being constructed. unshare system call on
- the other hand performs the following:
- 1) Check flags to force missing, but implied, flags
- 2) For each context structure, call the corresponding unshare
- helper function to allocate and duplicate a new context
- structure, if the appropriate bit is set in the flags argument.
- 3) If there is no error in allocation and duplication and there
- are new context structures then lock the current task structure,
- associate new context structures with the current task structure,
- and release the lock on the current task structure.
- 4) Appropriately release older, shared, context structures.
- 7) Low Level Design
- -------------------
- Implementation of unshare can be grouped in the following 4 different
- items:
- a) Reorganization of existing copy_* functions
- b) unshare system call service function
- c) unshare helper functions for each different process context
- d) Registration of system call number for different architectures
- 7.1) Reorganization of copy_* functions
- Each copy function such as copy_mm, copy_namespace, copy_files,
- etc, had roughly two components. The first component allocated
- and duplicated the appropriate structure and the second component
- linked it to the task structure passed in as an argument to the copy
- function. The first component was split into its own function.
- These dup_* functions allocated and duplicated the appropriate
- context structure. The reorganized copy_* functions invoked
- their corresponding dup_* functions and then linked the newly
- duplicated structures to the task structure with which the
- copy function was called.
- 7.2) unshare system call service function
- * Check flags
- Force implied flags. If CLONE_THREAD is set force CLONE_VM.
- If CLONE_VM is set, force CLONE_SIGHAND. If CLONE_SIGHAND is
- set and signals are also being shared, force CLONE_THREAD. If
- CLONE_NEWNS is set, force CLONE_FS.
- * For each context flag, invoke the corresponding unshare_*
- helper routine with flags passed into the system call and a
- reference to pointer pointing the new unshared structure
- * If any new structures are created by unshare_* helper
- functions, take the task_lock() on the current task,
- modify appropriate context pointers, and release the
- task lock.
- * For all newly unshared structures, release the corresponding
- older, shared, structures.
- 7.3) unshare_* helper functions
- For unshare_* helpers corresponding to CLONE_SYSVSEM, CLONE_SIGHAND,
- and CLONE_THREAD, return -EINVAL since they are not implemented yet.
- For others, check the flag value to see if the unsharing is
- required for that structure. If it is, invoke the corresponding
- dup_* function to allocate and duplicate the structure and return
- a pointer to it.
- 7.4) Appropriately modify architecture specific code to register the
- new system call.
- 8) Test Specification
- ---------------------
- The test for unshare should test the following:
- 1) Valid flags: Test to check that clone flags for signal and
- signal handlers, for which unsharing is not implemented
- yet, return -EINVAL.
- 2) Missing/implied flags: Test to make sure that if unsharing
- namespace without specifying unsharing of filesystem, correctly
- unshares both namespace and filesystem information.
- 3) For each of the four (namespace, filesystem, files and vm)
- supported unsharing, verify that the system call correctly
- unshares the appropriate structure. Verify that unsharing
- them individually as well as in combination with each
- other works as expected.
- 4) Concurrent execution: Use shared memory segments and futex on
- an address in the shm segment to synchronize execution of
- about 10 threads. Have a couple of threads execute execve,
- a couple _exit and the rest unshare with different combination
- of flags. Verify that unsharing is performed as expected and
- that there are no oops or hangs.
- 9) Future Work
- --------------
- The current implementation of unshare does not allow unsharing of
- signals and signal handlers. Signals are complex to begin with and
- to unshare signals and/or signal handlers of a currently running
- process is even more complex. If in the future there is a specific
- need to allow unsharing of signals and/or signal handlers, it can
- be incrementally added to unshare without affecting legacy
- applications using unshare.
|