OS Lab 4 - Users, Groups and Permissions
Objectives
Upon completion of this lab, you will be able to:
- Explain how the kernel represents user and group identities (UIDs, GIDs, supplementary groups) and how it enforces permissions on files and directories.
- Demonstrate how privilege elevation works via effective UIDs/GIDs and setuid/setgid binaries (e.g., via
sudo). - Describe how user-space conventions (account databases, name service switch) map human-readable names to kernel numeric IDs.
- Investigate and manipulate these mechanisms on a Linux system to reinforce understanding of the kernel vs. user-space boundary.
Introduction
In our previous lab, we explored processes as the fundamental unit of execution. Now, we investigate the security model that governs what these processes can do. This lab dives into the Linux security model, carefully separating the kernel’s rigid, number-based rules from the user-space’s human-friendly conventions layered on top. Understanding this distinction is critical for system administration, security, and software development.
Kernel Abstraction: The Real Security Model
This section focuses on how the Linux kernel itself sees users and permissions. To the kernel, a “user” is just a number (a UID), and security is an algorithm.
Identities and Permission Checking
Background
Every process running on a Linux system carries a set of numeric credentials. The most important are:
- User ID (UID): A number identifying the user who “owns” the process.
- Group ID (GID): A number identifying the process’s primary group.
- Supplementary Groups: A set of additional group IDs the process belongs to.
Likewise, every file and directory on the filesystem has metadata stored in its inode, which includes:
- An owner UID
- A group GID
- Permission bits (the mode), which define access rights for three distinct categories: the owner, the group, and others.
These permissions are the classic r (read), w (write), and x (execute) triplets. Their meaning, however, depends on whether the object is a file or a directory.
| Permission | Meaning for a File | Meaning for a Directory |
|---|---|---|
r (read)
|
Can read the contents of the file. | Can list the contents of the directory (i.e., see filenames). |
w (write)
|
Can modify or truncate the file. | Can create, delete, or rename files within the directory. |
x (execute)
|
Can execute the file (if it’s a program/script). | Can enter (e.g., cd) the directory and access its inodes.
|
The Permission Checking Algorithm
When a process (with its set of IDs) tries to access a file (with its owner/group/mode), the kernel performs a simple, sequential check:
- Is the process’s effective UID
0(superuser/root)?- Yes: Access is almost always granted. Stop. (This is a simplification; mechanisms like SELinux can add further checks).
- Does the process’s effective UID match the file’s owner UID?
- Yes: Apply the owner permission bits (
rwx—). Access is granted or denied based only on these bits. Stop.
- Yes: Apply the owner permission bits (
- Does any of the process’s GIDs (primary or supplementary) match the file’s group GID?
- Yes: Apply the group permission bits (
---rwx---). Access is granted or denied based only on these bits. Stop.
- Yes: Apply the group permission bits (
- None of the above?
- Apply the others permission bits (
------rwx). Access is granted or denied.
- Apply the others permission bits (
The superuser (UID 0) is special. It bypasses these standard checks. This power allows it to manage the system, but it also carries significant risk.
| Capability | Regular User (UID > 0) | Superuser (UID = 0) |
|---|---|---|
| Read/Write Files | Restricted by owner/group/other permissions. | Can read/write any file, regardless of permissions. |
Change Ownership (chown)
|
Cannot change file ownership, not even for their own files. | Can change any file’s owner and group to any user/group. |
Change Permissions (chmod)
|
Can only change permissions on files they own. | Can change permissions on any file. |
| Bind to Privileged Ports | Cannot bind to ports 1-1023. | Can bind to any port. |
| System Configuration | Limited to own user settings. | Can modify kernel parameters, load modules, change system-wide settings. |
Examples: File permissions
# Check your identity
id
# Create an empty file
touch /path/to/filename
# List file details
ls -l /path/to/filename
# Change permissions (numeric)
chmod 640 /path/to/filename
# Change ownership (root only)
sudo chown user:group /path/to/filename
# Read a file’s contents
cat /path/to/filename
# Run a command as another user
sudo -u username command
# Write text to a file as root
sudo tee /path/to/filename <<< "text"
# Remove a file (as root)
sudo rm /path/to/filename
Hands-on Exercise A: File Permissions
Let’s test this model with a file.
- First, check your own identity.
- Create a new empty file named
/tmp/lab4_testfile. - List the file’s details and observe that you are the owner.
- Change the file’s permissions to
640(rw-r-----). - Change the file’s owner and group to
root. List the details again to confirm. - As your normal user, attempt to read the file. This should fail. Document the “Permission denied” error.
- Now, try to read the file as the
nobodyuser. This should also fail. - Finally, demonstrate root’s power:
- Use
sudoto write the text “hello from root” into the file, bypassing its permissions. - Read the file using
sudoto confirm the text is there. - Use
sudoto change the file’s permissions to600(rw-------). - List the file’s details one last time.
- Use
- Clean up by removing the file as root.
Examples: Directory permissions
# Create a directory
mkdir /path/to/dirname
# Change permissions (symbolic)
chmod u-x,g+r /path/to/dirname
# List the directory itself (not its contents)
ls -ld /path/to/dirname
# Enter the directory
cd /path/to/dirname
# Remove a directory and all its contents
rm -r /path/to/dirname
Hands-on Exercise B: Directory Permissions
Directory permissions are different. Let’s test the x (execute) bit.
- Create a new directory named
/tmp/lab4_dirand a file namedsecretfileinside it. - Set the directory’s permissions to
700(rwx------). List the directory’s details to confirm. - Verify you can list the directory’s contents and read the
secretfileinside it. - Now, remove only the execute (
x) bit for the owner of/tmp/lab4_dir. - Try to
cdinto the directory. This will fail. - Try to list the directory’s contents. This will also fail.
- Try to read the
secretfileusing its full path. This will also fail, as you can’t traverse the directory. - Now, restore the execute bit (
u+x) but remove the read bit (u-r) for the owner of/tmp/lab4_dir. Its permissions should be--wx------. - Try to list the directory’s contents. This will fail.
- Try to
cdinto the directory. This will succeed. - Once inside, try to read the
secretfile(which you know exists). This will succeed. - Return to the parent directory (
cd ..). - Clean up: To remove the directory, you must first restore permissions (e.g.,
700) so you can delete its contents, then remove the directory and its contents.
Privilege Changes and sudo
Background
The permission model is static, but a process’s identity can change. The kernel tracks multiple UIDs for each process:
- Real UID (ruid): The UID of the user who launched the process. This rarely changes.
- Effective UID (euid): The UID the kernel uses for permission checks. This is the ID that matters for file access.
Normally, ruid == euid. However, a special permission bit on an executable file, the setuid bit, can change this.
- Setuid (Set User ID): If an executable file has this bit set (shown as
sinstead ofxin the owner’s execute-bit position, e.g.,-rwsr-xr-x), when any user executes it, the kernel sets the new process’s effective UID (euid) to be the UID of the file’s owner.
The sudo command is the classic example:
- The
sudobinary (/usr/bin/sudo) is owned byroot. - It has the
setuidbit set. - When a normal user (e.g.,
student,ruid=1001) runssudo, the kernel starts thesudoprocess withruid=1001buteuid=0(root). - Now running with root’s effective permissions, the
sudoprocess is allowed to read its configuration file,/etc/sudoers. - It checks
/etc/sudoersto see if the real user (student) is allowed to perform the requested action. - If allowed,
sudo(still running aseuid=0) uses its power to launch the target command (e.g.,apt update) asroot(or as another specified user).
This mechanism is also used by utilities like passwd (which must run as root to edit /etc/shadow) and login/sshd (which start as root to authenticate users, then drop privileges to become the user who just logged in).
A parallel setgid (Set Group ID) bit exists, which changes the process’s effective GID (egid) to the file’s group. This is less common today, as modern systems tend to give users more flexible supplementary groups.
Examples: Sudo and su
# List file permissions
ls -l /path/to/binary
# Run a command as another user
sudo -u username id
# Run a command as root (prompts for root password -- this will usually not work, because root's password is usually not set)
su -c 'id'
# Run a command as another user (prompts for that user's password)
su - username -c 'id'
# Create a script
echo '#!/bin/bash' > script.sh
# Append to the script
echo 'echo "My eUID is: $(id -u -n)"' >> script.sh
# Make the script executable
chmod +x script.sh
# Set the setuid bit (root only)
sudo chmod u+s script.sh
Hands-on Exercise C: Investigating sudo and su
- View the permissions and ownership of the
sudobinary (likely/usr/bin/sudo). Note thesbit. - View the permissions of the
subinary (likely/bin/su). Note if it is also setuid root. - Use
sudoto run theidcommand as thenobodyuser. - Run
idas your normal user and compare the output. - Use
suto attempt to run theidcommand, first asrootand then asnobody. - Observe the password prompts. Unlike
sudo(which asks for your password),suasks for the target user’s password.
Hands-on Exercise O1: Setuid Script (Optional)
(Optional, may be blocked by security policies) Attempt to create a setuid script. Note that for security reasons, most modern systems ignore the setuid bit on shell scripts. This only works on compiled binaries.
- Create a simple shell script at
/tmp/lab4_script.shthat prints the process’s effective and real user IDs. - Make the script executable.
- As root, change the script’s owner to
rootand set itssetuidbit. - List the script’s permissions to confirm the
sis present. - Run the script as your normal, non-root user.
- Observe the output: does the eUID show ‘root’ or your user? On most modern systems, the setuid bit will be ignored for scripts.
- Clean up the script file.
Additional Reading (Optional)
This lab covers the standard security model. For further study, explore these advanced topics that refine or alter this model:
- SUID and FSUID: Aside from the
ruidandeuid, each process has two more numeric ids. Thefsuid(filesystem UID) is an internal Linux mechanism that allows a privileged process (like an NFS server) to perform filesystem operations as another user without fully changing itseuid. Thefsuid(filesystem UID) is an internal Linux mechanism that allows a privileged process (like an NFS server) to perform filesystem operations as another user without fully changing itseuid; thesuid(saved set-user-ID) stores the previouseuidso a process (e.g., a setuid program) can drop privileges and later regain them safely. Similarly, there is anfsgidandsgid. - ACLs (Access Control Lists):
getfaclandsetfaclcommands manage permissions for specific additional users and groups, going beyond the simple owner/group/other model. - SELinux and AppArmor: optional kernel modules that provide stricter access control rules. AppArmor specifies restricitons for particular applications and is easier to slot into existing configurations; it is used by Ubuntu. SELinux provides very complex fine-grain control, but can break deployments which do not take it into account; it is used by Red Hat Enterprise Linux.
- Capabilities: A way to break root’s “all-or-nothing” power into discrete privileges (e.g.,
CAP_NET_BIND_SERVICEallows binding to privileged ports without granting full root). - User Namespaces: A key container technology that remaps UIDs, allowing a process to think it’s UID 0 inside its namespace while being a normal UID on the host.
User-Space Convention: The Human Layer
The kernel only cares about numbers. This section covers the user-space tools and files that map human-readable names like root or student to the kernel’s numeric UIDs and GIDs.
Accounts and the Password Database
Background
The kernel knows you as UID 1001, not as student. The mapping from name to number (and other metadata) is handled in user-space, primarily by a set of text files in /etc.
/etc/passwd: The main user database. It is world-readable and contains one line per user, with fields separated by colons (:).username:x:UID:GID:Full Name:/home/dir:/shellusername: Your login name.x: A placeholder. In the past, the encrypted password hash was here.UID: The all-important User ID number. This is what the kernel uses.GID: The user’s primary Group ID number.- Comment (GECOS): This is a comment field, historically called the GECOS (General Electric Comprehensive Operating System) field. It is a comma-separated list that conventionally stores the following fields. Most systems today just use the first part for the display name.
- User’s Full Name (e.g.,
John Doe) - Room Number
- Work Phone
- Home Phone
- Other contact info
- User’s Full Name (e.g.,
/home/dir: The user’s home directory./shell: The user’s default login shell (e.g.,/bin/bash).
/etc/shadow: Because/etc/passwdmust be world-readable (sols -lcan show names instead of numbers), the sensitive password hashes were moved here. This file is only readable by root.username:password_hash:last_change:etc.../etc/group: The group database, also world-readable.groupname:x:GID:member_listgroupname: The human-readable group name.GID: The numeric Group ID.member_list: A comma-separated list of additional users who are part of this group (for their supplementary groups).
Examples: Inspecting Account Databases
# View the top of a file (first 10 lines)
head -n 10 /path/to/file
# View a file as root
sudo cat /path/to/file
# Query the NSS database for a user
getent passwd <username>
# Query the NSS database for a group
getent group <groupname>
Hands-on Exercise D: Inspecting Account Databases
- Display the first 10 lines of the
/etc/passwduser database. - Attempt to display the first 5 lines of
/etc/shadow. This will fail. - Use
sudoto display the first 5 lines of/etc/shadowto prove root can read it. - Display the first 10 lines of the
/etc/groupdatabase. - Use the
getentcommand to query thepasswddatabase for therootuser and for your own user (using the$USERvariable). - Use
getentto query thegroupdatabase for thesudogroup and for your own primary group (which you can find from theidcommand).
Examples: Modifying GECOS and Passwords
# View user GECOS info
finger <username>
# Change your GECOS info interactively (current user)
chfn
# Change your password (current user)
passwd
# Find a user’s line in /etc/passwd
grep "^<username>:" /etc/passwd
Hands-on Exercise E: Modifying GECOS and Passwords
- Use the
fingercommand to view your user’s GECOS information. - Use the
chfncommand to interactively change your GECOS information (Full Name, Room Number, etc.). You may be prompted for your password. - Run
fingeragain to see the changes have been applied. - Check your entry in the
/etc/passwdfile (usinggetentorgrep) to see how the GECOS field (the 5th field) was updated. - Use the
passwdcommand to change your password. This command securely updates the/etc/shadowfile.
Name Service Switch (NSS)
Background
Storing all users in local /etc files doesn’t scale in a large organization. What if you want to log in to 1,000 different machines with the same username and password?
The Name Service Switch (NSS) is a user-space (specifically, C library) mechanism that makes this possible. It allows system functions (like getpwnam() which “gets password-entry-by-name”) to look for information in multiple sources.
The configuration file is /etc/nsswitch.conf. It contains lines like:
passwd: files systemd ldap group: files sss
This tells the system: “When looking up a user (passwd), first check local files (/etc/passwd), then ask the systemd user database, and if still not found, query the ldap server.”
This system is powerful because it allows a a system to pull user/group info from network services like LDAP, NIS, or SSS (System Security Services Daemon) without changing any kernel behavior. The kernel still only receives and operates on the final numeric UID/GID.
Examples: Inspecting NSS
# Print the nsswitch configuration
cat /etc/nsswitch.conf
# Query the NSS database for a specific user
getent passwd <username>
Hands-on Exercise F: Inspecting NSS
Display the lines from
/etc/nsswitch.confthat configure thepasswdandgroupdatabases (the lines starting withpasswd:andgroup:).Test the lookup system by using
getentto resolve thenobodyuser and thenogroupgroup.(Optional, use with extreme care) As root, edit
/etc/nsswitch.conf(e.g.,sudo nano /etc/nsswitch.conf). Put a#at the beginning of thegroup:line to comment it out, and add a new linegroup: sss(a service that is likely not running). Save the file.Now, try to resolve group names using
getent group sudoandls -l /. Observe that names may now show up as numbers.IMMEDIATELY restore
/etc/nsswitch.confto its original state and verifyls -lworks again. This exercise demonstrates how critical this user-space configuration is for the “human-friendly” layer.
Examples: Creating Users and Groups
# Add a group
sudo groupadd <groupname>
# Add a user with options (home dir, primary group, supplementary group, login shell)
sudo useradd -m -g <primary_group> -G <suppl_group> -s /bin/bash <username>
# Set a user’s password
sudo passwd <username>
# Switch to a user (login shell)
su - <username>
# Delete a user and their home directory
sudo userdel -r <username>
# Delete a group
sudo groupdel <groupname>
# Check the end of the /etc/group file (last 3 lines)
tail -n 3 /etc/group
Hands-on Exercise G: Creating Users and Groups
Let’s use the standard user-space tools to create a new user and group. These tools automatically update the /etc/passwd, /etc/shadow, and /etc/group files.
- As root, create a new group named
labtesters. - Verify the group was added by checking the end of the
/etc/groupfile and by usinggetent. - As root, create a new user named
testuser. When creating them, specify:- Their primary group should be
labtesters. - They should be added to the
sudosupplementary group. - Their home directory should be created (
-m). - Their login shell should be
/bin/bash.
- Their primary group should be
- Verify the user was created by querying the
passwdandshadow(withsudo) databases usinggetent. - Check the
labtestersandsudogroup entries (usinggetent) to confirmtestuser’s membership. - Set a password for
testuserso they can log in. - Use
suto start a new login shell astestuser. - Once logged in as
testuser, runidto check your identity andpwdto see your home directory. exitthetestuser’s shell to return to your original session.- Clean up: as root, delete the
testuser(making sure to remove their home directory) and delete thelabtestersgroup. - Verify they are gone using
getent.
Tool Summary
This lab uses two distinct categories of tools: those that interact directly with the kernel’s security model, and those that manage the user-space databases.
Kernel-Level & Privilege Tools
These commands directly manipulate kernel-level concepts (file ownership, process UIDs) or are used for privilege escalation.
| Command | Description | Common Flags |
|---|---|---|
chown
|
Change owner. Changes the UID and GID owner of a file/directory. Requires kernel-level privilege (e.g., eUID=0) to change owner to someone else. | -R: Recursiveuser:group: Set both user and group
|
chgrp
|
Change group. Changes the GID owner of a file/directory. You must be the owner of the file AND a member of the target group. | -R: Recursive
|
id
|
Display process identity (UID, GID, groups). | -u: Show UID only-g: Show GID only-n: Show name instead of number
|
sudo
|
Substitute user do. Executes a command as another user (default: root) based on /etc/sudoers rules. Uses setuid.
|
-u user: Run as user-i: Start a root login shell-l: List allowed commands
|
su
|
Substitute user. Switches to another user account (default: root). Authenticates using the target user’s password. | - or -l: Start a full login shell-c 'cmd': Run a single command
|
User-Space Account Database Tools
These commands read from or write to the user-space databases (e.g., /etc/passwd, /etc/shadow, /etc/group), which are then interpreted by NSS.
| Command | Description | Common Flags |
|---|---|---|
passwd
|
Change a user’s password. Securely updates /etc/shadow.
|
[username]: Change password for username (root only)-l: Lock account-u: Unlock account
|
getent
|
Get entries from NSS databases. The correct way to look up users/groups. | passwd [user]: Look up usergroup [group]: Look up groupshadow [user]: Look up shadow entry
|
chfn
|
Change finger. Modifies the GECOS field in /etc/passwd.
|
[username]: Modify for username (root only)
|
finger
|
Displays user information, primarily by parsing the GECOS field. | [username]: Show info for username
|
useradd
|
Creates a new user account. Updates /etc/passwd, /etc/shadow, /etc/group.
|
-m: Create home directory-g group: Set primary group-G groups: Set supplementary groups-s shell: Set login shell
|
groupadd
|
Creates a new group. Updates /etc/group.
|
[groupname]
|
Deliverables and Assessment
Submit a single document (PDF or Markdown) containing:
- Command Output: Screenshots or text-based command output for each non-optional hands-on exercise (A-G), clearly labelled by section.
- Conclusion Questions: Short written answers to the “Conclusion Questions” below.
Grading will consider the completeness of your outputs, the correctness and clarity of your reasoning in the conclusion answers, and your adherence to instructions.
Conclusion Questions
Please answer the following summary questions based on the lab’s content.
- Explain the kernel’s permission checking algorithm. If a file
/data/report.txtis owned byroot:webdevand has permissions640(rw-r-----), can the userstudent(who is a member of thewebdevgroup) read the file? Why or why not? - Why was the sensitive password hash moved from the world-readable
/etc/passwdto the root-only-readable/etc/shadow? What kernel-level permission difference enables this security? - Explain the relationship between the user-space tool
useradd, the file/etc/passwd, the Name Service Switch (NSS), and the kernel’s UID-based permission checks. How do they all interact when you runls -l? - What would happen if you (as root) manually edited
/etc/passwdand changed your user’s UID from1001to5001, but did not change the ownership of any files in your home directory (which are all still owned by kernel UID1001)? What specific problems would you face at your next login?