0% found this document useful (0 votes)
37 views41 pages

Writing Secure Privileged Programs

This document provides guidelines for writing secure privileged programs in Linux. It discusses how to avoid creating security holes by using safe coding practices and understanding Linux OS concepts. Some key guidelines covered include avoiding setuid-root programs where possible, checking return statuses of system calls, failing safely if errors occur, and operating with least privilege by dropping privileges when not needed.

Uploaded by

savio77
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
37 views41 pages

Writing Secure Privileged Programs

This document provides guidelines for writing secure privileged programs in Linux. It discusses how to avoid creating security holes by using safe coding practices and understanding Linux OS concepts. Some key guidelines covered include avoiding setuid-root programs where possible, checking return statuses of system calls, failing safely if errors occur, and operating with least privilege by dropping privileges when not needed.

Uploaded by

savio77
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 41

Writing Secure

Privileged Programs
linux.conf.au 2010
Wellington, New Zealand; 22 Jan 2010
Michael Kerrisk, jambit GmbH
ht t p: / / www. ker nel . or g/ doc/ man- pages/
ht t p: / / www. man7. or g/
2
2
Overview
2


3
3
Introduction

Avoiding creation of security holes by:

Using safe C coding practices

Understanding and using Linux/UNIX OS-level concepts


to improve security

Excludes topics like:

Authentication techniques

Cryptography & Random-number generation

Linux Security Modules

Virtualization

Cross-site scripting

SQL injection

etc.
4
4
Topics

Process credentials

Gaining privileges

Why worry?

Guidelines for secure programming

Useful reading


5
5
Process
Credentials
6
6
6
Process credentials

Every process has credentials:

User IDs (UIDs)

Group IDs (GIDs)

Supplementary group IDs

Credentials determine:

Ownership of process

File access permissions

Privileges to perform other operations

Set for login shell on startup

Inherited by child of fork()

Some credentials can change during exec()




7
7
User IDs

Real UID (RUID)

Who owns process

Effective UID (EUID)

File access permissions

Privileges for other operations

EUID == 0 vs EUID != 0

Saved set-user-ID (SUID)

(Described later)

(For unprivileged program, all IDs have same value)


8
8
Group IDs

Real GID (RGID)

Which group owns process

Effective GID (EGID)

File access permissions

Saved set-group-ID (SGID)

(Described later)

(For unprivileged program, all IDs have same value)

Supplementary group IDs

Additional groups used to check file access permissions

Derived from / et c/ gr oup file




9
9
File access permissions

Determined by EUID, EGID, & supplementary GIDs

Each file has permissions:

EUID matches file owner?


granted permissions for file owner

EGID or any supp. GID matches file group?


granted permissions for file group

Otherwise:
granted permissions for other

User perms can be < group perms; & group < other
10
10
Gaining
Privileges
20


11
11
Gaining privileges

Two ways to obtain privileges of user or group:

Run program in process belonging to user or group

Execute set-user-ID or set-group-ID program

Usual way to give privilege to nonprivileged users

Abbreviations: setuid program & setgid program


12
12
Setuid programs

Like other executables, except that set-user-ID


permission bit is enabled:
$ su
Passwor d:
# ls -l prog
- r wxr - xr - x 1 r oot r oot 302585 J an 22 10: 05 pr og
# chmod u+s prog
# ls -l prog
- r wsr - xr - x 1 r oot r oot 302585 J an 22 10: 05 pr og

When executed, process EUID is set to owner of file

Setuid-root program == setuid program owned by


root


13
13
Setgid programs

Analogous to setuid program


$ su
Passwor d:
# ls -l prog
- r wxr - xr - x 1 r oot r oot 302585 J an 22 10: 05 pr og
# chmod g+s prog
# ls -l prog
- r wxr - sr - x 1 r oot r oot 302585 J an 22 10: 05 pr og
14
14
Credential changes during exec()

What happens to process IDs during exec()?

RUID: unchanged

EUID: is set-user-ID permission bit enabled for


executable file?

Yes EUID set to file owner

No EUID unchanged

SUID: copied from EUID (after preceding step)

(Analogous changes to GIDs for setgid program)

Supplementary GIDs: unchanged




15
15
Credential changes during exec() (cont.)

Example:

Login as mtk
$ whoami
mt k
RUID == EUID == SUID == <mtk>
$ ls -l prog
- r wsr - xr - x 1 root r oot 302585 J an 22 10: 05 pr og
$ ./prog # Cr eat e new pr ocess t hat execs " pr og"
RUID == <mtk>; EUID == SUID == <root (0)>
16
16
33
Why Worry?


17
17
What's the problem?

Privileged program grants rights of another user


or group

If subverted, security is compromised

Especially dangerous for EUID of 0 and for N/W


services

Many ways to create bugs that lead to subversion

Some guidelines...
18
18
Guidelines
35


19
19
Click to add title
Guideline: Avoid writing setuid-
root programs
20
20
Setuid-root? Just say no!

If there's a way to avoid setuid-root, use it

(Maybe you don't really need privilege at all)

Limits potential damage if program is compromised

Two useful techniques:

Privilege separation

Use an ID other than root




21
21
Avoiding setuid-root: Privilege
separation

Isolate functionality requiring root privileges into a


separate process running as root

Request operations via IPC, or info passed


across exec()

Make inputs and functionality of program as


limited as possible!

Less flexibility == fewer chances to compromise


22
22
Example of privilege separation

Example:

grantpt(3) library function

Forks child process that execs a setuid-root program,


pt_chown

Changes ownership and permissions of pseudo-tty slave


corresponding to master specified via open file descriptor


23
23
Avoiding setuid-root: Use an ID other
than root

Suppose we have a program that updates a file


that shouldn't be updated by normal users

Bad: make file writable only by root, and use


setuid-root program

Better: create new, dedicated group ID, make file


writable by that group, and use setgid program

Damage if compromised is greatly limited

Examples:

wall(1), write(1) (tty group)

many games (games group)


24
24
Always check return status

Almost every system call and library function


returns a status indicating success or failure

Someday, the call you thought could never fail, will

Some system calls can fail even for root

e.g.,:
open a file for writing on a read-only file system;
fork() fails if process table is full


25
25
Click to add title
Guideline:
Check return statuses
26
26
Always check return status

Almost every system call and library function


returns a status indicating success or failure

Someday, the call you thought could never fail, will

Some system calls can fail even for root

e.g.,:
open a file for writing on a read-only file system;
fork() fails if process table is full

Always check the return status




27
27
Click to add title
Guideline: If the unexpected
occurs, fail safely
28
28
Handling unexpected errors

What if an unexpected error occurs?

Trying to fix things usually requires assumptions


that may not be valid (i.e., safe) in all cases

When the unexpected occurs, log a message and


give up:

Locally executed program: terminate

Network server: drop client request

Fail safely


29
29
Click to add title
Guideline: Operate with least
privilege
30
30
Operate with least privilege

A setuid program doesn't need privileged EUID all


the time

If compromise occurs while program is


unprivileged, damage is limited

Operate with least privilege:

Drop privilege (immediately!) at start of execution

Raise privilege temporarily when needed

Drop privilege permanently when it will never again be


required

(Techniques rely on saved set-*-IDs)




31
31
Saved set-user-ID

When setuid program is executed:

EUID of process is made same as file owner

EUID is copied to SUID

e.g., after exec of setuid-root program by mtk:

RUID: mtk (unprivileged ID)

EUID: 0

SUID: 0 (privileged ID)

(SGID is analogous for setgid programs)


32
32
Changing privileges in a setuid program

Raising/dropping privileges == switching EUID


between:

RUID (unprivileged)

SUID (privileged)

Permanently dropping privileges == setting EUID


and SUID to RUID

Changes via system calls




33
33
Changing process credentials

General rules:

EUID == 0: arbitrary changes to IDs

EUID != 0: change an ID to be same as another of the IDs

For some calls, -1 argument value means no change


System call IDs changed Notes
setuid(u)
setgid(g)
effective If EUID == 0, real and saved are also changed
to same value; semantics vary across systems
seteuid(e)
setegid(e)
effective
setreuid(r, e)
setregid(r, e)
real, saved Also changes saved UID, if real ID is changed
setresuid(r, e, s)
setresgid(r, e, s)
real, effective,
saved
Nonstandard
setgroups(n, list) supp. GIDs
34
34
Dropping and raising privilege
ui d_t or i g_eui d;
or i g_eui d = get eui d( ) ; / * Save privileged EUID */
/ * ( same as val ue i n SUI D) */
i f ( set eui d( get ui d( ) ) == - 1) / * Drop privileges */
er r Exi t ( " set eui d" ) ; / * ( Swi t ch t o RUI D) */
/ * Do unprivileged wor k */
i f ( set eui d( or i g_eui d) == - 1) / * Raise privileges */
er r Exi t ( " set eui d" ) ; / * ( Swi t ch back t o SUI D) */
/ * Do privileged wor k */
i f ( set eui d( get ui d( ) ) == - 1) / * Drop privileges */
er r Exi t ( " set eui d" ) ;
/ * Do unprivileged wor k */


35
35
Dropping privileges permanently

Dropping UID 0 in setuid-root program:


i f ( set ui d( get ui d( ) ) == - 1) / * Set s RUI D, EUI D, SUI D */
er r Exi t ( " set ui d" ) ;

But! Doesn't work if EUID != 0

i.e., setuid-non-root program; or setuid-root program


with privilege currently dropped

setuid() changes only EUID

(And call returns success status...)


36
36
Dropping privileges permanently (cont.)

If EUID != 0, either:

setuid-root program:
seteuid(orig_euid)); /* Regain privileged EUID */
setuid(getuid()); /* Drop all privileged UIDs */

setuid-non-root program:
setreuid(getuid(), getuid()); /* Changes all UIDs */

In any (Linux) program:


setresuid(getuid(), getuid(), getuid())


37
37
Problems with changing credentials

Too many system calls confusing!

Some calls aren't available on some systems

setres[ug]id() (but: nicest interface!)

Differing semantics when EUID==0 and EUID!=0

set[ug]id()

Differing semantics across systems

set[ug]id()

Kernel bugs or unusual scenarios mean calls may


unexpectedly fail (perhaps without error!)

http://userweb.kernel.org/~morgan/sendmail-capabilities-war-story.html

Easy to get it wrong!


38
38
Safely changing process credentials

Read the documentation!

http://www.kernel.org/doc/man-pages/

credentials(7)

Check return status from set*id() calls

Verify that IDs have actually changed

getres[ug]id() [Linux]; or / pr oc [other systems]

Write/employ a portable package to do the above

See [Tsafrir et al., 2008]




39
39
Click to add title
Guideline: Be careful when
executing another program
40
40
Executing programs

Drop privileges permanently before exec()

(See earlier techniques)

setuid(getuid()) is sufficient

successful exec() copies EUID to SUID

Never exec() a shell with EUID 0:

Shells are too complex to avoid all security loopholes

Likewise other interpreters, such as awk...

Avoid system(), popen()

Avoid setuid scripts

(Not even permitted on Linux)




41
41
Executing programs (cont.)

Close unneeded file descriptors

Privileged programs can open files that are not be


accessible to others

Leaving descriptors open across exec() is a security leak

Close-on-exec flag may be useful (see fcntl(2))


42
42
Click to add title
Guideline: Avoid exposing
sensitive information


43
43
Avoid exposing sensitive information

Sometimes, info in memory can land on disk

Erase sensitive info from memory as soon as no


longer needed

Lock pages into memory (mlock()) if having data


written to disk (swap area) is a concern

Disable core dumps

Set RLI MI T_CORE limit to 0; see setrlimit(2)


44
44
Click to add title
Guideline: Be careful of signals


45
45
Be aware of signals

Users can send arbitrary signals to a program at


any point time

If necessary, block, ignore, or catch signals to


prevent security problems

Keep signal handler design simple

e.g., just set global flag checked by main program

Minimizes bugs that may occur because of races


46
46
Race conditions

Time-of-check, time-of-use (TOCTOU) race


condition:
1) Program checks details of run-time environment
2)The user manages to change details of RTE

e.g., change file permissions; change target of symlink


3) Program continues, based on false assumptions

Security breach


47
47
Race conditions (cont.)

Classic example:

Check: Setuid-root program uses access(2) to


determine that a file is writable by real user (RUID)

Use: Program opens file for writing

Between check and use, things change:


48
48
Race conditions (cont.)

Chances of exploit can be greatly increased by:

Using stop/continue signals to widen window between


TOC and TOU

Repeated execution + scripts to deliver signals rapidly

Write code so as to avoid TOCTOU races; e.g.:

Program (temporarily) drops privileged ID

Program opens file for writing and checks return status




49
49
Click to add title
Guideline: Be careful when
performing file operations and
file I/O
50
50
File operations and file I/O

If creating a file, ensure that it is never vulnerable


(even briefly) to malicious manipulation

Ensure file is never publicly writable (umask(2) may help)

Ownership of new files taken from EUID

Don't create file and chown(2)

Do ensure EUID is correctly set before creating file

Perform checks on file descriptors, not pathnames

For example:

Don't use stat() and then open() (TOCTOU race!)

Do use open() and then fstat()




51
51
File operations and file I/O (cont.)

To ensure that you are creator of a file, use


open() O_EXCL

Avoid creating files in publicly writable directories


(e.g., / t mp)

Can be manipulated of removed by other users

If you must do so, use random filename (mkstemp(3))


52
52
Click to add title
Guideline: Don't trust user
inputs!


53
53
Don't trust user inputs!

Never trust input from users:

Interactive input

Command-line arguments

User-supplied files

Email

IPC channels

CGI inputs

Network packets

etc.
54
54
Don't trust user inputs! (cont.)

Validate and sanitize all inputs

Are numbers inside acceptable limits?

Are strings of acceptable length?

Are characters in string valid?

etc.


55
55
Don't trust user inputs! (cont.)

Classic example:

Suppose user supplies following input to snprintf():

In this example:

Check that characters are in set [][a-z_A-Z?*-]; or

Escape shell metacharacters with \


char cmd[ CMDLEN] , pat [ PATLEN] ;
f get s( pat , PATLEN, st di n) ;
snpr i nt f ( cmd, CMDLEN, "l s %s", pat ) ;
syst em( cmd) ;
x; r m/ et c/ passwd
==> syst em( " l s x; r m/ et c/ passwd" ) ;
56
56
Click to add title
Guideline: Don't trust
environment variables


57
57
Don't trust environment variables!

Values should be checked (like other user input)

EVs affect operation of many programs & libraries

e.g., PATH affects shell (and system(), popen(), execvp(),


execlp())

Manipulation may cause unexpected program to be executed

Ensure PATH value is safe, or (better) exec absolute pathnames

Safest approach:

Erase entire environment

Restore selected variables with known-safe values


58
58
Click to add title
Guideline: Don't trust the Run-
time Environment


59
59
Don't trust the run time environment!

Do you expect standard input, output, and error to


be open?

What about library functions?

What happens if you run out of disk space?

What happens if resource limits are set very low?

CPU time, file size, stack size, number of open files

What if fork() fails because there are too many


processes on system?
60
60
Don't trust the run time environment!
(cont.)

Do you check status of malloc() calls?

Do you expect signal mask to be empty?

sigprocmask(2), signal(7)

Are you assuming that initial umask is okay?

What if umask is 0700?

Attackers may try to subvert program by forcing


unexpected or low-resource scenarios


61
61
Click to add title
Guideline: Beware of buffer
overruns!!
62
62
Buffer overruns

A.K.A. stack smashing

Subvert program by making it run injected code

Extremely common flaw

See CERT (www.cert.org),


Bugtraq (www.securityfocus.com), LWN.net

Examples

2001 Code Red worm (MS IIS web server)

2003 SQL Slammer (MS SQL Server)

1988 Morris worm (fingerd (gets()), UNIX)




63
63
Buffer overruns (cont.)

Idea is to exploit this type of situation:


voi d g( ) {
char buf [ N] ;
/ * Code al l owi ng user i nput f or buf */
}
voi d f ( ) { g( ) ; }
mai n( ) { f ( ) ; }
64
64
Buffer overruns (cont.)

Suppose we can:

provide user input into buf, and

write beyond end of buf (no bounds checking)

Exploit is achieved by this transformation:




65
65
Buffer overruns (cont.)

Modern OSes/hardware use techniques to make


stack smashing harder:

Address-space randomization

Nonexecutable stacks

But, can be circumvented with more effort

Return to libc (see [Anley et al., 2007])

Repeated execution driven by scripts

See also [Erickson, 2008], [Aleph One, 1996]


66
66
Avoiding buffer overruns

Always bounds check user input

Never use gets(3)!

Use fgets(strbufp, len, stream)

Use scanf(), sprintf(), strcpy(), strcat() with caution

Guard use with boundary checking code, or

Use snprintf(), strncpy(), strncat(); but

Check for truncated result string

NB If result string is too long, strncpy() does not include NULL


terminator!


67
67
Format-string attacks

e.g., printf(argv[1]);

By including %n specifier in string, we can write


arbitrary values at specific address

%n == write # of characters so far output to address given


in arg. list

Can achieve similar exploit to buffer overruns, but


requires more work

See [Anley at al., 2007]

Don't permit user input as part of format string!


68
68
Heap overflows

Dynamic memory allocated and freed via malloc


package

All allocations from same area of memory (the


heap)

Similar concept to stack smashing: overrun a


buffer, in order to write data into sensitive buffer
elsewhere on heap

e.g., buffer might contain name of file to open for writing

Avoid in same way as for stack buffer overruns




69
69
Click to add title
Guideline: Be prepared for
denial-of-service attacks
70
70
Denial of (network) service attacks

What happens if client or server doesn't reply to


your message?

Use timeouts

Be prepared for overload attacks

What happens if traffic is 100x expected?

(Network attacks may be distributed; source addresses


may be spoofed)

If traffic volume exceeds expectations:

Degrade gracefully: throttle load (drop some requests)

Log details of situation (but throttle logging too!)




71
71
Denial of service attacks (cont.)

Can too many outstanding requests cause data


structures (e.g., arrays) to overflow?

Beware of algorithmic-complexity attacks

E.g., does right sequence of inputs turn your binary


search tree or hash table into a linked list?

Use data structures that avoid these problems

[Crosby & Wallach, 2003]


72
72
Click to add title
Guideline: Confine the
program / consider using
capabilities


73
73
Confine the program

Use chroot(2) to restrict process to subset of file-


system tree

But: setuid-root programs can break out of chroot jails

Consider using capabilities


74
74
Capabilities

Divide all-or-nothing power of root into distinct


units (34, as at Linux 2.6.33):

CAP_AUDIT_CONTROL, CAP_AUDIT_WRITE, CAP_CHOWN,


CAP_DAC_OVERRIDE, CAP_DAC_READ_SEARCH, CAP_FOWNER,
CAP_FSETID, CAP_IPC_LOCK, CAP_IPC_OWNER, CAP_KILL,
CAP_LEASE, CAP_LINUX_IMMUTABLE, CAP_MAC_ADMIN,
CAP_MAC_OVERRIDE, CAP_MKNOD, CAP_NET_ADMIN,
CAP_NET_BIND_SERVICE, CAP_NET_BROADCAST,
CAP_NET_RAW, CAP_SETFCAP, CAP_SETGID, CAP_SETPCAP,
CAP_SETUID, CAP_SYS_ADMIN, CAP_SYS_BOOT,
CAP_SYS_CHROOT, CAP_SYS_MODULE, CAP_SYS_NICE,
CAP_SYS_PACCT, CAP_SYS_PTRACE, CAP_SYS_RAWIO,
CAP_SYS_RESOURCE, CAP_SYS_TIME, CAP_SYS_TTY_CONFIG


75
75
Capabilities (cont.)

Instead of having UID 0, process can have


selected capabilities, without having other powers
of superuser

Takes operate with least privilege to finer granularity

Can have privileged program that can't access files


owned by root

Linux-specific...
76
76
Capabilities (cont.)

Partial implementation since Linux 2.2

File capabilities added in Linux 2.6.24

Capabilities can be associated with executable file

setcap(8) and getcap(8)

When file is executed, process gains capabilities


(analogous to setuid program)

Process has permitted and effective capability sets

Analogous to SUID and EUID in setuid programs

Use libcap API to raise/drop effective capabilities

Further info:

capabilities(7), [Hallyn, 2007], [Kerrisk, 2010]




77
77
Summary

Avoid writing setuid-root programs

Check return status from every call

Fail safely

Operate with least privilege at all times

Drop privileges permanently when no longer needed

Drop privilege before execing another program

Avoid exposing sensitive information

Be aware of signals

Avoid TOCTOU races

Be careful with file operations and file I/O

Don't trust: user inputs; environment variables; run time environment

Beware of buffer overruns

Be prepared for denial of service attacks

Consider using capabilities


78
78
Useful Reading
78


79
79
Useful reading
A very small sample of a very wide range of publications on security
Aleph One. 1996. Smashing the Stack for Fun and Profit
http://www.phrack.com/issues.html?issue=49&id=14#article
Anley, C., Heasman, J., Lindner, F., and Richarte, G. 2007. The Shellcoders Handbook:
Discovering and Exploiting Security Holes. Wiley.
Bishop, M. Various papers at http://nob.cs.ucdavis.edu/~bishop/secprog.
Bishop, M. 2003. Computer Security: Art and Science. Addison-Wesley.
Bishop, M. 2005. Introduction to Computer Security. Addison-Wesley.
Chen, H., Wagner, D., and Dean, D. 2002. Setuid Demystified, Proceedings of the 11th
USENIX Security Symposium.
http://www.cs.berkeley.edu/~daw/papers/setuid-usenix02.pdf
Crosby, S. A., and Wallach, D. S. 2003. Denial of Service via Algorithmic Complexity
Attacks, Proceedings of the 12th USENIX Security Symposium.
http://www.cs.rice.edu/~scrosby/hash/CrosbyWallach_UsenixSec2003.pdf
Drepper, U. 2009. Defensive Programming for Red Hat Enterprise Linux
http://people.redhat.com/drepper/defprogramming.pdf
.
80
80
Useful reading
Erickson, J. M. 2008. Hacking: The Art of Exploitation (2e). No Starch Press.
Garfinkel, S., et al.. 2003. Practical Unix and Internet Security (3e). OReilly.
Hallyn, S. 2007. POSIX file capabilities: Parceling the power of root.
http://www.ibm.com/developerworks/library/l-posixcap.html
Kerrisk, M., et al. capabilities(7) manual page
Kerrisk, M. 2010. The Linux Programming Interface. No Starch Press.
Peikari, C., and Chuvakin, A. 2004. Security Warrior. OReilly.
Tsafrir, D., da Silva, D., and Wagner, D. The Murky Issue of Changing Process Identity:
Revising Setuid Demystified, ;login: The USENIX Magazine, June 2008.
http://www.usenix.org/publications/login/2008-06/pdfs/tsafrir.pdf
Viega, J., and McGraw, G. 2002. Building Secure Software. Addison-Wesley.
Wheeler, D., Secure Programming for Linux and Unix HOWTO
http://www.dwheeler.com/secure-programs/.


121

81
Thanks!
http://userweb.kernel.org/~mtk/papers/lca2010/
writing_secure_privileged_programs.pdf
Michael Kerrisk
jambit GmbH
The Linux Programming Interface
No Starch Press, 2010 (soon)
ht t p: / / bl og. man7. or g/

You might also like