The general YottaDB philosophy is to use the security of the underlying operating system, and to neither subvert it nor extend it. When YottaDB invokes the POSIX system() interface, it ensures that the alias and path settings do not interfere with the intentions of the actions it takes. The purpose of this document is to discuss the implications of, exceptions to, and limitations of this philosophy (the “security model”).
YottaDB is not intended to operate robustly on a machine that is potentially subject to direct attack, such as a firewall or a machine operating in a “DMZ” (when external-facing services are exposed to an untrusted network).
Normal User and Group ID Rule¶
YottaDB processes run with normal UNIX user and group ids. YottaDB has no database daemon that needs to run with elevated privileges. Process code written in M will be able to read a database file if and only if the process has read permissions for that database file, and to update that database file if and only if the process has read/write permissions for that database file. (The concept of write-only access to a database file is not meaningful for YottaDB).
There are two exceptions to this rule. Also, special mention is made of YottaDB triggers, which require awareness of their behavior even though they comply with the Normal User and Group ID Rule.
Exceptions to the Normal User and Group IDs Rule exist for:
- Shared Memory when the Buffered Global (BG) access method is used, and
Processes with normal user and group ids do not have adequate permissions to effect necessary YottaDB interprocess communication and cleanup after abnormal process termination. A process called gtmsecshr runs as root in order to effect the following functionality:
- Interprocess communication, including sending SIGALARM and SIGCONT between processes where normal UNIX permissions do not permit such signals to be sent.
- Cleanup after processes that terminate abnormally, including removing semaphores, shared memory segments, and flushing database file headers (but not database blocks) from shared memory segments to disk.
Whenever a YottaDB process lacks adequate permissions to effect any of the above operations, it automatically invokes gtmsecshr if it is not already running. A complete list of gtmsecshr functionality appears in “gtmsecshr commands” .
In order to run as root, and to be invoked by a process that has normal user and group ids, the invocation chain for gtmsecshr requires an executable image that is owned by root and which has the setuid bit turned on in its file permissions.
Communication between YottaDB processes and gtmsecshr uses socket files in $ydb_tmp, which is also inherited from the YottaDB process that first invokes gtmsecshr. If the environment variable $ydb_tmp is undefined, if its value is longer than YottaDB can handle, or if it is defined to a value that is not an absolute pathname (starting with a /), $ydb_tmp is assumed to be the directory /tmp.
The gtmsecshr process receives messages via a socket file owned by root with a name of the form ydb_secshrnnnnnnnn, the nnnnnnnn being replaced by the hexadecimal ftok value of the gtmsecshr executable file. This value is reported by the YottaDB ftok utility on the gtmsecshr file, for example, $ydb_dist/ftok $ydb_dist/gtmsecshr.
YottaDB processes receive responses from gtmsecshr via socket files owned by the userid of the process with names of the form ydb_secshrnnnnnnnn, where nnnnnnnn is a hexadecimal version of the client’s process id, padded with leading zeroes. When a client process terminates abnormally, or is killed before it cleans up its socket file, it is possible for a subsequent client with the same process id (but a different userid) to be unable to delete the leftover socket file. In this case, it tries to send a message to gtmsecshr using a slightly modified client socket file of the form ydb_secshrnnnnnnnnx where x starts with “a” whose corresponding socket file does not already exist or is removable by the current client process (if all suffixes “a” through “z” are unavailable, the client process errors out with a “Too many leftover client socket files” message). gtmsecshr recognizes this specially modified socket file name and as part of servicing the client’s request, deletes the ydb_secshrnnnnnnnn socket file and all ydb_secshrnnnnnnnnx files that exist. The client process expects this file removal and creates a new ydb_secshrnnnnnnnn file for subsequent communications with gtmsecshr.
- When there is no gtmsecshr process running, by starting one up with incorrect values of $ydb_log and $ydb_tmp, a gtmsecshr process can be made to log errors in the syslog. Having incorrect values can also interfere with normal YottaDB operation until the incorrect gtmsecshr process times out and terminates, because YottaDB processes and gtmsecshr will be unable to communicate with one another.
- gtmsecshr can be made to delete client socket files by a rogue process. If a socket file is deleted under a running YottaDB process, gtmsecshr will be unable to reply to the process. It will timeout, create another and proceed. Thus, while the performance of a single process may temporarily be slowed, system operation will not be disrupted.
A YottaDB trigger is a code fragment stored in the database file that all processes performing a matching update to a global variable in that file execute automatically, for example, to maintain cross-reference indices and referential integrity. Any process that has read-write permissions for a database file can change the triggers in that database file, which can in turn force other processes updating that database to execute the changed triggers.
Based on the security model, the following are recommended best practices for securing YottaDB:
Secure the machine on which YottaDB operates behind layers of defenses that permit only legitimate accesses.
Restrict access to a system on which YottaDB runs to those who legitimately need it.
Post installation, a system administrator can optionally add a restrict.txt file in $ydb_dist to restrict the use of certain YottaDB facilities to a group-name. The owner and group for $ydb_dist/restrict.txt can be different from those used to install YottaDB. For more information, refer to “Configuring the Restriction facility”.
If all users who have access to a system do not require the ability to run YottaDB, limit the access to YottaDB to a group all users who need access belong to, and remove world access to YottaDB. (The YottaDB installation script presents an option to restrict access to YottaDB to members of a group). If such a group is called yottadbusers, the following command executed as root will accomplish this (if access was not restricted when YottaDB was installed):
chgrp -R yottadbusers $ydb_dist ; chmod -R o-rwx $ydb_dist
Ensure that database file ownership (user and group), UNIX user and group ids, and permissions at the UNIX level match the intended access. If finer grained access controls than those provided by user/group ids and permissions are needed, consider using (where appropriate and available) security products layered on top of the operating system.
Under typical conditions, YottaDB shared resources - journal files, shared memory, and semaphores - have the same group ids and access permissions as their database files, but may not be owned by the same userid, since the process creating the shared resource may have a different userid from the one that created the database. There are two edge cases to consider:
- Where the owner of the database file is not a member of the group of the database file, but is a member of the group of YottaDB’s libyottadb.so file. In this case, if a process with a userid other than the owner were to create a shared resource, a process with the userid of the owner would not have access to them. Therefore, YottaDB uses the group id of the libyottadb.so file if the process creating the shared resource is also a member of that group. In this case it would also restrict access to the resource to members of that group. If the process creating this resource is not a member of the libyottadb.so group, the group id of the shared resource remains that of the creating resource but the permissions allow world access. YottaDB advises against using a database file whose owner is not a member of the group of that file.
- Where the owner of the database file is neither a member of the group nor a member of the group of libyottadb.so. In this case, YottaDB uses world read-write permissions for the shared resources. YottaDB advises against the use of a database file whose owner is neither a member of the group of the file nor a member of the group of libyottadb.so.
The Mapped Memory (MM) access method does not use a shared memory segment for a buffer pool for database blocks - shared memory is used only for control structures. Therefore, consider using MM if there are processes that are are not considered trustworthy but which need read-only access to database files. Even with MM, processes that have read-only access to the database file still have read-write access to the control structures (for example, for M locks). It is conceivable that a rogue process with read-only access may somehow place information in the control structures (for example, bad M lock information) to induce a normal process with read-write access to record inconsistent information in the database.
If MM cannot be used, and processes that are not considered trustworthy need read-only access to database files, run those processes on a replicating instance specifically set up for that purpose.
If a database file does not change during normal operation (for example, it contains configuration parameters), make its permissions read only for everyone. On rare occasions when they need to be changed, shut down the application to get stand-alone access, temporarily make it read-write, make the changes, and then make it read-only once more.
YottaDB uses a wrapper for gtmsecshr by default. Source code for the wrapper is published. If processes that start up gtmsecshr cannot be trusted or coerced to have the correct values of $ydb_log and $ydb_tmp, modify the source code to set $ydb_log and $ydb_tmp to required values, recompile and reinstall your modified wrapper.
Consider implementing layered security software if it exists for your platform, for example, SELinux.
YottaDB neither endorses nor has tested any specific layered security product.
|WAKE_MESSAGE||Sends SIGALRM to specified process.||Used to inform receiving process that a resource (such as a critical section) it awaits has become available.|
|CONTINUE_PROCESS||Sends SIGCONT to specified process.||Used to awake a process that has been suspended while holding a resource. (Please do not ever suspend a YottaDB process.) In the event YottaDB finds a process suspended while holding a resource, it is sent a SIGCONT.|
|CHECK_PROCESS_ALIVE||Test sending a signal to specified process. (no longer needed)||Used to determine if a process owning a resource still exists; if not, the resource is available to be grabbed by another process that needs it.|
|REMOVE_SEM||Remove a specified POSIX semaphore.||Used to remove an abandoned semaphore (for example, if the last attached process terminated abnormally).|
|REMOVE_SHMMEM||Remove a specified shared memory segment.||Used to remove an abandoned shared memory segment. Before removing the segment, gtmsecshr checks that there are no processes attached to it.|
|REMOVE_FILE||Remove a specified file.||Used to remove an abandoned socket file (for example, as a result of abnormal process termination) used for interprocess communication on platforms that do not support memory semaphores (msems); unused on other platforms. Before removal, gtmsecshr verifies that the file is a socket file, in directory $ydb_tmp, and its name matches YottaDB socket file naming conventions.|
|FLUSH_DB_IPCS_INFO||Writes file header of specified database file to disk.||The ipc resources (shared memory and semaphore) created for a database file are stored in the database file header. The first process opening a database file initializes these fields while the last process to use the database clears them. If neither of them has read-write access permissions to the database file, they set/reset these fields in shared memory and gtmsecshr will write the database file header from shared memory to disk on their behalf.|