If you want your program to be portable to systems that do not have PAM, I suggestwriting a dummy PAM library that calls getpwor getpwentand crypt, or tryporting libpwdbto the target sys
Trang 1across multiple machines, which has both advantages and disadvantages DIPC is notavailable on other platforms (kernel mods are required) Programs that use DIPC mayalso have to deal with byte ordering problems.
Named pipes rely on the existence of a separate fifo object in the filesystem for eachpossible simultaneous connection, and probably do not queue connection requests; itappears that they honor file permissions
Psuedottys can probably be used as an IPC mechanism A variety of signals may bedelivered Filesystem permissions are checked but the filesystem objects are shared withother programs like telnetd,and so permissions need to be set at runtime by a processrunning as root You need a way to tell the other process which psuedottypair to use.TLI allows access to uids/gids but apparently it isn’t very well documented TLI is notthat widely available and may not even be available on Linux
Theidentddaemon runs on computers and may be polled to determine the name of theuser who owns a particular open TCP/IP connection using the RFC 1413 protocol The data returned by identdis not necessarily trustworthy but is still useful Only trustthe data from an identdserver for authentication purposes if you trust the security of themachine and the integrity of anyone who has root access
identdis typically used to identify users and log that information If there is trouble, thatinformation may help narrow down the blame Of course, anyone can run a bogus
identdserver on any machine they control That is actually not the weakness it appears
to be because after an attack your action will be to deny access to the smallest group sible, which includes the attacker If you can narrow it down to a particular user youdeny access to that user; otherwise, you deny access to the entire machine or even anentire network
pos-If you accept connections from the localhost or other secure machines on your local work,identdon those machines can usually be trusted to the same degree the machinesthemselves are and may be used to help authenticate users identdqueries may be vul-nerable to various “man in the middle” and TCP hijacking attacks, which should be takeninto account Use of identdin this manner also helps validate that local TCP connec-tions have not been spoofed; if that is the case, your identddaemon on the other side islikely to return an error that the connection in question does not exist on that machine.The attacker will have to work harder to spoof the original connection and the identd
net-one as well Your firewall should be configured to prevent outsiders from spoofing orhijacking TCP connections between internal hosts
Trang 2Beware, however, of ssh port forwarding or IP masquerading and identd And take cautions to insure that the response you received actually originated on the local host Asecret token of some sort is advisable to further verify the local origin and identity of aTCP/IP connection This token may be stored, for example, in a file accessible only by aparticular user.
pre-TCP Versus UDP
This may ruffle a few feathers, but I don’t recommend using UDP for anything because
of its serious security drawbacks TCP is vulnerable to DOS via open connections inwhich the data transfer is never completed, but in almost every other security aspect it issuperior to UDP UDP has some performance advantages that make it popular for appli-cations such as remote filesystem access and real-time video and audio Yet even thoseapplications tend to have TCP versions As a programmer, if you implement a UDP ver-sion you will probably have to supplement it with a TCP version to get through firewalls
You might as well start with the TCP version; there likely won’t be a compelling reason
no direction information for UDP; a firewall can’t tell if an arbitrary UDP packet is aninbound request (which should usually be blocked) or an inbound reply (which may need
to be allowed) Most firewalls block almost all UDP traffic and that which they don’tblock is very vulnerable to misuse
Any application that does use UDP should probably reject any packets that originatefrom certain well known ports, particularly the one used by DNS; those packets are prob-ably attacks that snuck through a firewall
The popularity of UDP for real-time audio and video is primarily due to the fact that if apacket doesn’t arrive there is no point in transmitting it TCP connections may be used tofor these applications with appropriate throttling algorithms, which limit the amount ofdata transmitted to what the link can sustainably handle UDP applications also shouldthrottle the data or quality will suffer The only real difference is that a few extra retrans-mitted TCP packets may use up bandwidth when the throttling is not perfect Multicastapplications are stuck with UDP; these applications will be completely unusable acrossmost firewalls
Trang 3Dynamic Versus Static Memory Allocation
Allocation of fixed size buffers can cause some inconvenience by imposing hard limits,but those limits are likely to be well known and clients can try to avoid them in advance.Differential truncation or residual data on a line after reaching a hard limit can causeproblems as mentioned previously
Programs that use dynamic memory are prone to memory leaks and fragmentation.Memory leaks are often not a big problem in short lived utility programs but they cancause problems in preforked server processes, which may normally live for days As aguard against memory leaks, I normally make the process check the number of requests
it has serviced and its total memory usage between requests, then have the process dieand be replaced by a fresh process if either limit has been exceeded The first checkkeeps minor leaks from consuming more memory than needed and the second stops fastleaks quickly
Programs that use dynamic memory can also be the targets of DOS attacks that exhaustavailable system memory Setting process limits with setrlimit()can help prevent totalexhaustion of system resources but it may result in the process being terminated withoutwarning; this could occur in an unexpected and inconvenient place, which could leaveunfinished business Having the process monitor its own usage can give it the opportuni-
ty to die more gracefully, but it may not always catch the problem in time unless thechecks permeate all code that reads or copies data
Buffer overflows in dynamically allocated memory can corrupt the memory pool itself;creative use of this might even permit an attacker to write to any arbitrary section ofmemory Programmers who make heavy use of dynamic memory often allocate a newmemory block after measuring the length of a string that will be copied; this is resistant
to buffer overflows on copies but other techniques need to be used when reading from adata stream
Use of stale pointers is a common problem in programs that use dynamic memory andcan result in crashes, unpredictable behavior, and other buffer overflows or values myste-riously appearing in the wrong variable It is helpful in programs that use either type ofmemory allocation scheme to include a distinctive signature field in each type of datastructure This will make it easier to detect many cases where a pointer points at thewrong data
Programs that use dynamic memory, with or without using setrlimit()or other ing techniques, still have hard limits, despite the rhetoric to the contrary; the limits arejust larger and often less predictable I prefer to avoid dynamic allocation in most casesand to exercise care when I do use it Both schemes require careful usage
Trang 4limit-Security Levels
The security level features implemented in newer kernels allow you to designate certainfiles as immutable or append only While you cannot really use those from your own pro-grams, they can be used to restrict access to important files, which may help reduce thedamage caused by some exploits
POSIX.1e Capabilities
POSIX.1e style capabilities being developed (Linux-Privs Project) will allow much finercontrol of the privileges a program has Instead of very course controls, such as beingroot and not being root, this will allow fine tuning of exactly which privileged systemcalls a program can execute By giving up all privileges that are not needed, a programcan minimize the effects of many exploits
A program that only needs the ability to bind to a restricted socket, for example, can give
up others Unfortunately, many daemons require the setuid()family of calls and I don’tknow of any plans to separate the ability to switch between various ordinary uids (nor-mal users) and switching to privileged ones (root, bin, etc.) This would be very handyfor the many daemons that access a user’s files on their behalf If you have write access
to root’s files, you can easily gain root privileges
Erasing Buffers
If you use some form of binary communications with other processes you should becareful to erase buffers, particularly the portion of strings after the terminating null, toinsure that you do not accidentally divulge sensitive information Many years ago, Iwrote a program that allowed me to obtain the plaintext of passwords from a NetWareserver immediately after they had been accessed by someone else in another building
The server did not clear its buffers and always sent a reply of a certain minimum length;
my program simply issued a system call that would fail and all but the first couple bytes
of the previous request’s response were returned unmodified
HTML Form Submissions Past Firewalls
Web browsers on machines inside your firewall can be tricked by outside Web sites intotransmitting arbitrary text to internal TCP based services (by specifying the target service
in the ACTIONattribute of the FORMtag) Some encodings permit more flexibility inattacks than others Many browsers will block a few well-known services from being thetarget of form submissions This deny known bad approach is problematic All text-based
Trang 5(and possibly some binary encoded) TCP services other than HTTP should look forstrings typically sent by Web browsers such as GET,PUT,POST,Content-Type:,Content- Length:,Referrer:, and Accept: If any line received begins with one of these strings,log an attempted security violation (preferably along with the Referrer:field) and ter-minate processing of data and commands on that connection.
Snooping, Hijacking, and Man in the Middle Attacks
When writing servers and clients, you should keep in mind that it is possible for anattacker to modify or take over an existing TCP connection UDP services are muchmore vulnerable A “man in middle” attack can take over a TCP connection or even mod-ify it in transit This is easier if the attacker controls a machine between the two systems,
or is at least attached to a network segment that the packets travel over Hijacking attackscan be done remotely without control over the intervening network Hijacking attacksnormally involve guessing the sequence numbers on packets and interjecting packetswith the right sequence number A vulnerability recently reported in the Linux TCP/IPstack allows hijacking without needing to guess the sequence number; this will probably
be fixed fairly quickly but many systems will still be running older kernels
Snooping (a.k.a sniffing or eavesdropping) on packets in transit is common This is ticularly common on ethernet segments where a compromised machine is used to snoopsome or all packets on the ethernet segment Every machine on a typical ethernet canintercept packets travelling between any two machines on that ethernet segment, includ-ing packets that are transiting the local network on their journey between two other net-works An attacker who has broken into your ISP’s Web server may be able to see everypacket that travels in and out of your Internet connection Hubs do nothing to protectagainst this Switches, bridges, routers, and firewalls reduce the vulnerability to snoopingand spoofing by reducing the network into smaller segments Many of these devices arenot designed with security in mind, however, and can be tricked to allow sniffing orspoofing; choose and configure your network hardware carefully
par-Particularly sensitive communications should require periodic re-validation, particularlybefore critical transactions such as those that would cause funds to be dispersed
Encryption is strongly recommended for sensitive communications
Any security sensitive internal communications should be behind a firewall Among otherchecks, the firewall should make sure that no outside host can spoof (masquerade as) anyinternal host, including localhost (127.0.0.1) This will make spoofing or hijacking ofinternal connections considerably more difficult but cannot protect connections whereone party is outside
Trang 6HTML Server Includes
If your Web server has the server include feature enabled, there are a number of securityimplications, depending on your server version and configuration An ordinary user onthe system (or anyone who can install Web pages) may be able to use server includes toread an otherwise restricted file Even worse, they may be able to execute arbitrary pro-grams on the machine Many CGI programs can be tricked into including server includetags in their output, which may be parsed by the server, allowing any remote user to dothe same things The server include tags may be included in form input, cookies, or theURL and may inadvertently be echoed by a CGI script
Preforked Server Issues
Preforked servers, where a server spawns a fixed number (or limited range depending onload) of child processes in advance to handle incoming connections, are very efficient buthave some special considerations The code that manages the number of child processesoften actually gives the server some protection against DOS attacks, which would causethe spawning of large numbers of processes Remote users will have as much or moretrouble getting through but the operation of the local machine is less likely to be disrupt-ed
Since preforked server processes often handle many different transactions, care must betaken to ensure that an attacker cannot influence the internal state in a way that couldaffect the processing of subsequent transactions You must also ensure that an attackercannot obtain information still stored in internal data structures about past transactions
Erasing data structures and the stack (use a recursive function that calls itself many timesand initializes a large automatic variable with zeros) will help Memory leaks will bemore of a problem in preforked servers and other long-lived processes
Timeouts
Any network client or server should have configurable timeouts with defaults appropriate
to the application In server processes, I normally set a timer using alarm()or
setitimer()at the beginning of each transaction The signal, if it arrives, must be dled appropriately In the event that a DOS attack is detected, it may be appropriate todramatically reduce the timeouts for the duration of the attack; this will adversely affectsome users but will probably improve service for most
Trang 7Three Factor Authentication
Authentication of users is normally based on one or more of the following three factors:biometric, knowledge, or possessions Biometric factors are things such as signatures,fingerprints, retina scans, and voice prints The second factor is based on something youknow, usually a secret password, key, or token The third is based on something you have
in your possession, such as a smart card, a ring, a credit card sized one time password ortime-based password generator, or a pregenerated list of challenge responses For highsecurity applications, it is advisable to use all three
There is an interesting device called the Biomouse, which is a small fingerprint reader Anewer version also includes a smart card reader in the same unit Linux drivers are avail-able
Many of these newfangled gadgets can be useful but they all have their limitations.Ignore all the sales hype that says they are invulnerable Smart cards should haveonboard encryption processors, not merely be memory-based devices Even then there is
an impressive array of technology available to attack smart cards (or any other integratedcircuit-based security device) Biometrics can be faked or recorded You leave thousands
of copies of your fingerprints every day that could be used to reconstruct your finger TheBiomouse senses pores as well as ridges, so a latent print may not be sufficient to recon-struct the necessary image but there can be other sources of that data, particularly fromthe biometric devices themselves The fingerprint scanner used by a merchant down thestreet when one of your employees cashed a check or the elevator button that is really aclandestine scanner may be the key to fooling your fingerprint scanners Voice prints can
be recorded The most common time-based token generator cards are based on oldundocumented algorithms that would not be likely to withstand a serious reverse engi-neering attack In extreme cases, biometric devices may be defeated by forcing an autho-rized user to allow access, or by very sophisticated mimicking devices The data fromthese gadgets may be vulnerable to interception on a compromised workstation or net-work These vulnerabilities are also a good reason to use two or three factor authentica-tion Gadgets can help to improve security, but beware of a false sense of security
Pluggable Authentication Modules
Linux has borrowed the Pluggable Authentication Module (PAM) concept from SunMicrosystems These separate out the authentication code from the application and put it
in some shared library modules, which may be configured as needed for various sites.PAM can be configured to use /etc/passwd, shadow passwords, one-time passwords,
Trang 8zero knowledge systems such as SRP, remote authentication servers, and biometric tems such as the Biomouse Other PAM modules check whether a user is on a local con-sole or a remote terminal Configuration files edited by the system manager instruct PAM
sys-on which modules to use for which applicatisys-ons and under which circumstances
Applications that use PAM need to be modified to use the PAM API and should to beprepared to act as the middleman for a more complicated dialog than simply asking for ausername and password The PAM guides are available online at
http://www.sics.se/~pelin/pam/and include a sample program
Changing passwords is supported by PAM but changing other fields in /etc/passwdand
/etc/shadowis not Use the putpwent()function or see the sample program inAppendix A, “A Symbol Table Library,” for an example of how to access the file directly
If you want your program to be portable to systems that do not have PAM, I suggestwriting a dummy PAM library that calls getpw()or getpwent()and crypt(), or tryporting libpwdbto the target system If you are not using PAM or libpwdb, you mayneed to deal with shadow passwords and NIS
General Program Robustness
It is important to write security sensitive programs to be as robust as possible Manysecurity exploits depend on the fact that programs behave in unexpected ways inresponse to unexpected circumstances
Check return values from functions Check errnoafter using functions that set errno
(such as some math functions) Make extensive use of assert()to verify assumptions
Functions that take pointers should do something sensible with NULL values Functionsthat take a size parameter, giving the size of a string parameter which will be modified,should handle a size of zero or even a negative size
Cryptography
This section will be brief and skimpy on the technical details due to export laws thatmake export of cryptographic hardware, software, or technical advice illegal, although abook is probably the safest way to export technical information on cryptography
Encryption is vital to safeguarding sensitive information, particularly in transit
Cryptography is used to ensure the privacy of information in transit or storage, cate users and messages, and prevent repudiation (denying that you originated a messagelater when it proves inconvenient)
Trang 9Small or large licenses for use of RSA’s encryption software, RSAref, in commercialsoftware (including the underlying algorithms) in clients and servers are obtained fromConsensus (http://www.consensus.com); there are some inconvenient terms regardingreverse engineering The cost per copy is significantly higher than the high volumelicenses available to large software companies, but this is probably the most viableoption for small software companies SSLeay (see the following section, “EncryptionSystems”) can be compiled to use RSAref If you want to use the various free applica-tions in a commercial environment, it is possible to obtain licenses to the RSA algorithmfor all free software on a given machine for price per machine; Informationon this can
be found at http://www.rsa.com
Types of Cryptographic Algorithms
Beware of any encryption system that relies on an unpublished algorithm These are ally extremely weak and might not even keep your kid sister out
usu-Hash functions provide one way (irreversible) encryption These are commonly used forpassword storage, to generate one time passwords, and as file signatures used to deter-mine whether a file has been altered Although you cannot decrypt a hashed password,you can encrypt passwords supplied by the user and compare the hash values Examples
of hash algorithms are MD5, MD2, MD4, SHA, Tiger, and RIPE-MD-160 Hash tions can also be turned into symmetric ciphers
func-Symmetric cipher algorithms use the same key to both encrypt and decrypt information.DES, 3DES, Blowfish, Twofish, RC4, and SAFER are examples of symmetric algo-rithms Some of these algorithms are limited to fixed key lengths; others allow variablekey lengths
One problem with symmetric algorithms is key distribution Both the sender and ent need to have the same secret key Asymmetric cipher algorithms use two separatekeys, one public and one private The public key can be made readily available A docu-ment encrypted with the public key can only be decrypted with the private key and viceversa Because these algorithms are normally much less efficient than symmetric sys-tems, asymmetric systems are normally used to exchange a unique secret session key,which is then used to encrypt the actual data stream using a symmetric algorithm.Asymmetric systems normally require much longer key lengths to achieve the same level
recipi-of security 1024 bits is commonly used for a symmetric system RSA, ElGamal, andLUC are public key (asymmetric) systems Elliptic curves are also used
Digital signatures use public key encryption and/or hashes to permit verifying the nator and/or content of a message and prevent repudiation of a message X.509 certifi-cates are essentially specially formatted and digitally signed binary documents that attest
Trang 10origi-to the identity of a person, company, or Web server The PGP encrypted mail systemrelies on key signatures, which are similar to certificates, to validate the association of aparticular public key with a particular person or organization Although certificates areusually issued by a central authority, key signatures are usually issued by specific indi-viduals and each user of PGP decides whose signatures to trust; this forms what isreferred to as a “web of trust”.
Cryptographically secure pseudo-random number generator algorithms are an importantpart of many encryption systems, particularly public key systems These are used formany purposes, including generating the unique session key, initially generating the pri-vate and public key pairs, and generating unique tokens for use a tokens for Web sites
RFC 1750 has recommendations for random number generators(ftp://ftp.isi.edu/in-notes/rfc1750.txt)
Zero knowledge systems can provide more security for user authentication without usingalgorithms that could encrypt data, and thus be subject to export controls Stanford’s SRP(Secure Remote Password) provides zero knowledge based password verification, which
is not vulnerable to eavesdropping Optionally, exchange of a session key for sessionencryption and a PAM module, and modified telnet and ftp programs are available Moreinformation is available at http://srp.stanford.edu/srp/
A more detailed overview of the different algorithms can be found on the Internet at
http://www.ssh.fi/tech/crypto/algorithms.html Bruce Schneier’s book Applied
Cryptography (2nd Edition, John Wiley & Sons, 1995) is the standard text in the field.
This book is actually exportable but the floppy containing the software included as ings in the book is not The cryptography FAQ, at http://www.cis.ohio-
list-state.edu/hypertext/faq/usenet/cryptography-faq/, has more additional tion, and most of the Web sites mentioned in this section will have links to other sites ofinterest
informa-Most ciphers are block oriented; they encrypt a block of some number of bits at a timeand the operation is repeated until the whole stream is encrypted Block chaining is fre-quently used so that the results of one block affect the operation of the next block Theblock length is often equal to the key length
Encryption Systems
The SSL algorithm is a public key based system introduced by Netscape and used toencrypt arbitrary TCP/IP data streams, and is widely used for encryption of Web pages
SSLeay is a very popular implementation of SSL It can be downloaded from
ftp://ftp.psy.uq.oz.au/pub/Crypto/and ftp://www.replay.com These Web sites
Trang 11also have some other cryptography software If you want to add encrypted TCP/IP munications to an application, check out SSLeay.
com-PGP, RIPEM, and GnuPG, CTC, S/MIME, and MOSS are public key based systems forsecure email Visit http://www.gnupg.org/for more information on GNU PrivacyGuard and http://www.bifroest.demon.co.uk/ctc/
SSH is a public key based replacement for the UNIX rshprogram SSH provides secureremote command execution, remote login, and remote copy Personal use and even somecommercial uses are free but a paid license is needed for many commercial uses Otherimplementations are available; see http://www.net.lut.ac.uk/psst/ If you are writ-ing a program that needs to invoke another program on another machine, SSH may suityour needs
IPSEC refers to a set of interoperable standards for packet encryption at the router level.SWAN (http://www.cygnus.com/~gnu/swan.html), NIST Cerberus
(http://www.antd.nist.gov/cerberus/), and the University of Arizona’s Linux IPSECimplementation (http://www.cs.arizona.edu/security/hpcc-blue/) are variousimplementations available for Linux
Encryption Vulnerabilities
Many algorithms are vulnerable to known plaintext and chosen plaintext attacks
Fortunately, most of the strong systems used today are resistant to these attacks
Even if the underlying cryptographic algorithm is impenetrable, various flaws in theapplication of that algorithm can introduce vulnerabilities The use of weak keys or weakrandom number sources (poor algorithm or poor seed) can cause problems Do not trustpublic key cryptography too much on systems that do not have a source of hardwareentropy for the random number generator Linux has /dev/random, to provide a source ofhardware entropy, derived from the timing of keyboard, mouse, interrupt, and disk accessevents When you disable unnecessary services on a Linux system, do not disable
/etc/rc.d/init.d/random, which saves state between reboots FreeBSD and OpenBSDalso have random devices but most other operating systems do not Accidentally givingaway the state of your random number generator by using it in other ways may simplifyattack, particularly with weaker random number generators
Breaking up data into small blocks encrypted separately can increase vulnerability inseveral ways This often interrupts the block chaining Padding may need to be used ifdata blocks are not an even multiple of the encryption block size It may be possible for
an attacker to insert blocks in the encrypted data stream The SSH version 1 protocolincluded a cryptographically weak CRC-32 hash (designed to protect against line noise,not sneaky people) to verify the integrity of each data block
Trang 12A buffer overflow in critical portions of the network handling code could provide a way
to compromise both the encrypted data streams and the computer system itself
Reusing the same key more than once is a problem on many commonly used symmetricciphers This is one reason that most public key systems exchange a unique session keyeach session for the faster symmetric algorithm used to encrypt the actual data, instead ofsaving the session key for future communications between the two parties Althoughmany public key systems will allow you to bypass the asymmetric algorithm and use thesymmetric algorithm using only a fixed secret key (which you have installed on both sys-tems), this should probably be avoided since many of the symmetric algorithms thesesystems use can be compromised by key reuse
Public key systems can be vulnerable to diverted connections, “man in the middle” and,
to a lesser extent, tcp hijacking attacks Since many public key systems exchange publickeys when they initiate a connection, there can be problems if you are talking to thewrong host or if an attacker is intercepting and modifying the data stream as it crossesthe Net; in these cases, the attacker can supply the wrong public key Using certificatesissued by a trusted authority for the machines at both ends of the connection or keeping apermanent record of known public keys between sessions can help
These are just some of the ways in which cryptosystems can be compromised Ratherthan attempt to provide an exhaustive list of vulnerabilities or detailed technical informa-tion, this section is intended to prompt the reader to think defensively and to conduct fur-ther research
Summary
Writing secure programs requires careful attention to detail and thinking defensively
You should also imagine yourself as an attacker and look for potentially exploitable vulnerabilities Using the information discussed in this chapter can help you spot theareas of your code that can provide the holes that people could exploit An independentcode review is recommended, as well as extensive testing in a non-mission critical environment
Trang 14I N T HIS C HAPTER
Trang 15As much as we all hate to admit it, software will have bugs This chapter describes one
of the Free Software Foundation’s premier tools,gdb, the GNU DeBugger While ging sessions will never be aggravation free,gdb’s advanced features lighten the load andenable you to be more productive Time and effort invested in learning gdbis time wellspent if you can track down and fix a serious bug in just a few minutes gdbcan makethis happen
As you learned in Chapter 3, “GNU cc,” debugging requires that your source code becompiled with -gin order to create an enhanced symbol table So, the following com-mand:
$ gcc -g file1.c file2.c -o prog
will cause progto be created with debugging symbols in its symbol table If you want,you can use gcc’s -ggdboption to generate still more (gdb-specific) debugging informa-tion However, to work most effectively, this option requires that you have access to thesource code for every library against which you link While this can be very useful incertain situations, it can also be expensive in terms of disk space In most cases, howev-
er, you should be able to get by with the plain -goption
As also noted in Chapter 3, it is possible to use both the -g and -O(optimization)options However, because optimization changes the resulting program, the relationshipyou expect to exist between the code you wrote and the executing binary may not exist.Variables or lines of code may have disappeared or variable assignments may occur attimes when you do not expect it My recommendation is that you wait until you havedebugged your code as completely as possible before starting to optimize it In the longrun, it will make your life, especially the parts of it you spend debugging, much simplerand less stressful
Do not strip your binaries if you distribute programs in binary form It is a ter of courtesy to your users and may even help you If you get a bug report from a user who obtained a binary-only version, she will be unable to provide helpful information if you used strip to discard all symbols from the binary in
mat-order to make the binary smaller Although she might be willing to download a
source distribution in order to recompile with debugging enabled, it would be presumptuous of you to ask.
Trang 16Using Basic gdb Commands
Most of what you will need to accomplish with gdbcan be done with a surprisinglysmall set of commands This section shows you just enough gdbcommands to get yougoing A later section, “Advanced gdbConcepts and Commands,” will cover a fewadvanced features that will come in handy
To start a debugging session, simply type gdb progname [corefile], replacing namewith the name of the program you want to debug Using a core file is optional, butwill enhance gdb’s debugging capabilities For this chapter, we will use Listing 36.1 towork through examples
Trang 17I tried to run it by typing ./debugme, and it immediately caused a segmentation fault anddumped core (on Red Hat 5.2).
The first step is to start gdb, using the program name,debugme, and the core file,core, asarguments:
$ gdb debugme core
The screen should resemble Figure 36.1 after gdbinitializes
F IGURE 36.1
The gdbstart-up screen.
If you don’t like the licensing messages (they annoy me), use the -q(or —quiet) option
to suppress them Another useful command-line option is -d dirname, where dirnameisthe name of a directory, to tell gdbwhere to find source code (it looks in the currentworking directory by default) As you can see from the figure,gdbreports the executablethat created the core file and why the program terminated In this case, the programcaused a signal 11, which is a segmentation fault It also helpfully displays the function
it was executing and the line it believes caused the fault (line 25)
The first thing you would want to do is run the program in the debugger The command
to do this is run You can pass any arguments to the runcommand that your programwould ordinarily accept In addition, the program will receive a properly set up shellenvironment as determined by the value of the environment variable $SHELL If youwant, however, you can use gdbcommands to set or unset arguments and environmentvariables after you have started a debugging session To do so, type set args arg1 arg2to set command-line arguments and set environment env1 env2to set environ-ment variables
Trang 18Attempting to run the program in the debugger, it stops after receiving the SIGSEGV
signal:
(gdb) run Starting program: /home/kwall/projects/lpu/36/src/debugme Program received signal SIGSEGV, Segmentation fault.
0x804848e in index_to_the_moon (ary=0xbffffa08) at debugme.c:25
25 ary[i] = i;
(gdb)
Inspecting Code in the Debugger
The question, though, is what was happening in the function index_to_the_moon? Youcan execute the backtracecommand to generate the function tree that led to the segfault The function trace looks like the following:
(gdb) backtrace
#0 0x804848e in index_to_the_moon (ary=0xbffffa08) at debugme.c:25
#1 0x804844f in main () at debugme.c:16
#2 0xb in ?? () (gdb)
documentation, and an excellent manual, Debugging With GDB, which is
avail-able online and by mail order from the FSF.
It is not necessary to type complete command names while using gdb Any abbreviation that is unique will do For example, back will suffice for backtrace
So, the problem was, indeed, in index_to_the_moon(), which was called from the
main()function It would be helpful, however, to have some idea of the context in which
Trang 19the offending line(s) of code exist For this purpose, use the listcommand, which takesthe general form,list [m,n] mand nare the starting and ending line numbers you wantdisplayed Just a bare listcommand will display ten lines of surrounding code, as illus-trated in the following:
(gdb) list 20
21 void index_to_the_moon(int ary[])
With a clear picture of what is happening in the code, you can then decide what has gonewrong
Examining Data
One of gdb’s most useful features is the capability to display both the type and the value
of almost any expression, variable, or array in a program being debugged It will printthe value of any expression legal in the language in which your program is written Thecommand is, predictably enough,print The following are some printcommands andtheir results:
(gdb) print i
$1 = 382 (gdb) print ary[i]
Cannot access memory at address 0xc0000000.
(gdb) print $1-1
$4 = 381
Trang 20You are not limited to using discrete values, because gdbcan display the values of anarbitrary region of memory To print the first memory locations associated with ary, usethe following command:
(gdb) print ary@10
$5 = {0xbffffa08, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8
The notation @10means to print the 10 values that begin at ary Say, on the other hand,that you want to print the five values stored in arybeginning with the 71st element Thecommand for this would be the following:
gdblooked at ary, saw that it was the address of the array’s base, and displayed it andthe following nine values as memory addresses Memory addresses are customarily dis-played in hexadecimal If you want to display the first ten values stored in ary, use theindexing operator, [], with the index of the first value, 0, as illustrated:
gdbalso can tell you the types of variables using the whatiscommand:
(gdb) whatis i type = int (gdb) whatis ary type = int * (gdb) whatis index_to_the_moon type = void (int *)
Trang 21This feature may seem rather useless because, of course, you know the types of all thevariables in your program (yeah, right!) But, you will change your mind the first timeyou have to debug someone else’s code or have to fix a multi-file project and have notlooked at one of the source files for a couple of months.
Setting Breakpoints
As you debug problematic code, it is often useful to halt execution at some point gdb
allows you to set breakpoints on several different kinds of code constructs, including linenumbers and function names, and also enables you to set conditional breakpoints, wherethe code only stops if a certain condition is met
To set a breakpoint on a line number, use the following syntax:
(gdb) break <filename:linenum>
(gdb) break <filename:funcname>
Conditional breakpoints are usually more useful They allow you temporarily to halt gram execution if a particular condition is met The correct syntax for setting conditionalbreakpoints is:
pro-(gdb) break <linenum or funcname> if <expr>
exprcan be any expression that evaluates to true (non-zero) For example, the followingbreak command stops execution at line 25 of debugmewhen the variable iequals 15:
(gdb) break 25 if i == 15 Breakpoint 1 at 0x804847c: file debugme.c, line 24.
(gdb) run Starting program: /home/kwall/projects/lpu/36/src/debugme Breakpoint 1, index_to_the_moon (ary=0xbffffa08) at debugme.c:25
25 ary[i] = i;
(gdb)
Trang 22As you can see,gdbstopped on line 25 A quick printcommand confirms that itstopped at the value of iwe requested:
delete command allows you to delete breakpoints, or you can merely disablethem
Figure 36.2 illustrates the output of the following commands:
(gdb) info breakpoints (gdb) delete 3
(gdb) disable 4 (gdb) info breakpoints
sophisti-In Figure 36.2, I used the infocommand to obtain a list of available breakpoints,
delet-ed the third breakpoint, disabldelet-ed the fourth, and then rdelet-edisplaydelet-ed breakpoint information
It probably will not surprise you that the command to re-enable a disabled breakpoint is
enable N, where Nis the breakpoint number
Examining and Changing Running Code
You have already seen the printand whatiscommands, so we will not rehash themhere, except to point out that if you use the printcommand to display the value of anexpression, and that expression modifies variables the program uses, you are changingvalues in a running program This is not necessarily a bad thing, but you do need tounderstand that what you are doing has side effects
Trang 23One of the whatiscommand’s shortcomings is that it only gives you the type of a able or function If you have a structure, such as the following:
vari-struct s { int index;
char *name;
} *S;
and type
(gdb) whatis S gdbreports only the name of the structure
type = struct s *
If you want the structure’s definition, use the ptypecommand as follows:
(gdb) ptype S type = struct s { int index;
char *name;
} *
If you want to change the value of a variable (keeping in mind that this change willaffect the running code), the gdbcommand is:
(gdb) set variable varname = value
where varnameis the variable you want to change and valueis varname’s new value.Returning to Listing 36.1, use the deletecommand to delete all the breakpoints andwatchpoints you may have set, and then set the following breakpoint:
loop Besides demonstrating that you can alter a running program, these steps also trate how to single-step through a program Thestepcommand executes a program onestatement at a time
Trang 24illus-The nextcommand, on the other hand, executes an entire function when it encountersone, while the stepcommand would only “step” into the function and continue execu-tion one statement at a time.
The final method for examining a running program I will discuss is calling functions,using the call,finish, and returncommands Table 36.1 lists the syntax and function
Trang 25Advanced gdb Concepts and Commands
This section discusses a few complicated concepts and some sophisticated commandsthat will make your gdbusage more productive and less frustrating The concepts include
gdb’s notions of variable scope and variable context The commands include traversingthe call stack, working with source files, the shellcommand, and attaching to an exist-ing process
Variable Scope and Context
At any given time,gdbconsiders a variable either active or inactive, which affects thevariables to which you have access and can examine and manipulate You cannot accessvariables that are not “in context” or are inactive There are a few rules that define whatconstitutes an active or in context variable
• Local variables in any function are active if that function is running or if controlhas passed to a function called by the controlling function Say the function foo()
calls the function bar(); as long as bar()is executing, all variables local to foo()
and bar()are active Once bar()has returned, only local variables in foo()areactive, and thus accessible
• Global variables are always active, regardless of whether the program is running
• Nonglobal variables are inactive unless the program is running
So much for variable context What is gdb’s notion of variable context? The complicationarises from the use of static variables, which are file local, that is, you can have identical-
ly named static variables in several files, and they will not conflict because they are notvisible outside the file in which they are defined Fortunately,gdbhas a way to identify
to which variable you are referring It resembles C++’s scope resolution operator Thesyntax is
file_or_funcname::varname
where varnameis the name of the variable to which you want to refer and
file_or_funcnameis the name of the file or the function in which it appears So, forexample, given two source code files,foo.cand bar.c, each containing a variablenamed baz, that is declared static, to refer to the one in foo.cyou might write the fol-lowing:
(gdb) print ‘foo.c’::baz
Trang 26The single quotes around the filename are required so that gdbknows you are referring
to a filename Similarly, given two functions,blat()and splat(), each with an integervariable named idx, the following commands would print the addresses of idxin eachfunction:
(gdb) print &blat::idx (gdb) print &splat::idx
Traversing the Call Stack
gdbprovides two commands for moving up and down the call stack, which is the chain
of function calls that got you to the current location in the code Imagine a program inwhich the main()function calls the function make_key(), which in turn calls the func-tion get_key_num() The function get_key_num()in turn calls number() Listing 36.2shows a dummy program illustrating this
1 /*
2 * Listing 36.2
3 * callstk.c - A complicated calling chain to illustrate
4 * traversing the call stack with gdb
15 int ret = make_key();
16 fprintf(stdout, “make_key returns %d\n”, ret);
Trang 27and then run the program with the runcommand It stops at line 32 Next, type the mandwhere, which prints the following (the hexadecimal addresses will almost certainly
The display shows the call chain in reverse order; that is, that number()(#0) was called
by make_key()(#1), which in turn had been called by the main()function The upmand moves up the call stack one function call, placing you on line 22 The downcom-mand moves control back the number()function Executing the stepcommand threetimes moves you back or up the get_key_num()function, at which point you could printthe value of the variable retto see its value Figure 36.3 illustrates the results of thecommand sequence just described
Trang 28control will prove invaluable to you as you hone your debugging skills and track downintractable bugs buried deep inside a chain of function calls.
Working with Source Files
Locating a specific function in a multi-file project is a breeze with gdb, provided you usethe -dswitch, mentioned in the section “Starting gdb”, to tell it where to find additionalsource code files This is a particularly helpful option when all of your source code is notlocated in your current working directory or in the program’s compilation directory(which is recorded in its symbol table) To specify one or more additional directories,start gdbusing one or more -d <dirname>options, as illustrated in the following:
$ gdb -d /source/project1 -d /oldsource/project1 -d
➥/home/gomer/src killerapp
To locate the next occurrence of a particular stringin the current file, use thesearch
<string>command Usereverse-search <string>to find the previous occurrence
Returning to Listing 36.2 for a moment, suppose the program has stopped at the point you set in the previous example, line 32 If you want to find the previous occur-rence of the word “return,” use the following command:
break-(gdb) reverse-search return gdbobliges and displays the text listed below:
(gdb) reverse-search return
29 return ret;
Using the searchand reverse-searchcommands is especially helpful in large sourcefiles that have dozens or hundreds of lines
Communicating with the Shell
While running a debugging session, you will often need to execute commands at theshell’s command prompt gdbprovides the shellcommand to enable you to do so with-out leaving gdb The syntax for this command is
Trang 29Attaching to a running process automatically halts it so you can inspect its status usingthe normal gdbcommands When you are done, simply type quit, which will detachfrom the running process and allow it to continue If gdbis already running, you can usethe attachandfilecommands to obtain access to the program First, use the filecom-mand to specify the program running in the process and to load its symbol table, as inthe following:
(gdb) file httpd Reading symbols from httpd (no debugging
➥symbols found) done.
(gdb) attach 386 Attaching to program `/usr/sbin/httpd’, Pid 386 Reading symbols from /lib/libm.so.6 done.
Reading symbols from /lib/libcrypt.so.1 done.
Reading symbols from /lib/libdb.so.2 done.
Reading symbols from /lib/libdl.so.2 done.
Reading symbols from /lib/libc.so.6 done.
Reading symbols from /lib/ld-linux.so.2 done.
Attaching to a Running Program
The final advanced procedure I will discuss is how to use gdbto attach to a runningprocess, such as a system daemon The procedure to accomplish this is very similar tostarting gdb, except that the second argument to gdbis the PID (process ID) of the exe-cutable to which you want to attach, rather than the name of the core file gdbwill com-plain that it cannot find a file named PID, but you can safely ignore this because gdb
always checks for a file first to see if there is a core file available Figure 36.4 is a cated display of U’s attempt to attach to the httpdserver daemon running on my system
Trang 30trun-As you can see from this example,attachexpects a process ID as its argument, thenproceeds to load symbols from the various libraries against which the attached programhas been linked Again, when you have completed examining the attached process, issuethedetachcommand to allow it to continue executing.
Summary
This chapter has only scratched the surface of gdb’s capabilities A full exposition ofwhat it can do would require several hundred pages As stated at the beginning of thischapter, the more time you invest in learning gdb, the more benefit you will derive fromyour debugging sessions In this chapter, you have learned how to start gdb, have seenthe basic commands required for the simplest usage, and have used some of its moreadvanced features gdbis your friend—learn to exploit it
Trang 34I N T HIS C HAPTER
by Kurt Wall
Trang 35The topic of package management, which is the creation, distribution, installation, andupgrade of software, particularly source code, usually gets no attention in programmingsurvey books such as this one This unfortunate oversight is remedied in this chapter,which looks at the GNU project’s tarand installutilities and Red Hat’s Red HatPackage Manager, RPM.
The previous thirty-six chapters focused on hacking code and on tools and utilities thatease the hacker’s endeavor However, the fastest, coolest code in the world will becomeshelfware if it is extraordinarily difficult to install or renders a user’s system useless aftershe installs it The same applies to upgrading existing software For many years, the FreeSoftware Foundation’s tarand installutilities were the de facto standard for distribut-
ing software, either in source or binary form They worked (and still work) well, if youunderstood their limitations, particularly with respect to version and dependency check-ing Red Hat’s RPM system addresses these and other warts of tarand install, and,properly used by hacker and end user alike, make software distribution a breeze
tar, which stands for Tape ARchiver, creates, manages, and extracts multi-file archives,known as “tarfiles,” or, more affectionately and idiomatically, “tarballs.”taris the tradi-tional utility used to create archives, along with cpio, which is not covered A completedescription of tarreaches well beyond this book’s scope, so this chapter focuses on typi-cal and simple usage as related to the creation and management of software distribution
It is also assumed that the user downloading your code knows how to unpack a tarballand view a README file that explains the idiosyncrasies of installing your software.Table 37.1 discusses tar’s command-line options, which the following sections discuss
in more detail
f archive_name Name the archive archive_name
r Append files to the archive
u Update existing files in the archive
t List the contents of the archive
v Generate verbose output
z Create or work with a compressed archive (gzip is the
default compression utility)
Trang 36Creating tar Files
In its simplest form, the command to create a tarball is
$ tar cf {archive_name} {file_Spec}
csays to “create” a tarball from the file(s) indicated by file_spec fsays to name thetarball archive_name You will generally want to compress the tarball to save disk spaceand download time The easiest way to do so, using GNU’s tar, is to add zto the optionlist, which causes tarto invoke another GNU utility,gzip, on the tarball to compress it,
as in the following:
$ tar czf {archive_name} {file_spec}
To illustrate, the CD-ROM that accompanies this book contains the source files used tobuild the tarutility itself (version 1.12, to be precise) First, create a tarball (you willneed to copy the contents of the file from the source code directory on the CD-ROM,
/source/37, to your hard disk):
$ tar cf tar.tar *
We use the standard wildcard (*) to request that all files and directories in the currentdirectory be stored in the tarball A quick lscommand shows that none of the sourcefiles were removed, but that a new file, named, as requested,tar.tar, was created:
total 3683 -rw-r r 1 kwall users 11451 Apr 19 1997 ABOUT-NLS -rw-r r 1 kwall users 1040 Apr 19 1997 AC-PATCHES -rw-r r 1 kwall users 9656 Apr 23 1997 AM-PATCHES -rw-r r 1 kwall users 732 Apr 18 1997 AUTHORS
drwxr-xr-x 2 kwall users 1024 Apr 25 1997 src -rw-r r 1 kwall users 10 Apr 25 1997 stamp-h.in -rw-r r 1 kwall users 3256320 May 3 22:54 tar.tar drwxr-xr-x 2 kwall users 1024 Apr 25 1997 tests
As you can see, the tarball is quite large You can either run gzipon the file separately,
or use tar’s zoption to reduce the file size and, thus, the download time:
$ tar czf tar.tar.gz *
$ ls -l tar.tar.gz -rw-r r 1 kwall users 2590545 May 3 23:42 tar.tar.gz
$ gzip tar.tar
$ ls -l tar.tar.gz -rw-r r 1 kwall users 1712020 May 3 23:41 tar.tar.gz
The compression option slows down tar’s operation somewhat, but saves typing On theother hand, calling gzipdirectly results in much better compression, but you have to type an additional command to prepare your package for distribution Hackers being lazycritters,Makefiles usually include a target such as distthat creates a gzipped tarball
Trang 37This reduces the amount of typing you’ll have to do and is also a convenience: simplytype make distand your package is ready to upload for the rest of the world to down-load.
So, now you have a nicely packaged and compressed tarball But, suddenly, you realize
you neglected to include the documentation You did write documentation, didn’t you?
Never fear, you can easily add new files to (or update existing files in) the tarball using
tar’s append or update options
To append your newly written documentation to the compressed tarball we created a fewsentences ago, execute
$ tar rfz tar.tar.gz *.doc
(which assumes that the files you want to append all have a .docextension) The r
instructs tarto append the specified files to the end of the tarball If, similarly, you ified some files already present in the archive and want to update the tarball with themodified files, use tar’s update option (u):
mod-$ tar uzf tar.tar.gz {updated_file_spec}
where updated_file_specindicates the files that have changed
Finally, if you lose track of what files your tarball contains, or their dates, you can listthe files in an archive using, predictably, the list option (t):
$ tar tzvf tar.tar.gz
We have added GNU’s standard option for verbose output,v Executing this commandproduces the following listing (truncated for brevity’s sake):
-rw-r r kwall/users 3246080 1999-05-03 23:48 ABOUT-NLS -rw-r r kwall/users 1040 1997-04-19 13:35 AC-PATCHES -rw-r r kwall/users 9656 1997-04-23 07:15 AM-PATCHES -rw-r r kwall/users 732 1997-04-18 13:32 AUTHORS -rw-r r kwall/users 85570 1997-04-25 18:21 BACKLOG -rw-r r kwall/users 2545 1997-04-24 06:16 BI-PATCHES -rw-r r kwall/users 17996 1996-03-24 11:49 COPYING
-rw-r r kwall/users 63 1997-04-25 14:05 doc/version.texi -rw-r r kwall/users 354244 1997-04-24 07:19 doc/tar.texi -rwxr-xr-x kwall/users 1961 1997-03-18 13:14 doc/convtexi.pl -rw-r r kwall/users 18106 1997-02-02 09:55 doc/getdate.texi -rw-r r kwall/users 9241 1997-04-15 16:28 doc/header.texi
Trang 38Understanding the install
Command
Considerinstalla cpcommand on steroids In addition to copying files, it sets theirpermissions and, if possible, their owner and group It can also create destination directo-ries if they do not already exist installis usually used in Makefiles as part of a rulefor a target named (something like) “install.” It can also be used in shell scripts
install’s general syntax is
$ install [option[ ]] source[ ] dest
where sourceis one or more files to copy and destis either the name of the target file
or, if multiple files are specified in source, a directory optioncan be one or more ues listed in Table 37.2
Option Argument Description
-g group Set the group ownership on file(s) to the GID or group
name specified in group The default GID is that of the ent process calling install
par o owner Set the ownership of file(s) to the UID or user name
speci-fied in owner The default owner is root.
-m mode Set the file mode (permissions) to the octal or symbolic
value specified in mode The default file mode is 755, or read/write/execute for owner and read/execute for group and other.
To specify destas a directory, use the following syntax:
$ install -d [option [ ]] dir[ ]
The -dswitch instructs installto create the directory dir, including any parent ries necessary, using any of the attributes listed in Table 37.2 or the default attributes
directo-In our first example, taken from the Makefilefor gdbm, the GNU database library, afterexpanding some of the makevariables, the “install” target is:
1 install: libgdbm.a gdbm.h gdbm.info
2 install -c -m 644 libgdbm.a $(libdir)/libgdbm.a
Trang 39The makevariables libdir,includedir,srcdir, and infodirare, respectively,
/usr/lib,/usr/include,/usr/src/build/info, and /usr/info So,libgdbm.aand
gdbm.hwill be read/write for the root user and read-only for everyone else The file
libgdbm.agets copied to /usr/lib; gdbm.h, the header, winds up in /usr/include TheTexinfo file,gdbm.info, gets copied from /usr/src/build/infoto
/usr/info/gdbm.info installoverwrites existing files of the same name The -c
option is included for compatibility with older versions of installon other UNIX sions You should include this, but, in most cases, it will be ignored
Under Linux, install silently ignores -c ; it has no effect.
Our second and final example, Listing 37.1, creates a set of directories under /tmpandsets some odd file modes on the files installed to demonstrate installfeatures the firstexample did not cover It is available as a shell script on the CD-ROM Unless you havepeculiar permissions on /tmp, it should execute without incident The script uses some ofthe files from the tarsource distribution on the CD-ROM Feel free to delete the entire
/tmp/lpu-installdirectory after it completes and you have inspected its contents
10 for DIR in 10 20 30
11 do
12 $INSTALL -c -d -o $USER $LPU/$DIR
13 $INSTALL -c -m 111 -o $USER $SRC/*.c $LPU/$DIR
14 done 15
16 if [ $USER = root ]; then
17 for GRP in $(cut -f1 -d: /etc/group)
18 do
19 $INSTALL -c -d -o $USER -g $GRP $LPU/$GRP
20 $INSTALL -c -m 400 -g $GRP *.el $LPU/$GRP
21 done
22 fi
Trang 40If the syntax of the shell script confuses you, re-read Chapter 34, “Shell Programmingwith GNU bash.” Or, skip it, since our interest here is install’s behavior (lines 12 and
13 and 19 and 20) Note, however, that the second code block (lines 16[nd]21) will fail ifnot run by the root user Line 12 creates three directories rooted in /tmp:
/tmp/lpu-install/10,/tmp/lpu-install/20, and /tmp/lpu-install/30 Line 13copies all of the C code files from the ./srcsubdirectory of the current working directo-
ry to each of these three subdirectories We use the -ooption to set user ownership,repetitive in this case because the default owner would be that of the user executing thescript
The second code block creates a set of directories named after each of the groups defined
on your system Each directory is owned by the default user, but the group name is thesame as the directory name (line 19) Line 20 copies any elispfiles in the current work-ing directory to the appropriate directory, again setting the group ownership to the direc-tory name and making the files read-only for the owner/user No other users or groupshave any privileges to the file This usage of installis strange, but nevertheless illus-trates why we consider install“a better cp” command
Understanding the Red Hat Package Manager (RPM)
The Red Hat Package Manager, although it bears Red Hat’s name, is a powerful, general,and open software packaging system used in Caldera’s OpenLinux, S.u.S.E.’s distribu-tion, and, of course, Red Hat Linux It is most frequently used for Linux, but versions of
it are available for many UNIX versions, including Solaris, SunOS, HP-UX, SCO, AIX,and Digital UNIX The discussion of RPM in this book focuses on creating source code
packages; Ed Bailey’s excellent book, Maximum RPM, covers mundane issues such as
installing, upgrading, and removing RPMs, as well as its uses by package creators andmaintainers Point your browser at http://www.rpm.org/for the latest version, completedocumentation, FAQs and HOWTOs, and a downloadable version of the book (but,regarding the book, you are strongly encouraged to purchase it and reward both authorand publisher for making it freely available)
Minimum Requirements
To create RPMs, you need RPM itself, the source code you want to compile, an rpmrc
file to set some RPM defaults and control its behavior, and a specfile to control thepackage build process It is assumed you have an otherwise functional development envi-ronment (compilers, tools, editors, cold pizza, Jolt cola, coffee, and such) and that yoursource code compiles successfully