setfsuid(2)
π setfsuid(2) β the set-user-identity-for-filesystem-checks girlie π
okay bestie, buckle up, this one's from the System Calls Manual and it's a β¨slightly cursedβ¨ little corner of Linux history. let's get into it π«Ά
πΈ NAME πΈ
setfsuid β set the user identity used for filesystem checks. that's it, that's the whole job π
π LIBRARY π
Standard C library (libc, -lc). the usual queen π
β¨ SYNOPSIS β¨
#include <sys/fsuid.h>
[[deprecated]] int setfsuid(uid_t fsuid);
yes bestie. [[deprecated]] is right there in the synopsis. the universe is telling you something. π
π¦ DESCRIPTION π¦
so on Linux, a process has two separate IDs doing two separate jobs:
- the filesystem user ID β Linux-specific, used for permission checking when you're accessing filesystem objects
- the effective user ID β used for all the other kinds of permission checks (peep
credentials(7)for the full lore)
normally these two are the same value. like, twins. matching. slay. that's because whenever a process's effective user ID changes, the kernel goes "and the filesystem user ID too, bestie" and updates it to match. so they stay in sync π
but a process can make them diverge β and that's exactly what setfsuid() is for. you call it, you hand it an fsuid, and your filesystem user ID becomes that value. boom. divergent era. π
so who actually calls this? explicit calls to setfsuid() and setfsgid(2) are (were) usually only made by programs like the Linux NFS server β things that need to change which user and group ID gets used for file access without also changing their real and effective user and group IDs. why avoid the normal change? because for a program like the NFS server, messing with the normal user IDs is (was) a security hole that can expose it to unwanted signals. yikes. π (though β plot twist β this whole issue is historical, more on that below π)
and who's allowed to do it? setfsuid() will succeed only if the caller is the superuser, or if fsuid matches one of these:
- the caller's real user ID
- the caller's effective user ID
- the caller's saved set-user-ID
- the caller's current filesystem user ID
otherwise? no slay for you. π
π₯ RETURN VALUE π₯
here's the iconic part: on both success and failure, this call returns the previous filesystem user ID of the caller. same value either way. no notes. π
π STANDARDS π
Linux. just Linux. that's the vibe. π§
π HISTORY π
Linux 1.2. back in the day, bb. π
so here's the story: when this system call first showed up, one process could send a signal to another process that had the same effective user ID. which meant that if a privileged process changed its effective user ID just to do file permission checking, it would lowkey become vulnerable to getting signals from some random unprivileged process that happened to share that user ID. not it. π
so the filesystem user ID attribute got added β letting a process change its user ID for file permission checking purposes only, without simultaneously becoming signal-vulnerable. problem solved, iconic. β¨
but since Linux 2.0, signal permission handling works differently (check kill(2) for the receipts), and the result is that a process can change its effective user ID without being vulnerable to signals from unwanted processes. so the whole reason setfsuid() existed just... evaporated. π¨
which means: setfsuid() is nowadays unneeded and should be avoided in new applications (same energy for setfsgid(2), fr fr).
also, a glow-up tale: the original Linux setfsuid() system call only supported 16-bit user IDs. then Linux 2.4 added setfsuid32() supporting 32-bit IDs. and the glibc setfsuid() wrapper function transparently deals with the variation across kernel versions, like a good wig. π
π§ C library/kernel differences π§
in glibc 2.15 and earlier, when the wrapper for this system call figures out that the argument can't be passed to the kernel without integer truncation (because the kernel is old and doesn't support 32-bit user IDs), it will return -1 and set errno to EINVAL β without even attempting the system call. ghosted. π»
π BUGS π
okay so this is the part where we all hold hands. π«Ά
no error indications of any kind are returned to the caller. none. zero. zip.
and because successful and unsuccessful calls return the same value, it is literally impossible to directly tell whether the call succeeded or failed. it's giving mystery box. π¦
so what's a bestie to do? the caller has to resort to looking at the return value from a further call, like setfsuid(-1) (which will always fail), in order to determine if a preceding call to setfsuid() actually changed the filesystem user ID. yeah. that's the workaround. i know. π
at the very least, EPERM should be returned when the call fails (because the caller lacks the CAP_SETUID capability). should. π
π SEE ALSO π
go read the girls, they ate. π
and that's the whole page, bestie!! this little trip through Linux history was brought to you by Linux man-pages 6.20, dated 2026-02-08 πβ¨ mwah, go touch some filesystem objects (with the correct permissions, obviously) π
π¦ where this page comes from
- arch rolling: man-pages 6.20-1 Β· BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND GPL-3.0-or-later AND LGPL-3.0-linking-exception AND LGPL-3.0-or-later AND LicenseRef-Public-Domain AND LicenseRef-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
- nixpkgs unstable: man-pages 6.20
- π the page's license: Linux-man-pages-copyleft
- Copyright 1995, Thomas K. Dyas <tdyas@eden.rutgers.edu>
- Copyright 2013-2019, Michael Kerrisk <mtk.manpages@gmail.com>
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms