OS Lab 4 - Users, Groups and Permissions

De la WikiLabs
Jump to navigationJump to search

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:

  1. 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).
  2. 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.
  3. 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.
  4. None of the above?
    • Apply the others permission bits (------rwx). Access is granted or denied.

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.

  1. First, check your own identity.
  2. Create a new empty file named /tmp/lab4_testfile.
  3. List the file’s details and observe that you are the owner.
  4. Change the file’s permissions to 640 (rw-r-----).
  5. Change the file’s owner and group to root. List the details again to confirm.
  6. As your normal user, attempt to read the file. This should fail. Document the “Permission denied” error.
  7. Now, try to read the file as the nobody user. This should also fail.
  8. Finally, demonstrate root’s power:
    • Use sudo to write the text “hello from root” into the file, bypassing its permissions.
    • Read the file using sudo to confirm the text is there.
    • Use sudo to change the file’s permissions to 600 (rw-------).
    • List the file’s details one last time.
  9. 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.

  1. Create a new directory named /tmp/lab4_dir and a file named secretfile inside it.
  2. Set the directory’s permissions to 700 (rwx------). List the directory’s details to confirm.
  3. Verify you can list the directory’s contents and read the secretfile inside it.
  4. Now, remove only the execute (x) bit for the owner of /tmp/lab4_dir.
  5. Try to cd into the directory. This will fail.
  6. Try to list the directory’s contents. This will also fail.
  7. Try to read the secretfile using its full path. This will also fail, as you can’t traverse the directory.
  8. 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------.
  9. Try to list the directory’s contents. This will fail.
  10. Try to cd into the directory. This will succeed.
  11. Once inside, try to read the secretfile (which you know exists). This will succeed.
  12. Return to the parent directory (cd ..).
  13. 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 s instead of x in 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:

  1. The sudo binary (/usr/bin/sudo) is owned by root.
  2. It has the setuid bit set.
  3. When a normal user (e.g., student, ruid=1001) runs sudo, the kernel starts the sudo process with ruid=1001 but euid=0 (root).
  4. Now running with root’s effective permissions, the sudo process is allowed to read its configuration file, /etc/sudoers.
  5. It checks /etc/sudoers to see if the real user (student) is allowed to perform the requested action.
  6. If allowed, sudo (still running as euid=0) uses its power to launch the target command (e.g., apt update) as root (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

  1. View the permissions and ownership of the sudo binary (likely /usr/bin/sudo). Note the s bit.
  2. View the permissions of the su binary (likely /bin/su). Note if it is also setuid root.
  3. Use sudo to run the id command as the nobody user.
  4. Run id as your normal user and compare the output.
  5. Use su to attempt to run the id command, first as root and then as nobody.
  6. Observe the password prompts. Unlike sudo (which asks for your password), su asks 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.

  1. Create a simple shell script at /tmp/lab4_script.sh that prints the process’s effective and real user IDs.
  2. Make the script executable.
  3. As root, change the script’s owner to root and set its setuid bit.
  4. List the script’s permissions to confirm the s is present.
  5. Run the script as your normal, non-root user.
  6. Observe the output: does the eUID show ‘root’ or your user? On most modern systems, the setuid bit will be ignored for scripts.
  7. 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 ruid and euid, each process has two more numeric ids. The fsuid (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 its euid. The fsuid (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 its euid; the suid (saved set-user-ID) stores the previous euid so a process (e.g., a setuid program) can drop privileges and later regain them safely. Similarly, there is an fsgid and sgid.
  • ACLs (Access Control Lists): getfacl and setfacl commands 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_SERVICE allows 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:/shell
    • username: 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.
      1. User’s Full Name (e.g., John Doe)
      2. Room Number
      3. Work Phone
      4. Home Phone
      5. Other contact info
    • /home/dir: The user’s home directory.
    • /shell: The user’s default login shell (e.g., /bin/bash).
  • /etc/shadow: Because /etc/passwd must be world-readable (so ls -l can 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_list
    • groupname: 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

  1. Display the first 10 lines of the /etc/passwd user database.
  2. Attempt to display the first 5 lines of /etc/shadow. This will fail.
  3. Use sudo to display the first 5 lines of /etc/shadow to prove root can read it.
  4. Display the first 10 lines of the /etc/group database.
  5. Use the getent command to query the passwd database for the root user and for your own user (using the $USER variable).
  6. Use getent to query the group database for the sudo group and for your own primary group (which you can find from the id command).

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

  1. Use the finger command to view your user’s GECOS information.
  2. Use the chfn command to interactively change your GECOS information (Full Name, Room Number, etc.). You may be prompted for your password.
  3. Run finger again to see the changes have been applied.
  4. Check your entry in the /etc/passwd file (using getent or grep) to see how the GECOS field (the 5th field) was updated.
  5. Use the passwd command to change your password. This command securely updates the /etc/shadow file.

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

  1. Display the lines from /etc/nsswitch.conf that configure the passwd and group databases (the lines starting with passwd: and group:).

  2. Test the lookup system by using getent to resolve the nobody user and the nogroup group.

  3. (Optional, use with extreme care) As root, edit /etc/nsswitch.conf (e.g., sudo nano /etc/nsswitch.conf). Put a # at the beginning of the group: line to comment it out, and add a new line group: sss (a service that is likely not running). Save the file.

    Now, try to resolve group names using getent group sudo and ls -l /. Observe that names may now show up as numbers.

    IMMEDIATELY restore /etc/nsswitch.conf to its original state and verify ls -l works 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.

  1. As root, create a new group named labtesters.
  2. Verify the group was added by checking the end of the /etc/group file and by using getent.
  3. As root, create a new user named testuser. When creating them, specify:
    • Their primary group should be labtesters.
    • They should be added to the sudo supplementary group.
    • Their home directory should be created (-m).
    • Their login shell should be /bin/bash.
  4. Verify the user was created by querying the passwd and shadow (with sudo) databases using getent.
  5. Check the labtesters and sudo group entries (using getent) to confirm testuser’s membership.
  6. Set a password for testuser so they can log in.
  7. Use su to start a new login shell as testuser.
  8. Once logged in as testuser, run id to check your identity and pwd to see your home directory.
  9. exit the testuser’s shell to return to your original session.
  10. Clean up: as root, delete the testuser (making sure to remove their home directory) and delete the labtesters group.
  11. 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: Recursive
user: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 user
group [group]: Look up group
shadow [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:

  1. Command Output: Screenshots or text-based command output for each non-optional hands-on exercise (A-G), clearly labelled by section.
  2. 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.

  1. Explain the kernel’s permission checking algorithm. If a file /data/report.txt is owned by root:webdev and has permissions 640 (rw-r-----), can the user student (who is a member of the webdev group) read the file? Why or why not?
  2. Why was the sensitive password hash moved from the world-readable /etc/passwd to the root-only-readable /etc/shadow? What kernel-level permission difference enables this security?
  3. 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 run ls -l?
  4. What would happen if you (as root) manually edited /etc/passwd and changed your user’s UID from 1001 to 5001, but did not change the ownership of any files in your home directory (which are all still owned by kernel UID 1001)? What specific problems would you face at your next login?