|
@@ -0,0 +1,295 @@
|
|
|
+
|
|
|
+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
|
|
|
+ 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.
|
|
|
+
|