< Previous PageNext Page > Hide TOC

Root and Login Sessions

From early on, Mac OS X was designed to be a secure operating system. One aspect of this security is the control exercised over inter-process communication. Processes are loosely gathered into groups and associated with either the root session or a login session. The mach_init program, also known as the bootstrap server, assigns each new process to an appropriate session based on factors such as who created the process and when.

Most root-level processes are placed in the root session. The root session is the first session to be created and the last to be destroyed. Only one root session ever exists on the system, and it is where most boot-time processes and daemons live. Processes in the root session are allowed to provide services to all users of the system. For example, lookupd and the mDNSResponder process both run in the root session. These processes are user-independent and vend basic services to anyone on the system.

Processes launched by a user or for a user’s benefit live in a login session. Each login session is associated with an authenticated user. The system may have multiple login sessions active at any given time, but each one is something of an island to the associated user. Console login sessions include processes such as the Finder and Dock; however, remote login connections contain only shell-level processes. Most of the communication between different login sessions is restricted by the bootstrap server. Communication is still possible but generally requires creating an explicit, and trusted, connection.

Important: The content of this article is intended primarily for developers writing daemons and other low-level processes; other developers may find the information interesting but should not need it in the general course of development. These sections also assume some knowledge of the Mach kernel environment, which is described in Kernel Programming in Darwin Documentation.

Contents:

Securing the User Space
Communicating Across Login Sessions
Session Lifespans
Identifying Login Sessions
How Login Sessions Affect Developers
Frameworks Available in the Root Session


Securing the User Space

By organizing processes into root and login sessions, the mach_init process is able to create a more trustworthy environment for users. Requests for Mach ports go through the mach_init process, which routes the requests to the appropriate target. The login session acts like a set of walls around a user’s processes, limiting port requests to those in the current login session or root session. Doing so prevents accidental or intentional attempts by processes in a different session to obtain access to the ports in the current login session. In a sense, login sessions are a lightweight firewall around the processes they represent.

Thus, login sessions give users an assurance that processes launched by other users do not interfere with their own processes. For example, a malicious user might write a program that pretends to be a known user service and use that program to gather information from other users. However, unless the malicious user has administrative access to the machine, the program runs in the login session of the malicious user. Because other users cannot see the program, they are protected from its effects.

Communicating Across Login Sessions

At boot time, the kernel launches the mach_init process, whose job is to handle lookup requests for Mach ports. As part of each request, mach_init also ensures that processes do not attempt to cross login session bounds illegally. This is not to say that crossing session bounds is completely forbidden. There are situations where it is appropriate and even necessary. For example, applications can use BSD sockets, shared files, shared memory, or distributed notifications to communicate with processes in other sessions; however, doing so requires cooperation between both sessions and involves a certain level of trust.

Conceptually, you can think of the root session as a parent session for all of the login sessions that follow. However, the parent-child analogy ends there. Processes in the root session have no inherent knowledge of processes in any of the active login sessions. Conversely, processes in login sessions do have knowledge of processes in the root session and can access them as needed for appropriate services. User processes in one login session do not have any inherent access to processes in other login sessions, though. Figure 1 illustrates this relationship.


Figure 1  Root and login session relationships

Root and login session relationships

Processes in the root session are not completely blind to processes in login sessions. When a user process requests a service from a daemon running in the root session, the process typically provides a port address over which to return the results. Because it has an explicit Mach port to talk to, the daemon can now send the results of the request directly back to the user process. Figure 2 illustrates this behavior.


Figure 2  Communicating with user processes

Communicating with user processes

Session Lifespans

As you might expect, the root session is the first to be created on the system. It is also the last to be destroyed when the system is shut down. The root session is the logical place in which to run daemons and system services that apply to all users. However, writing a daemon to run in the root session precludes the use of many higher-level system frameworks that require the presence of the window server. (For a list of frameworks you can use, see “Frameworks Available in the Root Session.”)

When a user logs in, either through the login window or ssh, the system creates a new login session. The login session remains in existence until all processes belong to it are terminated. When a user logs out, the system attempts to terminate the processes in that user’s login session. When the last process in a login session dies, the system closes out the login session and reclaims its memory.

Note: If a user process daemonizes itself prior to logout, it can live past the end of the user logout and prolong the existence of the login session. Some system services, such as the Apache web server, do this to avoid being shut down during a logout. Processes that survive the user logout continue to run in the login session. However, they must be able to run without the existence of the window server, which is terminated when the user logs out.

Applications can defer a user logout for various reasons, which are described in System Startup Programming Topics. Per-user services are shut down automatically and are not given the chance to abort the logout procedure.

Identifying Login Sessions

Each time a user is authenticated with the system, the Security layer of the system creates a unique ID to identify the user’s login session. This ID is the security session ID, often referred to simply as the session ID. Applications can use the session ID to distinguish among resources allocated in different login sessions.

Session IDs are not persistent between user logins. Each session ID is valid only for the duration of the current login session, and it is valid for all processes in that login session. If a user logs out and logs back in, a different session ID is asssigned to the new login session.

Note: Session IDs should not be confused with setsid sessions created by calling the setsid function. The two values are distinct and used for different purposes. The security session ID encompasses all processes launched within a given security session and may include multiple setsid sessions.

You should use session IDs to prevent namespace collisions with objects in other login sessions. If an application used a common name for a session-specific shared memory region, the same application in another session would likely encounter an error when trying to create that memory region using the same name. Including the session ID in the memory region name can prevent these kinds of errors.

For information on how to get session IDs, see “Getting Login Session Information.”

How Login Sessions Affect Developers

If you are writing applications for end users, the existence of login sessions requires more thought in your design. You must remember that multiple instances of your application may be running simultaneously and write your code to handle potential resource conflicts. If you need to communicate with processes in other login sessions, you need to use BSD sockets, distributed notifications, or some other form of trusted connection.

If you are writing only kernel code, root and login sessions are largely irrelevant. However, driver developers frequently need to write programs that run either in the kernel or in the root session and communicate with programs in one or more login sessions. For example, a driver developer might want to configure a sound driver based on the active user’s preferences. In this case, it would be necessary to write an agent program to run in each login session and communicate user-level changes to the driver.

Frameworks Available in the Root Session

Many system frameworks depend on the window server for part of their implementations. They either use the window server for drawing graphics, for tracking notifications, or for coordinating with the system in other ways. For most applications, this is not a problem at all and is actually necessary to implement some behaviors. However, if you are writing a daemon or other type of program to run in the root session, there is no window server process with which to communicate. As a result, many higher level frameworks cannot be used at all.



< Previous PageNext Page > Hide TOC


© 2003, 2005 Apple Computer, Inc. All Rights Reserved. (Last updated: 2005-07-07)


Did this document help you?
Yes: Tell us what works for you.
It’s good, but: Report typos, inaccuracies, and so forth.
It wasn’t helpful: Tell us what would have helped.