Implementing ACLs in Linux

advertisement
Jesse Dyer
Dennis Lu
Erik Welsh
Comp 527 – Fall 2001
Implementing ACLs in Linux
Introduction
Our project is an attempt to add Access Control Lists (ACLs) to the Linux
operating system. Unix natively has a basic file protection scheme based on the concept
of user/owner, group and other. Every file has a single owner and a single group
associated with it. The owner of the file controls the permissions on it, and can dictate
what group of people can access it, assuming they too are in that group of people, and
what kind of operations the rest of the world can perform on it. Users cannot arbitrarily
create groups; this is dictated by the contents of the /etc/passwd and /etc/group file. These
basic protections work well under most circumstances, but they have their drawbacks. As
users cannot create groups, it often becomes an all-or-nothing situation with permissions
on files and directories. If I want to give my friend Alice access to a file I own, and only
Alice, there is no way I can do it with basic permissions, unless a group exists that only
the two of us are in. From the administration perspective, a similar headache exists. A
company that has separate groups of administrators, all of whom have some
administrative duties on various machines, either has to create several groups, which can
get awkward and confusing, or turn to ACLs. ACLs, in a nutshell, are a set of attributes
on a file that specifies what specific users, or groups of users, can do to a file or directory.
File ACLs give a finer level and degree of accountability. Groups can become
unwieldy when there are dozens of people in them. Many times, there is a limit in the
number of groups a person can be in. In a highly granular system, this number could
prove inadequate. We want people to be able to operate only those utilities we want them
to, and grant access to them strictly based on ACLs. This gives us ultimate
accountability, and a situation will never arise where adding a person to a group will give
them too much access. We will first examine different types of ACL implementations.
Then we will discuss our implementation and its details.
Solaris comes standard with ACLs. It is a very basic implementation as it only
extends the traditional ugo permissions to allow for specific users or groups to have
permission to read, write, or execute a file. One extra feature is the addition of a mask
entry. The mask entry acts like an overriding permission set. For example, if Alice is
given read and execute permission on a file, but the mask only allows for read
permission, Alice will only have read permission although she had been given explicit
permission to execute a file. Solaris is almost POSIX compliant. The reason it is almost
compliant is the fact that technically, there is no standard. There are only two draft
proposals, but both were not accepted.
Microsoft NT uses a different type of ACL system. It is considered by many
people to be superior to most unix ACL implementations. They allow for even more finegrained control than Solaris. In addition to the standard permissions one can give, NT
allows the owner of a file to grant permission to let someone delete a file, modify the
permissions of, or take ownership of a file. One special feature of NT ACLs is the ability
to inherit permissions. This means that a file could get its permission set from its parent
directory. So, if a user wants all the files in a certain directory to have the same set of
permissions, the user can set the permission on the folder that contains those files and
with inheritance turned on, all the files in the directory will have the same permissions.
Another key feature of NT is the ability to explicitly deny users certain rights to a file.
This essentially acts like an exception list. For example, an owner might grant a particular
group access to a file but wants one person in the group not to have access. This cannot
be done with Solaris style ACLs, but in NT, the owner need only change the person’s
entry in the ACL to deny him access. The reason this works is that NT has an order in
which it applies it ACLs. It first checks for any explicit deny and then subsequently for
allow permissions. NT has the equivalent to the Solaris mask entry by using the
“Everyone” user.
Design of our ACL
Looking at the two major types of ACLs, we decided that we wanted the best of
both worlds. We have traditional rwx permissions and allow multiple users and groups to
be assigned to an ACL, but on top of that we added a permission to let other users or
groups modify the permissions on a file. Additionally, we added the inheritance property
in a similar fashion to how NT does inheritance and also the deny access control. By
adding these controls we also check permissions in a predefined order.
Implementation Background
Before describing the details of our implementation, we need to digress a little
and describe how the Linux file system works. The main component of the Linux file
system is the Virtual File System (VFS). The VFS acts as a layer of abstraction between
different file systems and the various programs that deal with file access. In NT, only
NTFS or versions of the FAT file system are supported, but in Linux, there are many
other types of file systems at a user’s disposal, such as HFS or reiserfs. In order to handle
all the different types of file systems, the VFS provides a common interface for the basic
file access functions. Different file systems must first register with the VFS. They then
need to provide function pointers for the various file operations that they will perform.
For example, if one wanted to open up a file in ext2 (the default Linux file system), the
object that represents the file will have a pointer to a function in the ext2 file system that
will open files. At the same time, if a file is in the NTFS, the NTFS file structure will
have a pointer to the NTFS file opening function. To the user of the system, both file
systems just work seamlessly.
Our ACLs are built on top of the ext2 file system. We forked the code base for it
and extended it. Ext2 (Second Extensible File System) is the default Linux file system. It
has several desirable features. It allows for variable size blocks in order to minimize
fragmentation. To maximize the amount of space given to data, it also allows the user to
specify the number of inodes to create in the file system. Whenever a file is allocated,
extra blocks are allocated to the inode in order to minimize fragmentation as the file
grows. The free blocks are also organized into groups and each file gets its free blocks
from the same group so that they are spatially close together. The superblock is also
replicated in every block group which makes crash recovery relatively easy. Ext2 is also
designed to be extended easily to add ACL functionality or perhaps the ability to use an
encrypted file system.
Implementation
Our implementation is built on ext2 on the Mandrake Linux distribution. Instead
of keeping ACL information in a separate block, we decided to make the inodes larger
and keep the ACL information in the inode itself. This made implementation easier and
lookup faster since we did not have to look for and read a separate block. However, the
drawbacks of this solution include the fact that we have to use more space for each inode
and that we are limited to only 32 users or groups that can be added to a particular file’s
ACL. In order to integrate with the Linux kernel, we compiled our code as a kernel
module. In addition, we had to modify programs like mke2fs to setup our file system,
and ext2fsck to check the integrity of our new file system.
The act of permission checking is pretty straightforward. If there is no ACL
present, we revert to traditional file permissions. Otherwise, if an ACL has been set, we
first search for any deny entry that could be applied to the user trying to access a file and
if one exists, the user is denied access to the file. Thus, even if a user is given explicit
permission to access a file in a particular way, if they belong to a group that has been
denied access to a file, then the user will also be denied.
We created a couple of user utilities to manage and view ACLs. The first utility is
setfacl. It is the main program to set and modify ACLs and can be run by the owner of a
file as well as anyone who has been given permission to modify the permissions on a file.
The other user utility is getfacl. This command simply reads the ACL of a particular file
and outputs it in a readable form to the terminal.
Applicability
One of the problems we think our ACL implementation would be good for is what
we call permission partitions. Traditionally, a company may have various groups
working within the same file system. However, the administrator would probably want
the ability to partition off the file system into areas that only the development, quality
assurance, or marketing team can access. The system administrator could give, for
example, the head of IT for development permission to modify all permissions in the
development mount. If the file system is setup to inherit permissions, his user now has
almost complete control of his portion of the file system, but not only is he not allowed to
modify basic system files (i.e. /etc/passwd), he cannot change anything in the quality
assurance or marketing mounts.
Indeed, virtually any large-scale operation is going to have complicated file
system needs. Resistance to corporate adoption of Linux is often argued based on its
weaknesses as a desktop. Although there are alternatives to ext2 available for Linux,
none of these offers the flexibility in control provided by the latest versions of NTFS.
Problems
Although much of the code is trivial to write, making it work within Linux was
often frustrating. Along the way, there were three major problems. First, the open source
code we used was poorly documented. In fact, there was almost not a single line of
documentation in the source of the ext2 files. Also, we did not realize it until late into the
project, that our utilities could not call kernel functions directly since they are user
programs. As such, we had to rewrite the code to work under that limitation. Finally,
since our code is dependent on having a file system to test on, testing was difficult.
We still have an outstanding problem relating to hard links to files and
inheritance. If a user decides to inherit from his parent directory, a field is filled with a
reference to the inode of his current parent. Using hard links, it is possible for the ACL
to refer to an inode that is no longer in use, potentially resulting in bad behavior when the
file is accessed. The easiest solution to this problem is to decide at each access what the
parent of a file is. Thus, different ACLs will be inherited by accessing the same file from
different directories. This will degrade performance and preclude the future scheme of
caching effective ACLs but it is the safest way to deal with the problem.
Future Work
In the future, we hope to make our work a patch to the kernel to be distributed
under the GPL. Also, we would like to do some research as to the optimal number of
ACLs to keep for a file so as to better utilize our space. Additionally, we would like to
implement a caching mechanism for effective ACLs. Effective ACLs are accessed
whenever inheritance permissions are checked. If we could cache them, it would make
inheritance checking more efficient. Another feature we would like to have is a GUI to
administer our ACLs similar to what NT has.
It is not reasonable, for an enterprise-level file system to arbitrarily limit the
number of entries in an ACL. We would like to store the first N entries within the inode
itself, and allocate blocks for any needs beyond that point.
We have also considered a different version of our ACLs that gives more
flexibility in the way we check permissions on an ACL. For example, we would like to
let the user specify the order in which to check permissions on a file. Currently, we
check any deny entries that could be applied to a user when checking whether to give
access to a file. Even if the user is explicitly allowed to access a file but a group to which
she belongs is denied access, then the user is denied access. A better ACL system would
let the person setting the permissions put the user’s ACL entry at a higher priority than
the group ACL entry. This way, the user would be given permission to access the file.
However, this type of ACL implementation would require more complicated user
controls. That is, a user will want to insert ACL entries in a particular location, as well as
rearrange an existing ACL. The most reasonable approach to providing this functionality
is through a graphical user interface.
Conclusion
We implemented a hybrid ACL system on the Linux platform. Current Linux
distributions do not have ACLs although the file systems it uses by default allows for
extensions. Our ACL system tries to take the best features of the Solaris and the NT ACL
implementations. We learned a lot about kernel hacking and about the Linux file system
along the way.
Download