setresuid(2)

๐Ÿ’… setresuid โ€” the girlies of the ID trio

okay so bestie, welcome to setresuid(2) ๐Ÿ’– this is a System Calls Manual page (yes, section 2, we're in the kernel-adjacent part of town) and today we're talking about setresuid, setresgid โ€” set real, effective, and saved user or group ID. no cap, it's giving credential glow-up.


๐ŸŽ€ LIBRARY

Standard C library (libc, -lc) โœจ


๐ŸŒธ SYNOPSIS

#define _GNU_SOURCE         /* See feature_test_macros(7) */
#include <unistd.h>

int setresuid(uid_t ruid, uid_t euid, uid_t suid);
int setresgid(gid_t rgid, gid_t egid, gid_t sgid);

๐Ÿฆ‹ DESCRIPTION

okay so setresuid() is literally the main character here: it sets the real user ID, the effective user ID, and the saved set-user-ID of the calling process. three IDs, one call, iconic. ๐Ÿ‘‘

now, if you're an unprivileged process, you don't get to just pick whatever, bestie. you may change your real UID, effective UID, and saved set-user-ID, each to one of: the current real UID, the current effective UID, or the current saved set-user-ID. that's the menu. no substitutions. ๐Ÿ“

but if you're a privileged process โ€” and on Linux that means one having the CAP_SETUID capability โ€” you may set your real UID, effective UID, and saved set-user-ID to arbitrary values. go off, king. ๐Ÿ”ฅ

if one of the arguments equals -1, the corresponding value is not changed. little "no thoughts, head empty" moment for that one arg. ๐Ÿ™ˆ

and here's the part everyone forgets: regardless of what changes are made to the real UID, effective UID, and saved set-user-ID, the filesystem UID is always set to the same value as the (possibly new) effective UID. always. it's attached to the effective UID like it's got separation anxiety. ๐Ÿ˜ญ

completely analogously, ๐Ÿ’œ setresgid() sets the real GID, effective GID, and saved set-group-ID of the calling process (and always modifies the filesystem GID to be the same as the effective GID), with the same restrictions for unprivileged processes. same energy, different ID family. slay. โœจ


โญ RETURN VALUE

on success, zero is returned. ๐Ÿซถ on error, -1 is returned, and errno is set to indicate the error.

โš ๏ธ note: there are cases where setresuid() can fail even when the caller is UID 0; it is a grave security error to omit checking for a failure return from setresuid(). like, do not skip this check. do not "it'll be fine" this check. check it. ๐Ÿ’€

๐ŸŒˆ ERRORS

  • EAGAIN โ€” the call would change the caller's real UID (i.e., ruid does not match the caller's real UID), but there was a temporary failure allocating the necessary kernel data structures. temporary, babes. kernel just needs a sec. ๐Ÿงš
  • EAGAIN โ€” ruid does not match the caller's real UID and this call would bring the number of processes belonging to the real user ID ruid over the caller's RLIMIT_NPROC resource limit. Since Linux 3.1, this error case no longer occurs (but robust applications should check for this error); see the description of EAGAIN in execve(2). yes this one shows up twice, we're listing both, periodt. ๐Ÿ’…
  • EINVAL โ€” one or more of the target user or group IDs is not valid in this user namespace. wrong namespace, wrong vibe check. ๐Ÿšซ
  • EPERM โ€” the calling process is not privileged (did not have the necessary capability in its user namespace) and tried to change the IDs to values that are not permitted. for setresuid(), the necessary capability is CAP_SETUID; for setresgid(), it is CAP_SETGID. unauthorized. blocked. ๐Ÿ™…

๐Ÿ‘‘ VERSIONS

๐Ÿงต C library/kernel differences

okay bestie, plot twist: 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. awkward!! ๐Ÿ˜ฌ

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 those for setresuid() and setresgid()) 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, but they actually all communicate. shocking. ๐ŸŽ€

for details, see nptl(7).


โœจ STANDARDS

POSIX.1-2024. certified. ๐Ÿ“œ


๐Ÿ•ฐ๏ธ HISTORY

POSIX.1-2024. Linux 2.1.44, glibc 2.3.2. HP-UX, FreeBSD. she's been around, she's well traveled. ๐ŸŒ

the original Linux setresuid() and setresgid() system calls supported only 16-bit user and group IDs. subsequently, Linux 2.4 added setresuid32() and setresgid32(), supporting 32-bit IDs. the glibc setresuid() and setresgid() wrapper functions transparently deal with the variations across kernel versions. glow-up era. โœจ


๐Ÿ’– SEE ALSO

getresuid(2), getuid(2), setfsgid(2), setfsuid(2), setreuid(2), setuid(2), capabilities(7), credentials(7), user_namespaces(7)


and that's the whole page, bestie!! ๐Ÿซถ this was written to match the Linux man-pages 6.20 era of the docs, dated 2026-02-08 ๐ŸŒธ go check your return values, stay in your user namespace, and remember: the filesystem UID is always tagging along with the effective one. iykyk ๐Ÿ’œ๐Ÿฆ‹

๐Ÿ“ฆ 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