setuid(2)
๐ setuid โ set user identity ๐
okay bestie, welcome to the setuid(2) page, part of the System Calls Manual, and honestly? this one's a banger. it's the syscall that changes who you are. main character energy fr.
โจ NAME โจ
setuid โ set user identity
๐ LIBRARY ๐
Standard C library (libc, -lc)
๐ซถ SYNOPSIS ๐ซถ
#include <unistd.h>
int setuid(uid_t uid);
๐ธ DESCRIPTION ๐ธ
so setuid() sets the effective user ID of the calling process. that's the one that decides what you're allowed to do, lowkey the important one.
if the calling process is privileged โ and bestie, "privileged" here means, more precisely, the process has the CAP_SETUID capability in its user namespace โ then the real UID and the saved set-user-ID get set too. all three. the whole glow-up. โจ
under Linux, setuid() is implemented like the POSIX version with the _POSIX_SAVED_IDS feature. what that buys you: a set-user-ID program (that isn't root) can drop all of its user privileges, go do some un-privileged work, and then reengage the original effective user ID in a secure manner. like taking off your heels, doing the errand, then putting them back on. iconic.
โ ๏ธ but listen. if the user is root, or the program is set-user-ID-root, you must take special care.setuid()checks the effective user ID of the caller, and if that's the superuser, then all process-related user IDs get set touid. and after that has happened? it is impossible for the program to regain root privileges. no takebacks. none. ๐
so, a set-user-ID-root program that wants to temporarily drop root privileges, assume the identity of an unprivileged user, and then regain root privileges afterward cannot use setuid(). it just can't, bestie. that's not the vibe. what you can do is accomplish this with seteuid(2). go see her. ๐
๐ RETURN VALUE ๐
- on success: zero is returned ๐ฅณ
- on error:
-1is returned, anderrnois set to indicate the error
โ ๏ธ note note note: there are cases wheresetuid()can fail even when the caller is UID 0. and it is a grave security error to omit checking for a failure return fromsetuid(). like, do not skip the check. that's the whole ballgame. ๐
๐ ERRORS ๐
EAGAINโ the call would change the caller's real UID (i.e.,uiddoes not match the caller's real UID), but there was a temporary failure allocating the necessary kernel data structures.EAGAINโuiddoes not match the real user ID of the caller and this call would bring the number of processes belonging to the real user IDuidover the caller'sRLIMIT_NPROCresource limit. since Linux 3.1 this error case no longer occurs โ but robust applications should still check for this error; see the description ofEAGAINinexecve(2).EINVALโ the user ID specified inuidis not valid in this user namespace.EPERMโ the user is not privileged (on Linux: does not have theCAP_SETUIDcapability in its user namespace) anduiddoes not match the real UID or saved set-user-ID of the calling process.
๐ฆ VERSIONS ๐ฆ
๐ง C library/kernel differences ๐ง
at the kernel level, user IDs and group IDs are a per-thread attribute. but POSIX requires that all threads in a process share the same credentials. so the NPTL threading implementation handles the POSIX requirements by providing wrapper functions for the various system calls that change process UIDs and GIDs.
these wrapper functions (including the one for setuid()) employ a signal-based technique to ensure that when one thread changes credentials, all of the other threads in the process also change their credentials. group project where everyone actually participates, imagine. ๐ญ
for details, see nptl(7).
โญ STANDARDS โญ
POSIX.1-2024.
๐ HISTORY ๐
POSIX.1-2001, SVr4.
not quite compatible with the 4.4BSD call, which sets all of the real, saved, and effective user IDs.
the original Linux setuid() system call supported only 16-bit user IDs. subsequently, Linux 2.4 added setuid32() supporting 32-bit IDs. the glibc setuid() wrapper function transparently deals with the variation across kernel versions โ she handles it, you don't have to. ๐
๐ NOTES ๐
Linux has the concept of the filesystem user ID, normally equal to the effective user ID. the setuid() call also sets the filesystem user ID of the calling process. see setfsuid(2).
if uid is different from the old effective UID, the process will be forbidden from leaving core dumps. so no crash souvenirs for you. ๐
๐ฅ SEE ALSO ๐ฅ
getuid(2), seteuid(2), setfsuid(2), setreuid(2), capabilities(7), credentials(7), user_namespaces(7)
and that's the page bestie, no cap. this was Linux man-pages 6.20, dated 2026-02-08, bringing you setuid(2) โ go change your identity (legally, via syscall) and slay responsibly. ๐โจ
๐ฆ 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 1994, Graeme W. Wilford <G.Wilford@ee.surrey.ac.uk>
- Copyright 2010-2015, 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