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 to uid. 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: -1 is returned, and errno is set to indicate the error
โš ๏ธ note note note: there are cases where setuid() can fail even when the caller is UID 0. and it is a grave security error to omit checking for a failure return from setuid(). like, do not skip the check. that's the whole ballgame. ๐Ÿ™ˆ

๐Ÿ’€ ERRORS ๐Ÿ’€

  • EAGAIN โ€” the call would change the caller's real UID (i.e., uid does not match the caller's real UID), but there was a temporary failure allocating the necessary kernel data structures.
  • EAGAIN โ€” uid does not match the real user ID of the caller and this call would bring the number of processes belonging to the real user ID uid over the caller's RLIMIT_NPROC resource limit. since Linux 3.1 this error case no longer occurs โ€” but robust applications should still check for this error; see the description of EAGAIN in execve(2).
  • EINVAL โ€” the user ID specified in uid is not valid in this user namespace.
  • EPERM โ€” the user is not privileged (on Linux: does not have the CAP_SETUID capability in its user namespace) and uid does 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
  • ๐Ÿ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms