secure coding guide contents introduction to secure coding guide 7

123
Secure Coding Guide

Upload: independent

Post on 28-Jan-2023

1 views

Category:

Documents


0 download

TRANSCRIPT

Secure Coding Guide

Contents

Introduction to Secure Coding Guide 7At a Glance 7

Hackers, Crackers, and Attackers 7No Platform Is Immune 8

How to Use This Document 9See Also 10

Types of Security Vulnerabilities 11Buffer Overflows 11Unvalidated Input 12Race Conditions 13Interprocess Communication 13Insecure File Operations 13Access Control Problems 14Secure Storage and Encryption 15Social Engineering 16

Avoiding Buffer Overflows and Underflows 17Stack Overflows 18Heap Overflows 20String Handling 22Calculating Buffer Sizes 25Avoiding Integer Overflows and Underflows 27Detecting Buffer Overflows 28Avoiding Buffer Underflows 29Security Features that Can Help 32

Address Space Layout Randomization 32Non-Executable Stack and Heap 32Debugging Heap Corruption Bugs 33

Validating Input and Interprocess Communication 34Risks of Unvalidated Input 34

Causing a Buffer Overflow 34Format String Attacks 35

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

2

URLs and File Handling 37Injection Attacks 38Social Engineering 38Modifications to Archived Data 39

Fuzzing 40Interprocess Communication and Networking 41

Race Conditions and Secure File Operations 44Avoiding Race Conditions 44

Time of Check Versus Time of Use 45Signal Handling 47

Securing Signal Handlers 47Securing File Operations 48

Check Result Codes 48Watch Out for Hard Links 49Watch Out for Symbolic Links 50Case-Insensitive File Systems Can Thwart Your Security Model 50Create Temporary Files Correctly 51Files in Publicly Writable Directories Are Dangerous 52Other Tips 58

Elevating Privileges Safely 60Circumstances Requiring Elevated Privileges 60The Hostile Environment and the Principle of Least Privilege 61

Launching a New Process 62Working with Command-Line Arguments 62Inheriting File Descriptors 62Abusing Environment Variables 63Modifying Process Limits 63File Operation Interference 64

Avoiding Elevated Privileges 64Running with Elevated Privileges 64Calls to Change Privilege Level 65Avoiding Forking Off a Privileged Process 66

authopen 67launchd 67

Limitations and Risks of Other Mechanisms 68Writing a Privileged Helper 70

Example: Preauthorizing 70Helper Tool Cautions 72

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

3

Contents

Authorization and Trust Policies 73Security in a KEXT 73

Designing Secure User Interfaces 74Use Secure Defaults 74Meet Users’ Expectations for Security 75Secure All Interfaces 76Place Files in Secure Locations 76Make Security Choices Clear 77Fight Social Engineering Attacks 79Use Security APIs When Possible 80

Designing Secure Helpers and Daemons 82Use App Sandbox 82Avoid Puppeteering 83

Use Whitelists 83Use Abstract Identifiers and Structures 83Use the Smell Test 84

Treat Both App and Helper as Hostile 85Run Daemons as Unique Users 85Start Other Processes Safely 86

Avoiding Injection Attacks and XSS 87Avoiding Injection Attacks 87

The Dangers of Mixed Data 88SQL Injection 90C-Language Command Execution and Shell Scripts 91Quoting for URLs 93Quoting for HTML and XML 93

Avoiding Cross-Site Scripting 93

Security Development Checklists 95Use of Privilege 95Data, Configuration, and Temporary Files 97Network Port Use 98Audit Logs 100Client-Server Authentication 102Integer and Buffer Overflows 106Cryptographic Function Use 106Installation and Loading 107

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

4

Contents

Use of External Tools and Libraries 109Kernel Security 110

Third-Party Software Security Guidelines 112Respect Users’ Privacy 112Provide Upgrade Information 112Store Information in Appropriate Places 112Avoid Requiring Elevated Privileges 113Implement Secure Development Practices 113Test for Security 113Helpful Resources 114

Document Revision History 115

Glossary 116

Index 120

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

5

Contents

Figures, Tables, and Listings

Avoiding Buffer Overflows and Underflows 17Figure 2-1 Schematic view of the stack 19Figure 2-2 Stack after malicious buffer overflow 20Figure 2-3 Heap overflow 21Figure 2-4 C string handling functions and buffer overflows 22Figure 2-5 Buffer overflow crash log 29Table 2-1 String functions to use and avoid 23Table 2-2 Avoid hard-coded buffer sizes 25Table 2-3 Avoid unsafe concatenation 26

Race Conditions and Secure File Operations 44Table 4-1 C file functions to avoid and to use 56

Elevating Privileges Safely 60Listing 5-1 Non-privileged process 71Listing 5-2 Privileged process 72

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

6

Secure coding is the practice of writing programs that are resistant to attack by malicious or mischievouspeople or programs. Secure coding helps protect a user’s data from theft or corruption. In addition, an insecureprogram can provide access for an attacker to take control of a server or a user’s computer, resulting in anythingfrom a denial of service to a single user to the compromise of secrets, loss of service, or damage to the systemsof thousands of users.

Secure coding is important for all software; if you write any code that runs on Macintosh computers or on iOSdevices, from scripts for your own use to commercial software applications, you should be familiar with theinformation in this document.

At a GlanceEvery program is a potential target. Attackers will try to find security vulnerabilities in your applications orservers. They will then try to use these vulnerabilities to steal secrets, corrupt programs and data, and gaincontrol of computer systems and networks. Your customers’ property and your reputation are at stake.

Security is not something that can be added to software as an afterthought; just as a shed made out of cardboardcannot be made secure by adding a padlock to the door, an insecure tool or application may require extensiveredesign to secure it. You must identify the nature of the threats to your software and incorporate securecoding practices throughout the planning and development of your product. This chapter explains the typesof threats that your software may face. Other chapters in this document describe specific types of vulnerabilitiesand give guidance on code hardening techniques to fix them.

Hackers, Crackers, and AttackersContrary to the usage by most news media, within the computer industry the term hacker refers to an expertprogrammer—one who enjoys learning about the intricacies of code or an operating system. In general, hackersare not malicious. When most hackers find security vulnerabilities in code, they inform the company ororganization that’s responsible for the code so that they can fix the problem. Some hackers—especially if theyfeel their warnings are being ignored—publish the vulnerabilities or even devise and publish exploits (codethat takes advantage of the vulnerability).

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

7

Introduction to Secure Coding Guide

The malicious individuals who break into programs and systems in order to do damage or to steal somethingare referred to as crackers, attackers, or black hats. Most attackers are not highly skilled, but take advantageof published exploit code and known techniques to do their damage. People (usually, though not always,young men) who use published code (scripts) to attack software and computer systems are sometimes calledscript kiddies.

Attackers may be motivated by a desire to steal money, identities, and other secrets for personal gain; corporatesecrets for their employer’s or their own use; or state secrets for use by hostile governments or terroristorganizations. Some crackers break into applications or operating systems just to show that they can do it;nevertheless, they can cause considerable damage. Because attacks can be automated and replicated, anyweakness, no matter how slight, can be exploited.

The large number of insiders who are attacking systems is of importance to security design because, whereasmalicious hackers and script kiddies are most likely to rely on remote access to computers to do their dirtywork, insiders might have physical access to the computer being attacked. Your software must be resistant toboth attacks over a network and attacks by people sitting at the computer keyboard—you cannot rely onfirewalls and server passwords to protect you.

No Platform Is ImmuneSo far, OS X has not fallen prey to any major, automated attack like the MyDoom virus. There are several reasonsfor this. One is that OS X is based on open source software such as BSD; many hackers have searched thissoftware over the years looking for security vulnerabilities, so that not many vulnerabilities remain. Another isthat the OS X turns off all routable networking services by default. Also, the email and internet clients usedmost commonly on OS X do not have privileged access to the operating system and are less vulnerable toattack than those used on some other common operating systems. Finally, Apple actively reviews the operatingsystem and applications for security vulnerabilities, and issues downloadable security updates frequently.

iOS is based on OS X and shares many of its security characteristics. In addition, it is inherently more securethan even OS X because each application is restricted in the files and system resources it can access. Beginningin version 10.7, Mac apps can opt into similar protection.

That’s the good news. The bad news is that applications and operating systems are constantly under attack.Every day, black hat hackers discover new vulnerabilities and publish exploit code. Criminals and script kiddiesthen use that exploit code to attack vulnerable systems. Also, security researchers have found manyvulnerabilities on a variety of systems that, if exploited, could have resulted in loss of data, allowing an attackerto steal secrets, or enabling an attacker to run code on someone else’s computer.

Introduction to Secure Coding GuideAt a Glance

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

8

A large-scale, widespread attack is not needed to cause monetary and other damages; a single break-in issufficient if the system broken into contains valuable information. Although major attacks of viruses or wormsget a lot of attention from the media, the destruction or compromising of data on a single computer is whatmatters to the average user.

For your users’ sake, you should take every security vulnerability seriously and work to correct known problemsquickly. If every Macintosh and iOS developer follows the advice in this document and other books on electronicsecurity, and if the owner of each Macintosh takes common-sense precautions such as using strong passwordsand encrypting sensitive data, then OS X and iOS will maintain their reputations for being safe, reliable operatingsystems, and your company’s products will benefit from being associated with OS X or iOS.

How to Use This DocumentThis document assumes that you have already read Security Overview .

The document begins with “Types of Security Vulnerabilities” (page 11), which gives a brief introduction tothe nature of each of the types of security vulnerability commonly found in software. This chapter providesbackground information that you should understand before reading the other chapters in the document. Ifyou’re not sure what a race condition is, for example, or why it poses a security risk, this chapter is the placeto start.

The remaining chapters in the document discuss specific types of security vulnerabilities in some detail. Thesechapters can be read in any order, or as suggested by the software development checklist in “SecurityDevelopment Checklists” (page 95).

● “Avoiding Buffer Overflows and Underflows” (page 17) describes the various types of buffer overflowsand explains how to avoid them.

● “Validating Input and Interprocess Communication” (page 34) discusses why and how you must validateevery type of input your program receives from untrusted sources.

● “Race Conditions and Secure File Operations” (page 44) explains how race conditions occur, discussesways to avoid them, and describes insecure and secure file operations.

● “Elevating Privileges Safely” (page 60) describes how to avoid running code with elevated privileges andwhat to do if you can’t avoid it entirely.

● “Designing Secure User Interfaces” (page 74) discusses how the user interface of a program can enhanceor compromise security and gives some guidance on how to write a security-enhancing UI.

● “Designing Secure Helpers and Daemons” (page 82) describes how to design helper applications in waysthat are conducive to privilege separation.

Introduction to Secure Coding GuideHow to Use This Document

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

9

In addition, the appendix “Security Development Checklists” (page 95) provides a convenient list of tasks thatyou should perform before shipping an application, and the appendix “Third-Party Software SecurityGuidelines” (page 112) provides a list of guidelines for third-party applications bundled with OS X.

See AlsoThis document concentrates on security vulnerabilities and programming practices of special interest todevelopers using OS X or iOS. For discussions of secure programming of interest to all programmers, see thefollowing books and documents:

● See Viega and McGraw, Building Secure Software , Addison Wesley, 2002; for a general discussion of secureprogramming, especially as it relates to C programming and writing scripts.

● See Wheeler,SecureProgramming for LinuxandUnixHOWTO , available at http://www.dwheeler.com/secure-programs/; for discussions of several types of security vulnerabilities and programming tips for UNIX-basedoperating systems, most of which apply to OS X.

● See Cranor and Garfinkel, Security and Usability: Designing Secure Systems that People Can Use , O’Reilly,2005; for information on writing user interfaces that enhance security.

For documentation of security-related application programming interfaces (APIs) for OS X (and iOS, wherenoted), see the following Apple documents:

● For an introduction to some security concepts and to learn about the security features available in OS X,see Security Overview .

● For information on secure networking, see Cryptographic Services Guide , Secure Transport Reference andCFNetwork Programming Guide .

● For information on OS X authorization and authentication APIs, see Authentication, Authorization, andPermissions Guide , Authorization Services Programming Guide , Authorization Services C Reference , andSecurity Foundation Framework Reference .

● If you are using digital certificates for authentication, see Cryptographic Services Guide , Certificate, Key,and Trust Services Reference (iOS version available) and Certificate, Key, and Trust Services ProgrammingGuide .

● For secure storage of passwords and other secrets, see Cryptographic Services Guide , Keychain ServicesReference (iOS version available) and Keychain Services Programming Guide .

For information about security in web application design, visit http://www.owasp.org/.

Introduction to Secure Coding GuideSee Also

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

10

Most software security vulnerabilities fall into one of a small set of categories:

● buffer overflows

● unvalidated input

● race conditions

● access-control problems

● weaknesses in authentication, authorization, or cryptographic practices

This chapter describes the nature of each type of vulnerability.

Buffer OverflowsA buffer overflow occurs when an application attempts to write data past the end (or, occasionally, past thebeginning) of a buffer.

Buffer overflows can cause applications to crash, can compromise data, and can provide an attack vector forfurther privilege escalation to compromise the system on which the application is running.

Books on software security invariably mention buffer overflows as a major source of vulnerabilities. Exactnumbers are hard to come by, but as an indication, approximately 20% of the published exploits reported bythe United States Computer Emergency Readiness Team (US-CERT) for 2004 involved buffer overflows.

Any application or system software that takes input from the user, from a file, or from the network has to storethat input, at least temporarily. Except in special cases, most application memory is stored in one of two places:

● stack—A part of an application’s address space that stores data that is specific to a single call to a particularfunction, method, block, or other equivalent construct.

● heap—General purpose storage for an application. Data stored in the heap remains available as long asthe application is running (or until the application explicitly tells the operating system that it no longerneeds that data).

Class instances, data allocated with malloc, core foundation objects, and most other application dataresides on the heap. (Note, however, that the local variables that actually point to the data are stored inthe stack.)

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

11

Types of Security Vulnerabilities

Buffer overflow attacks generally occur by compromising either the stack, the heap, or both. For moreinformation, read “Avoiding Buffer Overflows and Underflows” (page 17)

Unvalidated InputAs a general rule, you should check all input received by your program to make sure that the data is reasonable.

For example, a graphics file can reasonably contain an image that is 200 by 300 pixels, but cannot reasonablycontain an image that is 200 by -1 pixels. Nothing prevents a file from claiming to contain such an image,however (apart from convention and common sense). A naive program attempting to read such a file wouldattempt to allocate a buffer of an incorrect size, leading to the potential for a heap overflow attack or otherproblem. For this reason, you must check your input data carefully. This process is commonly known as inputvalidation or sanity checking.

Any input received by your program from an untrusted source is a potential target for attack. (In this context,an ordinary user is an untrusted source.) Examples of input from an untrusted source include (but are notrestricted to):

● text input fields

● commands passed through a URL used to launch the program

● audio, video, or graphics files provided by users or other processes and read by the program

● command line input

● any data read from an untrusted server over a network

● any untrusted data read from a trusted server over a network (user-submitted HTML or photos on a bulletinboard, for example)

Hackers look at every source of input to the program and attempt to pass in malformed data of every typethey can imagine. If the program crashes or otherwise misbehaves, the hacker then tries to find a way to exploitthe problem. Unvalidated-input exploits have been used to take control of operating systems, steal data,corrupt users’ disks, and more. One such exploit was even used to “jail break” iPhones.

“Validating Input and Interprocess Communication” (page 34) describes common types of input-validationvulnerabilities and what to do about them.

Types of Security VulnerabilitiesUnvalidated Input

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

12

Race ConditionsA race condition exists when changes to the order of two or more events can cause a change in behavior. Ifthe correct order of execution is required for the proper functioning of the program, this is a bug. If an attackercan take advantage of the situation to insert malicious code, change a filename, or otherwise interfere withthe normal operation of the program, the race condition is a security vulnerability. Attackers can sometimestake advantage of small time gaps in the processing of code to interfere with the sequence of operations,which they then exploit.

For more information about race conditions and how to prevent them, read “Race Conditions and Secure FileOperations” (page 44).

Interprocess CommunicationSeparate processes—either within a single program or in two different programs—sometimes have to shareinformation. Common methods include using shared memory or using some messaging protocol, such asSockets, provided by the operating system. These messaging protocols used for interprocess communicationare often vulnerable to attack; thus, when writing an application, you must always assume that the process atthe other end of your communication channel could be hostile.

For more information on how to perform secure interprocess communication, read “Validating Input andInterprocess Communication” (page 34).

Insecure File OperationsIn addition to time-of-check–time-of-use problems, many other file operations are insecure. Programmersoften make assumptions about the ownership, location, or attributes of a file that might not be true. Forexample, you might assume that you can always write to a file created by your program. However, if an attackercan change the permissions or flags on that file after you create it, and if you fail to check the result code aftera write operation, you will not detect the fact that the file has been tampered with.

Examples of insecure file operations include:

● writing to or reading from a file in a location writable by another user

● failing to make the right checks for file type, device ID, links, and other settings before using a file

● failing to check the result code after a file operation

● assuming that if a file has a local pathname, it has to be a local file

These and other insecure file operations are discussed in more detail in “Securing File Operations” (page 48).

Types of Security VulnerabilitiesRace Conditions

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

13

Access Control ProblemsAccess control is the process of controlling who is allowed to do what. This ranges from controlling physicalaccess to a computer—keeping your servers in a locked room, for example—to specifying who has access toa resource (a file, for example) and what they are allowed to do with that resource (such as read only). Someaccess control mechanisms are enforced by the operating system, some by the individual application or server,some by a service (such as a networking protocol) in use. Many security vulnerabilities are created by thecareless or improper use of access controls, or by the failure to use them at all.

Much of the discussion of security vulnerabilities in the software security literature is in terms of privileges,and many exploits involve an attacker somehow gaining more privileges than they should have. Privileges,also called permissions, are access rights granted by the operating system, controlling who is allowed to readand write files, directories, and attributes of files and directories (such as the permissions for a file), who canexecute a program, and who can perform other restricted operations such as accessing hardware devices andmaking changes to the network configuration. File permissions and access control in OS X are discussed in FileSystem Programming Guide .

Of particular interest to attackers is the gaining of root privileges, which refers to having the unrestrictedpermission to perform any operation on the system. An application running with root privileges can accesseverything and change anything. Many security vulnerabilities involve programming errors that allow anattacker to obtain root privileges. Some such exploits involve taking advantage of buffer overflows or raceconditions, which in some special circumstances allow an attacker to escalate their privileges. Others involvehaving access to system files that should be restricted or finding a weakness in a program—such as anapplication installer—that is already running with root privileges. For this reason, it’s important to always runprograms with as few privileges as possible. Similarly, when it is necessary to run a program with elevatedprivileges, you should do so for as short a time as possible.

Much access control is enforced by applications, which can require a user to authenticate before grantingauthorization to perform an operation. Authentication can involve requesting a user name and password, theuse of a smart card, a biometric scan, or some other method. If an application calls the OS X AuthorizationServices application interface to authenticate a user, it can automatically take advantage of whicheverauthentication method is available on the user’s system. Writing your own authentication code is a less securealternative, as it might afford an attacker the opportunity to take advantage of bugs in your code to bypassyour authentication mechanism, or it might offer a less secure authentication method than the standard oneused on the system. Authorization and authentication are described further in Security Overview .

Digital certificates are commonly used—especially over the Internet and with email—to authenticate usersand servers, to encrypt communications, and to digitally sign data to ensure that it has not been corruptedand was truly created by the entity that the user believes to have created it. Incorrect or careless use of digitalcertificates can lead to security vulnerabilities. For example, a server administration program shipped with a

Types of Security VulnerabilitiesAccess Control Problems

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

14

standard self-signed certificate, with the intention that the system administrator would replace it with a uniquecertificate. However, many system administrators failed to take this step, with the result that an attacker coulddecrypt communication with the server. [CVE-2004-0927]

It’s worth noting that nearly all access controls can be overcome by an attacker who has physical access to amachine and plenty of time. For example, no matter what you set a file’s permissions to, the operating systemcannot prevent someone from bypassing the operating system and reading the data directly off the disk. Onlyrestricting access to the machine itself and the use of robust encryption techniques can protect data frombeing read or corrupted under all circumstances.

The use of access controls in your program is discussed in more detail in “Elevating Privileges Safely” (page60).

Secure Storage and EncryptionEncryption can be used to protect a user’s secrets from others, either during data transmission or when thedata is stored. (The problem of how to protect a vendor’s data from being copied or used without permissionis not addressed here.) OS X provides a variety of encryption-based security options, such as

● FileVault

● the ability to create encrypted disk images

● keychain

● certificate-based digital signatures

● encryption of email

● SSL/TLS secure network communication

● Kerberos authentication

The list of security options in iOS includes

● passcode to prevent unauthorized use of the device

● data encryption

● the ability to add a digital signature to a block of data

● keychain

● SSL/TLS secure network communication

Types of Security VulnerabilitiesSecure Storage and Encryption

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

15

Each service has appropriate uses, and each has limitations. For example, FileVault, which encrypts the contentsof a user’s root volume (in OS X v10.7 and later) or home directory (in earlier versions), is a very importantsecurity feature for shared computers or computers to which attackers might gain physical access, such aslaptops. However, it is not very helpful for computers that are physically secure but that might be attackedover the network while in use, because in that case the home directory is in an unencrypted state and thethreat is from insecure networks or shared files. Also, FileVault is only as secure as the password chosen by theuser—if the user selects an easily guessed password, or writes it down in an easily found location, the encryptionis useless.

It is a serious mistake to try to create your own encryption method or to implement a published encryptionalgorithm yourself unless you are already an expert in the field. It is extremely difficult to write secure, robustencryption code that generates unbreakable ciphertext, and it is almost always a security vulnerability to try.For OS X, if you need cryptographic services beyond those provided by the OS X user interface and high-levelprogramming interfaces, you can use the open-source CSSM Cryptographic Services Manager. See thedocumentation provided with the Open Source security code, which you can download at http://developer.ap-ple.com/darwin/projects/security/. For iOS, the development APIs should provide all the services you need.

For more information about OS X and iOS security features, read Authentication, Authorization, and PermissionsGuide .

Social EngineeringOften the weakest link in the chain of security features protecting a user’s data and software is the user himself.As developers eliminate buffer overflows, race conditions, and other security vulnerabilities, attackers increasinglyconcentrate on fooling users into executing malicious code or handing over passwords, credit-card numbers,and other private information. Tricking a user into giving up secrets or into giving access to a computer to anattacker is known as social engineering.

For example, in February of 2005, a large firm that maintains credit information, Social Security numbers, andother personal information on virtually all U.S. citizens revealed that they had divulged information on at least150,000 people to scam artists who had posed as legitimate businessmen. According to Gartner (www.gart-ner.com), phishing attacks cost U.S. banks and credit card companies about $1.2 billion in 2003, and this numberis increasing. They estimate that between May 2004 and May 2005, approximately 1.2 million computer usersin the United States suffered losses caused by phishing.

Software developers can counter such attacks in two ways: through educating their users, and through clearand well-designed user interfaces that give users the information they need to make informed decisions.

For more advice on how to design a user interface that enhances security, see “Designing Secure UserInterfaces” (page 74).

Types of Security VulnerabilitiesSocial Engineering

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

16

Buffer overflows, both on the stack and on the heap, are a major source of security vulnerabilities in C,Objective-C, and C++ code. This chapter discusses coding practices that will avoid buffer overflow and underflowproblems, lists tools you can use to detect buffer overflows, and provides samples illustrating safe code.

Every time your program solicits input (whether from a user, from a file, over a network, or by some othermeans), there is a potential to receive inappropriate data. For example, the input data might be longer thanwhat you have reserved room for in memory.

When the input data is longer than will fit in the reserved space, if you do not truncate it, that data will overwriteother data in memory. When this happens, it is called a buffer overflow. If the memory overwritten containeddata essential to the operation of the program, this overflow causes a bug that, being intermittent, might bevery hard to find. If the overwritten data includes the address of other code to be executed and the user hasdone this deliberately, the user can point to malicious code that your program will then execute.

Similarly, when the input data is or appears to be shorter than the reserved space (due to erroneous assumptions,incorrect length values, or copying raw data as a C string), this is called a buffer underflow. This can cause anynumber of problems from incorrect behavior to leaking data that is currently on the stack or heap.

Although most programming languages check input against storage to prevent buffer overflows and underflows,C, Objective-C, and C++ do not. Because many programs link to C libraries, vulnerabilities in standard librariescan cause vulnerabilities even in programs written in “safe” languages. For this reason, even if you are confidentthat your code is free of buffer overflow problems, you should limit exposure by running with the least privilegespossible. See “Elevating Privileges Safely” (page 60) for more information on this topic.

Keep in mind that obvious forms of input, such as strings entered through dialog boxes, are not the onlypotential source of malicious input. For example:

1. Buffer overflows in one operating system’s help system could be caused by maliciously prepared embeddedimages.

2. A commonly-used media player failed to validate a specific type of audio files, allowing an attacker toexecute arbitrary code by causing a buffer overflow with a carefully crafted audio file.

[1CVE-2006-1591 2CVE-2006-1370]

There are two basic categories of overflow: stack overflows and heap overflows. These are described in moredetail in the sections that follow.

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

17

Avoiding Buffer Overflows and Underflows

Stack OverflowsIn most operating systems, each application has a stack (and multithreaded applications have one stack perthread). This stack contains storage for locally scoped data.

The stack is divided up into units called stack frames. Each stack frame contains all data specific to a particularcall to a particular function. This data typically includes the function’s parameters, the complete set of localvariables within that function, and linkage information—that is, the address of the function call itself, whereexecution continues when the function returns). Depending on compiler flags, it may also contain the addressof the top of the next stack frame. The exact content and order of data on the stack depends on the operatingsystem and CPU architecture.

Each time a function is called, a new stack frame is added to the top of the stack. Each time a function returns,the top stack frame is removed. At any given point in execution, an application can only directly access thedata in the topmost stack frame. (Pointers can get around this, but it is generally a bad idea to do so.) Thisdesign makes recursion possible because each nested call to a function gets its own copy of local variablesand parameters.

Avoiding Buffer Overflows and UnderflowsStack Overflows

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

18

Figure 2-1 illustrates the organization of the stack. Note that this figure is schematic only; the actual contentand order of data put on the stack depends on the architecture of the CPU being used. See OS X ABI FunctionCall Guide for descriptions of the function-calling conventions used in all the architectures supported by OSX.

Figure 2-1 Schematic view of the stack

Function A

Function B

Function C

Function A data

Parameters for callto function B

Function A return address

Function B data

Parameters for callto function C

Function B return address

Function C data

Space for parameters fornext subroutine call

Function C return address

In general, an application should check all input data to make sure it is appropriate for the purpose intended(for example, making sure that a filename is of legal length and contains no illegal characters). Unfortunately,in many cases, programmers do not bother, assuming that the user will not do anything unreasonable.

This becomes a serious problem when the application stores that data into a fixed-size buffer. If the user ismalicious (or opens a file that contains data created by someone who is malicious), he or she might providedata that is longer than the size of the buffer. Because the function reserves only a limited amount of spaceon the stack for this data, the data overwrites other data on the stack.

As shown in Figure 2-2, a clever attacker can use this technique to overwrite the return address used by thefunction, substituting the address of his own code. Then, when function C completes execution, rather thanreturning to function B, it jumps to the attacker’s code.

Avoiding Buffer Overflows and UnderflowsStack Overflows

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

19

Because the application executes the attacker’s code, the attacker’s code inherits the user’s permissions. If theuser is logged on as an administrator (the default configuration in OS X), the attacker can take complete controlof the computer, reading data from the disk, sending emails, and so forth. (In iOS, applications are much morerestricted in their privileges and are unlikely to be able to take complete control of the device.)

Figure 2-2 Stack after malicious buffer overflow

Function A

Function B

Function C

Function A data

Parameters for callto function B

Function A return address

Function B data

Parameters for callto function C

Function B return address

Function C data

Space for parameters fornext subroutine call

Function C return address

Parameter overflow

Address of attackerʼs code

In addition to attacks on the linkage information, an attacker can also alter program operation by modifyinglocal data and function parameters on the stack. For example, instead of connecting to the desired host, theattacker could modify a data structure so that your application connects to a different (malicious) host.

Heap OverflowsAs mentioned previously, the heap is used for all dynamically allocated memory in your application. When youuse malloc, the C++ new operator, or equivalent functions to allocate a block of memory or instantiate anobject, the memory that backs those pointers is allocated on the heap.

Avoiding Buffer Overflows and UnderflowsHeap Overflows

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

20

Because the heap is used to store data but is not used to store the return address value of functions andmethods, and because the data on the heap changes in a nonobvious way as a program runs, it is less obvioushow an attacker can exploit a buffer overflow on the heap. To some extent, it is this nonobviousness thatmakes heap overflows an attractive target—programmers are less likely to worry about them and defendagainst them than they are for stack overflows.

Figure 2-1 illustrates a heap overflow overwriting a pointer.

Figure 2-3 Heap overflow

Bufferoverflow

Data

Buffer

Data

Pointer

Data

Data

Data

Data

In general, exploiting a buffer overflow on the heap is more challenging than exploiting an overflow on thestack. However, many successful exploits have involved heap overflows. There are two ways in which heapoverflows are exploited: by modifying data and by modifying objects.

An attacker can exploit a buffer overflow on the heap by overwriting critical data, either to cause the programto crash or to change a value that can be exploited later (overwriting a stored user ID to gain additional access,for example). Modifying this data is known as a non-control-data attack. Much of the data on the heap isgenerated internally by the program rather than copied from user input; such data can be in relatively consistentlocations in memory, depending on how and when the application allocates it.

Avoiding Buffer Overflows and UnderflowsHeap Overflows

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

21

An attacker can also exploit a buffer overflow on the heap by overwriting pointers. In many languages suchas C++ and Objective-C, objects allocated on the heap contain tables of function and data pointers. By exploitinga buffer overflow to change such pointers, an attacker can potentially substitute different data or even replacethe instance methods in a class object.

Exploiting a buffer overflow on the heap might be a complex, arcane problem to solve, but crackers thrive onjust such challenges. For example:

1. A heap overflow in code for decoding a bitmap image allowed remote attackers to execute arbitrary code.

2. A heap overflow vulnerability in a networking server allowed an attacker to execute arbitrary code bysending an HTTP POST request with a negative “Content-Length” header.

[1CVE-2006-0006 2CVE-2005-3655]

String HandlingStrings are a common form of input. Because many string-handling functions have no built-in checks for stringlength, strings are frequently the source of exploitable buffer overflows. Figure 2-4 illustrates the differentways three string copy functions handle the same over-length string.

Figure 2-4 C string handling functions and buffer overflows

L A R G E R \0

L A R G E

L A R G \0

Char destination[5]; char *source = “LARGER”;

strcpy(destination, source);

strncpy(destination, source, sizeof(destination));

strlcpy(destination, source, sizeof(destination));

As you can see, the strcpy function merely writes the entire string into memory, overwriting whatever cameafter it.

The strncpy function truncates the string to the correct length, but without the terminating null character.When this string is read, then, all of the bytes in memory following it, up to the next null character, might beread as part of the string. Although this function can be used safely, it is a frequent source of programmer

Avoiding Buffer Overflows and UnderflowsString Handling

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

22

mistakes, and thus is regarded as moderately unsafe. To safely use strncpy, you must either explicitly zerothe last byte of the buffer after calling strncpy or pre-zero the buffer and then pass in a maximum lengththat is one byte smaller than the buffer size.

Only the strlcpy function is fully safe, truncating the string to one byte smaller than the buffer size andadding the terminating null character.

Table 2-1 summarizes the common C string-handling routines to avoid and which to use instead.

Table 2-1 String functions to use and avoid

Use these insteadDon’t use these functions

strlcatstrcat

strlcpystrcpy

strlcatstrncat

strlcpystrncpy

snprintf (see note) or asprintfsprintf

vsnprintf (see note) or vasprintfvsprintf

fgets (see note) or use Core Foundation or Foundation APIsgets

Avoiding Buffer Overflows and UnderflowsString Handling

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

23

Security Note for snprintf and vsnprintf: The functions snprintf, vsnprintf, and variants aredangerous if used incorrectly. Although they do behave functionally like strlcat and similar inthat they limit the bytes written to n-1, the length returned by these functions is the length thatwould have been printed if n were infinite .

For this reason, you must not use this return value to determine where to null-terminate the stringor to determine how many bytes to copy from the string at a later time.

Security Note for fgets: Although the fgets function provides the ability to read a limited amountof data, you must be careful when using it. Like the other functions in the “safer” column, fgetsalways terminates the string. However, unlike the other functions in that column, it takes a maximumnumber of bytes to read, not a buffer size.

In practical terms, this means that you must always pass a size value that is one fewer than the sizeof the buffer to leave room for the null termination. If you do not, the fgets function will dutifullyterminate the string past the end of your buffer, potentially overwriting whatever byte of data followsit.

You can also avoid string handling buffer overflows by using higher-level interfaces.

● If you are using C++, the ANSI C++ string class avoids buffer overflows, though it doesn’t handle non-ASCIIencodings (such as UTF-8).

● If you are writing code in Objective-C, use the NSString class. Note that an NSString object has to beconverted to a C string in order to be passed to a C routine, such as a POSIX function.

● If you are writing code in C, you can use the Core Foundation representation of a string, referred to as aCFString, and the string-manipulation functions in the CFString API.

The Core Foundation CFString is “toll-free bridged” with its Cocoa Foundation counterpart, NSString. Thismeans that the Core Foundation type is interchangeable in function or method calls with its equivalentFoundation object. Therefore, in a method where you see an NSString * parameter, you can pass in a valueof type CFStringRef, and in a function where you see a CFStringRef parameter, you can pass in anNSString instance. This also applies to concrete subclasses of NSString.

SeeCFStringReference , Foundation Framework Reference , andCarbon-Cocoa IntegrationGuide for more detailson using these representations of strings and on converting between CFString objects and NSString objects.

Avoiding Buffer Overflows and UnderflowsString Handling

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

24

Calculating Buffer SizesWhen working with fixed-length buffers, you should always use sizeof to calculate the size of a buffer, andthen make sure you don’t put more data into the buffer than it can hold. Even if you originally assigned a staticsize to the buffer, either you or someone else maintaining your code in the future might change the buffersize but fail to change every case where the buffer is written to.

The first example, Table 2-2, shows two ways of allocating a character buffer 1024 bytes in length, checkingthe length of an input string, and copying it to the buffer.

Table 2-2 Avoid hard-coded buffer sizes

Do this:Instead of this:

#define BUF_SIZE 1024

...

char buf[BUF_SIZE];

...

if (size < BUF_SIZE) {

...

}

char buf[1024];

...

if (size <= 1023) {

...

}

char buf[1024];

...

if (size < sizeof(buf)) {

...

}

char buf[1024];

...

if (size < 1024) {

...

}

The two snippets on the left side are safe as long as the original declaration of the buffer size is never changed.However, if the buffer size gets changed in a later version of the program without changing the test, then abuffer overflow will result.

The two snippets on the right side show safer versions of this code. In the first version, the buffer size is setusing a constant that is set elsewhere, and the check uses the same constant. In the second version, the bufferis set to 1024 bytes, but the check calculates the actual size of the buffer. In either of these snippets, changingthe original size of the buffer does not invalidate the check.

TTable 2-3, shows a function that adds an .ext suffix to a filename.

Avoiding Buffer Overflows and UnderflowsCalculating Buffer Sizes

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

25

Table 2-3 Avoid unsafe concatenation

Do this:Instead of this:

{

char file[MAX_PATH];

...

addsfx(file, sizeof(file));

...

}

static *suffix = ".ext";

size_t addsfx(char *buf, uint size)

{

size_t ret = strlcat(buf, suffix, size);

if (ret >= size) {

fprintf(stderr, "Buffer too small....\n");

}

return ret;

}

{

char file[MAX_PATH];

...

addsfx(file);

...

}

static *suffix = ".ext";

char *addsfx(char *buf)

{

return strcat(buf, suffix);

}

Both versions use the maximum path length for a file as the buffer size. The unsafe version in the left columnassumes that the filename does not exceed this limit, and appends the suffix without checking the length ofthe string. The safer version in the right column uses the strlcat function, which truncates the string if itexceeds the size of the buffer.

Important: You should always use an unsigned variable (such as size_t) when calculating sizes of buffersand of data going into buffers. Because negative numbers are stored as large positive numbers, if you usesigned variables, an attacker might be able to cause a miscalculation in the size of the buffer or data bywriting a large number to your program. See “Avoiding Integer Overflows and Underflows” (page 27) formore information on potential problems with integer arithmetic.

For a further discussion of this issue and a list of more functions that can cause problems, see Wheeler, SecureProgramming for Linux and Unix HOWTO (http://www.dwheeler.com/secure-programs/).

Avoiding Buffer Overflows and UnderflowsCalculating Buffer Sizes

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

26

Avoiding Integer Overflows and UnderflowsIf the size of a buffer is calculated using data supplied by the user, there is the potential for a malicious userto enter a number that is too large for the integer data type, which can cause program crashes and otherproblems.

In two’s-complement arithmetic (used for signed integer arithmetic by most modern CPUs), a negative numberis represented by inverting all the bits of the binary number and adding 1. A 1 in the most-significant bitindicates a negative number. Thus, for 4-byte signed integers, 0x7fffffff = 2147483647, but 0x80000000= -2147483648

Therefore,

int 2147483647 + 1 = - 2147483648

If a malicious user specifies a negative number where your program is expecting only unsigned numbers, yourprogram might interpret it as a very large number. Depending on what that number is used for, your programmight attempt to allocate a buffer of that size, causing the memory allocation to fail or causing a heap overflowif the allocation succeeds. In an early version of a popular web browser, for example, storing objects into aJavaScript array allocated with negative size could overwrite memory. [CVE-2004-0361]

In other cases, if you use signed values to calculate buffer sizes and test to make sure the data is not too largefor the buffer, a sufficiently large block of data will appear to have a negative size, and will therefore pass thesize test while overflowing the buffer.

Depending on how the buffer size is calculated, specifying a negative number could result in a buffer too smallfor its intended use. For example, if your program wants a minimum buffer size of 1024 bytes and adds to thata number specified by the user, an attacker might cause you to allocate a buffer smaller than the minimumsize by specifying a large positive number, as follows:

1024 + 4294966784 = 512

0x400 + 0xFFFFFE00 = 0x200

Also, any bits that overflow past the length of an integer variable (whether signed or unsigned) are dropped.For example, when stored in a 32-bit integer, 2**32 == 0. Because it is not illegal to have a buffer with a sizeof 0, and because malloc(0) returns a pointer to a small block, your code might run without errors if anattacker specifies a value that causes your buffer size calculation to be some multiple of 2**32. In other words,for any values of n and m where (n * m) mod 2**32 == 0, allocating a buffer of size n*m results in a validpointer to a buffer of some very small (and architecture-dependent) size. In that case, a buffer overflow isassured.

Avoiding Buffer Overflows and UnderflowsAvoiding Integer Overflows and Underflows

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

27

To avoid such problems, when performing buffer math, you should always include range checks to make sureno integer overflow is about to occur.

A common mistake when performing these tests is to check the result of a potentially overflowing multiplicationor other operation:

size_t bytes = n * m;

if (bytes < n || bytes < m) { /* BAD BAD BAD */

... /* allocate "bytes" space */

}

Unfortunately, the C language specification allows the compiler to optimize out such tests [CWE-733, CERTVU#162289]. Thus, the only correct way to test for integer overflow is to divide the maximum allowable resultby the multiplier and comparing the result to the multiplicand or vice-versa. If the result is smaller than themultiplicand, the product of those two values would cause an integer overflow.

For example:

if (n > 0 && m > 0 && SIZE_MAX/n >= m) {

size_t bytes = n * m;

... /* allocate "bytes" space */

}

Detecting Buffer OverflowsTo test for buffer overflows, you should attempt to enter more data than is asked for wherever your programaccepts input. Also, if your program accepts data in a standard format, such as graphics or audio data, youshould attempt to pass it malformed data. This process is known as fuzzing.

If there are buffer overflows in your program, it will eventually crash. (Unfortunately, it might not crash untilsome time later, when it attempts to use the data that was overwritten.) The crash log might provide someclues that the cause of the crash was a buffer overflow. If, for example, you enter a string containing the

Avoiding Buffer Overflows and UnderflowsDetecting Buffer Overflows

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

28

uppercase letter “A” several times in a row, you might find a block of data in the crash log that repeats thenumber 41, the ASCII code for “A” (see Figure 2-2). If the program is trying to jump to a location that is actuallyan ASCII string, that’s a sure sign that a buffer overflow was responsible for the crash.

Figure 2-5 Buffer overflow crash log

Exception: EXC_BAD_ACCESS (0x0001)Codes: KERN_INVALID_ADDRESS (0x0001) at 0x41414140

Thread 0 Crashed:

Thread 0 crashed with PPC Thread State 64: srr0: 0x0000000041414140 srr1: 0x000000004200f030 vrsave: 0x0000000000000000 cr: 0x48004242 xer: 0x0000000020000007 1r: 0x0000000041414141 ctr: 0x000000009077401c r0: 0x0000000041414141 r1: 0x00000000bfffe660 r2: 0x0000000000000000 r3: 000000000000000001 r4: 0x0000000000000041 r5: 0x00000000bfffdd50 r6: 0x0000000000000052 r7: 0x00000000bfffe638 r8: 0x0000000090774028 r9: 0x00000000bfffddd8 r10: 0x00000000bfffe380 r11: 0x0000000024004248 r12: 0x000000009077401c r13: 0x00000000a365c7c0 r14: 0x0000000000000100 r15: 0x0000000000000000 r16: 0x00000000a364c75c r17: 0x00000000a365c75c r18: 0x00000000a365c75c r19: 0x00000000a366c75c r20: 0x0000000000000000 r21: 0x0000000000000000 r22: 0x00000000a365c75c r23: 0x000000000034f5b0 r24: 0x00000000a3662aa4 r25: 0x000000000054c840 r26: 0x00000000a3662aa4 r27: 0x0000000000002f44 r28: 0x000000000034c840 r29: 0x0000000041414141 r30: 0x0000000041414141 r31: 0x0000000041414141

If there are any buffer overflows in your program, you should always assume that they are exploitable and fixthem. It is much harder to prove that a buffer overflow is not exploitable than to just fix the bug. Also notethat, although you can test for buffer overflows, you cannot test for the absence of buffer overflows; it isnecessary, therefore, to carefully check every input and every buffer size calculation in your code.

For more information on fuzzing, see “Fuzzing” (page 40) in “Validating Input and InterprocessCommunication” (page 34).

Avoiding Buffer UnderflowsFundamentally, buffer underflows occur when two parts of your code disagree about the size of a buffer orthe data in that buffer. For example, a fixed-length C string variable might have room for 256 bytes, but mightcontain a string that is only 12 bytes long.

Buffer underflow conditions are not always dangerous; they become dangerous when correct operationdepends upon both parts of your code treating the data in the same way. This often occurs when you readthe buffer to copy it to another block of memory, to send it across a network connection, and so on.

There are two broad classes of buffer underflow vulnerabilities: short writes, and short reads.

Avoiding Buffer Overflows and UnderflowsAvoiding Buffer Underflows

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

29

A short write vulnerability occurs when a short write to a buffer fails to fill the buffer completely. When thishappens, some of the data that was previously in the buffer is still present after the write. If the applicationlater performs an operation on the entire buffer (writing it to disk or sending it over the network, for example),that existing data comes along for the ride. The data could be random garbage data, but if the data happensto be interesting, you have an information leak.

Further, when such an underflow occurs, if the values in those locations affect program flow, the underflowcan potentially cause incorrect behavior up to and including allowing you to skip past an authentication orauthorization step by leaving the existing authorization data on the stack from a previous call by another user,application, or other entity.

Short write example (system call): For example, consider a UNIX system call that requires a commanddata structure, and includes an authorization token in that data structure. Assume that there aremultiple versions of the data structure, with different lengths, so the system call takes both thestructure and the length. Assume that the authorization token is fairly far down in the structure.

Suppose a malicious application passes in a command structure, and passes a size that encompassesthe data up to, but not including, the authorization token. The kernel’s system call handler callscopyin, which copies a certain number of bytes from the application into the data structure in thekernel’s address space. If the kernel does not zero-fill that data structure, and if the kernel does notcheck to see if the size is valid, there is a narrow possibility that the stack might still contain theprevious caller’s authorization token at the same address in kernel memory. Thus, the attacker isable to perform an operation that should have been disallowed.

A short read vulnerability occurs when a read from a buffer fails to read the complete contents of a buffer. Ifthe program then makes decisions based on that short read, any number of erroneous behaviors can result.This usually occurs when a C string function is used to read from a buffer that does not actually contain a validC string.

A C string is defined as a string containing a series of bytes that ends with a null terminator. By definition, itcannot contain any null bytes prior to the end of the string. As a result, C-string-based functions, such asstrlen, strlcpy, and strdup, copy a string until the first null terminator, and have no knowledge of thesize of the original source buffer.

By contrast, strings in other formats (a CFStringRef object, a Pascal string, or a CFDataRef blob, for example)have an explicit length and can contain null bytes at arbitrary locations in the data. If you convert such a stringinto a C string and then evaluate that C string, you get incorrect behavior because the resulting C stringeffectively ends at the first null byte.

Avoiding Buffer Overflows and UnderflowsAvoiding Buffer Underflows

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

30

Short read example (SSL verification): An example of a short read vulnerability occurred in manySSL stacks a few years ago. By applying for an SSL cert for a carefully crafted subdomain of a domainthat you own, you could effectively create a certificate that was valid for arbitrary domains.

Consider a subdomain in the form targetdomain.tld[null_byte].yourdomain.tld.

Because the certificate signing request contains a Pascal string, assuming that the certificate authorityinterprets it correctly, the certificate authority would contact the owner of yourdomain.tld andwould ask for permission to deliver the certificate. Because you own the domain, you would agreeto it. You would then have a certificate that is valid for the rather odd-looking subdomain in question.

When checking the certificate for validity, however, many SSL stacks incorrectly converted that Pascalstring into a C string without any validity checks. When this happened, the resulting C string containedonly the targetdomain.tld portion. The SSL stack then compared that truncated version withthe domain the user requested, and interpreted the certificate as being valid for the targeted domain.

In some cases, it was even possible to construct wildcard certificates that were valid for every possibledomain in such browsers (*.com[null].yourdomain.tld would match every .com address, forexample).

If you obey the following rules, you should be able to avoid most underflow attacks:

● Zero-fill all buffers before use. A buffer that contains only zeros cannot contain stale sensitive information.

● Always check return values and fail appropriately.

● If a call to an allocation or initialization function fails (AuthorizationCopyRights, for example), do notevaluate the resulting data, as it could be stale.

● Use the value returned from read system calls and other similar calls to determine how much data wasactually read. Then either:

● Use that result to determine how much data is present instead of using a predefined constant or

● fail if the function did not return the expected amount of data.

● Display an error and fail if a write call, printf call, or other output call returns without writing all of thedata, particularly if you might later read that data back.

● When working with data structures that contain length information, always verify that the data is the sizeyou expected.

● Avoid converting non-C strings (CFStringRef objects, NSString objects, CFDataRef objects, Pascalstrings, and so on) into C strings if possible. Instead, work with the strings in their original format.

If this is not possible, always perform length checks on the resulting C string or check for null bytes in thesource data.

Avoiding Buffer Overflows and UnderflowsAvoiding Buffer Underflows

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

31

● Avoid mixing buffer operations and string operations. If this is not possible, always perform length checkson the resulting C string or check for null bytes in the source data.

● Save files in a fashion that prevents malicious tampering or truncation. (See “Race Conditions and SecureFile Operations” (page 44) for more information.)

● Avoid integer overflows and underflows. (See “Calculating Buffer Sizes” (page 25) for details.)

Security Features that Can HelpOS X and iOS provide two features that can make it harder to exploit stack and buffer overflows: address spacelayout randomization (ASLR) and a non-executable stack and heap. These features are briefly explained in thesections that follow.

Address Space Layout RandomizationRecent versions of OS X and iOS, where possible, choose different locations for your stack, heap, libraries,frameworks, and executable code each time you run your software. This makes it much harder to successfullyexploit buffer overflows because it is no longer possible to know where the buffer is in memory, nor is it possibleto know where libraries and other code are located.

Address space layout randomization requires some help from the compiler—specifically, it requiresposition-independent code.

● If you are compiling an executable that targets OS X v10.7 and later (-macosx_version_min) or IOS v4.3and later (-ios_version_min), the necessary flags are enabled by default. You can disable this feature,if necessary, with the -no_pie flag, but for maximum security, you should not do so.

● If you are compiling an executable that targets an earlier OS, you must explicitly enableposition-independent executable support by adding the -pie flag.

Non-Executable Stack and HeapRecent processors support a feature called the NX bit that allows the operating system to mark certain partsof memory as non-executable. If the processor tries to execute code in any memory page marked asnon-executable, the program in question crashes.

OS X and iOS take advantage of this feature by marking the stack and heap as non-executable. This makesbuffer overflow attacks harder because any attack that places executable code on the stack or heap and thentries to run that code will fail.

Avoiding Buffer Overflows and UnderflowsSecurity Features that Can Help

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

32

Note: For 32-bit OS X apps, if your app allows execution on OS X prior to v10.7, only the stack ismarked non-executable, not the heap.

Most of the time, this is the behavior that you want. However, in some rare situations (such as writing ajust-in-time compiler), it may be necessary to modify that behavior.

There are two ways to make the stack and heap executable:

● Pass the -allow_stack_execute flag to the compiler. This makes the stack (not the heap) executable.

● Use the mprotect system call to mark specific memory pages as executable.

The details are beyond the scope of this document. For more information, see the manual page for mprotect.

Debugging Heap Corruption BugsTo help you debug heap corruption bugs, you can use the libgmalloc library. It provides additional detectionof overflows through the use of guard pages and other techniques. To enable this library, type the followingcommand in Terminal:

export DYLD_INSERT_LIBRARIES=/usr/lib/libgmalloc.dylib

Then run your software from Terminal (either by running the executable itself or using the open command).For more information, see the manual page for libgmalloc.

Avoiding Buffer Overflows and UnderflowsSecurity Features that Can Help

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

33

A major, and growing, source of security vulnerabilities is the failure of programs to validate all input fromoutside the program—that is, data provided by users, from files, over the network, or by other processes. Thischapter describes some of the ways in which unvalidated input can be exploited, and some coding techniquesto practice and to avoid.

Risks of Unvalidated InputAny time your program accepts input from an uncontrolled source, there is a potential for a user to pass indata that does not conform to your expectations. If you don’t validate the input, it might cause problemsranging from program crashes to allowing an attacker to execute his own code. There are a number of waysan attacker can take advantage of unvalidated input, including:

● Buffer overflows

● Format string vulnerabilities

● URL commands

● Code insertion

● Social engineering

Many Apple security updates have been to fix input vulnerabilities, including a couple of vulnerabilities thathackers used to “jailbreak” iPhones. Input vulnerabilities are common and are often easily exploitable, but arealso usually easily remedied.

Causing a Buffer OverflowIf your application takes input from a user or other untrusted source, it should never copy data into a fixed-lengthbuffer without checking the length and truncating it if necessary. Otherwise, an attacker can use the inputfield to cause a buffer overflow. See “Avoiding Buffer Overflows and Underflows” (page 17) to learn more.

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

34

Validating Input and Interprocess Communication

Format String AttacksIf you are taking input from a user or other untrusted source and displaying it, you need to be careful that yourdisplay routines do not process format strings received from the untrusted source. For example, in the followingcode the syslog standard C library function is used to write a received HTTP request to the system log. Becausethe syslog function processes format strings, it will process any format strings included in the input packet:

/* receiving http packet */

int size = recv(fd, pktBuf, sizeof(pktBuf), 0);

if (size) {

syslog(LOG_INFO, "Received new HTTP request!");

syslog(LOG_INFO, pktBuf);

}

Many format strings can cause problems for applications. For example, suppose an attacker passes the followingstring in the input packet:

"AAAA%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%n"

This string retrieves eight items from the stack. Assuming that the format string itself is stored on the stack,depending on the structure of the stack, this might effectively move the stack pointer back to the beginningof the format string. Then the %n token would cause the print function to take the number of bytes written sofar and write that value to the memory address stored in the next parameter, which happens to be the formatstring. Thus, assuming a 32-bit architecture, the AAAA in the format string itself would be treated as the pointervalue 0x41414141, and the value at that address would be overwritten with the number 76.

Doing this will usually cause a crash the next time the system has to access that memory location, but by usinga string carefully crafted for a specific device and operating system, the attacker can write arbitrary data to anylocation. See the manual page for printf for a full description of format string syntax.

To prevent format string attacks, make sure that no input data is ever passed as part of a format string. To fixthis, just include your own format string in each such function call. For example, the call

printf(buffer)

may be subject to attack, but the call

printf("%s", buffer)

is not. In the second case, all characters in the buffer parameter—including percent signs (%)—are printed outrather than being interpreted as formatting tokens.

Validating Input and Interprocess CommunicationRisks of Unvalidated Input

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

35

This situation can be made more complicated when a string is accidentally formatted more than once. Thefollowing example incorrectly passes the result of a call to the NSString method stringWithFormat: asthe value of the informativeTextWithFormat parameter of the NSAlert methodalertWithMessageText:defaultButton:alternateButton:otherButton:informativeTextWithFormat:.As a result, the string is formatted twice, and the data from the imported certificate is used as part of the formatstring for the NSAlert method.

alert = [NSAlert alertWithMessageText:"Certificate Import Succeeded"

defaultButton:"OK"

alternateButton:nil

otherButton:nil

informativeTextWithFormat:[NSString stringWithFormat: /* BAD! BAD! BAD! */

@"The imported certificate \"%@\" has been selected in the certificatepop-up.",

[selectedCert identifier]]];

[alert setAlertStyle:NSInformationalAlertStyle];

[alert runModal];

Instead, the string should be formatted only once, as follows:

alert = [NSAlert alertWithMessageText:"Certificate Import Succeeded"

defaultButton:"OK"

alternateButton:nil

otherButton:nil

informativeTextWithFormat:@"The imported certificate \"%@\" has been selectedin the certificate pop-up.",

[selectedCert identifier]];

...

The following commonly-used functions and methods are subject to format-string attacks:

● Standard C

● printf and other functions listed on the printf(3) manual page

● sscanf and other functions listed on the scanf(3) manual page

● syslog and vsyslog

● Carbon

Validating Input and Interprocess CommunicationRisks of Unvalidated Input

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

36

● AEBuildDesc and vAEBuildDesc

● AEBuildParameters and vAEBuildParameters

● AEBuildAppleEvent and vAEBuildAppleEvent

● Core Foundation

● CFStringCreateWithFormat

● CFStringCreateWithFormatAndArguments

● CFStringAppendFormat

● CFStringAppendFormatAndArguments

● Cocoa

● stringWithFormat:, initWithFormat:, and other NSStringmethods that take formatted stringsas arguments

● appendFormat: in the NSMutableString class

● alertWithMessageText:defaultButton:alternateButton:otherButton:informativeTextWithFormat:in NSAlert

● predicateWithFormat:, predicateWithFormat:arguments:, andpredicateWithFormat:argumentArray: in NSPredicate

● raise:format: and raise:format:arguments: in NSException

● NSRunAlertPanel and other Application Kit functions that create or return panels or sheets

URLs and File HandlingIf your application has registered a URL scheme, you have to be careful about how you process commandssent to your application through the URL string. Whether you make the commands public or not, hackers willtry sending commands to your application. If, for example, you provide a link or links to launch your applicationfrom your web site, hackers will look to see what commands you’re sending and will try every variation onthose commands they can think of. You must be prepared to handle, or to filter out, any commands that canbe sent to your application, not only those commands that you would like to receive.

For example, if you accept a command that causes your application to send credentials back to your webserver, don’t make the function handler general enough so that an attacker can substitute the URL of theirown web server. Here are some examples of the sorts of commands that you should not accept:

● myapp://cmd/run?program=/path/to/program/to/run

● myapp://cmd/set_preference?use_ssl=false

● myapp://cmd/[email protected]&file=some/data/file

● myapp://cmd/delete?data_to_delete=my_document_ive_been_working_on

Validating Input and Interprocess CommunicationRisks of Unvalidated Input

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

37

● myapp://cmd/login_to?server_to_send_credentials=some.malicious.webserver.com

In general, don’t accept commands that include arbitrary URLs or complete pathnames.

If you accept text or other data in a URL command that you subsequently include in a function or method call,you could be subject to a format string attack (see “Format String Attacks” (page 35)) or a buffer overflowattack (see “Causing a Buffer Overflow” (page 34)). If you accept pathnames, be careful to guard against stringsthat might redirect a call to another directory; for example:

myapp://use_template?template=/../../../../../../../../some/other/file

Injection AttacksUnvalidated URL commands and text strings sometimes allow an attacker to insert code into a program, whichthe program then executes. You are at risk from injection attacks whenever your code works with data that isloosely structured and contains a blend of two or more different types of data.

For example, if your application passes queries to a SQL database, those queries contain two types of data:the command itself (telling the database what to do) and the data that the command uses. The data is typicallyseparated from the command by quotation marks. However, if the data you are storing contains quotationmarks, your software must properly quote those additional marks so that they are not interpreted as the endof the data. Otherwise, a malicious attacker could pass your software a string containing quote marks followedby a semicolon to end the command, followed by a second command to run, at which point the SQL databasewould dutifully execute the injected code provided by the attacker.

Avoiding injection attacks correctly requires more than mere input validation, so it is covered separately in thesection “Avoiding Injection Attacks” (page 87) in “Avoiding Injection Attacks and XSS” (page 87).

Social EngineeringSocial engineering—essentially tricking the user—can be used with unvalidated input vulnerabilities to turna minor annoyance into a major problem. For example, if your program accepts a URL command to delete afile, but first displays a dialog requesting permission from the user, you might be able to send a long-enoughstring to scroll the name of the file to be deleted past the end of the dialog. You could trick the user intothinking he was deleting something innocuous, such as unneeded cached data. For example:

myapp://cmd/delete?file=cached data that is slowing down your system.,realfile

The user then might see a dialog with the text “Are you sure you want to delete cached data that is slowingdown your system.” The name of the real file, in this scenario, is out of sight below the bottom of the dialogwindow. When the user clicks the “OK” button, however, the user’s real data is deleted.

Validating Input and Interprocess CommunicationRisks of Unvalidated Input

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

38

Other examples of social engineering attacks include tricking a user into clicking on a link in a malicious website or following a malicious URL.

For more information about social engineering, read “Designing Secure User Interfaces” (page 74).

Modifications to Archived DataArchiving data, also known as object graph serialization, refers to converting a collection of interconnectedobjects into an architecture-independent stream of bytes that preserves the identity of and the relationshipsbetween the objects and values. Archives are used for writing data to a file, transmitting data between processesor across a network, or performing other types of data storage or exchange.

For example, in Cocoa, you can use a coder object to create and read from an archive, where a coder objectis an instance of a concrete subclass of the abstract class NSCoder.

Object archives are problematic from a security perspective for several reasons.

First, an object archive expands into an object graph that can contain arbitrary instances of arbitrary classes.If an attacker substitutes an instance of a different class than you were expecting, you could get unexpectedbehavior.

Second, because an application must know the type of data stored in an archive in order to unarchive it,developers typically assume that the values being decoded are the same size and data type as the values theyoriginally coded. However, when the data is stored in an insecure manner before being unarchived, this is nota safe assumption. If the archived data is not stored securely, it is possible for an attacker to modify the databefore the application unarchives it.

If your initWithCoder: method does not carefully validate all the data it decodes to make sure it is wellformed and does not exceed the memory space reserved for it, then by carefully crafting a corrupted archive,an attacker could potentially cause a buffer overflow or trigger another vulnerability and possibly seize controlof the system.

Further, if your initWithCoder: method calls the decodeObjectForKey: method, by the time that callreturns, it may already be too late to prevent misbehavior. If you are using archives in such a way that the datacould potentially be stored or transmitted in an insecure fashion or could potentially come from an untrustedsource, you should use decodeObjectOfClass:forKey: instead, and you should limit the contents of yourfile format to classes that conform to the NSSecureCoding protocol.

Third, some objects return a different object during unarchiving (see the NSKeyedUnarchiverDelegatemethod unarchiver:didDecodeObject:) or when they receive the message awakeAfterUsingCoder:.NSImage is one example of such a class—it may register itself for a name when unarchived, potentially takingthe place of an image the application uses. An attacker might be able to take advantage of this to insert amaliciously corrupt image file into an application.

Validating Input and Interprocess CommunicationRisks of Unvalidated Input

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

39

It’s worth keeping in mind that, even if you write completely safe code, there might still be security vulnerabilitiesin libraries called by your code. Specifically, the initWithCoder: methods of the superclasses of your classesare also involved in unarchiving.

Note: Be aware that nib files are archives, and these cautions apply equally to them. A nib file loadedfrom a signed application bundle should be trustable, but a nib file stored in an insecure location isnot.

See “Risks of Unvalidated Input” (page 34) for more information on the risks of reading unvalidated input,“Securing File Operations” (page 48) for techniques you can use to keep your archive files secure, and theother sections in this chapter for details on validating input.

FuzzingFuzzing, or fuzz testing, is the technique of randomly or selectively altering otherwise valid data and passingit to a program to see what happens. If the program crashes or otherwise misbehaves, that’s an indication ofa potential vulnerability that might be exploitable. Fuzzing is a favorite tool of hackers who are looking forbuffer overflows and the other types of vulnerabilities discussed in this chapter. Because it will be employedby hackers against your program, you should use it first, so you can close any vulnerabilities before they do.

Although you can never prove that your program is completely free of vulnerabilities, you can at least get ridof any that are easy to find this way. In this case, the developer’s job is much easier than that of the hacker.Whereas the hacker has to not only find input fields that might be vulnerable, but also must determine theexact nature of the vulnerability and then craft an attack that exploits it, you need only find the vulnerability,then look at the source code to determine how to close it. You don’t need to prove that the problem isexploitable—just assume that someone will find a way to exploit it, and fix it before they get an opportunityto try.

Fuzzing is best done with scripts or short programs that randomly vary the input passed to a program. Dependingon the type of input you’re testing—text field, URL, data file, and so forth—you can try HTML, javascript, extralong strings, normally illegal characters, and so forth. If the program crashes or does anything unexpected,you need to examine the source code that handles that input to see what the problem is, and fix it.

For example, if your program asks for a filename, you should attempt to enter a string longer than the maximumlegal filename. Or, if there is a field that specifies the size of a block of data, attempt to use a data block largerthan the one you indicated in the size field.

Validating Input and Interprocess CommunicationFuzzing

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

40

The most interesting values to try when fuzzing are usually boundary values. For example, if a variable containsa signed integer, try passing the maximum and minimum values allowed for a signed integer of that size, alongwith 0, 1, and -1. If a data field should contain a string with no fewer than 1 byte and no more than 42 bytes,try zero bytes, 1 byte, 42 bytes, and 43 bytes. And so on.

In addition to boundary values, you should also try values that are way, way outside the expected values. Forexample, if your application is expecting an image that is up to 2,000 pixels by 3,000 pixels, you might modifythe size fields to claim that the image is 65,535 pixels by 65,535 pixels. Using large values can uncover integeroverflow bugs (and in some cases, NULL pointer handling bugs when a memory allocation fails). See “AvoidingInteger Overflows and Underflows” (page 27) in “Avoiding Buffer Overflows and Underflows” (page 17) formore information about integer overflows.

Inserting additional bytes of data into the middle or end of a file can also be a useful fuzzing technique in somecases. For example, if a file’s header indicates that it contains 1024 bytes after the header, the fuzzer could adda 1025th byte. The fuzzer could add an additional row or column of data in an image file. And so on.

Interprocess Communication and NetworkingWhen communicating with another process, the most important thing to remember is that you cannot generallyverify that the other process has not been compromised. Thus, you must treat it as untrusted and potentiallyhostile. All interprocess communication is potentially vulnerable to attacks if you do not properly validateinput, avoid race conditions, and perform any other tests that are appropriate when working with data froma potentially hostile source.

Above and beyond these risks, however, some forms of interprocess communication have specific risks inherentto the communication mechanism. This section describes some of those risks.

Mach messagingWhen working with Mach messaging, it is important to never give the Mach task port of your process toany other. If you do, you are effectively allowing that process to arbitrarily modify the address space yourprocess, which makes it trivial to compromise your process.

Instead, you should create a Mach port specifically for communicating with a given client.

Note: Mach messaging in OS X is not a supported API. No backwards compatibility guarantees are made for applicationsthat use it anyway.

Remote procedure calls (RPC) and Distributed Objects:If your application uses remote procedure calls or Distributed Objects, you are implicitly saying that youfully trust whatever process is at the other end of the connection. That process can call arbitrary functions

Validating Input and Interprocess CommunicationInterprocess Communication and Networking

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

41

within your code, and may even be able to arbitrarily overwrite portions of your code with maliciouscode.

For this reason, you should avoid using remote procedure calls or Distributed Objects when communicatingwith potentially untrusted processes, and in particular, you should never use these communicationtechnologies across a network boundary except among hosts that you control.

Shared Memory:If you intend to share memory across applications, be careful to allocate any memory on the heap inpage-aligned, page-sized blocks. If you share a block of memory that is not a whole page (or worse, ifyou share some portion of your application’s stack), you may be providing the process at the other endwith the ability to overwrite portions of your code, stack, or other data in ways that can produce incorrectbehavior, and may even allow injection of arbitrary code.

In addition to these risks, some forms of shared memory can also be subject to race condition attacks.Specifically, memory mapped files can be replaced with other files between when you create the file andwhen you open it. See “Securing File Operations” (page 48) for more details.

Finally, named shared memory regions and memory mapped files can be accessed by any other processrunning as the user. For this reason, it is not safe to use non-anonymous shared memory for sendinghighly secret information between processes. Instead, allocate your shared memory region prior tocreating the child process that needs to share that region, then pass IPC_PRIVATE as the key for shmgetto ensure that the shared memory identifier is not easy to guess.

Note: Shared memory regions are detached if you call exec or other similar functions. If you need to pass data in a

secure way across an exec boundary, you must pass the shared memory ID to the child process. Ideally, you should

do this using a secure mechanism, such as a pipe created using a call to pipe.

After the last child process that needs to use a particular shared memory region is running, the processthat created the region should call shmctl to remove the shared memory region. Doing so ensures thatno further processes can attach to that region even if they manage to guess the region ID.

shmctl(id, IPC_RMID, NULL);

Validating Input and Interprocess CommunicationInterprocess Communication and Networking

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

42

Signals:A signal, in this context, is a particular type of content-free message sent from one process to anotherin a UNIX-based operating system such as OS X. Any program can register a signal handler function toperform specific operations upon receiving a signal.

In general, it is not safe to do a significant amount of work in a signal handler. There are only a handfulof library functions and system calls that are safe to use in a signal handler (referred to as async-signal-safecalls), and this makes it somewhat difficult to safely perform work inside a call.

More importantly, however, as a programmer, you are not in control of when your application receivesa signal. Thus, if an attacker can cause a signal to be delivered to your process (by overflowing a socketbuffer, for example), the attacker can cause your signal handler code to execute at any time, betweenany two lines of code in your application. This can be problematic if there are certain places whereexecuting that code would be dangerous.

For example, in 2004, a signal handler race condition was found in open-source code present in manyUNIX-based operating systems. This bug made it possible for a remote attacker to execute arbitrary codeor to stop the FTP daemon from working by causing it to read data from a socket and execute commandswhile it was still running as the root user. [CVE-2004-0794]

For this reason, signal handlers should do the minimum amount of work possible, and should performthe bulk of the work at a known location within the application’s main program loop.

For example, in an application based on Foundation or Core Foundation, you can create a pair of connectedsockets by calling socketpair, call setsockopt to set the socket to non-blocking, turn one end intoa CFStream object by calling CFStreamCreatePairWithSocket, and then schedule that stream onyour run loop. Then, you can install a minimal signal handler that uses the write system call (which isasync-signal-safe according to POSIX.1) to write data into the other socket. When the signal handlerreturns, your run loop will be woken up by data on the other socket, and you can then handle the signalat your convenience.

Important: If you are writing to a socket in a signal handler and reading from it in a run loop on your mainprogram thread, you must set the socket to non-blocking. If you do not, it is possible to cause your applicationto hang by sending it too many signals.

The queue for a socket is of finite size. When it fills up, if the socket is set to non-blocking, the write call fails, andthe global variable errno is set to EAGAIN. If the socket is blocking, however, the write call blocks until the queueempties enough to write the data.

If a write call in a signal handler blocks, this prevents the signal handler from returning execution to the run loop.If that run loop is responsible for reading data from the socket, the queue will never empty, the write call willnever unblock, and your application will basically hang (at least until the write call is interrupted by another signal).

Validating Input and Interprocess CommunicationInterprocess Communication and Networking

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

43

When working with shared data, whether in the form of files, databases, network connections, shared memory,or other forms of interprocess communication, there are a number of easily made mistakes that can compromisesecurity. This chapter describes many such pitfalls and how to avoid them.

Avoiding Race ConditionsA race condition exists when changes to the order of two or more events can cause a change in behavior. Ifthe correct order of execution is required for the proper functioning of the program, this is a bug. If an attackercan take advantage of the situation to insert malicious code, change a filename, or otherwise interfere withthe normal operation of the program, the race condition is a security vulnerability. Attackers can sometimestake advantage of small time gaps in the processing of code to interfere with the sequence of operations,which they then exploit.

OS X, like all modern operating systems, is a multitasking OS; that is, it allows multiple processes to run orappear to run simultaneously by rapidly switching among them on each processor. The advantages to the userare many and mostly obvious; the disadvantage, however, is that there is no guarantee that two consecutiveoperations in a given process are performed without any other process performing operations between them.In fact, when two processes are using the same resource (such as the same file), there is no guarantee thatthey will access that resource in any particular order unless both processes explicitly take steps to ensure it.

For example, if you open a file and then read from it, even though your application did nothing else betweenthese two operations, some other process might alter the file after the file was opened and before it was read.If two different processes (in the same or different applications) were writing to the same file, there would beno way to know which one would write first and which would overwrite the data written by the other. Suchsituations cause security vulnerabilities.

There are two basic types of race condition that can be exploited: time of check–time of use (TOCTOU), andsignal handling.

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

44

Race Conditions and Secure File Operations

Time of Check Versus Time of UseIt is fairly common for an application to need to check some condition before undertaking an action. Forexample, it might check to see if a file exists before writing to it, or whether the user has access rights to reada file before opening it for reading. Because there is a time gap between the check and the use (even thoughit might be a fraction of a second), an attacker can sometimes use that gap to mount an attack. Thus, this isreferred to as a time-of-check–time-of-use problem.

Temporary FilesA classic example is the case where an application writes temporary files to publicly accessible directories.You can set the file permissions of the temporary file to prevent another user from altering the file.However, if the file already exists before you write to it, you could be overwriting data needed by anotherprogram, or you could be using a file prepared by an attacker, in which case it might be a hard link orsymbolic link, redirecting your output to a file needed by the system or to a file controlled by the attacker.

To prevent this, programs often check to make sure a temporary file with a specific name does not alreadyexist in the target directory. If such a file exists, the application deletes it or chooses a new name for thetemporary file to avoid conflict. If the file does not exist, the application opens the file for writing, becausethe system routine that opens a file for writing automatically creates a new file if none exists.

An attacker, by continuously running a program that creates a new temporary file with the appropriatename, can (with a little persistence and some luck) create the file in the gap between when the applicationchecked to make sure the temporary file didn’t exist and when it opens it for writing. The applicationthen opens the attacker’s file and writes to it (remember, the system routine opens an existing file if thereis one, and creates a new file only if there is no existing file).

The attacker’s file might have different access permissions than the application’s temporary file, so theattacker can then read the contents. Alternatively, the attacker might have the file already open. Theattacker could replace the file with a hard link or symbolic link to some other file (either one owned bythe attacker or an existing system file). For example, the attacker could replace the file with a symboliclink to the system password file, so that after the attack, the system passwords have been corrupted tothe point that no one, including the system administrator, can log in.

For a real-world example, in a vulnerability in a directory server, a server script wrote private and publickeys into temporary files, then read those keys and put them into a database. Because the temporaryfiles were in a publicly writable directory, an attacker could have created a race condition by substitutingthe attacker’s own files (or hard links or symbolic links to the attacker’s files) before the keys were reread,thus causing the script to insert the attacker’s private and public keys instead. After that, anything

Race Conditions and Secure File OperationsAvoiding Race Conditions

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

45

encrypted or authenticated using those keys would be under the attacker’s control. Alternatively, theattacker could have read the private keys, which can be used to decrypt encrypted data. [CVE-2005-2519]

Similarly, if an application temporarily relaxes permissions on files or folders in order to perform someoperation, an attacker might be able to create a race condition by carefully timing his or her attack tooccur in the narrow window in which those permissions are relaxed.

To learn more about creating temporary files securely, read “Create Temporary Files Correctly” (page 51).

Interprocess CommunicationTime-of-check–time-of-use problems do not have to involve files, of course. They can apply to any datastorage or communications mechanism that does not perform operations atomically.

Suppose, for example, that you wrote a program designed to automatically count the number of peopleentering a sports stadium for a game. Each turnstile talks to a web service running on a server wheneversomeone walks through. Each web service instance inherently runs as a separate process. Each time aturnstile sends a signal, an instance of the web service starts up, retrieves the gate count from a database,increments it by one, and writes it back to the database. Thus, multiple processes are keeping a singlerunning total.

Now suppose two people enter different gates at exactly the same time. The sequence of events mightthen be as follows:

1. Server process A receives a request from gate A.

2. Server process B receives a request from gate B.

3. Server process A reads the number 1000 from the database.

4. Server process B reads the number 1000 from the database.

5. Server process A increments the gate count by 1 so that Gate == 1001.

6. Server process B increments the gate count by 1 so that Gate == 1001.

7. Server process A writes 1001 as the new gate count.

8. Server process B writes 1001 as the new gate count.

Because server process B read the gate count before process A had time to increment it and write it back,both processes read the same value. After process A increments the gate count and writes it back, processB overwrites the value of the gate count with the same value written by process A. Because of this racecondition, one of the two people entering the stadium was not counted. Since there might be long linesat each turnstile, this condition might occur many times before a big game, and a dishonest ticket clerkwho knew about this undercount could pocket some of the receipts with no fear of being caught.

Other race conditions that can be exploited, like the example above, involve the use of shared data orother interprocess communication methods. If an attacker can interfere with important data after it iswritten and before it is re-read, he or she can disrupt the operation of the program, alter data, or do other

Race Conditions and Secure File OperationsAvoiding Race Conditions

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

46

mischief. The use of non-thread-safe calls in multithreaded programs can result in data corruption. If anattacker can manipulate the program to cause two such threads to interfere with each other, it may bepossible to mount a denial-of-service attack.

In some cases, by using such a race condition to overwrite a buffer in the heap with more data than thebuffer can hold, an attacker can cause a buffer overflow. As discussed in “Avoiding Buffer Overflows andUnderflows” (page 17), buffer overflows can be exploited to cause execution of malicious code.

The solution to race conditions involving shared data is to use a locking mechanism to prevent oneprocess from changing a variable until another is finished with it. There are problems and hazardsassociated with such mechanisms, however, and they must be implemented carefully. And, of course,locking mechanisms only apply to processes that participate in the locking scheme. They cannot preventan untrusted application from modifying the data maliciously. For a full discussion, see Wheeler, SecureProgramming for Linux and Unix HOWTO , at http://www.dwheeler.com/secure-programs/.

Time-of-check–time-of-use vulnerabilities can be prevented in different ways, depending largely on the domainof the problem. When working with shared data, you should use locking to protect that data from otherinstances of your code. When working with data in publicly writable directories, you should also take theprecautions described in “Files in Publicly Writable Directories Are Dangerous” (page 52).

Signal HandlingBecause signal handlers execute code at arbitrary times, they can be used to cause incorrect behavior. Indaemons running as root, running the wrong code at the wrong time can even cause privilege escalation.“Securing Signal Handlers” (page 47) describes this problem in more detail.

Securing Signal HandlersSignal handlers are another common source of race conditions. Signals from the operating system to a processor between two processes are used for such purposes as terminating a process or causing it to reinitialize.

If you include signal handlers in your program, they should not make any system calls and should terminateas quickly as possible. Although there are certain system calls that are safe from within signal handlers, writinga safe signal handler that does so is tricky. The best thing to do is to set a flag that your program checksperiodically, and do no other work within the signal handler. This is because the signal handler can be interruptedby a new signal before it finishes processing the first signal, leaving the system in an unpredictable state or,worse, providing a vulnerability for an attacker to exploit.

Race Conditions and Secure File OperationsSecuring Signal Handlers

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

47

For example, in 1997, a vulnerability was reported in a number of implementations of the FTP protocol in whicha user could cause a race condition by closing an FTP connection. Closing the connection resulted in thenear-simultaneous transmission of two signals to the FTP server: one to abort the current operation, and oneto log out the user. The race condition occurred when the logout signal arrived just before the abort signal.

When a user logged onto an FTP server as an anonymous user, the server would temporarily downgrade itsprivileges from root to nobody so that the logged-in user had no privileges to write files. When the user loggedout, however, the server reassumed root privileges. If the abort signal arrived at just the right time, it wouldabort the logout procedure after the server had assumed root privileges but before it had logged out the user.The user would then be logged in with root privileges, and could proceed to write files at will. An attackercould exploit this vulnerability with a graphical FTP client simply by repeatedly clicking the “Cancel” button.[CVE-1999-0035]

For a brief introduction to signal handlers, see the Little Unix Programmers Group site at http://users.act-com.co.il/~choo/lupg/tutorials/signals/signals-programming.html. For a discourse on how signal handler raceconditions can be exploited, see the article by Michal Zalewski at http://www.bindview.com/Services/razor/Pa-pers/2001/signals.cfm.

Securing File OperationsInsecure file operations are a major source of security vulnerabilities. In some cases, opening or writing to afile in an insecure fashion can give attackers the opportunity to create a race condition (see “Time of CheckVersus Time of Use” (page 45)). Often, however, insecure file operations give an attacker the ability to readconfidential information, perform a denial of service attack, take control of an application, or even take controlof the entire system.

This section discusses what you should do to make your file operations more secure.

Check Result CodesAlways check the result codes of every routine that you call. Be prepared to handle the situation if the operationfails. Most file-based security vulnerabilities could have been avoided if the developers of the programs hadchecked result codes.

Some common mistakes are listed below.

When writing to files or changing file permissionsA failure when change permissions on a file or to open a file for writing can be caused by many things,including:

● Insufficient permissions on the file or enclosing directory.

Race Conditions and Secure File OperationsSecuring File Operations

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

48

● The immutable flag (set with the chflags utility or the chflags system call).

● A network volume becoming unavailable.

● An external drive getting unplugged.

● A drive failure.

Depending on the nature of your software, any one of these could potentially be exploited if you do notproperly check error codes.

See the manual pages for the chflags, chown, and chgrp commands and the chflags and chownfunctions for more information.

When removing filesAlthough the rm command can often ignore permissions if you pass the -f flag, it can still fail.

For example, you can’t remove a directory that has anything inside it. If a directory is in a location whereother users have access to it, any attempt to remove the directory might fail because another processmight add new files while you are removing the old ones.

The safest way to fix this problem is to use a private directory that no one else has access to. If that’s notpossible, check to make sure the rm command succeeded and be prepared to handle failures.

Watch Out for Hard LinksA hard link is a second name for a file—the file appears to be in two different locations with two differentnames.

If a file has two (or more) hard links and you check the file to make sure that the ownership, permissions, andso forth are all correct, but fail to check the number of links to the file, an attacker can write to or read fromthe file through their own link in their own directory. Therefore, among other checks before you use a file, youshould check the number of links.

Do not, however, simply fail if there’s a second link to a file, because there are some circumstances where alink is okay or even expected. For example, every directory is linked into at least two places in the hierarchy—thedirectory name itself and the special . record from the directory that links back to itself. Also, if that directorycontains other directories, each of those subdirectories contains a .. record that points to the outer directory.

You need to anticipate such conditions and allow for them. Even if the link is unexpected, you need to handlethe situation gracefully. Otherwise, an attacker can cause denial of service just by creating a link to the file.Instead, you should notify the user of the situation, giving them as much information as possible so they cantry to track down the source of the problem.

Race Conditions and Secure File OperationsSecuring File Operations

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

49

Watch Out for Symbolic LinksA symbolic link is a special type of file that contains a path name. Symbolic links are more common than hardlinks.

Functions that follow symbolic links automatically open, read, or write to the file whose path name is in thesymbolic link file rather than the symbolic link file itself. Your application receives no notification that a symboliclink was followed; to your application, it appears as if the file addressed is the one that was used.

An attacker can use a symbolic link, for example, to cause your application to write the contents intended fora temporary file to a critical system file instead, thus corrupting the system. Alternatively, the attacker cancapture data you are writing or can substitute the attacker’s data for your own when you read the temporaryfile.

In general, you should avoid functions, such as chown and stat, that follow symbolic links (see Table 4-1 (page56) for alternatives). As with hard links, your program should evaluate whether a symbolic link is acceptable,and if not, should handle the situation gracefully.

Case-Insensitive File Systems Can Thwart Your Security ModelIn OS X, any partition (including the boot volume) can be either case-sensitive, case-insensitive butcase-preserving, or, for non-boot volumes, case-insensitive. For example, HFS+ can be either case-sensitive orcase-insensitive but case-preserving. FAT32 is case-insensitive but case-preserving. FAT12, FAT16, and ISO-9660(without extensions) are case-insensitive.

An application that is unaware of the differences in behavior between these volume formats can cause serioussecurity holes if you are not careful. In particular:

● If your program uses its own permission model to provide or deny access (for example, a web server thatallows access only to files within a particular directory), you must either enforce this with a chroot jail orbe vigilant about ensuring that you correctly identify paths even in a case-insensitive world.

Among other things, this means that you should ideally use a whitelisting scheme rather than a blacklistingscheme (with the default behavior being “deny”). If this is not possible, for correctness, you must compareeach individual path part against your blacklist using case-sensitive or case-insensitive comparisons,depending on what type of volume the file resides on.

For example, if your program has a blacklist that prevents users from uploading or downloading the file/etc/ssh_host_key, if your software is installed on a case-insensitive volume, you must also rejectsomeone who makes a request for /etc/SSH_host_key, /ETC/SSH_HOST_KEY, or even/ETC/ssh_host_key.

Race Conditions and Secure File OperationsSecuring File Operations

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

50

● If your program periodically accesses a file on a case-sensitive volume using the wrong mix of uppercaseand lowercase letters, the open call will fail... until someone creates a second file with the name yourprogram is actually asking for.

If someone creates such a file, your application will dutifully load data from the wrong file. If the contentsof that file affect your application’s behavior in some important way, this represents a potential attackvector.

This also presents a potential attack vector if that file is an optional part of your application bundle thatgets loaded by dyld when your application is launched.

Create Temporary Files CorrectlyThe temporary directories in OS X are shared among multiple users. This requires that they be writable bymultiple users. Any time you work on files in a location to which others have read/write access, there’s thepotential for the file to be compromised or corrupted.

The best way to handle this is to create a safe temporary directory that only you can access, then write thefiles into that directory.

To do this:

● In a cocoa app, call NSTemporaryDirectory.

● At the POSIX layer, call confstr and pass the constant _CS_DARWIN_USER_TEMP_DIR as the nameparameter.

Next, to maximize your protection against malicious apps running as the same user, use appropriate functionsto create folders and files within that directory, as described below.

POSIX LayerUse the mkstemp function to create temporary files at the POSIX layer. The mkstemp function guaranteesa unique filename and returns a file descriptor, thus allowing you skip the step of checking the openfunction result for an error, which might require you to change the filename and call open again.

If you must create a temporary file in a public directory manually, you can use the open function withthe O_CREAT and O_EXCL flags set to create the file and obtain a file descriptor. The O_EXCL flag causesthis function to return an error if the file already exists. Be sure to check for errors before proceeding.

After you’ve opened the file and obtained a file descriptor, you can safely use functions that take filedescriptors, such as the standard C functions write and read, for as long as you keep the file open. Seethe manual pages for open(2), mkstemp(3), write(2), and read(2) for more on these functions,and see Wheeler, Secure Programming for Linux and Unix HOWTO for advantages and shortcomings tousing these functions.

Race Conditions and Secure File OperationsSecuring File Operations

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

51

CocoaThere are no Cocoa methods that create a file and return a file descriptor. However, you can call thestandard C open function from an Objective-C program to obtain a file descriptor (see “Working withPublicly Writable Files Using POSIX Calls” (page 55)). Or you can call the mkstemp function to create atemporary file and obtain a file descriptor. Then you can use the NSFileHandle methodinitWithFileDescriptor: to initialize a file handle, and other NSFileHandle methods to safelywrite to or read from the file. Documentation for the NSFileHandle class is in Foundation FrameworkReference .

To obtain the path to the default location to store temporary files (stored in the $TMPDIR environmentvariable), you can use the NSTemporaryDirectory function. Note that NSTemporaryDirectory canreturn /tmp under certain circumstances such as if you link on a pre-OS X v10.3 development target.Therefore, if you’re using NSTemporaryDirectory, you either have to be sure that using /tmp is suitablefor your operation or, if not, you should consider that an error case and create a more secure temporarydirectory if that happens.

The changeFileAttributes:atPath: method in the NSFileManager class is similar to chmod orchown, in that it takes a file path rather than a file descriptor. You shouldn’t use this method if you’reworking in a public directory or a user’s home directory. Instead, call the fchown or fchmod function(see Table 4-1 (page 56)). You can call the NSFileHandle class’s fileDescriptor method to get thefile descriptor of a file in use by NSFileHandle.

In addition, when working with temporary files, you should avoid the writeToFile:atomicallymethods of NSString and NSData. These are designed to minimize the risk of data loss when writingto a file, but do so in a way that is not recommended for use in directories that are writable by others.See “Working with Publicly Writable Files Using Cocoa” (page 57) for details.

Files in Publicly Writable Directories Are DangerousFiles in publicly writable directories must be treated as inherently untrusted. An attacker can delete the fileand replace it with another file, replace it with a symbolic link to another file, create the file ahead of time, andso on. There are ways to mitigate each of these attacks to some degree, but the best way to prevent them isto not read or write files in a publicly writable directory in the first pace. If possible, you should create asubdirectory with tightly controlled permissions, then write your files inside that subdirectory.

If you must work in a directory to which your process does not have exclusive access, however, you must checkto make sure a file does not exist before you create it. You must also verify that the file you intend to read fromor write to is the same file that you created.

To this end, you should always use routines that operate on file descriptors rather than pathnames whereverpossible, so that you can be certain you’re always dealing with the same file. To do this, pass the O_CREAT andO_EXCL flags to the open system call. This creates a file, but fails if the file already exists.

Race Conditions and Secure File OperationsSecuring File Operations

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

52

Note: If you cannot use file descriptors directly for some reason, you should explicitly create filesas a separate step from opening them. Although this does not prevent someone from swapping ina new file between those operations, at least it narrows the attack window by making it possible todetect if the file already exists.

Before you create the file, however, you should first set your process’s file creation mask (umask). The filecreation mask is a bitmask that alters the default permissions of all new files and directories created by yourprocess. This bitmask is typically specified in octal notation, which means that it must begin with a zero (not0x).

For example, if you set the file creation mask to 022, any new files created by your process will have rw-r--r--permissions because the write permission bits are masked out. Similarly, any new directories will haverw-r-xr-x permissions.

Note: New files never have the execute bit set. Directories, however, do. Therefore, you shouldgenerally mask out execute permission when masking out read permission unless you have a specificreason to allow users to traverse a directory without seeing its contents.

To limit access to any new files or directories so that only the user can access them, set the file creation maskto 077.

You can also mask out permissions in such a way that they apply to the user, though this is rare. For example,to create a file that no one can write or execute, and that only the user can read, you could set the file creationmask to 0377. This is not particularly useful, but it is possible.

There are several ways to set the file creation mask:

In C code:In C code, you can set the file creation mask globally using the umask system call.

You can also pass the file creation mask to the open or mkdir system call when creating a file or directory.

Note: For maximum portability when writing C code, you should always create your masks using the file mode constants

defined in <sys/stat.h>.

For example:

umask(S_IRWXG|S_IRWXO);

Race Conditions and Secure File OperationsSecuring File Operations

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

53

In shell scripts:In shell scripts, you set the file creation mask by using the umask shell builtin. This is documented in themanual pages for sh or csh.

For example:

umask 0077;

As an added security bonus, when a process calls another process, the new process inherits the parent process’sfile creation mask. Thus, if your process starts another process that creates a file without resetting the filecreation mask, that file similarly will not be accessible to other users on the system. This is particularly usefulwhen writing shell scripts.

For more information on the file creation mask, see the manual page for umask and Viega and McGraw, BuildingSecure Software , Addison Wesley, 2002. For a particularly lucid explanation of the use of a file creation mask,see http://web.archive.org/web/20090517063338/http://www.sun.com/bigadmin/content/submitted/umask_per-missions.html?.

Before you read a file (but after opening it), make sure it has the owner and permissions you expect (usingfstat). Be prepared to fail gracefully (rather than hanging) if it does not.

Here are some guidelines to help you avoid time-of-check–time-of-use vulnerabilities when working with filesin publicly writable directories. For more detailed discussions, especially for C code, see Viega and McGraw,Building Secure Software , Addison Wesley, 2002, and Wheeler, Secure Programming for Linux and Unix HOWTO ,available at http://www.dwheeler.com/secure-programs/.

● If at all possible, avoid creating temporary files in a shared directory, such as /tmp, or in directories ownedby the user. If anyone else has access to your temporary file, they can modify its content, change itsownership or mode, or replace it with a hard or symbolic link. It’s much safer to either not use a temporaryfile at all (use some other form of interprocess communication) or keep temporary files in a directory youcreate and to which only your process (acting as your user) has access.

● If your file must be in a shared directory, give it a unique (and randomly generated) filename (you can usethe C function mkstemp to do this), and never close and reopen the file. If you close such a file, an attackercan potentially find it and replace it before you reopen it.

Here are some public directories that you can use:

● ~/Library/Caches/TemporaryItems

When you use this subdirectory, you are writing to the user’s own home directory, not some otheruser’s directory or a system directory. If the user’s home directory has the default permissions, it canbe written to only by that user and root. Therefore, this directory is not as susceptible to attack fromoutside, nonprivileged users as some other directories might be.

Race Conditions and Secure File OperationsSecuring File Operations

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

54

● /var/run

This directory is used for process ID (pid) files and other system files needed just once per startupsession. This directory is cleared out each time the system starts up.

● /var/db

This directory is used for databases accessible to system processes.

● /tmp

This directory is used for general shared temporary storage. It is cleared out each time the systemstarts up.

● /var/tmp

This directory is used for general shared temporary storage. Although you should not count on datastored in this directory being permanent, unlike /tmp, the /var/tmp directory is currently not clearedout on reboot.

For maximum security, you should always create temporary subdirectories within these directories, setappropriate permissions on those subdirectories, and then write files into those subdirectories.

The following sections give some additional hints on how to follow these principles when you are usingPOSIX-layer C code, Carbon, and Cocoa calls.

Working with Publicly Writable Files Using POSIX CallsIf you need to open a preexisting file to modify it or read from it, you should check the file’s ownership, type,and permissions, and the number of links to the file before using it.

To safely opening a file for reading, for example, you can use the following procedure:

1. Call the open function and save the file descriptor. Pass the O_NOFOLLOW to ensure that it does not followsymbolic links.

2. Using the file descriptor, call the fstat function to obtain the stat structure for the file you just opened.

3. Check the user ID (UID) and group ID (GID) of the file to make sure they are correct.

4. Check the file's mode flags to make sure that it is a normal file, not a FIFO, device file, or other special file.Specifically, if the stat structure is named st, then the value of (st.st_mode & S_IFMT) should beequal to S_IFREG.

5. Check the read, write, and execute permissions for the file to make sure they are what you expect.

6. Check that there is only one hard link to the file.

7. Pass around the open file descriptor for later use rather than passing the path.

Race Conditions and Secure File OperationsSecuring File Operations

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

55

Note that you can avoid all the status checking by using a secure directory instead of a public one to hold yourprogram’s files.

Table 4-1 shows some functions to avoid—and the safer equivalent functions to use—in order to avoid raceconditions when you are creating files in a public directory.

Table 4-1 C file functions to avoid and to use

Functions to use insteadFunctions to avoid

open returns a file descriptor; creates a file and returnsan error if the file already exists when the O_CREATand O_EXCL options are used

fopen returns a file pointer; automaticallycreates the file if it does not exist but returnsno error if the file does exist

fchmod takes a file descriptorchmod takes a file path

fchown takes a file descriptor and does not followsymbolic links

chown takes a file path and follows symboliclinks

lstat takes a file path but does not follow symboliclinks;

fstat takes a file descriptor and returns informationabout an open file

stat takes a file path and follows symboliclinks

mkstemp creates a temporary file with a unique name,opens it for reading and writing, and returns a filedescriptor

mktemp creates a temporary file with a uniquename and returns a file path; you need toopen the file in another call

Working with Publicly Writable Files Using CarbonIf you are using the Carbon File Manager to create and open files, you should be aware of how the File Manageraccesses files.

● The file specifier FSSpec structure uses a path to locate files, not a file descriptor. Functions that use anFSSpec file specifier are deprecated and should not be used in any case.

● The file reference FSRef structure uses a path to locate files and should be used only if your files are in asafe directory, not in a publicly accessible directory. These functions include FSGetCatalogInfo,FSSetCatalogInfo, FSCreateFork, and others.

● The File Manager creates and opens files in separate operations. The create operation fails if the file alreadyexists. However, none of the file-creation functions return a file descriptor.

Race Conditions and Secure File OperationsSecuring File Operations

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

56

If you’ve obtained the file reference of a directory (from the FSFindFolder function, for example), you canuse the FSRefMakePath function to obtain the directory’s path name. However, be sure to check the functionresult, because if the FSFindFolder function fails, it returns a null string. If you don’t check the function result,you might end up trying to create a temporary file with a pathname formed by appending a filename to a nullstring.

Working with Publicly Writable Files Using CocoaThe NSString and NSData classes have writeToFile:atomically: methods designed to minimize therisk of data loss when writing to a file. These methods write first to a temporary file, and then, when they’resure the write is successful, they replace the written-to file with the temporary file. This is not always anappropriate thing to do when working in a public directory or a user’s home directory, because there are anumber of path-based file operations involved. Instead, initialize an NSFileHandle object with an existingfile descriptor and use NSFileHandle methods to write to the file, as mentioned above. The following code,for example, uses the mkstemp function to create a temporary file and obtain a file descriptor, which it thenuses to initialize NSFileHandle:

fd = mkstemp(tmpfile); // check return for -1, which indicates an error

NSFileHandle *myhandle = [[NSFileHandle alloc] initWithFileDescriptor:fd];

Working with Publicly Writable Files in Shell ScriptsScripts must follow the same general rules as other programs to avoid race conditions. There are a few tipsyou should know to help make your scripts more secure.

First, when writing a script, set the temporary directory ($TMPDIR) environment variable to a safe directory.Even if your script doesn’t directly create any temporary files, one or more of the routines you call might createone, which can be a security vulnerability if it’s created in an insecure directory. See the manual pages forsetenv and setenv for information on changing the temporary directory environment variable. For the samereason, set your process’ file code creation mask (umask) to restrict access to any files that might be createdby routines run by your script (see “Securing File Operations” (page 48) for more information on the umask).

It’s also a good idea to use the dtruss command on a shell script so you can watch every file access to makesure that no temporary files are created in an insecure location. See the manual pages for dtrace and dtrussfor more information.

Do not redirect output using the operators > or >> to a publicly writable location. These operators do notcheck to see whether the file already exists, and they follow symbolic links.

Race Conditions and Secure File OperationsSecuring File Operations

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

57

Instead, pass the -d flag to the mktemp command to create a subdirectory to which only you have access. It’simportant to check the result to make sure the command succeeded. if you do all your file operations in thisdirectory, you can be fairly confident that no one with less than root access can interfere with your script. Formore information, see the manual page for mktemp.

Do not use the test command (or its left bracket ([) equivalent) to check for the existence of a file or otherstatus information for the file before writing to it. Doing so always results in a race condition; that is, it is possiblefor an attacker to create, write to, alter, or replace the file before you start writing. See the manual page fortest for more information.

For a more in-depth look at security issues specific to shell scripts, read “Shell Script Security” in Shell ScriptingPrimer .

Other TipsHere are a few additional things to be aware of when working with files:

● Before you attempt a file operation, make sure it is safe to perform the operation on that file. For example,before attempting to read a file (but after opening it), you should make sure that it is not a FIFO or a devicespecial file.

● Just because you can write to a file, that doesn’t mean you should write to it. For example, the fact thata directory exists doesn’t mean you created it, and the fact that you can append to a file doesn’t meanyou own the file or no one else can write to it.

● OS X can perform file operations on files in several different file systems. Some operations can be doneonly on certain systems. For example, certain file systems honor setuid files when executed from themand some don’t. Be sure you know what file system you’re working with and what operations can becarried out on that system.

● Local pathnames can point to remote files. For example, the path /volumes/foo might actually besomeone’s FTP server rather than a locally-mounted volume. Just because you’re accessing something bya pathname, that does not guarantee that it’s local or that it should be accessed.

● A user can mount a file system anywhere they have write access and own the directory. In other words,almost anywhere a user can create a directory, they can mount a file system on top of it. Because this canbe done remotely, an attacker running as root on a remote system could mount a file system into yourhome directory. Files in that file system would appear to be files in your home directory owned by root.For example, /tmp/foo might be a local directory, or it might be the root mount point of a remotelymounted file system. Similarly, /tmp/foo/bar might be a local file, or it might have been created onanother machine and be owned by root over there. Therefore, you can’t trust files based only on ownership,and you can’t assume that setting the UID to 0 was done by someone you trust. To tell whether the file ismounted locally, use the fstat call to check the device ID. If the device ID is different from that of filesyou know to be local, then you’ve crossed a device boundary.

Race Conditions and Secure File OperationsSecuring File Operations

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

58

● Remember that users can read the contents of executable binaries just as easily as the contents of ordinaryfiles. For example, the user can run strings to quickly see a list of (ostensibly) human-readable stringsin your executable.

● When you fork a new process, the child process inherits all the file descriptors from the parent unless youset the close-on-exec flag. If you fork and execute a child process and drop the child process’ privilegesso its real and effective IDs are those of some other user (to avoid running that process with elevatedprivileges), then that user can use a debugger to attach the child process. They can then run arbitrary codefrom that running process. Because the child process inherited all the file descriptors from the parent, theuser now has access to every file opened by the parent process. See “Inheriting File Descriptors” (page62) for more information on this type of vulnerability.

Race Conditions and Secure File OperationsSecuring File Operations

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

59

By default, applications run as the currently logged in user. Different users have different rights when it comesto accessing files, changing systemwide settings, and so on, depending on whether they are admin users orordinary users. Some tasks require additional privileges above and beyond what even an admin user can doby default. An application or other process with such additional rights is said to be running with elevatedprivileges. Running code with root or administrative privileges can intensify the dangers posed by securityvulnerabilities. This chapter explains the risks, provides alternatives to privilege elevation, and describes howto elevating privileges safely when you can’t avoid it.

Note: Elevating privileges is not allowed in applications submitted to the Mac App Store (and is notpossible in iOS).

Circumstances Requiring Elevated PrivilegesRegardless of whether a user is logged in as an administrator, a program might have to obtain administrativeor root privileges in order to accomplish a task. Examples of tasks that require elevated privileges include:

● manipulating file permissions, ownership

● creating, reading, updating, or deleting system and user files

● opening privileged ports (those with port numbers less than 1024) for TCP and UDP connections

● opening raw sockets

● managing processes

● reading the contents of virtual memory

● changing system settings

● loading kernel extensions

If you have to perform a task that requires elevated privileges, you must be aware of the fact that running withelevated privileges means that if there are any security vulnerabilities in your program, an attacker can obtainelevated privileges as well, and would then be able to perform any of the operations listed above.

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

60

Elevating Privileges Safely

The Hostile Environment and the Principle of Least PrivilegeAny program can come under attack, and probably will. By default, every process runs with the privileges ofthe user or process that started it. As a result, if an attacker uses a buffer overflow or other security vulnerability(see “Types of Security Vulnerabilities” (page 11)) to execute code on someone else’s computer, they cangenerally run their code with whatever privileges the logged-in user has.

If a user has logged on with restricted privileges, your program should run with those restricted privileges.This effectively limits the amount of damage an attacker can do, even if he successfully hijacks your programinto running malicious code. Do not assume that the user is logged in with administrator privileges; you shouldbe prepared to run a helper application with elevated privileges if you need them to accomplish a task. However,keep in mind that, if you elevate your process’s privileges to run as root, an attacker can gain those elevatedprivileges and potentially take over control of the whole system.

If an attacker can gain administrator privileges, they can elevate to root privileges and gain access to any dataon the user’s computer. Therefore, it is good security practice to log in as an administrator only when performingthe rare tasks that require admin privileges. Because the default setting for OS X is to make the computer’sowner an administrator, you should encourage your users to create a separate non-admin login and to usethat for their everyday work. In addition, if possible, you should not require admin privileges to install yoursoftware.

The idea of limiting risk by limiting access goes back to the “need to know” policy followed by governmentsecurity agencies (no matter what your security clearance, you are not given access to information unless youhave a specific need to know that information). In software security, this policy is often called the principle ofleast privilege.

The principle of least privilege states:

“Every program and every user of the system should operate using the least set of privileges necessary tocomplete the job.”

—Saltzer, J.H. AND Schroeder, M.D., “The Protection of Information in Computer Systems,” Proceedingsof the IEEE , vol. 63, no. 9, Sept 1975.

In practical terms, the principle of least privilege means you should avoid running as root, or—if you absolutelymust run as root to perform some task—you should run a separate helper application to perform the privilegedtask (see “Writing a Privileged Helper” (page 70)). Also, to the extent possible your software (or portions thereof)should run in a sandbox that restricts its privileges even further, as described in “Designing Secure Helpersand Daemons” (page 82).

By running with the least privilege possible, you:

● Limit damage from accidents and errors, including maliciously introduced accidents and errors

Elevating Privileges SafelyThe Hostile Environment and the Principle of Least Privilege

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

61

● Reduce interactions of privileged components, and therefore reduce unintentional, unwanted, and improperuses of privilege (side effects)

Keep in mind that, even if your code is free of errors, vulnerabilities in any libraries your code links in can beused to attack your program. For example, no program with a graphical user interface should run with privilegesbecause the large number of libraries used in any GUI application makes it virtually impossible to guaranteethat the application has no security vulnerabilities.

There are a number of ways an attacker can take advantage of your program if you run as root. Some possibleapproaches are described in the following sections.

Launching a New ProcessBecause any new process runs with the privileges of the process that launched it, if an attacker can trick yourprocess into launching his code, the malicious code runs with the privileges of your process. Therefore, if yourprocess is running with root privileges and is vulnerable to attack, the attacker can gain control of the system.There are many ways an attacker can trick your code into launching malicious code, including buffer overflows,race conditions, and social engineering attacks (see “Types of Security Vulnerabilities” (page 11)).

Working with Command-Line ArgumentsBecause all command-line arguments, including the program name (argv[0]), are under the control of theuser, you should not trust argv[0] to point to your program. If you use the command line to re-execute yourown application or tool, for example, a malicious user might have substituted a different app for argv[0]. Ifyou then pass that to a function that uses the first argument as the name of the program to run, you are nowexecuting the attacker’s code with your privileges.

In addition, if you must run external tools, be sure to do so in a safe way. See “C-Language Command Executionand Shell Scripts” (page 91) for more information. However, where possible, software running as the root usershould avoid running external tools.

Inheriting File DescriptorsWhen you create a new process, the child process inherits its own copy of the parent process’s file descriptors(see the manual page for fork). Therefore, if you have a handle on a file, network socket, shared memory, orother resource that’s pointed to by a file descriptor and you fork off a child process, you must be careful toeither close the file descriptor or you must make sure that the child process cannot be tampered with. Otherwise,a malicious user can use the subprocess to tamper with the resources referenced by the file descriptors.

For example, if you open a password file and don’t close it before forking a process, the new subprocess hasaccess to the password file.

Elevating Privileges SafelyThe Hostile Environment and the Principle of Least Privilege

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

62

To set a file descriptor so that it closes automatically when you execute a new process (such as by using theexecve system call), use the fcntl system call to set the close-on-exec flag. You must set this flag individuallyfor each file descriptor; there’s no way to set it for all.

Abusing Environment VariablesMost libraries and utilities use environment variables. Sometimes environment variables can be attacked withbuffer overflows or by inserting inappropriate values. If your program links in any libraries or calls any utilities,your program is vulnerable to attacks through any such problematic environment variables. If your programis running as root, the attacker might be able to bring down or gain control of the whole system in this way.Examples of environment variables in utilities and libraries that have been attacked in the past include:

1. The dynamic loader: LD_LIBRARY_PATH, DYLD_LIBRARY_PATH are often misused, causing unwantedside effects.

2. libc: MallocLogFile

3. Core Foundation: CF_CHARSET_PATH

4. perl: PERLLIB, PERL5LIB, PERL5OPT

[2CVE-2005-2748 (corrected in Apple Security Update 2005-008) 3CVE-2005-0716 (corrected in Apple

Security Update 2005-003) 4CVE-2005-4158]

Environment variables are also inherited by child processes. If you fork off a child process, your parent processshould validate the values of all environment variables before it uses them in case they were altered by thechild process (whether inadvertently or through an attack by a malicious user).

Modifying Process LimitsYou can use the setrlimit system call to limit the consumption of system resources by a process. For example,you can set the largest size of file the process can create, the maximum amount of CPU time the process canconsume, and the maximum amount of physical memory a process may use. These process limits are inheritedby child processes.

If an attacker uses setrlimit to alter these limits, it can cause operations to fail when they ordinarily wouldnot have failed. For example, a vulnerability was reported for a version of Linux that made it possible for anattacker, by decreasing the maximum file size, to limit the size of the /etc/passwd and /etc/shadow files.Then, the next time a utility accessed one of these files, it truncated the file, resulting in a loss of data anddenial of service. [CVE-2002-0762]

Elevating Privileges SafelyThe Hostile Environment and the Principle of Least Privilege

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

63

Similarly, if a piece of software does not do proper error checking, a failure in one operation could change thebehavior of a later operation. For example, if lowering the file descriptor limit prevents a file from being openedfor writing, a later piece of code that reads the file and acts on it could end up working with a stale copy ofthe data.

File Operation InterferenceIf you’re running with elevated privileges in order to write or read files in a world-writable directory or a user’sdirectory, you must be aware of time-of-check–time-of-use problems; see “Time of Check Versus Time ofUse” (page 45).

Avoiding Elevated PrivilegesIn many cases, you can accomplish your task without needing elevated privileges. For example, suppose youneed to configure the environment (add a configuration file to the user’s home directory or modify aconfiguration file in the user’s home directory) for your application. You can do this from an installer runningas root (the installer command requires administrative privileges; see the installer manual page).However, if you have the application configure itself, or check whether configuration is needed when it startsup, then you don’t need to run as root at all.

An example of using an alternate design in order to avoid running with elevated privileges is given by the BSDps command, which displays information about processes that have controlling terminals. Originally, BSD usedthe setgid bit to run the ps command with a group ID of kmem, which gave it privileges to read kernel memory.More recent implementations of the ps command use the sysctl utility to read the information it needs,removing the requirement that ps run with any special privileges.

Running with Elevated PrivilegesIf you do need to run code with elevated privileges, there are several approaches you can take:

● You can run a daemon with elevated privileges that you call on when you need to perform a privilegedtask. The preferred method of launching a daemon is to use the launchd daemon (see “launchd” (page67)). It is easier to use launchd to launch a daemon and easier to communicate with a daemon than itis to fork your own privileged process.

● You can use the authopen command to read, create, or update a file (see “authopen” (page 67)).

● You can use a BSD system call to change privilege level (see “Calls to Change Privilege Level” (page 65)).These commands have confusing semantics. You must be careful to use them correctly, and it’s veryimportant to check the return values of these calls to make sure they succeeded.

Elevating Privileges SafelyAvoiding Elevated Privileges

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

64

Note that in general, unless your process was initially running as root, it cannot elevate its privilege withthese calls or take on the privileges of any other user. However, a process running as root can discard(temporarily or permanently) those privileges. Any process can change from acting on behalf of one groupto another (within the set of groups to which it belongs).

Note: Older software sometimes sets the setuid and setgid bits for the executable file, and setsthe owner and group of the file to the privilege level it needs (often with the root user and thewheel group). Then when the user runs that tool, it runs with the elevated privileges of the tool’sowner and group rather than with the privileges of the user who executed it. This technique isstrongly discouraged because the user has the ability to manipulate the execution environment bycreating additional file descriptors, changing environment variables, and so on, making it relativelydifficult to do in a safe way.

However you decide to run your privileged code, you should make it do as little as possible, and ensure thatthe code drops any additional privilege as soon as it has accomplished its task (see “Writing a PrivilegedHelper” (page 70)). Although architecturally this is often the best solution, it is very difficult to do correctly,especially the first time you try. Unless you have a lot of experience with forking off privileged processes, youmight want to try one of the other solutions first.

Calls to Change Privilege LevelThere are several commands you can use to change the privilege level of a program. The semantics of thesecommands are tricky, and vary depending on the operating system on which they’re used.

Important: If you are running with both a group ID (GID) and user ID (UID) that are different from thoseof the user, you have to drop the GID before dropping the UID. Once you’ve changed the UID, you may nolonger have sufficient privileges to change the GID.

Important: As with every security-related operation, you must check the return values of your calls tosetuid, setgid, and related routines to make sure they succeeded. Otherwise you might still be runningwith elevated privileges when you think you have dropped privileges.

Here are some notes on the most commonly used system calls for changing privilege level:

Elevating Privileges SafelyCalls to Change Privilege Level

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

65

● The setuid function sets the real and effective user IDs and the saved user ID of the current process toa specified value. The setuid function is the most confusing of the UID-setting system calls. Not onlydoes the permission required to use this call differ among different UNIX-based systems, but the actionof the call differs among different operating systems and even between privileged and unprivilegedprocesses. If you are trying to set the effective UID, you should use the seteuid function instead.

● The setreuid function modifies the real UID and effective UID, and in some cases, the saved UID. Thepermission required to use this call differs among different UNIX-based systems, and the rule by whichthe saved UID is modified is complicated. For this function as well, if your intent is to set the effective UID,you should use the seteuid function instead.

● The seteuid function sets the effective UID, leaving the real UID and saved UID unchanged. In OS X, theeffective user ID may be set to the value of the real user ID or of the saved set-user-ID. (In some UNIX-basedsystems, this function allows you to set the EUID to any of the real UID, saved UID, or EUID.) Of the functionsavailable on OS X that set the effective UID, the seteuid function is the least confusing and the leastlikely to be misused.

● The setgid function acts similarly to the setuid function, except that it sets group IDs rather than userIDs. It suffers from the same shortcomings as the setuid function; use the setegid function instead.

● The setregid function acts similarly to the setreuid function, with the same shortcomings; use thesetegid function instead.

● The setegid function sets the effective GID. This function is the preferred call to use if you want to setthe EGID.

For more information on permissions, see the “Understanding Permissions” chapter in Authentication,Authorization,andPermissionsGuide . For information onsetuidand related commands, seeSetuidDemystifiedby Chen, Wagner, and Dean (Proceedings of the 11th USENIX Security Symposium, 2002), available athttp://www.usenix.org/publications/library/proceedings/sec02/full_papers/chen/chen.pdf and the manualpages for setuid, setreuid, setregid, and setgroups. The setuid(2)manual page includes informationabout seteuid, setgid, and setegid as well.

Avoiding Forking Off a Privileged ProcessThere are a couple of functions you might be able to use to avoid forking off a privileged helper application.The authopen command lets you obtain temporary rights to create, read, or update a file. You can use thelaunchd daemon to start a process with specified privileges and a known environment.

Elevating Privileges SafelyAvoiding Forking Off a Privileged Process

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

66

authopenWhen you run the authopen command, you provide the pathname of the file that you want to access. Thereare options for reading the file, writing to the file, and creating a new file. Before carrying out any of theseoperations, the authopen command requests authorization from the system security daemon, whichauthenticates the user (through a password dialog or other means) and determines whether the user hassufficient rights to carry out the operation. See the manual page for authopen(1) for the syntax of thiscommand.

launchdStarting with OS X v10.4, the launchd daemon is used to launch daemons and other programs automatically,without user intervention. (If you need to support systems running versions of the OS earlier than OS X v10.4,you can use startup items.)

The launchd daemon can launch both systemwide daemons and per-user agents, and can restart thosedaemons and agents after they quit if they are still needed. You provide a configuration file that tells launchdthe level of privilege with which to launch your routine.

You can also use launchd to launch a privileged helper. By factoring your application into privileged andunprivileged processes, you can limit the amount of code running as the root user (and thus the potentialattack surface). Be sure that you do not request higher privilege than you actually need, and always dropprivilege or quit execution as soon as possible.

There are several reasons to use launchd in preference to writing a daemon running as the root user or afactored application that forks off a privileged process:

● Because launchd launches daemons on demand, your daemon needs not worry about whether otherservices are available yet. When it makes a request for one of those services, the service gets startedautomatically in a manner that is transparent to your daemon.

● Because launchd itself runs as the root user, if your only reason for using a privileged process is to run adaemon on a low-numbered port, you can let launchd open that port on your daemon’s behalf and passthe open socket to your daemon, thus eliminating the need for your code to run as the root user.

● Because launchd can launch a routine with elevated privileges, you do not have to set the setuid orsetgid bits for the helper tool. Any routine that has the setuid or setgid bit set is likely to be a targetfor attack by malicious users.

● A privileged routine started by launchd runs in a controlled environment that can’t be tampered with.If you launch a helper tool that has the setuid bit set, it inherits much of the launching application’senvironment, including:

● Open file descriptors (unless their close-on-exec flag is set).

Elevating Privileges SafelyAvoiding Forking Off a Privileged Process

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

67

● Environment variables (unless you use posix_spawn, posix_spawnp, or an exec variant that takesan explicit environment argument, such as execve).

● Resource limits.

● The command-line arguments passed to it by the calling process.

● Anonymous shared memory regions (unattached, but available to reattach, if desired).

● Mach port rights.

There are probably others. It is much safer to use launchd, which completely controls the launchenvironment.

● It’s much easier to understand and verify the security of a protocol between your controlling applicationand a privileged daemon than to handle the interprocess communication needed for a process you forkedyourself. When you fork a process, it inherits its environment from your application, including file descriptorsand environment variables, which might be used to attack the process (see “The Hostile Environment andthe Principle of Least Privilege” (page 61)). You can avoid these problems by using launchd to launch adaemon.

● It’s easier to write a daemon and launch it with launchd than to write factored code and fork off a separateprocess.

● Because launchd is a critical system component, it receives a lot of peer review by in-house developersat Apple. It is less likely to contain security vulnerabilities than most production code.

● The launchd.plist file includes key-value pairs that you can use to limit the system services—such asmemory, number of files, and cpu time—that the daemon can use.

For more information on launchd, see the manual pages for launchd, launchctl, and launchd.plist,and Daemons and Services Programming Guide . For more information about startup items, see Daemons andServices Programming Guide .

Limitations and Risks of Other MechanismsIn addition to launchd, the following lesser methods can be used to obtain elevated privileges. In each case,you must understand the limitations and risks posed by the method you choose.

● setuid

If an executable's setuid bit is set, the program runs as whatever user owns the executable regardlessof which process launches it. There are two approaches to using setuid to obtain root (or another user’s)privileges while minimizing risk:

● Launch your program with root privileges, perform whatever privileged operations are necessaryimmediately, and then permanently drop privileges.

Elevating Privileges SafelyLimitations and Risks of Other Mechanisms

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

68

● Launch a setuid helper tool that runs only as long as necessary and then quits.

If the operation you are performing needs a group privilege or user privilege other than root, you shouldlaunch your program or helper tool with that privilege only, not with root privilege, to minimize thedamage if the program is hijacked.

It’s important to note that if you are running with both a group ID (GID) and user ID (UID) that are differentfrom those of the user, you have to drop the GID before dropping the UID. Once you’ve changed the UID,you can no longer change the GID. As with every security-related operation, you must check the returnvalues of your calls to setuid, setgid, and related routines to make sure they succeeded.

For more information about the use of the setuid bit and related routines, see “Elevating PrivilegesSafely” (page 60).

● SystemStarter

When you put an executable in the /Library/StartupItems directory, it is started by theSystemStarter program at boot time. Because SystemStarter runs with root privileges, you can startyour program with any level of privilege you wish. Be sure to use the lowest privilege level that you canuse to accomplish your task, and to drop privilege as soon as possible.

Startup items run daemons with root privilege in a single global session; these processes serve all users.

For OS X v10.4 and later, the use of startup items is deprecated; use the launchd daemon instead. Formore information on startup items and startup item privileges, see “Startup Items” inDaemons and ServicesProgramming Guide .

● AuthorizationExecWithPrivilege

The Authorization Services API provides the AuthorizationExecuteWithPrivileges function, whichlaunches a privileged helper as the root user.

Although this function can execute any process temporarily with root privileges, it is not recommendedexcept for installers that have to be able to run from CDs and self-repairing setuid tools. See AuthorizationServices Programming Guide for more information.

● xinetd

In earlier versions of OS X, the xinetd daemon was launched with root privileges at system startup andsubsequently launched internet services daemons when they were needed. Thexinetd.conf configurationfile specified the UID and GID of each daemon started and the port to be used by each service.

Starting with OS X v10.4, you should use launchd to perform the services formerly provided by xinetd.SeeDaemonsandServicesProgrammingGuide for information about converting fromxinetd tolaunchd.See the manual pages for xinetd(8) and xinetd.conf(5) for more information about xinetd.

● Other

If you are using some other method to obtain elevated privilege for your process, you should switch toone of the methods described here and follow the cautions described in this chapter and in “ElevatingPrivileges Safely” (page 60).

Elevating Privileges SafelyLimitations and Risks of Other Mechanisms

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

69

Writing a Privileged HelperIf you’ve read this far and you’re still convinced that part of your application needs elevated privileges, thissection provides some tips and sample code. In addition, see Authorization Services Programming Guide formore advice on the use of Authorization Services and the proper way to factor an application.

As explained in the Authorization Services documentation, it is very important that you check the user’s rightsto perform the privileged operation, both before and after launching your privileged helper tool. Your helpertool, owned by root and with the setuid bit set, has sufficient privileges to perform whatever task it has todo. However, if the user doesn’t have the rights to perform this task, you shouldn’t launch the tool and—if thetool gets launched anyway—the tool should quit without performing the task. Your nonprivileged processshould first use Authorization Services to determine whether the user is authorized and to authenticate theuser if necessary (this is called preauthorizing ; see Listing 5-1 (page 71)). Then launch your privileged process.The privileged process then should authorize the user again, before performing the task that requires elevatedprivileges; see Listing 5-2 (page 72). As soon as the task is complete, the privileged process should terminate.

In determining whether a user has sufficient privileges to perform a task, you should use rights that you havedefined and put into the policy database yourself. If you use a right provided by the system or by some otherdeveloper, the user might be granted authorization for that right by some other process, thus gaining privilegesto your application or access to data that you did not authorize or intend. For more information about policiesand the policy database, (see the section “The Policy Database” in the “Authorization Concepts” chapter ofAuthorization Services Programming Guide ).

In the code samples shown here, the task that requires privilege is killing a process that the user does not own.

Example: PreauthorizingIf a user tries to kill a process that he doesn’t own, the application has to make sure the user is authorized todo so. The following numbered items correspond to comments in the code sample:

1. If the process is owned by the user, and the process is not the window server or the login window, goahead and kill it.

2. Call the permitWithRight:flags: method to determine whether the user has the right to kill theprocess. The application must have previously added this right—in this example, calledcom.apple.processkiller.kill—to the policy database. The permitWithRight:flags:methodhandles the interaction with the user (such as an authentication dialog). If this method returns 0, itcompleted without an error and the user is considered preauthorized.

3. Obtain the authorization reference.

4. Create an external form of the authorization reference.

5. Create a data object containing the external authorization reference.

Elevating Privileges SafelyWriting a Privileged Helper

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

70

6. Pass this serialized authorization reference to the setuid tool that will kill the process (Listing 5-2 (page72)).

Listing 5-1 Non-privileged process

if (ownerUID == _my_uid && ![[contextInfo processName]

isEqualToString:@"WindowServer"] && ![[contextInfo processName]

isEqualToString:@"loginwindow"]) {

// 1[self killPid:pid withSignal:signal];

} else {

SFAuthorization *auth = [SFAuthorization authorization];

if (![auth permitWithRight:"com.apple.proccesskiller.kill" flags:

kAuthorizationFlagDefaults|kAuthorizationFlagInteractionAllowed|

// 2kAuthorizationFlagExtendRights|kAuthorizationFlagPreAuthorize])

{

// 3AuthorizationRef authRef = [auth authorizationRef];

AuthorizationExternalForm authExtForm;

// 4OSStatus status = AuthorizationMakeExternalForm(authRef, &authExtForm);

if (errAuthorizationSuccess == status) {

NSData *authData = [NSData dataWithBytes: authExtForm.bytes

// 5length: kAuthorizationExternalFormLength];

// 6[_agent killProcess:pid signal:signal authData: authData];

}

}

}

The external tool is owned by root and has its setuid bit set so that it runs with root privileges. It imports theexternalized authorization rights and checks the user’s authorization rights again. If the user has the rights,the tool kills the process and quits. The following numbered items correspond to comments in the code sample:

1. Convert the external authorization reference to an authorization reference.

2. Create an authorization item array.

3. Create an authorization rights set.

Elevating Privileges SafelyWriting a Privileged Helper

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

71

4. Call the AuthorizationCopyRights function to determine whether the user has the right to kill theprocess. You pass this function the authorization reference. If the credentials issued by the Security Serverwhen it authenticated the user have not yet expired, this function can determine whether the user isauthorized to kill the process without reauthentication. If the credentials have expired, the Security Serverhandles the authentication (for example, by displaying a password dialog). (You specify the expirationperiod for the credentials when you add the authorization right to the policy database.)

5. If the user is authorized to do so, kill the process.

6. If the user is not authorized to kill the process, log the unsuccessful attempt.

7. Release the authorization reference.

Listing 5-2 Privileged process

AuthorizationRef authRef = NULL;

OSStatus status = AuthorizationCreateFromExternalForm(

// 1(AuthorizationExternalForm *)[authData bytes], &authRef);

if ((errAuthorizationSuccess == status) && (NULL != authRef)) {

AuthorizationItem right = {"com.apple.proccesskiller.kill",

// 20L, NULL, 0L};

// 3AuthorizationItemSet rights = {1, &right};

status = AuthorizationCopyRights(authRef, &rights, NULL,

kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed |

// 4kAuthorizationFlagExtendRights, NULL);

if (errAuthorizationSuccess == status)

// 5kill(pid, signal);

else

NSLog(@"Unauthorized attempt to signal process %d with %d",

// 6pid, signal);

// 7AuthorizationFree(authRef, kAuthorizationFlagDefaults);

}

Helper Tool CautionsIf you write a privileged helper tool, you need to be very careful to examine your assumptions. For example,you should always check the results of function calls; it is dangerous to assume they succeeded and to proceedon that assumption. You must be careful to avoid any of the pitfalls discussed in this document, such as bufferoverflows and race conditions.

Elevating Privileges SafelyWriting a Privileged Helper

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

72

If possible, avoid linking in any extra libraries. If you do have to link in a library, you must not only be sure thatthe library has no security vulnerabilities, but also that it doesn’t link in any other libraries. Any dependencieson other code potentially open your code to attack.

In order to make your helper tool as secure as possible, you should make it as short as possible—have it doonly the very minimum necessary and then quit. Keeping it short makes it less likely that you made mistakes,and makes it easier for others to audit your code. Be sure to get a security review from someone who did nothelp write the tool originally. An independent reviewer is less likely to share your assumptions and more likelyto spot vulnerabilities that you missed.

Authorization and Trust PoliciesIn addition to the basic permissions provided by BSD, the OS X Authorization Services API enables you to usethe policy database to determine whether an entity should have access to specific features or data within yourapplication. Authorization Services includes functions to read, add, edit, and delete policy database items.

You should define your own trust policies and put them in the policy database. If you use a policy providedby the system or by some other developer, the user might be granted authorization for a right by some otherprocess, thus gaining privileges to your application or access to data that you did not authorize or intend.Define a different policy for each operation to avoid having to give broad permissions to users who need onlynarrow privileges. For more information about policies and the policy database, see the section “The PolicyDatabase” in the “Authorization Concepts” chapter of Authorization Services Programming Guide .

Authorization Services does not enforce access controls; rather, it authenticates users and lets you know whetherthey have permission to carry out the action they wish to perform. It is up to your program to either deny theaction or carry it out.

Security in a KEXTBecause kernel extensions have no user interface, you cannot call Authorization Services to obtain permissionsthat you do not already have. However, in portions of your code that handle requests from user space, youcan determine what permissions the calling process has, and you can evaluate access control lists (ACLs; seethe section “ACLs” in the “OS X File System Security” in File System Programming Guide section in the “FileSystem Details” chapter of File System Programming Guide ).

In OS X v10.4 and later, you can also use the Kernel Authorization (Kauth) subsystem to manage authorization.For more information on Kauth, see Technical Note TN2127, Kernel Authorization (http://developer.ap-ple.com/technotes/tn2005/tn2127.html).

Elevating Privileges SafelyAuthorization and Trust Policies

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

73

The user is often the weak link in the security of a system. Many security breaches have been caused by weakpasswords, unencrypted files left on unprotected computers, and successful social engineering attacks. Therefore,it is vitally important that your program’s user interface enhance security by making it easy for the user tomake secure choices and avoid costly mistakes.

In a social engineering attack, the user is tricked into either divulging secret information or running maliciouscode. For example, the Melissa virus and the Love Letter worm each infected thousands of computers whenusers downloaded and opened files sent in email.

This chapter discusses how doing things that are contrary to user expectations can cause a security risk, andgives hints for creating a user interface that minimizes the risk from social engineering attacks. Secure humaninterface design is a complex topic affecting operating systems as well as individual programs. This chaptergives only a few hints and highlights.

For an extensive discussion of this topic, see Cranor and Garfinkel, Security and Usability: Designing SecureSystems that People Can Use , O’Reilly, 2005. There is also an interesting weblog on this subject maintained byresearchers at the University of California at Berkeley (http://usablesecurity.com/).

Use Secure DefaultsMost users use an application’s default settings and assume that they are secure. If they have to make specificchoices and take multiple actions in order to make a program secure, few will do so. Therefore, the defaultsettings for your program should be as secure as possible.

For example:

● If your program launches other programs, it should launch them with the minimum privileges they needto run.

● If your program supports optionally connecting by SSL, the checkbox should be checked by default.

● If your program displays a user interface that requires the user to decide whether to perform a potentiallydangerous action, the default option should be the safe choice. If there is no safe choice, there should beno default. (See “UI Element Guidelines: Controls” in OS X Human Interface Guidelines .)

And so on.

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

74

Designing Secure User Interfaces

There is a common belief that security and convenience are incompatible. With careful design, this does nothave to be so. In fact, it is very important that the user not have to sacrifice convenience for security, becausemany users will choose convenience in that situation. In many cases, a simpler interface is more secure, becausethe user is less likely to ignore security features and less likely to make mistakes.

Whenever possible, you should make security decisions for your users: in most cases, you know more aboutsecurity than they do, and if you can’t evaluate the evidence to determine which choice is most secure, thechances are your users will not be able to do so either.

For a detailed discussion of this issue and a case study, see the article “Firefox and the Worry-Free Web” inCranor and Garfinkel, Security and Usability: Designing Secure Systems that People Can Use .

Meet Users’ Expectations for SecurityIf your program handles data that the user expects to be kept secret, make sure that you protect that data atall times. That means not only keeping it in a secure location or encrypting it on the user’s computer, but nothanding it off to another program unless you can verify that the other program will protect the data, and nottransmitting it over an insecure network. If for some reason you cannot keep the data secure, you should makethis situation obvious to users and give them the option of canceling the insecure operation.

Important: The absence of an indication that an operation is secure is not a good way to inform the userthat the operation is insecure. A common example of this is any web browser that adds a lock icon (usuallysmall and inconspicuous) on web pages that are protected by SSL/TLS or some similar protocol. The userhas to notice that this icon is not present (or that it’s in the wrong place, in the case of a spoofed web page)in order to take action. Instead, the program should prominently display some indication for each webpage or operation that is not secure.

The user must be made aware of when they are granting authorization to some entity to act on their behalfor to gain access to their files or data. For example, a program might allow users to share files with other userson remote systems in order to allow collaboration. In this case, sharing should be off by default. If the userturns it on, the interface should make clear the extent to which remote users can read from and write to fileson the local system. If turning on sharing for one file also lets remote users read any other file in the samefolder, for example, the interface must make this clear before sharing is turned on. In addition, as long assharing is on, there should be some clear indication that it is on, lest users forget that their files are accessibleby others.

Designing Secure User InterfacesMeet Users’ Expectations for Security

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

75

Authorization should be revocable: if a user grants authorization to someone, the user generally expects to beable to revoke that authorization later. Whenever possible, your program should not only make this possible,it should make it easy to do. If for some reason it will not be possible to revoke the authorization, you shouldmake that clear before granting the authorization. You should also make it clear that revoking authorizationcannot reverse damage already done (unless your program provides a restore capability).

Similarly, any other operation that affects security but that cannot be undone should either not be allowed orthe user should be made aware of the situation before they act. For example, if all files are backed up in acentral database and can’t be deleted by the user, the user should be aware of that fact before they recordinformation that they might want to delete later.

As the user’s agent, you must carefully avoid performing operations that the user does not expect or intend.For example, avoid automatically running code if it performs functions that the user has not explicitly authorized.

Secure All InterfacesSome programs have multiple user interfaces, such as a graphical user interface, a command-line interface,and an interface for remote access. If any of these interfaces require authentication (such as with a password),then all the interfaces should require it. Furthermore, if you require authentication through a command lineor remote interface, be sure the authentication mechanism is secure—don’t transmit passwords in cleartext,for example.

Place Files in Secure LocationsUnless you are encrypting all output, the location where you save files has important security implications. Forexample:

● FileVault can secure the root volume (or the user’s home folder prior to OS X v10.7), but not other locationswhere the user might choose to place files.

● Folder permissions can be set in such a way that others can manipulate their contents.

You should restrict the locations where users can save files if they contain information that must be protected.If you allow the user to select the location to save files, you should make the security implications of a particularchoice clear; specifically, they must understand that, depending on the location of a file, it might be accessibleto other applications or even remote users.

Designing Secure User InterfacesSecure All Interfaces

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

76

Make Security Choices ClearMost programs, upon detecting a problem or discrepancy, display a dialog box informing the user of theproblem. Often this approach does not work, however. For one thing, the user might not understand thewarning or its implications. For example, if the dialog warns the user that the site to which they are connectinghas a certificate whose name does not match the name of the site, the user is unlikely to know what to do withthat information, and is likely to ignore it. Furthermore, if the program puts up more than a few dialog boxes,the user is likely to ignore all of them.

To solve this problem, when giving the user a choice that has security implications, make the potentialconsequences of each choice clear. The user should never be surprised by the results of an action. The choicegiven to the user should be expressed in terms of consequences and trade-offs, not technical details.

For example, a choice of encryption methods should be based on the level of security (expressed in simpleterms, such as the amount of time it might take to break the encryption) versus the time and disk space requiredto encrypt the data, rather than on the type of algorithm and the length of the key to be used. If there are nopractical differences of importance to the user (as when the more secure encryption method is just as efficientas the less-secure method), just use the most secure method and don’t give the user the choice at all.

Be sensitive to the fact that few users are security experts. Give as much information—in clear, nontechnicalterms—as necessary for them to make an informed decision. In some cases, it might be best not to give themthe option of changing the default behavior.

For example, most users don’t know what a digital certificate is, let alone the implications of accepting acertificate signed by an unknown authority. Therefore, it is probably not a good idea to let the user permanentlyadd an anchor certificate (a certificate that is trusted for signing other certificates) unless you can be confidentthat the user can evaluate the validity of the certificate. (Further, if the user is a security expert, they’ll knowhow to add an anchor certificate to the keychain without the help of your application anyway.)

If you are providing security features, you should make their presence clear to the user. For example, if yourmail application requires the user to double click a small icon in order to see the certificate used to sign amessage, most users will never realize that the feature is available.

In an often-quoted but rarely applied monograph, Jerome Saltzer and Michael Schroeder wrote “It is essentialthat the human interface be designed for ease of use, so that users routinely and automatically apply theprotection mechanisms correctly. Also, to the extent that the user’s mental image of his protection goalsmatches the mechanisms he must use, mistakes will be minimized. If he must translate his image of his protectionneeds into a radically different specification language, he will make errors.” (Saltzer and Schroeder, “TheProtection of Information in Computer Systems,” Proceedings of the IEEE 63:9, 1975.)

For example, you can assume the user understands that the data must be protected from unauthorized access;however, you cannot assume the user has any knowledge of encryption schemes or knows how to evaluatepassword strength. In this case, your program should present the user with choices like the following:

Designing Secure User InterfacesMake Security Choices Clear

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

77

● “Is your computer physically secure, or is it possible that an unauthorized user will have physical accessto the computer?”

● “Is your computer connected to a network?”

From the user’s answers, you can determine how best to protect the data. Unless you are providing an “expert”mode, do not ask the user questions like the following:

● “Do you want to encrypt your data, and if so, with which encryption scheme?”

● “How long a key should be used?”

● “Do you want to permit SSH access to your computer?”

These questions don’t correspond with the user’s view of the problem. Therefore, the user’s answers to suchquestions are likely to be erroneous. In this regard, it is very important to understand the user’s perspective.Very rarely is an interface that seems simple or intuitive to a programmer actually simple or intuitive to averageusers.

To quote Ka-Ping Yee (User Interaction Design for Secure Systems , at http://www.eecs.berke-ley.edu/Pubs/TechRpts/2002/CSD-02-1184.pdf):

In order to have a chance of using a system safely in a world of unreliable and sometimes adversarialsoftware, a user needs to have confidence in all of the following statements:

● Things don’t become unsafe all by themselves. (Explicit Authorization)

● I can know whether things are safe. (Visibility)

● I can make things safer. (Revocability)

● I don’t choose to make things unsafe. (Path of Least Resistance)

● I know what I can do within the system. (Expected Ability)

● I can distinguish the things that matter to me. (Appropriate Boundaries)

● I can tell the system what I want. (Expressiveness)

● I know what I’m telling the system to do. (Clarity)

● The system protects me from being fooled. (Identifiability, Trusted Path)

For additional tips, read “Dialogs” in OS X Human Interface Guidelines and “Alerts, Action Sheets, and ModalViews” in iOS Human Interface Guidelines .

Designing Secure User InterfacesMake Security Choices Clear

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

78

Fight Social Engineering AttacksSocial engineering attacks are particularly difficult to fight. In a social engineering attack, the attacker foolsthe user into executing attack code or giving up private information.

A common form of social engineering attack is referred to as phishing . Phishing refers to the creation of anofficial-looking email or web page that fools the user into thinking they are dealing with an entity with whichthey are familiar, such as a bank with which they have an account. Typically, the user receives an email informingthem that there is something wrong with their account, and instructing them to click on a link in the email.The link takes them to a web page that spoofs a real one; that is, it includes icons, wording, and graphicalelements that echo those the user is used to seeing on a legitimate web page. The user is instructed to entersuch information as their social security number and password. Having done so, the user has given up enoughinformation to allow the attacker to access the user’s account.

Fighting phishing and other social engineering attacks is difficult because the computer’s perception of anemail or web page is fundamentally different from that of the user. For example, consider an email containinga link to http://scamsite.example.com/ but in which the link’s text says Apple Web Store. From thecomputer’s perspective, the URL links to a scam site, but from the user’s perspective, it links to Apple’s onlinestore. The user cannot easily tell that the link does not lead to the location they expect until they see the URLin their browser; the computer similarly cannot determine that the link’s text is misleading.

To further complicate matters, even when the user looks at the actual URL, the computer and user may perceivethe URL differently. The Unicode character set includes many characters that look similar or identical to commonEnglish letters. For example, the Russian glyph that is pronounced like “r” looks exactly like an English “p” inmany fonts, though it has a different Unicode value. These characters are referred to as homographs. Whenweb browsers began to support internationalized domain names (IDN), some phishers set up websites thatlooked identical to legitimate ones, using homographs in their web addresses to fool users into thinking theURL was correct.

Some creative techniques have been tried for fighting social engineering attacks, including trying to recognizeURLs that are similar to, but not the same as, well-known URLs, using private email channels for communicationswith customers, using email signing, and allowing users to see messages only if they come from known, trustedsources. All of these techniques have problems, and the sophistication of social engineering attacks is increasingall the time.

For example, to foil the domain name homograph attack, many browsers display internationalized domainnames (IDN) in an ASCII format called “Punycode.” For example, an impostor website with the URLhttp://www.apple.com/ that uses a Roman script for all the characters except for the letter “a”, for whichit uses a Cyrillic character, is displayed as http://www.xn--pple-43d.com.

Different browsers use different schemes when deciding which internationalized domain names to show andwhich ones to translate. For example, Safari uses this form when a URL contains characters in two or morescripts that are not allowed in the same URL, such as Cyrillic characters and traditional ASCII characters. Other

Designing Secure User InterfacesFight Social Engineering Attacks

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

79

browsers consider whether the character set is appropriate for the user’s default language. Still others maintaina whitelist of registries that actively prevent such spoofing and use punycode for domains from all otherregistries.

For a more in-depth analysis of the problem, more suggested approaches to fighting it, and some case studies,see Security and Usability: Designing Secure Systems that People Can Use by Cranor and Garfinkel.

To learn more about social engineering techniques in general, read The Art of Deception: Controlling the HumanElement of Security by Mitnick, Simon, and Wozniak.

Use Security APIs When PossibleOne way to avoid adding security vulnerabilities to your code is to use the available security APIs wheneverpossible. The Security Interface Framework API provides a number of user interface views to support commonlyperformed security tasks.

iOS Note: The Security Interface Framework is not available in iOS. In iOS, applications are restrictedin their use of the keychain, and it is not necessary for the user to create a new keychain or changekeychain settings.

The Security Interface Framework API provides the following views:

● The SFAuthorizationView class implements an authorization view in a window. An authorization viewis a lock icon and accompanying text that indicates whether an operation can be performed. When theuser clicks a closed lock icon, an authorization dialog displays. Once the user is authorized, the lock iconappears open. When the user clicks the open lock, Authorization Services restricts access again and changesthe icon to the closed state.

● The SFCertificateView and SFCertificatePanel classes display the contents of a certificate.

● The SFCertificateTrustPanel class displays and optionally lets the user edit the trust settings in acertificate.

● The SFChooseIdentityPanel class displays a list of identities in the system and lets the user select one.(In this context, identity refers to the combination of a private key and its associated certificate.)

● The SFKeychainSavePanel class adds an interface to an application that lets the user save a newkeychain. The user interface is nearly identical to that used for saving a file. The difference is that this classreturns a keychain in addition to a filename and lets the user specify a password for the keychain.

● The SFKeychainSettingsPanel class displays an interface that lets the user change keychain settings.

Designing Secure User InterfacesUse Security APIs When Possible

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

80

Documentation for the Security Interface framework is in Security Interface Framework Reference .

Designing Secure User InterfacesUse Security APIs When Possible

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

81

Privilege separation is a common technique for making applications more secure. By breaking up an applicationinto functional units that each require fewer privileges, you can make it harder to do anything useful with anysingle part of that application if someone successfully compromises it.

However, without proper design, a privilege-separated app is not significantly more secure than anon-privilege-separated app. For proper security, each part of the app must treat other parts of the app asuntrusted and potentially hostile. To that end, this chapter provides dos and don’ts for designing a helper app.

There are two different ways that you can perform privilege separation:

● Creating a pure computation helper to isolate risky operations. This technique requires the main applicationto be inherently suspicious of any data that the helper returns, but does not require that the helper besuspicious of the application.

● Creating a helper or daemon to perform tasks without granting the application the right to perform them.This requires not only that the main application not trust the helper, but also that the helper not trust themain application.

The techniques used for securing the two types of helpers differ only in the level of paranoia required by thehelper.

Use App SandboxAt the core of privilege separation is the need to actually give the various components different levels ofprivilege. The recommended way to do this is through the use of App Sandbox. This technology allows youto restrict what your main app and its helper apps can do.

By default, when you enable App Sandbox on an app, that app has a basic level of system access that includesthe ability to write files in a special per-app container directory, perform computation, and access certain basicsystem services. From that baseline, you add additional privileges by adding entitlements, such as the abilityto read and write files chosen by the user through an open or save dialog, the ability to make outgoing networkrequests, the ability to listen for incoming network requests, and so on.

The process of sandboxing an app or its helpers is beyond the scope of this book. To learn more about choosingentitlements for your app and its helpers, read App Sandbox Design Guide .

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

82

Designing Secure Helpers and Daemons

Avoid PuppeteeringWhen a helper application is so tightly controlled by the main application that it does not make any decisionsby itself, this is called puppeteering. This is inherently bad design because if the application gets compromised,the attacker can then control the helper similarly, in effect taking over pulling the helper’s “strings”. Thiscompletely destroys the privilege separation boundary. Therefore, unless you are creating a pure computationhelper, splitting code into a helper application that simply does whatever the main app tells it to do is usuallynot a useful division of labor.

In general, a helper must be responsible for deciding whether or not to perform a particular action. If you lookat the actions that an application can perform with and without privilege separation, those lists should bedifferent; if they are not, then you are not gaining anything by separating the functionality out into a separatehelper.

For example, consider a helper that downloads help content for a word processor. If the helper fetches anyarbitrary URL that the word processor sends it, the helper can be trivially exploited to send arbitrary data toan arbitrary server. For example, an attacker who took control of the browser could tell the helper to accessthe URL http://badguy.example.com/saveData?hereIsAnEncodedCopyOfTheUser%27sData.

The subsections that follow describe solutions for this problem.

Use WhitelistsOne way to fix this is with whitelists. The helper should include a specific list of resources that it can access.For example, this helper could include:

● A host whitelist that includes only the domain example.org. Requests to URLs in that domain wouldsucceed, but the attacker could not cause the helper to access URLs in a different domain.

● An allowed path prefix whitelist. The attacker would not be able to use cross-site scripting on theexample.org bulletin board to redirect the request to another location. (This applies mainly to appsusing a web UI.)

You can also avoid this by handling redirection manually.

● An allowed file type whitelist. This could limit the helper to the expected types of files. (Note that file typewhitelists are more interesting for helpers that access files on the local hard drive.)

● A whitelist of specific URIs to which GET or POST operations are allowed.

Use Abstract Identifiers and StructuresA second way to avoid puppeteering is by abstracting away the details of the request itself, using data structuresand abstract identifiers instead of providing URIs, queries, and paths.

Designing Secure Helpers and DaemonsAvoid Puppeteering

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

83

A trivial example of this is a help system. Instead of the app passing a fully-formed URI for a help search request,it might pass a flag field whose value tells the helper to “search by name” or “search by title” and a string valuecontaining the search string. This flag field is an example of an abstract identifier; it tells the helper what to dowithout telling it how to do it.

Taken one step further, when the helper returns a list of search results, instead of returning the names andURIs for the result pages, it could return the names and an opaque identifier (which may be an index into thelast set of search results). By doing so, the application cannot access arbitrary URIs because it never interactswith the actual URIs directly.

Similarly, if you have an application that works with project files that reference other files, in the absence ofAPI to directly support this, you can use a temporary exception to give a helper access to all files on the disk.To make this more secure, the helper should provide access only to files that actually appear in the user-openedproject. The helper might do this by requiring the application to request files by some arbitrary identifiergenerated by the helper rather than by name or path. This makes it harder for the application to ask the helperto open arbitrary files. This can further be augmented with sniffing, as described in “Use the Smell Test” (page84).

The same concept can be extended to other areas. For example, if the application needs to change a recordin a database, the helper could send the record as a data structure, and the app could send back the altereddata structure along with an indication of which values need to change. The helper could then verify thecorrectness of the unaltered data before modifying the remaining data.

Passing the data abstractly also allows the helper to limit the application’s access to other database tables. Italso allows the helper to limit what kinds of queries the application can perform in ways that are morefine-grained than would be possible with the permissions system that most databases provide.

Use the Smell TestIf a helper application has access to files that the main application cannot access directly, and if the mainapplication asks the helper to retrieve the contents of that file, it is useful for the helper to perform tests onthe file before sending the data to ensure that the main application has not substituted a symbolic link to adifferent file. In particular, it is useful to compare the file extension with the actual contents of the file to seewhether the bytes on disk make sense for the apparent file type. This technique is called file type sniffing.

For example, the first few bytes of any image file usually provide enough information to determine the filetype. If the first four bytes are JFIF, the file is probably a JPEG image file. If the first four bytes are GIF8, thefile is probably a GIF image file. If the first four bytes are MM.* or II*., the file is probably a TIFF file. And soon.

If the request passes this smell test, then the odds are good that the content is of the expeced type.

Designing Secure Helpers and DaemonsAvoid Puppeteering

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

84

Treat Both App and Helper as HostileBecause the entire purpose of privilege separation is to prevent an attacker from being able to do anythinguseful after compromising one part of an application, both the helper and the app must assume that the otherparty is potentially hostile. This means each piece must:

● Avoid buffer overflows (“Avoiding Buffer Overflows and Underflows” (page 17)).

● Validate all input from the other side (“Validating Input and Interprocess Communication” (page 34)).

● Avoid insecure interprocess communication mechanisms (“Validating Input and InterprocessCommunication” (page 34))

● Avoid race conditions (“Avoiding Race Conditions” (page 44)).

● Treat the contents of any directory or file to which the other process has write access as fundamentallyuntrusted (“Securing File Operations” (page 48)). This list potentially includes:

● The entire app container directory.

● Preference files.

● Temporary files.

● User files.

And so on. If you follow these design principles, you will make it harder for an attacker to do anythinguseful if he or she compromises your app.

Run Daemons as Unique UsersFor daemons that start with elevated privileges and then drop privileges, you should always use a locally uniqueuser ID for your program. If you use some standard UID such as _unknown or nobody, then any other processrunning with that same UID can interact with your program, either directly through interprocess communication,or indirectly by altering configuration files. Thus, if someone hijacks another daemon on the same server, theycan then interfere with your daemon; or, conversely, if someone hijacks your daemon, they can use it to interferewith other daemons on the server.

You can use Open Directory services to obtain a locally unique UID. Note that UIDs from 0 through 500 arereserved for use by the system.

Designing Secure Helpers and DaemonsTreat Both App and Helper as Hostile

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

85

Note: You should generally avoid making security decisions based on the user’s ID or name for tworeasons:

● Many APIs for determining the user ID and user name are inherently untrustworthy becausethey return the value of the USER.

● Someone could trivially make a copy of your app and change the string to a different value,then run the app.

Start Other Processes SafelyWhen it comes to security, not all APIs for running external tools are created equal. In particular:

Avoid the POSIX system function. Its simplicity makes it a tempting choice, but also makes it much moredangerous than other functions. When you use system, you become responsible for completely sanitizingthe entire command, which means protecting any characters that are treated as special by the shell. You areresponsible for understanding and correctly using the shell’s quoting rules, knowing which characters areinterpreted within each type of quotation marks, and so on. This is no small feat even for expert shell scriptprogrammers, and is strongly inadvisable for everyone else. Bluntly put, you will get it wrong.

Set up your own environment correctly ahead of time. Many APIs search for the tool you want to run inlocations specified by the PATH environment variable. If an attacker can modify that variable, the attacker canpotentially trick your app into starting a different tool and running it as the current user.

You can avoid this problem by either explicitly setting the PATH environment variable yourself or by avoidingvariants of exec or posix_spawn that use the PATH environment variable to search for executables.

Use absolute paths where possible, or relative paths if absolute paths are not available. By explicitlyspecifying a path to an executable rather than just its name, the PATH environment variable is not consultedwhen the OS determines which tool to run.

For more information about environment variables and shell special characters, read Shell Scripting Primer .

Designing Secure Helpers and DaemonsStart Other Processes Safely

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

86

Injection attacks and cross-site scripting (XSS) are two types of vulnerabilities often associated with webdevelopment. However, similar problems can occur in any type of application. By becoming familiar with thesetypes of attacks and understanding the antipatterns that they represent, you can avoid them in your software.

Avoiding Injection AttacksThere are two types of data in the world: unstructured data and structured data. The type you choose can havea significant impact on what you must do to make your software secure.

Unstructured data is rare. It mainly includes plain text files when they are used solely as a means of displayingtext. More often than not, what appears to be unstructured data is actually weakly structured data.

With structured data, different parts of the data have different meaning. Whenever a single piece of datacontains two or more different types of data in this way, the potential for injection attacks exists. The potentialrisks vary depending on how you mix the data—specifically, whether it is strictly structured orweakly structured .

Strictly structured data has a fixed format that defines where each piece of information should be stored. Asimple data format for a store’s inventory might, for example, specify that there should be 4 bytes containinga record number followed by 100 bytes of human-readable description. Strictly structured data is fairlystraightforward to work with. Although the interpretation of each byte depends on its location within the data,as long as you avoid overflowing any fixed-size buffers and do appropriate checks to ensure the values makesense, the security risks are usually relatively low.

Weakly structured data, however, is somewhat more problematic from a security perspective. Weakly structureddata is a hybrid scheme in which portions of the data have variable length. Weakly structured data can befurther divided into one of two categories: explicitly sized data and implicitly sized data.

Explicitly sized data provides a length value at the start of any variable-length data. For the most part, suchdata is straightforward to interpret, but care must be taken to ensure that the length values are reasonable.They should not, for example, extend past the end of the file.

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

87

Avoiding Injection Attacks and XSS

Implicitly sized data is more difficult to interpret. It uses special delimiter characters within the data itself todescribe how the data should be interpreted. For example, it might use commas to separate fields, or quotationmarks to separate data from the commands that operate on that data. For example, SQL and shell commandmix the command words themselves with the data that the command operates on. HTML files mix tags withtext. And so on.

Because unstructured, strictly structured, and weakly structured data with explicit lengths are less likely topose security risks, the remainder of this section focuses on weakly structured data with implicit lengths.

The Dangers of Mixed DataAs mentioned previously, whenever you mix two types of data—control statements and actual data separatedby delimiters, for example—you run the risk of misbehavior. These risks must be considered both when readingdata and when constructing data for later use.

The easiest way to demonstrate the problem is by example. Consider the following snippet of JSON data:

{

"mydictionary" :

{

"foo" : "Computer jargon",

"bar" : "More computer jargon"

}

}

This structure describes a nested set of key-value pairs. The keys—mydictionary, foo, and bar—are ofvariable length, as are their values (a dictionary, plus the strings Computer jargon and More computerjargon. Their length is determined by a parser—a piece of software that reads and analyzes a complex pieceof data, splitting it into its constituent parts. When parsing JSON data, the parser looks for a double quotationmark that marks the beginning and end of each string.

Now suppose that your software is an online dictionary that allows users to add words, checking them to makesure they are not impolite words before adding them. What happens if the user maliciously enters somethinglike the following?

Term: baz

Definition: Still more computer jargon", "naughtyword": "A word you should not say

Avoiding Injection Attacks and XSSAvoiding Injection Attacks

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

88

A naive piece of software might insert the definition into the JSON file by wrapping both the term and definition(as is) in quotation marks. The resulting JSON file would look like this:

{

"mydictionary" :

{

"foo" : "Computer jargon",

"bar" : "More computer jargon",

"baz" : "Still more computer jargon", "naughtyword": "A word you shouldnot say"

}

}

Because whitespace is not significant in JSON, the result is that two terms have now been added to thedictionary, and the second term was never checked for politeness by your software.

Instead, the software should have performed quoting on the data—scanning the input for characters thathave special meaning in the context of the enclosing content and modifying or otherwise marking them sothat they are not interpreted as special characters. For example, you can protect quotation marks in JSON bypreceding them with a backslash (\), as shown here:

{

"mydictionary" :

{

"foo" : "Computer jargon",

"bar" : "More computer jargon",

"baz" : "Still more computer jargon\", \"naughtyword\": \"A word you shouldnot say"

}

}

Now, when the parser reads the JSON, it correctly reads the definition of baz as Still more computerjargon.", "naughtyword": "A word you should not say. Thus, the naughty word is not defined,because it is just part of the definition of baz. Of course, this still leaves the question of whether you shouldhave checked for inappropriate words in the definitions, but that’s a separate question.

Avoiding Injection Attacks and XSSAvoiding Injection Attacks

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

89

SQL InjectionThe most common type of injection attack is SQL injection, a technique that takes advantage of the syntax ofSQL to inject arbitrary commands. A SQL statement looks something like this:

INSERT INTO users (name, description) VALUES ("John Doe", "A really hoopy frood.");

This example contains a mixture of instructions (the INSERT statement itself ) and data (the strings to beinserted).

Naive software might construct a query manually by simple string concatenation. Such an approach is verydangerous, particularly if the data comes from an untrusted source, because if the user name or descriptioncontains a double quotation mark, that untrusted source can then provide command data instead of valuedata.

To compound the problem, the SQL language provides a comment operator, --, which causes the SQL serverto ignore the rest of the line. For example, if a user enters the following text as his or her user name:

joe", "somebody"); DROP TABLE users; --

the resulting command would looks like this:

INSERT INTO users (name, description) VALUES ("joe", "somebody"); DROP TABLE users;--", "A really hoopy frood.");

and the database would insert the user, but would then dutifully delete all user accounts and the table thatholds them, rendering the service nonfunctional.

A slightly less naive program might check for double quotation marks and refuse to allow you to use them inyour user name or description. As a rule, this is undesirable for several reasons:

● This approach may not be compatible with UTF-8. UTF-8 characters frequently contain the same numericvalues as quotation marks, which means that (for example) a capital G with a cedilla might be incorrectlystored in your database, depending on how your SQL server handles UTF-8 (or doesn’t).

● If you change your query slightly to use single quotes, your solution breaks.

● If the user puts a backslash before the quotation mark, your solution breaks (unless you also quote those)because the two backslashes are then treated as a literal character.

● If you check for illegal characters in JavaScript but do not perform similar checks on the server side, amalicious user can get around the checks and inject code anyway.

Avoiding Injection Attacks and XSSAvoiding Injection Attacks

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

90

● If you check for illegal characters in JavaScript, because the user cannot easily see whether you have similarchecks on the server side, your users will worry about your site’s security.

● One of your users might really want his or her user name to be "; DROP TABLE users; -- or perhapssomething slightly less extreme.

Instead, the correct solution is to either use your SQL client library’s built-in functions for quoting strings or,where possible, to use parameterized SQL queries in which you substitute placeholders for the strings themselves.For example, a parameterized SQL query might look like this:

INSERT INTO users (name, description) VALUES (?, ?);

You would then provide the name and description values out-of-band in an array. Depending on how yourparticular database implementation handles these sorts of queries, the statement might still get convertedback into the same mixed-data query, but given the number of people who use most major databases, mistakesin any conversion routines provided by the database itself are likely to be caught and fixed quickly.

For more information about avoiding SQL injection attacks on applications that use Core Data in complexways, read “Creating Predicates” in Predicate Programming Guide .

C-Language Command Execution and Shell ScriptsIn the C programming language, there are a number of acceptable ways to execute an external command,using exec, posix_spawn, NSTask, and related functions and classes. There are also many wrong ways touse these and other functions. This section provides some tips on how to avoid security holes when runningexternal commands.

● Don’t use system. The system function runs an external shell process and passes a command stringdirectly to that shell. This means that you must properly quote any arguments that you pass to thecommands. The system function is particularly problematic if those arguments come from potentiallyuntrusted sources. For this reason, you should avoid using the system function except with hard-codedcommands.

● Don’t use popen. The popen has the same security risks as system. Instead of using popen, either usethe NSTask class or construct the pipe and execute the command yourself.

The NSTask class makes it easy to communicate with the standard input, output, and error descriptors ofa child process. You can learn more by reading NSTask Class Reference .

At the POSIX level you can achieve the same thing with the pipe system call, as follows:

1. Use the pipe system call to create one or more pairs of connected pipes.

2. Use the fork system call to create a child process.

Avoiding Injection Attacks and XSSAvoiding Injection Attacks

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

91

3. In the child process, use the dup2 system call to replace one or more of the standard input, standardoutput, and standard error file descriptors with the pipe endpoint of your choice.

4. In the child process, use exec, posix_spawn, or related functions to start the desired tool.

5. In the parent process, read from or write to the opposite end of each pipe.

For example:

int pipes[2];

if (pipe(pipes) < -1) {

... // Handle the error

}

int pid = fork();

if (pid == -1) {

... // Handle the error

} else if (!pid) {

// In the child process:

dup2(pipe[1], STDOUT_FILENO); // or STDIN_FILENO or STDERR_FILENO

close(pipe[0]);

exec(...) or posix_spawn(...) // Run the external tool.

} else {

// In the parent process:

close(pipe[1]);

read(pipe[0], ...);

waitpid(pid, ...); // Wait for the child process to go away.

}

For details, see the manual pages for pipe, fork, dup2, exec, posix_spawn, and waitpid.

● Avoid shell scripts where possible. Whether you are using NSTask or any of the functions above, avoidusing shell scripts to execute commands, because shell quoting is easy to get wrong. Instead, execute thecommands individually.

Avoiding Injection Attacks and XSSAvoiding Injection Attacks

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

92

● Audit any shell scripts. If your software runs shell scripts and passes potentially untrusted data to them,your software could be affected by any quoting bugs in those scripts. You should carefully audit thesescripts for quoting errors that might lead to security holes.

For more information, read “Quoting Special Characters” in Shell Scripting Primer and “Shell Script Security”in Shell Scripting Primer .

Quoting for URLsThe rules for quoting a URL are complex and are beyond the scope of this document. OS X and iOS provideroutines to help you, but you must be certain to use the correct routine for what you are trying to do.

To learn more, read “Converting Strings to URL Encoding” in Networking Overview .

Quoting for HTML and XMLThe safest way to work with HTML and XML is to use a library that provides objects for each node, such as theNSXMLParser class or the libxml2 API. However, if you must construct HTML or XML manually, there arefive special characters that must be quoted explicitly when converting text to HTML or XML:

● Less than (<)—Replace with &lt; everywhere

● Greater than (>)—Replace with &gt; everywhere

● Ampersand (&)—Replace with &amp; everywhere

● Double quote (")—Replace with &quot; inside attribute values

● Single quote (")—Replace with &apos; inside attribute values

Important: In certain contexts (such as within JavaScript code), quoting those five characters may not besufficient. Read XSS Prevention Cheat Sheet for more details.

To learn more about the security holes that can result from failure to quote HTML content properly, read“Avoiding Cross-Site Scripting” (page 93).

Avoiding Cross-Site ScriptingAnother significant risk associated with web development is cross-site scripting . Cross-site scripting refers toinjecting code into a website that causes it to behave differently than it otherwise would. An attacker might,for example, inject a key logger that displays a fake login dialog and sends the passwords back to the attacker.

There are many types of cross-site scripting vulnerabilities:

Avoiding Injection Attacks and XSSAvoiding Cross-Site Scripting

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

93

● If a website displays content provided in a URL query string without proper sanitization, an attacker cancreate a hyperlink that executes arbitrary JavaScript code. When the victim follows that link, theattacker-provided script runs in the victim’s browser session.

● Websites that allow users to share HTML-based content with one another can inadvertently serve maliciousJavaScript code provided by users, whether in a standalone script tag or hidden in various HTML attributesand CSS properties. When another user visits that page, the malicious JavaScript code runs in the victim’sbrowser session.

● Scripts that use eval on strings that contain user-provided data can be made to execute arbitrary codeif they do not properly sanitize that user-provided data.

And so on. The details of cross-site scripting are beyond the scope of this document. To learn more aboutcross-site scripting and about how to avoid it, read XSS Prevention Cheat Sheet. From there, you can find linksto a number of other articles on web security. You can also find a number of third-party books on cross-sitescripting.

Avoiding Injection Attacks and XSSAvoiding Cross-Site Scripting

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

94

This appendix presents a set of security audit checklists that you can use to help reduce the securityvulnerabilities of your software. These checklists are designed to be used during software development. If youread this section all the way through before you start coding, you may avoid many security pitfalls that aredifficult to correct in a completed program.

Note that these checklists are not exhaustive; you might not have any of the potential vulnerabilities discussedhere and still have insecure code. Also, as the author of the code, you are probably too close to the code tobe fully objective, and thus may overlook certain flaws. For this reason, it’s very important that you have yourcode reviewed for security problems by an independent reviewer. A security expert would be best, but anycompetent programmer, if aware of what to look for, might find problems that you may have missed. Inaddition, whenever the code is updated or changed in any way, including to fix bugs, it should be checkedagain for security problems.

Important: All code should have a security audit before being released.

Use of PrivilegeThis checklist is intended to determine whether your code ever runs with elevated privileges, and if it does,how best to do so safely. Note that it’s best to avoid running with elevated privileges if possible; see “AvoidingElevated Privileges” (page 64).

1. Reduce privileges whenever possible.

If you are using privilege separation with sandboxing or other privilege-limiting techniques, you shouldbe careful to ensure that your helper tools are designed to limit the damage that they can cause if themain application gets compromised, and vice-versa. Read “Designing Secure Helpers and Daemons” (page82) to learn how.

Also, for daemons that start with elevated privileges and then drop privileges, you should always use alocally unique user ID for your program. See “Run Daemons as Unique Users” (page 85) to learn more.

2. Use elevated privileges sparingly, and only in privileged helpers.

In most cases, a program can get by without elevated privileges, but sometimes a program needs elevatedprivileges to perform a limited number of operations, such as writing files to a privileged directory oropening a privileged port.

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

95

Security Development Checklists

If an attacker finds a vulnerability that allows execution of arbitrary code, the attacker’s code runs withthe same privilege as the running code, and can take complete control of the computer if that code hasroot privileges. Because of this risk, you should avoid elevating privileges if at all possible.

If you must run code with elevated privileges, here are some rules:

● Never run your main process as a different user. Instead, create a separate helper tool that runs withelevated privileges.

● Your helper tool should do as little as possible.

● Your helper tool should restrict what you can ask it to do as much as possible.

● Your helper tool should either drop the elevated privileges or stop executing as soon as possible.

Important: If all or most of your code runs with root or other elevated privileges, or if you have complexcode that performs multiple operations with elevated privileges, then your program could have aserious security vulnerability. You should seek help in performing a security audit of your code toreduce your risk.

See “Elevating Privileges Safely” (page 60) and “Designing Secure Helpers and Daemons” (page 82) formore information.

3. Use launchd when possible.

If you are writing a daemon or other process that runs with elevated privileges, you should always uselaunchd to start it. (To learn why other mechanisms are not recommended, read “Limitations and Risksof Other Mechanisms” (page 68).)

For more information on launchd, see the manual pages for launchd, launchctl, and launchd.plist,and Daemons and Services Programming Guide . For more information about startup items, see Daemonsand Services Programming Guide . For more information on ipfw, see the ipfw manual page.

4. Avoid using sudo programmatically.

If authorized to do so in the sudoers file, a user can use sudo to execute a command as root. The sudocommand is intended for occasional administrative use by a user sitting at the computer and typing intothe Terminal application. Its use in scripts or called from code is not secure.

After executing the sudo command—which requires authenticating by entering a password—there is afive-minute period (by default) during which the sudo command can be executed without furtherauthentication. It’s possible for another process to take advantage of this situation to execute a commandas root.

Further, there is no encryption or protection of the command being executed. Because sudo is used toexecute privileged commands, the command arguments often include user names, passwords, and otherinformation that should be kept secret. A command executed in this way by a script or other code canexpose confidential data to possible interception and compromise.

Security Development ChecklistsUse of Privilege

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

96

5. Minimize the amount of code that must be run with elevated privileges.

Ask yourself approximately how many lines of code need to run with elevated privileges. If this answer iseither “all” or is a difficult number to compute, then it will be very difficult to perform a security review ofyour software.

If you can’t determine how to factor your application to separate out the code that needs privileges, youare strongly encouraged to seek assistance with your project immediately. If you are an ADC member, youare encouraged to ask for help from Apple engineers with factoring your code and performing a securityaudit. If you are not an ADC member, see the ADC membership page at http://developer.apple.com/pro-grams/.

6. Never run a GUI application with elevated privileges.

You should never run a GUI application with elevated privileges. Any GUI application links in many librariesover which you have no control and which, due to their size and complexity, are very likely to containsecurity vulnerabilities. In this case, your application runs in an environment set by the GUI, not by yourcode. Your code and your user’s data can then be compromised by the exploitation of any vulnerabilitiesin the libraries or environment of the graphical interface.

Data, Configuration, and Temporary FilesSome security vulnerabilities are related to reading or writing files. This checklist is intended to help you findany such vulnerabilities in your code.

1. Be careful when working with files in untrusted locations.

If you write to any directory owned by the user, then there is a possibility that the user will modify orcorrupt your files.

Similarly, if you write temporary files to a publicly writable place (for example, /tmp, /var/tmp,/Library/Caches or another specific place with this characteristic), an attacker may be able to modifyyour files before the next time you read them.

If your code reads and writes files (and in particular if it uses files for interprocess communication), youshould put those files in a safe directory to which only you have write access.

For more information about vulnerabilities associated with writing files, and how to minimize the risks,see “Time of Check Versus Time of Use” (page 45).

2. Avoid untrusted configuration files, preference files, or environment variables.

In many cases, the user can control environment variables, configuration files, and preferences. If you areexecuting a program for the user with elevated privileges, you are giving the user the opportunity toperform operations that they cannot ordinarily do. Therefore, you should ensure that the behavior of yourprivileged code does not depend on these things.

Security Development ChecklistsData, Configuration, and Temporary Files

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

97

This means:

● Validate all input, whether directly from the user or through environment variables, configurationfiles, preferences files, or other files.

In the case of environment variables, the effect might not be immediate or obvious; however the usermight be able to modify the behavior of your program or of other programs or system calls.

● Make sure that file paths do not contain wildcard characters, such as ../ or ~, which an attacker canuse to switch the current directory to one under the attacker’s control.

● Explicitly set the privileges, environment variables, and resources available to the running process,rather than assuming that the process has inherited the correct environment.

3. Load kernel extensions carefully (or not at all).

A kernel extension is the ultimate privileged code—it has access to levels of the operating system thatcannot be touched by ordinary code, even running as root. You must be extremely careful why, how, andwhen you load a kernel extension to guard against being fooled into loading the wrong one. It’s possibleto load a root kit if you’re not sufficiently careful. (A root kit is malicious code that, by running in the kernel,can not only take over control of the system but can cover up all evidence of its own existence.)

To make sure that an attacker hasn’t somehow substituted his or her own kernel extension for yours, youshould always store kernel extensions in secure locations. You may, if desired, use code signing or hashesto further verify their authenticity, but this does not remove the need to protect the extension withappropriate permissions. (Time-of-check vs. time-of-use attacks are still possible.) Note that in recentversions of OS X, this is partially mitigated by the KEXT loading system, which refuses to load any kextbinary whose owner is not root or whose group is not wheel.

In general, you should avoid writing kernel extensions (see “Keep Out” in Kernel Programming Guide ).However, if you must use a kernel extension, use the facilities built into OS X to load your extension andbe sure to load the extension from a separate privileged process.

See “Elevating Privileges Safely” (page 60) to learn more about the safe use of root access. See KernelProgramming Guide for more information on writing and loading kernel extensions. For help on writingdevice drivers, see I/O Kit Fundamentals .

Network Port UseThis checklist is intended to help you find vulnerabilities related to sending and receiving information over anetwork. If your project does not contain any tool or application that sends or receives information over anetwork, skip to “Audit Logs” (page 100) (for servers) or “Integer and Buffer Overflows” (page 106) for all otherproducts.

1. Use assigned port numbers.

Security Development ChecklistsNetwork Port Use

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

98

Port numbers 0 through 1023 are reserved for use by certain services specified by the Internet AssignedNumbers Authority (IANA; see http://www.iana.org/). On many systems including OS X, only processesrunning as root can bind to these ports. It is not safe, however, to assume that any communications comingover these privileged ports can be trusted. It’s possible that an attacker has obtained root access and usedit to bind to a privileged port. Furthermore, on some systems, root access is not needed to bind to theseports.

You should also be aware that if you use the SO_REUSEADDR socket option with UDP, it is possible for alocal attacker to hijack your port.

Therefore, you should always use port numbers assigned by the IANA, you should always check returncodes to make sure you have connected successfully, and you should check that you are connected tothe correct port. Also, as always, never trust input data, even if it’s coming over a privileged port. Whetherdata is being read from a file, entered by a user, or received over a network, you must validate all input.

See “Validating Input and Interprocess Communication” (page 34) for more information about validatinginput.

2. Choose an appropriate transport protocol.

Lower-level protocols, such as UDP, provide higher performance for some types of traffic, but are easierto spoof than higher-level protocols, such as TCP.

Note that if you’re using TCP, you still need to worry about authenticating both ends of the connection,but there are encryption layers you can add to increase security.

3. Use existing authentication services when authentication is needed.

If you’re providing a free and nonconfidential service, and do not process user input, then authenticationis not necessary. On the other hand, if any secret information is being exchanged, the user is allowed toenter data that your program processes, or there is any reason to restrict user access, then you shouldauthenticate every user.

OS X provides a variety of secure network APIs and authorization services, all of which performauthentication. You should always use these services rather than creating your own authenticationmechanism. For one thing, authentication is very difficult to do correctly, and dangerous to get wrong. Ifan attacker breaks your authentication scheme, you could compromise secrets or give the attacker anentry to your system.

The only approved authorization mechanism for networked applications is Kerberos; see “Client-ServerAuthentication” (page 102). For more information on secure networking, see Secure Transport Referenceand CFNetwork Programming Guide .

4. Verify access programmatically.

UI limitations do not protect your service from attack. If your service provides functionality that shouldonly be accessible to certain users, that service must perform appropriate checks to determine whetherthe current user is authorized to access that functionality.

Security Development ChecklistsNetwork Port Use

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

99

If you do not do this, then someone sufficiently familiar with your service can potentially performunauthorized operations by modifying URLs, sending malicious Apple events, and so on.

5. Fail gracefully.

If a server is unavailable, either because of some problem with the network or because the server is undera denial of service attack, your client application should limit the frequency and number of retries andshould give the user the opportunity to cancel the operation.

Poorly-designed clients that retry connections too frequently and too insistently, or that hang while waitingfor a connection, can inadvertently contribute to—or cause their own—denial of service.

6. Design your service to handle high connection volume.

Your daemon should be capable of surviving a denial of service attack without crashing or losing data. Inaddition, you should limit the total amount of processor time, memory, and disk space each daemon canuse, so that a denial of service attack on any given daemon does not result in denial of service to everyprocess on the system.

You can use the ipfwfirewall program to control packets and traffic flow for internet daemons. For moreinformation on ipfw, see the ipfwmanual page. For more advice on dealing with denial of service attacks,see Wheeler,SecureProgramming for LinuxandUnixHOWTO , available at http://www.dwheeler.com/secure-programs/.

7. Design hash functions carefully.

Hash tables are often used to improve search performance. However, when there are hash collisions (wheretwo items in the list have the same hash result), a slower (often linear) search must be used to resolve theconflict. If it is possible for a user to deliberately generate different requests that have the same hash result,by making many such requests an attacker can mount a denial of service attack.

It is possible to design hash tables that use complex data structures such as trees in the collision case.Doing so can significantly reduce the damage caused by these attacks.

Audit LogsIt’s very important to audit attempts to connect to a server or to gain authorization to use a secure program.If someone is attempting to attack your program, you should know what they are doing and how they aredoing it.

Furthermore, if your program is attacked successfully, your audit log is the only way you can determine whathappened and how extensive the security breach was. This checklist is intended to help you make sure youhave an adequate logging mechanism in place.

Security Development ChecklistsAudit Logs

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

100

Important: Don’t log confidential data, such as passwords, which could then be read later by a malicioususer.

1. Audit attempts to connect.

Your daemon or secure program should audit connection attempts (both successful attempts and failures).

Note that an attacker can attempt to use the audit log itself to create a denial of service attack; therefore,you should limit the rate of entering audit messages and the total size of the log file. You also need tovalidate the input to the log itself, so that an attacker can’t enter special characters such as the newlinecharacter that you might misinterpret when reading the log.

See Wheeler, Secure Programming for Linux and Unix HOWTO for some advice on audit logs.

2. Use the libbsm auditing library where possible.

The libbsm auditing library is part of the TrustedBSD project, which in turn is a set of trusted extensionsto the FreeBSD operating system. Apple has contributed to this project and has incorporated the auditlibrary into the Darwin kernel of the OS X operating system. (This library is not available in iOS.)

You can use the libbsm auditing library to implement auditing of your program for login and authorizationattempts. This library gives you a lot of control over which events are audited and how to handle denialof service attacks.

The libbsm project is located at http://www.opensource.apple.com/darwinsource/Current/bsm/. Fordocumentation of the BSM service, see the “Auditing Topics” chapter in Sun Microsystems’ SystemAdministration Guide: Security Services located at http://docs.sun.com/app/docs/doc/806-4078/6jd6cjs67?a=view.

3. If you cannot use libbsm, be careful when writing audit trails.

When using audit mechanisms other than libbsm, there are a number of pitfalls you should avoid,depending on what audit mechanism you are using:

● syslog

Prior to the implementation of the libbsm auditing library, the standard C library function syslogwas most commonly used to write data to a log file. If you are using syslog, consider switching tolibbsm, which gives you more options to deal with denial of service attacks. If you want to stay withsyslog, be sure your auditing code is resistant to denial of service attacks, as discussed in step 1.

● Custom log file

If you have implemented your own custom logging service, consider switching to libbsm to avoidinadvertently creating a security vulnerability. In addition, if you use libbsm your code will be moreeasily maintainable and will benefit from future enhancements to the libbsm code.

If you stick with your own custom logging service, you must make certain that it is resistant to denialof service attacks (see step 1) and that an attacker can’t tamper with the contents of the log file.

Security Development ChecklistsAudit Logs

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

101

Because your log file must be either encrypted or protected with access controls to prevent tampering,you must also provide tools for reading and processing your log file.

Finally, be sure your custom logging code is audited for security vulnerabilities.

Client-Server AuthenticationIf any private or secret information is passed between a daemon and a client process, both ends of theconnection should be authenticated. This checklist is intended to help you determine whether your daemon’sauthentication mechanism is safe and adequate. If you are not writing a daemon, skip to “Integer and BufferOverflows” (page 106).

1. Do not store, validate, or modify passwords yourself.

It’s a very bad idea to store, validate, or modify passwords yourself, as it’s very hard to do so securely, andOS X and iOS provide secure facilities for just that purpose.

● In OS X, you can use the keychain to store passwords and Authorization Services to create, modify,delete, and validate user passwords (see Keychain Services Programming Guide and AuthorizationServices Programming Guide ).

● In OS X, if you have access to an OS X Server setup, you can use Open Directory (see Open DirectoryProgramming Guide ) to store passwords and authenticate users.

● On an iOS device, you can use the keychain to store passwords. iOS devices authenticate the applicationthat is attempting to obtain a keychain item rather than asking the user for a password. By storingdata in the keychain, you also ensure that they remain encrypted in any device backups.

2. Never send passwords over a network connection in cleartext form.

You should never assume that an unencrypted network connection is secure. Information on an unencryptednetwork can be intercepted by any individual or organization between the client and the server.

Even an intranet, which does not go outside of your company, is not secure. A large percentage of cybercrime is committed by company insiders, who can be assumed to have access to a network inside a firewall.

OS X provides APIs for secure network connections; see Secure Transport Reference and CFNetworkProgramming Guide for details.

3. Use server authentication as an anti-spoofing measure.

Although server authentication is optional in the SSL/TLS protocols, you should always do it. Otherwise,an attacker might spoof your server, injuring your users and damaging your reputation in the process.

4. Use reasonable pasword policies.

● Password strength

Security Development ChecklistsClient-Server Authentication

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

102

In general, it is better to provide the user with a means to evaluate the strength of a proposed passwordrather than to require specific combinations of letters, numbers, or punctuation, as arbitrary rulestend to cause people to choose bad passwords to fit the standard (Firstname.123) instead of choosinggood passwords.

● Password expiration

Password expiration has pros and cons. If your service transmits passwords in cleartext form, it isabsolutely essential.

If your password transmission is considered secure, however, password expiration can actually weakensecurity by causing people to choose weaker passwords that they can remember or to write theirpasswords down on sticky notes on their monitors.

See Password Expiration Considered Harmful for more information.

● Non-password authentication

Hardware-token-based authentication provides far more security than any password scheme becausethe correct response changes every time you use it. These tokens should always be combined with aPIN, and you should educate your users so that they do not write their user name or PIN on the tokenitself.

● Disabled accounts

When an employee leaves or a user closes an account, the account should be disabled so that it cannotbe compromised by an attacker. The more active accounts you have, the greater the probability thatone will have a weak password.

● Expired accounts

Expiring unused accounts reduces the number of active accounts, and in so doing, reduces the riskof an old account getting compromised by someone stealing a password that the user has used forsome other service.

Note, however, that expiring a user account without warning the user first is generally a bad idea. Ifyou do not have a means of contacting the user, expiring accounts are generally considered poorform.

● Changing passwords

You can require that the client application support the ability to change passwords, or you can requirethat the user change the password using a web interface on the server itself.

In either case, the user (or the client, on behalf of the user) must provide the previous password alongwith the new password (twice unless the client is updating it programmatically over a sufficientlyrobust channel).

● Lost password retrieval (such as a system that triggers the user’s memory or a series of questionsdesigned to authenticate the user without a password)

Security Development ChecklistsClient-Server Authentication

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

103

Make sure your authentication method is not so insecure that an attacker doesn’t even bother to trya password, and be careful not to leak information, such as the correct length of the password, theemail address to which the recovered password is sent, or whether the user ID is valid.

You should always allow (and perhaps even require) customer to choose their own security questions.Pre-written questions are inherently dangerous because any question that is general enough for youto ask it of a large number of people is:

● likely to be a request for information that a large number of that person’s friends already know.In all likelihood, everyone who attended your high school can guess (in a handful of guesses)who your kindergarten teacher was, who your high school mascot was, and so on.

● probably on your public profile on a social networking site. For example, if you ask where youwere born, chances are that’s public information. Even if it isn’t on your profile, someone can digit up through government records.

● potentially guessable given other information about the person. For example, given the last fourdigits of a social security number, someone’s birthdate, and the city in which that person wasborn, you can fairly easily guess then entire social security number.

Finally, you should always allow your users the option of not filing out security questions. The mereexistence of security questions makes their accounts less secure, so security-conscious individualsshould be allowed to refuse those questions entirely.

● Limitations on password length (adjustable by the system administrator)

In general, you should require passwords to be at least eight characters in length. (As a side note, ifyour server limits passwords to a maximum of eight characters, you need to rethink your design. Thereshould be no maximum password length at all, if possible.)

The more of these policies you enforce, the more secure your server will be. Rather than creating yourown password database—which is difficult to do securely—you should use the Apple Password Server.See Open Directory Programming Guide for more information about the Password Server, Directory ServiceFramework Reference for a list of Directory Services functions, and the manual pages for pwpolicy(8),passwd(1), passwd(5), and getpwent(3) at http://developer.apple.com/documentation/Darwin/Ref-erence/ManPages/index.html for tools to access the password database and set password policies.

5. Do not store unencrypted passwords and do not reissue passwords.

In order to reissue a password, you first have to cache the unencrypted password, which is bad securitypractice. Furthermore, when you reissue a password, you might also be reusing that password in aninappropriate security context.

For example, suppose your program is running on a web server, and you use SSL to communicate withclients. If you take a client’s password and use it to log into a database server to do something on theclient’s behalf, there’s no way to guarantee that the database server keeps the password secure and does

Security Development ChecklistsClient-Server Authentication

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

104

not pass it on to another server in cleartext form. Therefore, even though the password was in a securecontext when it was being sent to the web server over SSL, when the web server reissues it, it’s in aninsecure context.

If you want to spare your client the trouble of logging in separately to each server, you should use somekind of forwardable authentication, such as Kerberos. For more information on Apple’s implementationof Kerberos, see http://developer.apple.com/darwin/projects/kerberos/.

Under no circumstances should you design a system in which system administrators or other employeescan see users’ passwords. Your users are trusting you with passwords that they may use for other sites;therefore, it is extremely reckless to allow anyone else to see those passwords. Administrators should beallowed to reset passwords to new values, but should never be allowed to see the passwords that arealready there.

6. Support Kerberos.

Kerberos is the only authorization service available over a network for OS X servers, and it offerssingle-sign-on capabilities. If you are writing a server to run on OS X, you should support Kerberos. Whenyou do:

a. Be sure you’re using the latest version (v5).

b. Use a service-specific principal, not a host principal. Each service that uses Kerberos should have itsown principal so that compromise of one key does not compromise more than one service. If you usea host principal, anyone who has your host key can spoof login by anybody on the system.

The only alternative to Kerberos is combining SSL/TLS authentication with some other means ofauthorization such as an access control list.

7. Restrict guest access appropriately.

If you allow guest access, be sure that guests are restricted in what they can do, and that your user interfacemakes clear to the system administrator what guests can do. Guest access should be off by default. It’sbest if the administrator can disable guest access.

Also, as noted previously, be sure to limit what guests can do in the code that actually performs theoperation, not just in the code that generates the user interface. Otherwise, someone with sufficientknowledge of the system can potentially perform those unauthorized operations in other ways (by modifyingURLs, for example).

8. Do not implement your own directory service.

Open Directory is the directory server provided by OS X for secure storage of passwords and userauthentication. It is important that you use this service and not try to implement your own, as securedirectory servers are difficult to implement and an entire directory’s passwords can be compromised if it’sdone wrong. See Open Directory Programming Guide for more information.

9. Scrub (zero) user passwords from memory after validation.

Security Development ChecklistsClient-Server Authentication

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

105

Passwords must be kept in memory for the minimum amount of time possible and should be written over,not just released, when no longer needed. It is possible to read data out of memory even if the applicationno longer has pointers to it.

Integer and Buffer OverflowsAs discussed in “Avoiding Buffer Overflows and Underflows” (page 17), buffer overflows are a major source ofsecurity vulnerabilities. This checklist is intended to help you identify and correct buffer overflows in yourprogram.

1. Use unsigned values when calculating memory object offsets and sizes.

Signed values make it easier for an attacker to cause a buffer overflow, creating a security vulnerability,especially if your application accepts signed values from user input or other outside sources.

Be aware that data structures referenced in parameters might contain signed values.

See “Avoiding Integer Overflows and Underflows” (page 27) and “Calculating Buffer Sizes” (page 25) fordetails.

2. Check for integer overflows (or signed integer underflows) when calculating memory object offsetsand sizes.

You must always check for integer overflows or underflows when calculating memory offsets or sizes.Integer overflows and underflows can corrupt memory in ways that can lead to execution of arbitrarycode.

See “Avoiding Integer Overflows and Underflows” (page 27) and “Calculating Buffer Sizes” (page 25) fordetails.

3. Avoid unsafe string-handling functions.

The functions strcat, strcpy, strncat, strncpy, sprintf, vsprintf, and gets have no built-inchecks for string length, and can lead to buffer overflows.

For alternatives, read “String Handling” (page 22).

Cryptographic Function UseThis checklist is intended to help you determine whether your program has any vulnerabilities related to useof encryption, cryptographic algorithms, or random number generation.

1. Use trusted random number generators.

Do not attempt to generate your own random numbers.

Security Development ChecklistsInteger and Buffer Overflows

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

106

There are several ways to obtain high-quality random numbers:

● In iOS, use the Randomization Services programming interface.

● In OS X:

● Read from /dev/random in OS X (see the manual page for random).

● Use the read_random function in the header file random.h in the Apple CSP module, which ispart of Apple’s implementation of the CDSA framework (available at http://developer.apple.com/dar-win/projects/security/).

Note that rand does not return good random numbers and should not be used.

2. Use TLS/SSL instead of custom schemes.

You should always use accepted standard protocols for secure networking. These standards have gonethrough peer review and so are more likely to be secure.

In addition, you should always use the most recent version of these protocols.

To learn more about the secure networking protocols available in OS X and iOS, read “Transmitting DataSecurely” in Cryptographic Services Guide .

3. Don’t roll your own crypto algorithms.

Always use existing optimized functions. It is very difficult to implement a secure cryptographic algorithm,and good, secure cryptographic functions are readily available.

To learn about the cryptographic services available in OS X and iOS, read Cryptographic Services Guide .

Installation and LoadingMany security vulnerabilities are caused by problems with how programs are installed or code modules areloaded. This checklist is intended to help you find any such problems in your project.

1. Don’t install components in /Library/StartupItemsor/System/Library/Extensions.

Code installed into these directories runs with root permissions. Therefore, it is very important that suchprograms be carefully audited for security vulnerabilities (as discussed in this checklist) and that they havetheir permissions set correctly.

For information on proper permissions for startup items, see “Startup Items”. (Note that in OS X v10.4 andlater, startup items are deprecated; you should use launchd to launch your daemons instead. SeeDaemonsand Services Programming Guide for more information.)

For information on permissions for kernel extensions, see Kernel Extension Programming Topics . (Notethat beginning in OS X v10.2, OS X checks for permissions problems and refuses to load extensions unlessthe permissions are correct.)

2. Don’t use custom install scripts.

Security Development ChecklistsInstallation and Loading

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

107

Custom install scripts add unnecessary complexity and risk, so when possible, you should avoid thementirely.

If you must use a custom install script, you should:

● If your installer script runs in a shell, read and follow the advice in “Shell Script Security” in ShellScripting Primer .

● Be sure that your script follows the guidelines in this checklist just as the rest of your application does.

In particular:

● Don’t write temporary files to globally writable directories.

● Don’t execute with higher privileges than necessary.

In general, your script should execute with the same privileges the user has normally, and shoulddo its work in the user’s directory on behalf of the user.

● Don’t execute with elevated privileges any longer than necessary.

● Set reasonable permissions on your installed app.

For example, don’t give everyone read/write permission to files in the app bundle if only theowner needs such permission.

● Set your installer’s file code creation mask (umask) to restrict access to the files it creates (see“Securing File Operations” (page 48)).

● Check return codes, and if anything is wrong, log the problem and report the problem to theuser through the user interface.

For advice on writing installation code that needs to perform privileged operations, see AuthorizationServices Programming Guide . For more information about writing shell scripts, read Shell Scripting Primer .

3. Load plug-ins and libraries only from secure locations.

An application should load plug-ins only from secure directories. If your application loads plug-ins fromdirectories that are not restricted, then an attacker might be able to trick the user into downloadingmalicious code, which your application might then load and execute.

Important: In code running with elevated privileges, directories writable by the user are not consideredsecure locations.

Be aware that the dynamic link editor (dyld) might link in plugins, depending on the environment inwhich your code is running. If your code uses loadable bundles (CFBundle or NSBundle), then it isdynamically loading code and could potentially load bundles written by a malicious hacker.

See Code Loading Programming Topics for more information about dynamically loaded code.

Security Development ChecklistsInstallation and Loading

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

108

Use of External Tools and LibrariesIf your program includes or uses any command-line tools, you have to look for security vulnerabilities specificto the use of such tools. This checklist is intended to help you find and correct such vulnerabilities.

1. Execute tools safely.

If you are using routines such as popen or system to send commands to the shell, and you are usinginput from the user or received over a network to construct the command, you should be aware that theseroutines do not validate their input. Consequently, a malicious user can pass shell metacharacters—suchas an escape sequence or other special characters—in command line arguments. These metacharactersmight cause the following text to be interpreted as a new command and executed.

In addition, when calling functions such as execlp, execvp, popen, or system that use the PATHenvironment variable to search for executables, you should always specify a complete absolute path toany tool that you want to run. If you do not, a malicious attacker can potentially cause you to run a differenttool using an environment variable attack. When possible, use execvP (which takes an explicit searchpath argument) or avoid these functions altogether.

See Viega and McGraw, Building Secure Software , Addison Wesley, 2002, and Wheeler, Secure Programmingfor LinuxandUnixHOWTO , available at http://www.dwheeler.com/secure-programs/, for more informationon problems with these and similar routines and for secure ways to execute shell commands.

2. Do not pass sensitive information on the command line.

If your application executes command-line tools, keep in mind that your process environment is visibleto other users (see man ps(1)). You must be careful not to pass sensitive information in an insecuremanner. Instead, pass sensitive information to your tool through some other means such as:

● Pipe or standard input

A password is safe while being passed through a pipe; however, you must be careful that the processsending the password obtains and stores it in a safe manner.

● Environment variables

Environment variables can potentially be read by other processes and thus may not be secure. If youuse environment variables, you must be careful to avoid passing them to any processes that yourcommand-line tool or script might spawn.

See “Shell Script Security” in Shell Scripting Primer for details.

● Shared memory

Named and globally-shared memory segments can be read by other processes. See “InterprocessCommunication and Networking” (page 41) for more information about secure use of shared memory.

● Temporary file

Security Development ChecklistsUse of External Tools and Libraries

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

109

Temporary files are safe only if kept in a directory to which only your program has access. See “Data,Configuration, and Temporary Files” (page 97), earlier in this chapter, for more information ontemporary files.

3. Validate all arguments (including the name).

Also, remember that anyone can execute a tool—it is not executable exclusively through your program.Because all command-line arguments, including the program name (argv(0)), are under the control ofthe user, your tool should validate every parameter (including the name, if the tool’s behavior dependson it).

Kernel SecurityThis checklist is intended to help you program safely in the kernel.

Note: Coding in the kernel poses special security risks and is seldom necessary. See Coding in theKernel for alternatives to writing kernel-level code.

1. Verify the authenticity of Mach-based services.

Kernel-level code can work directly with the Mach component. A Mach port is an endpoint of acommunication channel between a client who requests a service and a server that provides the service.Mach ports are unidirectional; a reply to a service request must use a second port.

If you are using Mach ports for communication between processes, you should check to make sure youare contacting the correct process. Because Mach bootstrap ports can be inherited, it is important forservers and clients to authenticate each other. You can use audit trailers for this purpose.

You should create an audit record for each security-related check your program performs. See “AuditLogs” (page 100), earlier in this chapter, for more information on audit records.

2. Verify the authenticity of other user-space services.

If your kernel extension was designed to communicate with only a specific user-space daemon, you shouldcheck not only the name of the process, but also the owner and group to ensure that you arecommunicating with the correct process.

3. Handle buffers correctly.

When copying data to and from user space, you must:

a. Check the bounds of the data using unsigned arithmetic—just as you check all bounds (see “Integerand Buffer Overflows” (page 106), earlier in this chapter)—to avoid buffer overflows.

b. Check for and handle misaligned buffers.

Security Development ChecklistsKernel Security

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

110

c. Zero all pad data when copying to or from user-space memory.

If you or the compiler adds padding to align a data structure in some way, you should zero the paddingto make sure you are not adding spurious (or even malicious) data to the user-space buffer, and tomake sure that you are not accidentally leaking sensitive information that may have been in that pageof memory previously.

4. Limit the memory resources a user may request.

If your code does not limit the memory resources a user may request, then a malicious user can mount adenial of service attack by requesting more memory than is available in the system.

5. Sanitize any kernel log messages.

Kernel code often generates messages to the console for debugging purposes. If your code does this, becareful not to include any sensitive information in the messages.

6. Don’t log too much.

The kernel logging service has a limited buffer size to thwart denial of service attacks against the kernel.This means that if your kernel code logs too frequently or too much, data can be dropped.

If you need to log large quantities of data for debugging purposes, you should use a different mechanism,and you must disable that mechanism before deploying your kernel extension. If you do not, then yourextension could become a denial-of-service attack vector.

7. Design hash functions carefully.

Hash tables are often used to improve search performance. However, when there are hash collisions (wheretwo items in the list have the same hash result), a slower (often linear) search must be used to resolve theconflict. If it is possible for a user to deliberately generate different requests that have the same hash result,by making many such requests an attacker can mount a denial of service attack.

It is possible to design hash tables that use complex data structures such as trees in the collision case.Doing so can significantly reduce the damage caused by these attacks.

Security Development ChecklistsKernel Security

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

111

This appendix provides secure coding guidelines for software to be bundled with Apple products.

Insecure software can pose a risk to the overall security of users’ systems. Security issues can lead to negativepublicity and end-user support problems for Apple and third parties.

Respect Users’ PrivacyYour bundled software may use the Internet to communicate with your servers or third party servers. If so, youshould provide clear and concise information to the user about what information is sent or retrieved and thereason for sending or receiving it.

Encryption should be used to protect the information while in transit. Servers should be authenticated beforetransferring information.

Provide Upgrade InformationProvide information on how to upgrade to the latest version. Consider implementing a “Check for updates…”feature. Customers expect (and should receive) security fixes that affect the software version they are running.

You should have a way to communicate available security fixes to customers.

If possible, you should use the Mac App Store for providing upgrades. The Mac App Store provides a single,standard interface for updating all of a user’s software. The Mac App Store also provides an expedited appreview process for handling critical security fixes.

Store Information in Appropriate PlacesStore user-specific information in the home directory, with appropriate file system permissions.

Take special care when dealing with shared data or preferences.

Follow the guidelines about file system permissions set forth in File System Programming Guide .

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

112

Third-Party Software Security Guidelines

Take care to avoid race conditions and information disclosure when using temporary files. If possible, use auser-specific temporary file directory.

Avoid Requiring Elevated PrivilegesDo not require or encourage users to be logged in as an admin user to install or use your application. Youshould regularly test your application as a normal user to make sure that it works as expected.

Implement Secure Development PracticesEducate your developers on how to write secure code to avoid the most common classes of vulnerabilities:

● Buffer overflows

● Integer overflows

● Race conditions

● Format string vulnerabilities

Pay special attention to code that:

● deals with potentially untrusted data, such as documents or URLs

● communicates over the network

● handles passwords or other sensitive information

● runs with elevated privileges such as root or in the kernel

Use APIs appropriate for the task:

● Use APIs that take security into account in their design.

● Avoid low-level C code when possible (e.g. use NSString instead of C-strings).

● Use the security features of OS X to protect user data.

Test for SecurityAs appropriate for your product, use the following QA techniques to find potential security issues:

● Test for invalid and unexpected data in addition to testing what is expected. (Use fuzzing tools, includeunit tests that test for failure, and so on.)

Third-Party Software Security GuidelinesAvoid Requiring Elevated Privileges

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

113

● Static code analysis

● Code reviews and audits

Helpful ResourcesThe other chapters in this document describe best practices for writing secure code, including more informationon the topics referenced above.

Security Overview and Cryptographic Services Guide contain detailed information on security functionality inOS X that developers can use.

Third-Party Software Security GuidelinesHelpful Resources

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

114

This table describes the changes to Secure Coding Guide .

NotesDate

Added information about non-executable stacks and heaps, address spacelayout randomization, injection attacks, and cross-site scripting.

2014-02-11

Made minor typographical fixes.2012-06-11

Fixed minor errors throughout.2012-02-16

Updated for OS X v10.7.2012-01-09

Added security guidelines.2010-02-12

Added article on validating input--including the dangers of loadinginsecurely stored archives--and added information about the iOS whererelevant.

2008-05-23

New document that describes techniques to use and factors to considerto make your code more secure from attack.

2006-05-23

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

115

Document Revision History

AES encryption Abbreviation for AdvancedEncryption Standard encryption. A FederalInformation Processing Standard (FIPS), describedin FIPS publication 197. AES has been adopted bythe U.S. government for the protection of sensitive,non-classified information.

attacker Someone deliberately trying to make aprogram or operating system do something that it’snot supposed to do, such as allowing the attackerto execute code or read private data.

authentication The process by which a person orother entity (such as a server) proves that it is who(or what) it says it is. Compare with authorization.

authorization The process by which an entity suchas a user or a server gets the right to perform aprivileged operation. (Authorization can also referto the right itself, as in “Bob has the authorizationto run that program.”) Authorization usually involvesfirst authenticating the entity and then determiningwhether it has the appropriate privileges. See alsoauthentication.

buffer overflow The insertion of more data into amemory buffer than was reserved for the buffer,resulting in memory locations outside the bufferbeing overwritten. See also heap overflow and stackoverflow.

CDSA Abbreviation for Common Data SecurityArchitecture. An open software standard for asecurity infrastructure that provides a wide array ofsecurity services, including fine-grained access

permissions, authentication of users, encryption, andsecure data storage. CDSA has a standard applicationprogramming interface, called CSSM.

CERT Coordination Center A center of Internetsecurity expertise, located at the SoftwareEngineering Institute, a federally funded researchand development center operated by CarnegieMellon University. CERT is an acronym for ComputerEmergency Readiness Team.)

certificate See digital certificate.

Common Criteria A standardized process and setof standards that can be used to evaluate thesecurity of software products developed by thegovernments of the United States, Canada, theUnited Kingdom, France, Germany, and theNetherlands.

cracker See attacker.

CSSM Abbreviation for Common Security ServicesManager. A public application programminginterface for CDSA. CSSM also defines an interfacefor plug-ins that implement security services for aparticular operating system and hardwareenvironment.

CVE Abbreviation for Common Vulnerabilities andExposures. A dictionary of standard names forsecurity vulnerabilities located athttp://www.cve.mitre.org/. You can run an Internetsearch on the CVE number to read details about thevulnerability.

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

116

Glossary

digital certificate A collection of data used to verifythe identity of the holder. OS X supports the X.509standard for digital certificates.

exploit A program or sample code thatdemonstrates how to take advantage of avulnerability.)

FileVault An OS X feature, configured through theSecurity system preference, that encrypts everythingin on the root volume (or everything in the user’shome directory prior to OS X v10.7).

hacker An expert programmer—generally one withthe skill to create an exploit. Most hackers do notattack other programs, and some publish exploitswith the intent of forcing software developers to fixvulnerabilities. See also script kiddie.

heap A region of memory reserved for use by aprogram during execution. Data can be written toor read from any location on the heap, which growsupward (toward higher memory addresses). Comparewith stack.

heap overflow A buffer overflow in the heap.

homographs Characters that look the same buthave different Unicode values, such as the Romancharacter p and the Russian glyph that is pronouncedlike “r”.

integer overflow A buffer overflow caused byentering a number that is too large for an integerdata type.

Kerberos An industry-standard protocol created bythe Massachusetts Institute of Technology (MIT) toprovide authentication over a network.

keychain A database used in OS X to storeencrypted passwords, private keys, and other secrets.It is also used to store certificates and othernon-secret information that is used in cryptographyand authentication.

Keychain Access utility An application that can beused to manipulate data in the keychain.

Keychain Services A public API that can be used tomanipulate data in the keychain.

level of trust The confidence a user can have in thevalidity of a certificate. The level of trust for acertificate is used together with the trust policy toanswer the question “Should I trust this certificatefor this action?”

nonrepudiation A process or technique making itimpossible for a user to deny performing anoperation (such as using a specific credit cardnumber).

Open Directory The directory server provided byOS X for secure storage of passwords and userauthentication.

permissions See privileges.

phishing A social engineering technique in whichan email or web page that spoofs one from alegitimate business is used to trick a user into givingpersonal data and secrets (such as passwords) tosomeone who has malicious intent.

policy database A database containing the set ofrules the Security Server uses to determineauthorization.

privileged operation An operation that requiresspecial rights or privileges.

privileges The type of access to a file or directory(read, write, execute, traverse, and so forth) grantedto a user or to a group.

Glossary

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

117

race condition The occurrence of two events outof sequence.

root kit Malicious code that, by running in thekernel, can not only take over control of the systembut can also cover up all evidence of its ownexistence.

root privileges Having the unrestricted permissionto perform any operation on the system.

script kiddie Someone who uses published code(scripts) to attack software and computer systems.

signal A message sent from one process to anotherin a UNIX-based operating system (such as OS X)

social engineering As applied to security, trickinga user into giving up secrets or into giving access toa computer to an attacker.

smart card A plastic card similar in size to a creditcard that has memory and a microprocessorembedded in it. A smart card can store and processinformation, including passwords, certificates, andkeys.

stack A region of memory reserved for use by aspecific program and used to control program flow.Data is put on the stack and removed in alast-in–first-out fashion. The stack grows downward(toward lower memory addresses). Compare withheap.

stack overflow A buffer overflow on the stack.

time of check–time of use (TOCTOU) A racecondition in which an attacker creates, writes to, oralters a file between the time when a programchecks the status of the file and when the programwrites to it.

trust policy A set of rules that specify theappropriate uses for a certificate that has a specificlevel of trust. For example, the trust policy for a

browser might state that if a certificate has expired,the user should be prompted for permission beforea secure session is opened with a web server.

vulnerability A feature of the way a program waswritten—either a design flaw or a bug—that makesit possible for a hacker or script kiddie to attack theprogram.

Glossary

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

118

Apple Inc.Copyright © 2014 Apple Inc.All rights reserved.

No part of this publication may be reproduced,stored in a retrieval system, or transmitted, in anyform or by any means, mechanical, electronic,photocopying, recording, or otherwise, withoutprior written permission of Apple Inc., with thefollowing exceptions: Any person is herebyauthorized to store documentation on a singlecomputer for personal use only and to printcopies of documentation for personal useprovided that the documentation containsApple’s copyright notice.

No licenses, express or implied, are granted withrespect to any of the technology described in thisdocument. Apple retains all intellectual propertyrights associated with the technology describedin this document. This document is intended toassist application developers to developapplications only for Apple-labeled computers.

Apple Inc.1 Infinite LoopCupertino, CA 95014408-996-1010

Apple, the Apple logo, Carbon, Cocoa, eMac,FileVault, iPhone, Keychain, Mac, Mac OS,Macintosh, Numbers, Objective-C, OS X, Pages,Safari, and Sand are trademarks of Apple Inc.,registered in the U.S. and other countries.

.Mac is a service mark of Apple Inc., registered inthe U.S. and other countries.

App Store and Mac App Store are service marksof Apple Inc.

Java is a registered trademark of Oracle and/orits affiliates.

Ping is a registered trademark of KarstenManufacturing and is used in the U.S. underlicense.

UNIX is a registered trademark of The OpenGroup.

iOS is a trademark or registered trademark ofCisco in the U.S. and other countries and is usedunder license.

Even though Apple has reviewed this document,APPLE MAKES NO WARRANTY OR REPRESENTATION,EITHER EXPRESS OR IMPLIED, WITH RESPECT TO THISDOCUMENT, ITS QUALITY, ACCURACY,MERCHANTABILITY, OR FITNESS FOR A PARTICULARPURPOSE. AS A RESULT, THIS DOCUMENT IS PROVIDED“AS IS,” AND YOU, THE READER, ARE ASSUMING THEENTIRE RISK AS TO ITS QUALITY AND ACCURACY.

IN NO EVENT WILL APPLE BE LIABLE FOR DIRECT,INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIALDAMAGES RESULTING FROM ANY DEFECT ORINACCURACY IN THIS DOCUMENT, even if advised ofthe possibility of such damages.

THE WARRANTY AND REMEDIES SET FORTH ABOVEARE EXCLUSIVE AND IN LIEU OF ALL OTHERS, ORALOR WRITTEN, EXPRESS OR IMPLIED. No Apple dealer,agent, or employee is authorized to make anymodification, extension, or addition to this warranty.

Some states do not allow the exclusion or limitationof implied warranties or liability for incidental orconsequential damages, so the above limitation orexclusion may not apply to you. This warranty givesyou specific legal rights, and you may also have otherrights which vary from state to state.

Symbols

_unknown user 85

A

access control 14applications

interfaces 74–79arguments, command line 62, 110argv(0) 62attackers 8audit logs 100authentication 14, 99authopen 67Authorization Services 73authorization

granting 14revoking 76

AuthorizationExecWithPrivilege 69

B

buffer overflows 11, 17–29calculating buffer sizes 25–26checklist 106detecting 28integer arithmetic 27strings 22

buffer overflows See also heap , stack 17

C

certificates digital certificates 14CFBundle 108chflags 49

chmod 56chown 56close-on-exec flag 59code insertion 38command-line arguments 62, 110command-line tools 109configuration files 97crackers 8

D

default settings 74denial of service 100device ID 58digital certificate

identity 80digital certificates 14document organization 9dyld 108dynamic link editor 108

E

elevated privileges 60, 95encryption 15environment variables 63, 97

F

fchmod 56fchown 56file descriptor 51, 52

inheriting 59file descriptors 62file locations 76

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

120

Index

file operationsCarbon 56Cocoa 52insecure 13, 48–59POSIX 51

file system, remotely mounted 58files

temporary 97FileVault 76firewall 100fopen 56format string attacks 35fstat 56fuzzing 40

G

GID 65group ID 65guest access 105GUI 97

H

hackers 7hard link 49hash function 100, 111heap 11

overflow 20, 22

I

identity 80input validation 12input

data structures 106inappropriate 17testing 28to audit logs 101types of 17validating 19, 34–41, 109

insecure file operations 13, 48–59installer 64integer overflows 27interface, user 77ipfw 100

K

Kerberos 105kernel extensions 73, 98kernel messages 111kernel

checklist 110KEXT 73

L

launchd 67, 96least privilege, principle of 61left bracket 58libbsm 101/Library/StartupItems 69logs, audit 100lstat 56

M

Mach ports 110mkstemp 54, 56mktemp 56

N

negative numbers 27network ports 99nobody user 85NSBundle 108NSTemporaryDirectory 52

Index

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

121

O

open 56organization of document 9

P

passwords 102permissions 53permissions See also privilegesphishing 16, 79plug-ins 108policy database 70, 73port numbers 99ports, Mach 110private key

identity 80privileges 14, 60–73

elevated 60, 95level, changing 65principle of least privilege 61root 14

process limits 63

R

race conditions 13, 44interprocess communication 13scripts 57time of check–time of use 45–47

45–47random numbers 106references 10remotely mounted file system 58rm 49root kit 98root privileges 14

S

script kiddies 8

scripts, avoiding race conditions 57Security Objective-C API 80setegid 66seteuid 66setgid 66setregid 66setreuid 66setrlimit 63setuid 66, 68SFAuthorizationView 80SFCertificatePanel 80SFCertificateTrustPanel 80SFCertificateView 80SFChooseIdentityPanel 80SFKeychainSavePanel 80SFKeychainSettingsPanel 80shell commands 109signal handler 47social engineering 16, 38, 79stack 11

overflow 18–20stat 56statistics of threats and attacks 16string-handling functions 22, 106sudo 96symbolic link 50syslog 101SystemStarter 69

T

temporary files 51, 54, 97and scripts 57default location 52

test 58twos-complement arithmetic 27

U

UID 65

Index

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

122

unique 85umask 53URL commands 12, 37user ID 65user interface 77

V

validating input 12, 34–41

W

wildcard characters 98

X

xinetd 69

Index

2014-02-11 | Copyright © 2014 Apple Inc. All Rights Reserved.

123