转自 : http://www.linuxjournal.com/article/5737
A common topic of discussion nowadays issecurity, and for good reason. Security is becoming more importantas the world becomes further networked. Like all good systems,Linux is evolving in order to address increasingly importantsecurity concerns.
One aspect of security is user privileges. UNIX-style userprivileges come in two varieties, user and root. Regular users areabsolutely powerless; they cannot modify any processes or files buttheir own. Access to hardware and most network specifications alsoare denied. Root, on the other hand, can do anything from modifyingall processes and files to having unrestricted network and hardwareaccess. In some cases root can even physically damagehardware.
Sometimes a middle ground is desired. A utility needs specialprivileges to perform its function, but unquestionable god-likeroot access is overkill. The ping utility is setuid root simply soit can send and receive ICMP messages. The danger lies in the factthat ping can be exploited before it has dropped its rootprivileges, giving the attacker root access to your server.
Fortunately, such a middle ground now exists, and it's calledPOSIX capabilities. Capabilities divide system access into logicalgroups that may be individually granted to, or removed from,different processes. Capabilities allow system administrators tofine-tune what a process is allowed to do, which may help themsignificantly reduce security risks to their system. The best partis that your system already supports it. If you're lucky, nopatching should be necessary.
A list of all the capabilities that your system is, well,capable of, is available in /usr/include/linux/capability.h,starting with CAP_CHOWN. They're pretty self-explanatory and wellcommented. Capability checks are sprinkled throughout the kernelsource, and grepping for them can make for some fun midnightreading.
Each capability is nothing more than a bit in a bitmap. With32 bits in a capability set, and 28 sets currently defined, thereare currently discussions as to how to expand this number. Somepurists believe that additional capabilities would be tooconfusing, while others argue that there should be many more, evena capability for each system call. Time and Linus will ultimatelydecide how this exciting feature develops.
As of kernel 2.4.17, the file /proc/sys/kernel/cap-boundcontains a single 32-bit integer that defines the current globalcapability set. The global capability set determines what everyprocess on the system is allowed to do. If a capability is strippedfrom the system, it is impossible for any process, even rootprocesses, to regain them.
For example, many crackers' rootkits (a set of tools thatcover up their activities and install backdoors into the system)will load kernel modules that hide illicit processes and files fromthe system administrator. To counter this, the administrator couldsimply remove the CAP_SYS_MODULE capability from the system as thelast step in the system startup process. This step would preventany kernel modules from being loaded or unloaded. Once a capabilityhas been removed, it cannot be re-added. The system must berestarted (which means you might have to use the power button ifyou've removed the CAP_SYS_BOOT capability) to regain thefull-capability set.
Okay, I lied. There are two ways to add back acapability:
init can re-add capabilities, in theory; there's noactual implementation to my knowledge. This is to facilitatecapability-aware systems in the event that init needs to changerunlevels.
If a process is capable of CAP_SYS_RAWIO, it canmodify kernel memory through /dev/mem. Among other things, it canmodify kernel memory to grant itself whatever access it desires.Remove CAP_SYS_RAWIO, but be careful: by removing CAP_SYS_RAWIO,programs such as X most likely will fail to run.
Editing cap-bound by hand is kind of tedious. Fortunately foryou, there's a utility called lcap that provides a friendlierinterface to cap-bound. Here's how one would remove CAP_SYS_CHOWN:
lcap CAP_SYS_CHOWNOnce done, it becomes impossible to change a file's owner:
chown nobody test.txt chown: changing ownership of `test.txt': Operation not permittedHere's how you would remove all capabilities except CAP_SYS_BOOT,CAP_SYS_KILL and CAP_SYS_NICE:
lcap -z CAP_SYS_BOOT CAP_SYS_KILL CAP_SYS_NICEOne thing to note: modifying cap-bound restricts the capabilitiesof future processes only. Okay, not exactly future processes butany process that calls exec(2) (see the function compute_creds inthe kernel source file fs/exec.c). Currently running processes keepthe capabilities with which they started.
Modifying the capabilities of an existing process leads usinto the next section, and here's the catch I spoke about above.Running lcap with no arguments lists what your system is capableof. If you see that CAP_SETPCAP is disabled, you need to make achange to your kernel. It's simple enough to describe here. In thekernel source tree, edit include/linux/capability.h. You'rechanging the lines:
#define CAP_INIT_EFF_SET to_cap_t(~0 & ~CAP_TO_MASK(CAP_SETPCAP)) #define CAP_INIT_INH_SET to_cap_t(0)
so that they read:
#define CAP_INIT_EFF_SET to_cap_t(~0) #define CAP_INIT_INH_SET to_cap_t(~0)and then recompile.
There's actually a reason that CAP_SETPCAP is disabled bydefault: it's deemed a security risk to leave it enabled on aproduction system (a patch exists for this condition but has yet tobe applied as of this writing). To be on the safe side, make sureto remove this capability when you're done playing.
As of this writing, the syscalls capset and capget manipulatecapabilities for a process. There are no guarantees that thisinterface won't change. Portable applications are encouraged to uselibcap(www.kernel.org/pub/linux/libs/security/linux-privs/kernel-2.4)instead.
The prototype for capset is
int capset(cap_user_header_t header, const cap_user_data_t data);
HEADER is a fancy way to say which pid you're operating on:
typedef struct __user_cap_header_struct { __u32 version; int pid; } *cap_user_header_t;If pid is -1, you will modify the capabilities of all currentlyrunning processes. Less than -1 and you modify the process groupequal to pid times -1. The semantics are similar to those ofkill(2).
The DATA argument allows you to choose which capability setsyou plan to modify. There are three:
typedef struct __user_cap_data_struct { __u32 effective; __u32 permitted; __u32 inheritable; } *cap_user_data_t;
The permitted set contains all of the capabilities that aprocess is ultimately capable of realizing.
The effective set is the capabilities a process has electedto utilize from its permitted set. It's as if you had a hugearsenal of poetry (permitted set) but chose only to arm yourselfwith Allen Ginsberg for the task at hand (effective set).
The inheritable set defines which capabilities may be passedon to any programs that replace the current process image viaexec(2). Please note that fork(2) does nothing special withcapabilities. The child simply receives an exact copy of all threecapabilities sets.
Only capabilities in the permitted set can be added to theeffective or inheritable set. Capabilities cannot be added to thepermitted set of a process unless CAP_SETPCAP is set.
Sadly, capabilities still lack filesystem support, limitingtheir usefulness to a degree. Someday, the mainstream kernels willallow you to enable capabilities in a program's inode, obviatingthe setuid bit in many system utilities.
Once fully supported, permitting the ping utility to open rawsockets could be as simple as:
chattr +CAP_NET_RAW /bin/ping
Unfortunately, more pressing kernel issues have delayed workin this area.
If you're so inclined, you can use libcap to hack yourfavorite services so that they are capability-aware and drop theprivileges they no longer need at startup. Several patches existfor xntpd that do just this; some even provide their modifiedversion as an RPM. Try a Google search if you're interested in acapability-aware version of some root-level process you findyourself often shaking a fist at.
setpcap can be used tomodify the capability set of an existing process. For example, ifthe PID of a regular user's shell is 4235, here's how you can givethat user's shell the ability to send signals to anyprocess:
setpcaps 'cap_kill=ep' 4235
An example use of this would be to allow a friend who isusing your machine to debug a CGI script to kill any Apacheprocesses that get stuck in infinite loops. You'd run it againsttheir login shell once and forget about them.
Here's an example that utilizes execcap and sucap to run pingas the user “nobody”, with only the CAP_NET_RAW capability. Ourtarget of choice for ping iswww.yahoo.com:
execcap 'cap_net_raw=ep' /sbin/sucap nobody nobody /bin/ping www.yahoo.com
This sample isn't terribly useful because you need to be rootto execute it, but it does illustrate what is possible. Despitesome of these shortcomings, system administrators still can takemeasures to increase the security of their system. A system withoutCAP_SYS_BOOT, CAP_SYS_RAWIO and CAP_SYS_MODULE is extremelydifficult for an intruder to modify. They cannot hack kernelmemory, install new modules or restart the system so that it runs abackdoored kernel.
If your system logs are append-only and your core systemutilities immutable (see chattr(3) for details), removing theCAP_LINUX_IMMUTABLE capability will make it virtually impossiblefor intruders to erase their tracks or install compromisedutilities. Traffic sniffers like tcpdump become unusable onceCAP_NET_RAW is removed. Remove CAP_SYS_PTRACE and you've turned offprogram debugging. Such a hostile environment is a script kiddy'sworst nightmare, and there is no choice but to disconnect and waitfor the intrusion to be discovered.
Conclusion
Capabilities can provide sophisticated, fine-grained accesscontrol over all aspects of a Linux system. At last, securityparanoids will have some tools they so desperately need in theirendless fight against “them”.