Linux interview questions
Prep Linux interviews from file modes and signals through systemd, cgroups v2, and production troubleshooting — tagged Beginner to Expert.
Beginner → Intermediate → Advanced → Expert — answers are written the way you’d say them in a real interview. Advanced and Expert go deeper with war-story detail, architecture diagrams, and the follow-up an interviewer often asks next.
Explain Linux file permissions.Intermediate
Each file has read/write/execute bits for owner, group, and others — like 640 for rw-r-----. On directories, execute means you can enter or traverse; read means you can list names.
ls -l app.sh # -rwxr-x--- → user rwx, group r-x, other --- = 750 chmod 640 app.sh chmod u+x,o-r app.sh
chmod numeric vs symbolic?Beginner
Numeric encodes rwx as bits: r=4, w=2, x=1, summed per class — 755 is rwxr-xr-x. Symbolic edits relative bits like u+x or go-w, which is safer when I only want one change.
chmod 644 file chmod 755 dir chmod g+w,o-rwx file
Hard link vs symbolic link?Beginner
A hard link is another directory entry for the same inode — same data, same filesystem. A symlink is a path pointer that can cross filesystems and break if the target moves.
ln file hard ln -s file soft ls -li file hard soft
What is umask?Beginner
It's a mask subtracted from default create modes — 022 yields 644 files and 755 directories. It sets the default posture for new files per shell or service.
umask touch new; ls -l new # 666 masked by 022 → 644
What do SUID, SGID, and the sticky bit do?Advanced
SUID runs a binary as the file owner — like passwd. SGID runs as the group, or makes new files inherit a directory's group. Sticky on a directory like /tmp means only the owner can delete their own files.
SUID and SGID binaries are a classic local privilege-escalation path and belong on a regular audit with find -perm -4000/-2000. Package-managed SUID like passwd or sudo is expected; random SUID under /home or /tmp is not. SGID directories help shared team drops inherit group ownership; sticky on /tmp prevents users from deleting each other's files. A capital S or T in ls means the special bit is set without execute — usually a mistake.
ls -l /usr/bin/passwd # -rwsr-xr-x → s in owner exec = SUID find / -perm -4000 -type f 2>/dev/null | head
Interviewer often follows with: How do file capabilities change the need for SUID?
How do POSIX ACLs extend permissions?Intermediate
When owner/group/other isn't enough, ACLs add per-user or per-group entries via setfacl and getfacl. A trailing + in ls -l marks that an ACL is present.
setfacl -m u:alice:rw report.txt getfacl report.txt ls -l report.txt # -rw-rw-r--+ → the + means ACL
Interview: a world-writable SUID binary shows up in an audit — what do you do?Expert
I'd treat it as a critical privilege-escalation risk. Remove SUID or fix ownership and mode, find who created it, and check whether it was already abused.
SUID root plus writable by others means any local user can replace the binary contents — depending on the write target — or abuse a poorly written SUID helper. Immediate actions for me: chmod u-s, quarantine the path, compare against package manager file integrity, inspect shell history and auth logs, and hunt for unexpected root-owned cron or systemd units. Capital S in ls means the SUID bit is set but execute isn't — usually a misconfiguration. Regular find audits for -4000/-2000 should be part of baseline hardening.
ls -l /usr/local/bin/suspect chmod u-s /usr/local/bin/suspect rpm -Vf /usr/local/bin/suspect 2>/dev/null || debsums -c 2>/dev/null | head find / -perm -4000 -type f 2>/dev/null
Interviewer often follows with: How do capabilities replace many classic SUID needs?
Interview: explain Linux capabilities vs full root.Advanced
Capabilities split root into discrete privileges — CAP_NET_BIND_SERVICE, CAP_SYS_ADMIN, and so on. I'd grant only what a service needs instead of UID 0 with the full set.
Historically everything needed root; capabilities — and ambient, inherited, bounding sets — let you bind low ports or use raw sockets without a full root shell. systemd can set AmbientCapabilities= and CapabilityBoundingSet=. Containers drop capabilities the same way. CAP_SYS_ADMIN is dangerously broad — I'd treat it nearly like root. File capabilities via setcap can replace SUID for specific binaries, but they're still privilege and must be inventoried. getpcaps and capsh --print help inspect the current set.
capsh --print getpcaps $$ sudo setcap 'cap_net_bind_service=+ep' /usr/local/bin/api getcap /usr/local/bin/api
Interviewer often follows with: What is the difference between permitted, effective, and bounding sets?
Expert: design least-privilege file access for a multi-user deploy directory.Expert
I'd own by a deploy group, mode 750/640, optional ACLs for break-glass readers, no world access, and sticky or immutable bits only where justified. Prefer group ownership over chmod 777.
Pattern I'd use: root or deploy owns the tree, group app can read/execute, others get nothing. Shared drop directories use SGID so new files inherit the group, plus sticky if users must not delete each other's files. Secrets stay 600 root:root or a dedicated secrets group, never in world-readable config. ACLs help when two teams need different access without exploding group membership — but document them because ls alone under-communicates. Pair with systemd UMask=, ProtectSystem=, and ReadWritePaths= so the service can't wander the filesystem even if compromised.
chown -R root:app /opt/app
find /opt/app -type d -exec chmod 750 {} \;
find /opt/app -type f -exec chmod 640 {} \;
chmod 750 /opt/app/bin/*
setfacl -m g:audit:rx /opt/app/logsInterviewer often follows with: How would systemd ProtectHome and ProtectSystem complement this?
Who can change ownership of a file?Beginner
Only root can chown arbitrarily. Ordinary users can chmod their own files and may chgrp to a group they belong to, depending on policy.
sudo chown app:app /var/lib/app/data chgrp app report.txt ls -l report.txt
Process vs thread on Linux?Beginner
A process has its own address space; threads share one process's memory. Both are kernel tasks — threads just share more via clone() flags.
ps -eLf | head cat /proc/self/status | grep Threads
SIGTERM vs SIGKILL vs SIGHUP?Intermediate
SIGTERM asks a process to exit and can be caught for cleanup. SIGKILL can't be caught or ignored. SIGHUP often means "reload config" for daemons.
kill -TERM 4823 kill -HUP 4823 kill -9 4823 kill -l
What is a zombie process? An orphan?Intermediate
A zombie has exited but its parent hasn't wait()ed — it only holds a PID slot. An orphan's parent died; init or systemd adopts and reaps it.
ps -eo pid,ppid,stat,cmd | awk '$3 ~ /Z/' # fix the parent — you cannot kill a zombie itself
What do nice and ionice control?Advanced
nice from -20 to 19 hints CPU scheduling priority — higher nice is nicer, less CPU. ionice sets I/O priority classes. I'd use them for batch jobs; hard isolation still needs cgroups.
nice is a scheduler hint, not a hard cap — a niced process can still saturate CPUs if nothing else competes. ionice classes matter mainly with CFQ/BFQ-style fairness; on modern multi-queue SSDs the effect can be subtle. For isolation guarantees I'd use cgroup cpu.max / io.max — systemd CPUQuota=, IOWeight=. Still use nice/ionice for best-effort batch jobs on shared bastions.
nice -n 10 ./batch.sh ionice -c2 -n7 ./batch.sh renice 15 -p <pid>
Interviewer often follows with: When would you choose cgroup CPUQuota over nice?
How does systemd manage a service?Advanced
A unit file declares ExecStart, dependencies, restart policy, and resource limits. systemd tracks the service as a cgroup, captures logs to the journal, and orders boot via targets.
Each service gets a cgroup so forked children can't escape supervision. Restart= and StartLimitBurst prevent crash loops from hammering the box. I'd prefer Type=notify or an explicit PIDFile over guessing with Type=simple or forking. Logs go to the journal. Hardening directives — ProtectSystem, PrivateTmp, CapabilityBoundingSet, NoNewPrivileges — close a lot of post-compromise paths without rewriting the app.
# /etc/systemd/system/app.service [Service] ExecStart=/usr/bin/app Restart=on-failure MemoryMax=512M systemctl enable --now app journalctl -u app -f
Interviewer often follows with: What is the difference between Requires= and Wants=?
Interview: a service ignores SIGTERM on deploy — how do you debug?Expert
I'd confirm what PID 1 in the unit actually is, whether it traps TERM, and what TimeoutStopSec does. Escalate to SIGKILL only after I understand cleanup needs.
systemd sends SIGTERM to the main process — or the control group with KillMode= — waits TimeoutStopSec, then SIGKILL. If ExecStart is a shell script without exec, the script may be PID 1 and never forward signals to the child. I've hit that more than once. Fix with exec in the script, Type=notify/forking correctly set, or KillMode=mixed. strace -p on the main PID during stop shows whether TERM arrives. Containers have the same class of bug when ENTRYPOINT is shell-form.
systemctl cat app systemctl show app -p MainPID -p TimeoutStopUSec -p KillMode strace -p "$(systemctl show -p MainPID --value app)" -e signal journalctl -u app -b --no-pager | tail
Interviewer often follows with: What does KillMode=control-group change vs process?
Interview: when do you use systemctl isolate or rescue targets?Advanced
rescue.target and emergency.target are for broken boots or maintenance — fewer services, root shell. isolate replaces the current target; I'd use it carefully because it stops everything not in the destination.
multi-user.target is the usual server default; graphical.target adds a display manager. rescue is single-user-ish with local FS mounted; emergency is even more minimal. From GRUB you can append systemd.unit=rescue.target. isolate multi-user.target is how you leave rescue. I'd avoid casual isolate on production hosts over SSH — you can kill the session's dependencies.
systemctl get-default systemctl list-units --type=target # GRUB: systemd.unit=rescue.target
Interviewer often follows with: How do you find which unit failed and blocked boot?
Expert: how should a long-running daemon handle signals in production?Expert
Catch SIGTERM/SIGINT for graceful drain, SIGHUP for reload if supported, handle SIGPIPE or EPIPE, and leave SIGKILL to the supervisor as last resort. Document the drain timeout for orchestrators.
Graceful stop means stop accepting work, finish in-flight requests within a deadline, flush logs, then exit 0. systemd TimeoutStopSec and Kubernetes terminationGracePeriodSeconds must be at least that deadline. Reload via SIGHUP shouldn't drop connections when possible. Double-signal patterns — TERM then wait then KILL — are normal. I wouldn't rely on SIGKILL for routine deploys — it skips cleanup and can corrupt on-disk state. Pair with readiness probes so traffic leaves before TERM.
[Service] ExecStart=/usr/bin/app ExecReload=/bin/kill -HUP $MAINPID TimeoutStopSec=30 KillSignal=SIGTERM FinalKillSignal=SIGKILL
Interviewer often follows with: How do you test graceful drain in CI without a full cluster?
How do you find and stop a runaway process?Beginner
I'd identify it with top or ps sorted by CPU or memory, confirm it's safe to stop, send SIGTERM first, then SIGKILL only if it ignores me.
ps -eo pid,%cpu,%mem,cmd --sort=-%cpu | head kill -TERM <pid> kill -9 <pid>
What is PID 1’s special role?Intermediate
PID 1 — systemd on most servers — parents orphans, reaps zombies, and handles system signals. Inside containers your app is often PID 1 — it must reap children or use --init.
docker run --init app:1 # or install tini as ENTRYPOINT
A server is slow — how do you start?Beginner
I'd check load and the four resources: CPU, memory, disk I/O, and network. Correlate with recent changes and journalctl before deep-diving one process.
uptime top -o %CPU free -m df -h journalctl -p err -b --no-pager | tail
What does load average mean?Beginner
Average runnable plus uninterruptible — D-state, often I/O — tasks over 1/5/15 minutes. Compare to CPU count — load around cores means busy; sustained much higher means saturation.
uptime nproc # load 3.9 on 4 cores ≈ fully busy, not necessarily overloaded
How do you use strace and lsof?Advanced
strace shows syscalls — where a process blocks or fails. lsof lists open files and sockets. Together they answer "what is it waiting on?" and "what is holding this file?"
strace answers syscall-level "what is it doing or failing on" — I'd attach with care on latency-sensitive processes and use -e to filter. lsof maps fds to paths and sockets; +L1 finds deleted-but-open files filling disks. For CPU hotspots I'd prefer perf over blind strace. In containers, nsenter or kubectl debug may be required to see the right namespaces. Always confirm you have the right PID — container PID vs host PID.
strace -f -e trace=openat,connect,network -p <pid> lsof -p <pid> lsof +L1 | grep deleted
Interviewer often follows with: How do you strace a process inside a container from the host?
How do you read journalctl for a unit?Intermediate
journalctl -u unit -b shows this boot's logs; -f follows; --since and -p filter time and priority. Persistent journal needs Storage=persistent in journald.conf.
journalctl -u nginx -b --no-pager journalctl -u nginx --since "1 hour ago" -p warning journalctl -k -b | grep -i oom
What is cgroups v2 used for?Advanced
The unified hierarchy that limits and accounts CPU, memory, I/O, and PIDs per leaf. systemd and containers place each service or pod in a cgroup and enforce memory.max / cpu.max.
cgroup v2 is a single unified hierarchy — no split cpu vs memory trees. Controllers like memory, cpu, io, pids enforce limits and accounting per leaf. systemd places units under system.slice; containers get their own leaves so one workload's memory.max OOM doesn't necessarily take the host. Delegation matters for rootless and nested runtimes. When limits disagree — app heap bigger than cgroup memory.max — expect exit 137.
systemctl status app ls /sys/fs/cgroup/system.slice/app.service/ cat /sys/fs/cgroup/system.slice/app.service/memory.current
Interviewer often follows with: Where do you read memory.current for a systemd unit?
Interview: df says full but du does not add up — why?Advanced
A deleted file still open by a process keeps blocks until the fd closes. df counts them; du walking the tree can't see them. I'd find it with lsof and restart or truncate the holder.
Classic with long-lived apps that rotate logs incorrectly — delete instead of truncate or copytruncate. Containers and journald can show the same symptom. Fix: identify deleted-but-open paths via lsof +L1 or /proc/<pid>/fd, truncate the fd or restart the process, then fix log rotation. Also check sparse files and mount bind overlays when numbers still look wrong.
df -h /var lsof +L1 | grep deleted # truncate without restart if safe: # : > /proc/<pid>/fd/3
Interviewer often follows with: How should logrotate be configured to avoid this?
Interview: diagnose an OOM kill.Expert
I'd check dmesg and journal for "Out of memory" / "Killed process", inspect oom_score, and whether a cgroup memory.max triggered a local kill vs host-wide pressure.
The kernel OOM killer picks a victim using oom_score / oom_score_adj when reclaim fails. In cgroup v2, hitting memory.max often kills inside that cgroup first — the container dies with 137 — without taking down the whole host. That's desired isolation. Host OOMs mean the machine was overcommitted. Remedies: raise limits only if capacity exists, fix leaks, tune JVM/Node heaps to fit the cgroup, set oom_score_adj for sacrificial batch jobs, and add memory pressure alerts before the kill.
dmesg -T | grep -i -A2 'killed process' journalctl -k -b | grep -i 'out of memory' cat /proc/<pid>/oom_score /proc/<pid>/oom_score_adj
Interviewer often follows with: How do you tell cgroup OOM from host OOM quickly?
Expert: walk a CPU-saturation incident with evidence.Expert
I'd identify the process with top or pidstat, split user vs system time, sample stacks with perf, and check for runaway threads, livelocks, or noisy neighbors in the same cgroup or CPU set.
USE method: utilization, saturation, errors per resource. High %us points at application code; high %sy at syscalls, spinlocks, or networking; high %steal on hypervisors. Softirq overload shows in /proc/softirqs and can look like "CPU wait" without a busy user process. For Java/.NET I'd use async profilers; for native, perf top or flamegraphs. Fix may be code, reducing parallelism, CPU affinity or cgroup cpu.max, or moving off a noisy host. Always capture a short timeline: when it started, deploys, and traffic deltas.
top -o %CPU pidstat -u 1 5 perf top -p <pid> mpstat -P ALL 1 5
Interviewer often follows with: What does sustained high load with low %CPU usually imply?
Expert: how do memory pressure and page cache interact?Expert
Linux uses free RAM for page cache and reclaim under pressure. "Low free" is normal; I'd watch available, PSI, swap-in, and thrashing — not just the free column.
free -m available estimates what can be given to new workloads without swapping. Under cgroup limits, a container can OOM while the host still has cache. PSI files under /proc/pressure/ show some/full stalls for cpu/memory/io and are excellent early warnings. Dropping caches with drop_caches is a diagnostic hammer, not a fix — it can hurt performance. Prefer fixing the consumer, sizing limits, and making sure working sets fit.
free -m cat /proc/pressure/memory vmstat 1 5 sar -r 1 5
Interviewer often follows with: Why can a container OOM while free -m on the host still looks fine?
High iowait — what do you check next?Advanced
I'd look at iostat and pidstat for the busy device and processes in D state, then whether it's read-heavy cold cache, write storms, or a failing disk. Storage latency is saturation even when CPU looks idle.
iowait means CPUs are idle waiting on I/O. Correlate with await/util in iostat, nfsstat for network mounts, and dmesg for storage errors. Fix paths: reduce sync write amplification, move logs to faster disks, raise queue depth carefully, or fix an application that fsyncs too often. Parallelism that stampedes the same spindle makes it worse.
iostat -xz 1 5 ps -eo pid,stat,wchan:32,cmd | awk '$2 ~ /D/' pidstat -d 1 5
Interviewer often follows with: How do you distinguish NFS latency from local disk latency?
How do you find what is listening on a port?Intermediate
ss -tulpn — or lsof -i :PORT — shows the listener, PID, and process. I'd trace that PID back to a systemd unit or container.
ss -tulpn | grep :8080 ps -p <pid> -o pid,cmd systemctl status <pid>
Walk the TCP three-way handshake.Beginner
Client SYN → server SYN-ACK → client ACK → ESTABLISHED. Close is a FIN/ACK exchange; the active closer usually enters TIME_WAIT to absorb late packets.
ss -tan state established | head ss -tan state time-wait | wc -l
How does name resolution work on a modern Linux host?Intermediate
nsswitch.conf orders sources — files, DNS, and so on. Apps call getaddrinfo; systemd-resolved often sits in the middle. dig talks to DNS directly — getent shows what apps see.
getent hosts api.internal resolvectl query api.internal cat /etc/nsswitch.conf | grep hosts
When do you use tcpdump vs ss?Intermediate
ss answers "what sockets exist and in what state". tcpdump answers "what packets are on the wire". I'd use ss first, then tcpdump when I need handshake or payload-level proof.
ss -tulpn tcpdump -ni eth0 port 443 -c 20 tcpdump -ni any host 10.0.0.5 and port 5432 -c 50
Interview: host is unreachable — how do you debug layer by layer?Expert
I'd resolve the name, ping or arp the IP, check the route, then test the port and firewall. Localize whether it's DNS, L3, or L4/policy.
A structured path beats random tool spam: getent or resolvectl for DNS, ip route get for egress path and interface, ping only if ICMP is allowed — failure is inconclusive on filtered networks — traceroute or mtr for path, then nc or curl for the port. Check nftables/iptables and security groups in parallel. On servers, also verify the service is bound to the expected address — 0.0.0.0 vs 127.0.0.1.
getent hosts app.example ip route get 10.0.0.5 ping -c1 10.0.0.5 nc -vz 10.0.0.5 443 nft list ruleset | head
Interviewer often follows with: Why can ping fail while HTTPS works?
Interview: explain nftables/iptables packet flow at a high level.Advanced
Packets hit hooks — prerouting, input, forward, output, postrouting. Chains match and accept, drop, reject, or jump. nftables is the modern unified framework; iptables often translates into it.
Local delivery uses input; routed traffic uses forward. Docker and kube-proxy historically inserted many iptables rules — order and firewalld coexistence cause surprising drops. I'd always list counters to see which rule matches. Prefer one firewall manager; mixing ufw, firewalld, and raw iptables invites last-change-wins bugs. Conntrack state matters for established flows and NAT.
nft list ruleset iptables -L -n -v --line-numbers iptables -t nat -L -n -v
Interviewer often follows with: Where would you look for Docker-published port DNAT rules?
Expert: walk power-on to login and how you localize a boot hang.Expert
UEFI → GRUB → kernel plus initramfs → systemd as PID 1 → targets and units → getty. Each stage has distinct logs; the last message tells you where it stuck.
Firmware/POST failures never reach GRUB. GRUB issues point at bootloader config or disk. initramfs hangs often mean missing modules, wrong root= UUID, or encrypt/unlock prompts. After switch-root, systemd records unit failures; journalctl -b -p err and systemctl --failed are my first stops. For early boot, enable persistent journal or read /run/log when disk wasn't writable. Kernel panics dump to console; remote serial or IPMI helps headless hosts. Masking a bad unit from a live USB is a common recovery path.
systemctl --failed journalctl -b -p err --no-pager | tail -n 50 journalctl -u NetworkManager -b
Interviewer often follows with: How do you boot into rescue from GRUB without a live USB?
Expert: debug intermittent TCP resets in production.Expert
I'd capture both ends with tcpdump, compare seq/ack and who sent RST, check conntrack exhaustion, middleboxes, and app idle timeouts. Correlate with load balancer health flaps.
An RST from the local stack often means nothing listening, or an application closed aggressively. RSTs from a middlebox can indicate ACL/IDS or asymmetric routing. TIME_WAIT accumulation and nf_conntrack_table full show up in dmesg and cause drops that look like resets. Idle timeouts on LBs shorter than app keepalives create client-visible blips — fix with better health checks and idle settings. Always note source ports and whether only one AZ or path is affected.
tcpdump -ni eth0 host 10.0.0.8 and port 5432 -w /tmp/db.pcap ss -s dmesg | grep -i conntrack conntrack -C 2>/dev/null
Interviewer often follows with: How do you tell an application RST from a firewall RST in a pcap?
What is the difference between INPUT and FORWARD chains?Intermediate
INPUT filters traffic destined for the local host. FORWARD filters traffic routed through the host — containers, VMs, routers. Misplacing rules is a common Docker/firewall footgun.
iptables -L INPUT -n -v iptables -L FORWARD -n -v # bridge/container traffic often needs FORWARD allow
How do you check default route and DNS quickly?Beginner
ip route show default for the gateway and iface; resolvectl status or /etc/resolv.conf for resolvers. Wrong route or empty resolvers look like "the network is down."
ip route show default ip -br addr resolvectl status | head
Incident: the OOM killer shot sshd / the JVM you needed, while a runaway batch job survived. How do you explain and fix it?Expert
OOM score is heuristic — unprotected critical processes can die first. I'd raise protection for sshd and agents, put the batch job in a memory cgroup with a hard limit, and fix the leak.
The killer picks the highest oom_score_adj victim that frees enough memory. Large, old, unprotected allocators lose; processes with oom_score_adj=-1000 are immune — careful: mistaking a leaky app for "critical" just panics the box later. systemd has OOMScoreAdjust=; containers need memory.max so the workload dies inside its cgroup before the host. Post-incident: journalctl -k for the kill, inspect /proc/<pid>/oom_score, confirm whether it was global OOM or a cgroup OOM. Long term: limits on batch queues, swap policy awareness, and alerts on mem.pressure.
journalctl -k -b | grep -i 'killed process' cat /proc/$(pgrep -o sshd)/oom_score /proc/$(pgrep -o sshd)/oom_score_adj # systemd drop-in: OOMScoreAdjust=-500 for sshd; MemoryMax= for the batch slice
Interviewer often follows with: How does a cgroup OOM differ from a system-wide OOM in symptoms?
After a power outage, every node reboots and the shared NFS/API backend melts under a thundering herd. How do you break the stampede?Advanced
I'd stagger service starts with randomized delay and dependencies, shed non-critical unit Wants, and add client-side backoff with jitter so reconnects don't align.
Cold boot aligns cron, systemd After=network-online, and app reconnect loops. Fix layers: systemd RestartSec= with jittery backoff, rate-limited timers, load-balancer slow-start, and server-side admission control. For NFS, enable graceful reconnect and avoid simultaneous fsck/mount storms across the fleet. Runbooks should include "boot into rescue and start tiers manually" when automation makes the outage worse. I'd chaos-test reboot of N% of the fleet, not only single hosts.
systemctl show myapp | grep -E 'Restart|After' # drop-in: RestartSec=30, RandomizedDelaySec= on timers # app: exponential backoff + jitter on DB connect
Interviewer often follows with: Where do you put jitter — systemd, the app client, or the load balancer?
Disk shows 50% used on `df -h` but writers fail with "No space left on device". What do you check?Advanced
Inodes. df -i often shows 100% while block usage looks fine — millions of tiny files exhausted the inode table.
Ext4/XFS inode exhaustion is classic with mail spools, container overlay trees, or app session caches. Diagnosis: df -i, find directories with huge file counts, identify the producer. Remediation: delete or archive tiny-file trees, raise inode ratio only on mkfs — too late for a live FS — and move workloads to filesystems sized for the file-count pattern. Also distinguish quota failures from true ENOSPC. Monitor both block and inode usage.
df -h / df -i / find /var/spool -xdev -type f | wc -l du -sh /var/spool/* 2>/dev/null | sort -h | tail
Interviewer often follows with: Can you add inodes to an existing ext4 filesystem without recreating it?
Clients report TLS handshake failures to an internal API that still answers HTTP on :80. How do you debug on the host?Advanced
I'd verify the listener, cert chain and clock, then capture the handshake. Usual causes: expired cert, SNI mismatch, missing intermediate, or TLS version/cipher mismatch.
openssl s_client -connect host:443 -servername … shows chain, dates, and alert codes. Check system time — skew breaks validity — file permissions on key material, and whether the process reloaded after cert rotation. tcpdump helps spot RST mid-handshake vs alert. Intermediate-not-served is still common with incomplete fullchain.pem. For mTLS, verify client cert CA trust on the server side separately. Application "connection reset" logs often hide handshake alerts — I'd always get the TLS layer view.
date -u openssl s_client -connect api.internal:443 -servername api.internal </dev/null 2>&1 | openssl x509 -noout -dates -subject ss -tulpn | grep ':443'
Interviewer often follows with: How do you tell a missing intermediate from a hostname mismatch in s_client output?
Load average is 40 on an 8-CPU box, but top shows ~5% user CPU and high iowait. What is actually wrong?Advanced
Tasks are blocked on storage — D state — so the run queue looks huge while CPUs sit idle waiting. I'd find the hot disk and the processes stuck in iowait.
Load average counts runnable plus uninterruptible sleep. Heavy NFS, failing disks, or sync-heavy writes produce D-state piles and high wa% without busy CPU. Tools: iostat -xz, pidstat -d, ps for wchan, and dmesg for storage errors. Fix the I/O path — faster volume, less fsync amplification, repair NFS, isolate noisy neighbors — adding CPU cores won't help. Distinguish steal% from iowait. Container hosts often hide the writer as a container PID — map back with nsenter or docker top.
uptime; mpstat 1 5 iostat -xz 1 5 ps -eo pid,stat,wchan:32,cmd | awk '$2 ~ /D/'
Interviewer often follows with: Why can NFS latency inflate load average more than local SSD latency for the same app?
A systemd unit flaps: start → fail → restart forever, masking the root error. How do you stabilize and find the cause?Advanced
I'd stop the restart storm — mask or set StartLimit — read the first failure in the journal, fix the Exec or config, then re-enable with sane RestartSec limits.
Restart=always without StartLimitBurst turns a config typo into a noisy loop that fills the journal and can thundering-herd dependencies. Triage: systemctl status, journalctl -u -b, look at ExitCode/StatusErrno, run the ExecStart by hand under the same User= and Environment=. Temporary: systemctl mask --now or edit Restart=on-failure with StartLimitIntervalSec=. Permanent: fix the binary path, permissions, or After= ordering. Avoid RemainAfterExit mistakes for Type=oneshot services that look "active" while broken.
systemctl status myapp --no-pager journalctl -u myapp -b -p err --no-pager | head -n 40 systemctl mask --now myapp # stop the storm while fixing # drop-in: StartLimitIntervalSec=300 StartLimitBurst=3 RestartSec=10
Interviewer often follows with: What is the difference between `systemctl disable` and `systemctl mask` during an incident?
Hardening ticket: a service still retains CAP_SYS_ADMIN despite CapabilityBoundingSet= in the unit. What did you miss?Expert
Bounding set only caps what can be gained — AmbientCapabilities, file capabilities on the binary, or a helper that re-execs with a wider set can still surprise you. I'd inspect the effective set at runtime.
systemd CapabilityBoundingSet= reduces the bounding set for the unit's processes; AmbientCapabilities= raises ambient. A binary with setcap or SUID can still exercise file capabilities within what the bounding set allows — if CAP_SYS_ADMIN remains in the bounding set, it's game on. Containers add another layer. Verify with getpcaps on the live PID, capsh --print, and systemctl show | grep Cap. Prefer drop ALL then add back; treat CAP_SYS_ADMIN as near-root. Also check PrivateDevices=, ProtectSystem=, and NoNewPrivileges=.
systemctl show myapp | grep -i cap pid=$(systemctl show -p MainPID --value myapp); getpcaps $pid grep Cap /proc/$pid/status # drop-in: CapabilityBoundingSet= CAP_NET_BIND_SERVICE NoNewPrivileges=true
Interviewer often follows with: Does NoNewPrivileges= block ambient capabilities already granted to the service?
You find a container process that can see host interfaces and PIDs it should not. How do you prove a namespace leak?Expert
I'd compare /proc/<pid>/ns/* inodes to the host init namespace. Matching net or pid inodes means the container was started with host namespaces or joined them.
Each namespace has an inode; ls -l /proc/1/ns/net vs /proc/<container_pid>/ns/net tells you if they share. docker inspect HostConfig.NetworkMode/PidMode/UTSMode should match. Causes: --network=host, --pid=host, mis-set RuntimeClass, or a breakout that joined namespaces. Impact: host network sockets and process signalling become reachable — treat as isolation failure. Remediate by redeploying with private namespaces, then hunt for how the flag was introduced. Pair with runtime detections on setns and host-ns starts.
ls -l /proc/1/ns/net /proc/1/ns/pid
pid=$(docker inspect -f '{{.State.Pid}}' app)
ls -l /proc/$pid/ns/net /proc/$pid/ns/pid
docker inspect app --format 'Net={{.HostConfig.NetworkMode}} Pid={{.HostConfig.PidMode}}'Interviewer often follows with: Can two containers share a netns with each other without sharing the host netns?
Kerberos/TLS auth starts failing fleet-wide after an NTP outage. Clocks drifted 10+ minutes. What is your recovery order?Expert
I'd fix time sources first — chrony or ntp — verify step vs slew, then restart time-sensitive services. I wouldn't mass-rotate certs until clocks are sane.
Skew breaks Kerberos tickets, TLS notBefore/notAfter, and cookie expirations. Recovery: check timedatectl/chronyc tracking, restore reliable NTP peers, allow chrony to step if far skewed, then bounce SSSD/httpd/app pools. Avoid generating new certs "because TLS failed" while clocks are wrong — you'll mint more confusion. Prevent with multiple NTP sources, monitoring offset, and guest VM tools sync on hypervisors. Document that auth outages can be time, not IdP.
timedatectl status chronyc tracking chronyc -a 'makestep' # then systemctl restart sssd httpd
Interviewer often follows with: When is stepping the clock safer than slewing during an auth outage?
A long-lived Java service slowly exhausts file descriptors; new connections fail with EMFILE. How do you confirm and mitigate live?Expert
I'd count FDs under /proc/<pid>/fd, raise the limit only as a bridge, then find the leak — sockets, files, or never-closed JDBC — and patch or restart with a hard ulimit ceiling.
Diagnosis: ls /proc/pid/fd | wc -l vs LimitNOFILE from systemctl show, ss -s for socket accumulation, lsof -p for the dominant type. Soft limits can be raised live carefully; hard limits need unit edits. Temporary: restart to reclaim, scale out, or kill runaway children. Root cause: connection pool mis-size, FD leak on exception paths, or log file handles. Set LimitNOFILE= deliberately — unlimited hides leaks until the host fails. Alert on fd usage percent of the limit.
pid=$(pgrep -o java); ls /proc/$pid/fd | wc -l systemctl show myapp | grep LimitNOFILE ss -s # drop-in: LimitNOFILE=65535 — then fix the leak
Interviewer often follows with: How do you tell a connection-pool misconfiguration from a true FD leak?
After a package update, a previously working daemon fails with mysterious "Permission denied" though modes look correct. What is your SELinux path?Advanced
I'd check for AVC denials in the audit log, restore contexts, and only then consider a focused boolean — I wouldn't chmod 777 to "make it work."
RPM updates can leave mislabeled files if admins copied trees without restorecon. Diagnosis: ausearch -m AVC -ts recent, sealert, ls -Z vs expected type. Fix: restorecon -Rv on the tree, ensure the unit uses the right SELinux domain, or ship a proper policy module for custom paths. setenforce 0 is a diagnostic toggle, not a production fix. On AppArmor hosts the analog is dmesg/journal DENIED plus aa-status. Interview signal: label/MAC before blaming application code.
ausearch -m AVC -ts recent | tail ls -Z /var/www/app restorecon -Rv /var/www/app getenforce
Interviewer often follows with: How do you permanently allow a custom data directory without disabling SELinux?
Kernel soft lockups and brief hangs appear under memory pressure, but no process is obviously spinning CPU. How do you approach it?Expert
I'd treat it as reclaim/scheduler distress: check mem.pressure, thrashing, I/O in D state, and recent kernel/driver changes — not only user CPU profiles.
Soft lockup messages mean a CPU failed to schedule within the threshold — often while stuck in kernel reclaim, a bad driver, or holding a lock under memory pressure. Collect: dmesg/journal -k around the event, /proc/pressure/*, vmstat si/so, and whether transparent huge pages or a specific filesystem ioctl correlates. Mitigations: reduce memory overcommit, tune oom/cgroup limits so a single tenant dies first, update kernel for known reclaim bugs, and capture a sysrq dump if hangs reproduce. I wouldn't "just add swap" as the only fix — it can lengthen thrash windows.
dmesg -T | grep -i 'soft lockup\|hung task' cat /proc/pressure/memory vmstat 1 5 # capture: sysrq thaws / show task states if safe in the environment
Interviewer often follows with: How does PSI memory pressure change your response compared to classic free -m?