Setting unix file permissions numerically
June 10, 2010
You probably know this. Like all people, I have gaps in my knowledge, and this was one of them. I fixed it. Here’s what I learned, so maybe someone out there can learn too…
When you first get into Linux (or Unix), file permissions probably seem confusing if you’ve ever used any other operating system (like Windows/DOS, for instance). Then you learn what the rwx’s mean and everything makes sense.
I’m almost ashamed to admit that, until very recently, I was unfamiliar with setting the sticky bit and the suid/sgid bits numerically, because for some reason, it never clicked. Of course, it’s really easy to remember once you look at it the right way.
To illustrate what I’m talking about, lets look at some remedial file permissions…
The very basic file permissions are read, write, and execute, and are represented visually when performing ‘ls -l’ by a series of flags, ‘r’, ‘w’, and ‘x’. The group of three is presented three times: once for the user who owns the file, once for the group who owns the file, and ones for other users (who don’t belong to the group that owns the file). It looks like this:
$ ls -l test
-rw-r–r– 1 msimmons enterprise^admins 7 2010-02-25 12:17 test
It probably looks familiar. The first way that most of us learn to modify these commands is with the flag representations of the permissions, using the ‘chmod’ command. Like this:
msimmons@newcastle:~/test$ ls -al test.sh
-rw-r–r– 1 msimmons enterprise^admins 0 2010-06-10 16:24 test.sh
msimmons@newcastle:~/test$ chmod +x test.sh
msimmons@newcastle:~/test$ ls -al test.sh
-rwxr-xr-x 1 msimmons enterprise^admins 0 2010-06-10 16:24 test.sh
As you can see, after the ‘chmod’ command, the execute bits are set on the file. After a while, you probably learn the numeric codes, too. Then you can do things like this:
msimmons@newcastle:~/test$ ls -al test.sh
-rwxr-xr-x 1 msimmons enterprise^admins 0 2010-06-10 16:24 test.sh
msimmons@newcastle:~/test$ chmod 644 test.sh
msimmons@newcastle:~/test$ ls -al test.sh
-rw-r–r– 1 msimmons enterprise^admins 0 2010-06-10 16:24 test.sh
In case you’re rusty (or never learned), the numeric codes are actually in octal, and go from 0-7. Each of the flags are assigned a value:
rwx --- 421
Remember that the set of flags appears three times, for user, group, and others:
rwx rwx rwx --- --- --- 421 421 421
This makes it really easy to numerically set the flags. You just take the match the flag at the top with the value at the bottom, group them by user, group, and other, then add up each group. Here’s an example:
I have a script that I want to make read, write, and execute by me, read and execute for the group, but not readable at all by anyone outside of the group. In other words, I want permissions to look like this:
rwx r-x ---Looking at the table above, we can match the flags with the values like this:
rwx r-x --- 421 401 000That should be pretty apparent, right? Now we just add up each of the groups.
rwx r-x --- 421 401 000 7 5 0In other words, the permissions that I want are 750. So I can use chmod and specify that:
msimmons@newcastle:~/test$ chmod 750 test.sh
msimmons@newcastle:~/test$ ls -l test.sh
-rwxr-x— 1 msimmons enterprise^admins 0 2010-06-10 16:24 test.sh
Terrific, that worked perfectly. I feel like I should include a warning now, about the “others” group. If you set that writable…in other words, if that last “w” bit is set, anyone on the entire computer can write to your file, empty its contents, and replace them with whatever they want. If it’s a script, they can make that script do whatever they want. You almost certainly do not want this. Good security begins from the ground up, and good security is that of the least permissions. If someone only needs to read something, there is no reason to set the ‘write’ bit for them.
Note that you can technically remove the ‘write’ bit from yourself. ‘rm’ then asks if you want to remove the write-protected file (unless, of course, you use -f, in which case the file is merrily blown away).
Right, so that’s basic numeric usage. Most of that was probably remedial, however now is the exciting part…or at least, exciting to me, because I recently learned it.
SUID, SGID, and Sticky Bits
You have probably heard of SUID…you probably haven’t heard of SGID, and you might have heard of Sticky Bits. Here’s brief explanation…
The Set User ID (SUID) bit on a binary program indicates that, when the program is run, it operates as the user who owns the file. If a binary is owned by root, for instance, and has the SUID bit enabled, then that program runs as root, no matter who launches it. The ‘ping’ command is a perfect example:
msimmons@newcastle:~/test$ ls -l `which ping`
-rwsr-xr-x 1 root root 30856 2007-12-10 12:33 /bin/ping
The reason that ‘ping’ is SUID is because it needs to create raw ICMP sockets (which, if you’re not a network programmer, just means that it creates them manually so that they can have very specific flags and contents, rather than relying on the ‘safer’ standard calls). Because the root user is the only one with permission to do this, ping needs to run with root privileges. Hence the SUID bit.
This is probably ringing alarm bells in your head, which is a good thing. You should be concerned, because a bug (or exploit) in a SUID program is essentially a giant gaping hole in the security of your system. If someone managed to find a way to exploit ‘ping’ before it dropped privileges, then computers everywhere would be vulnerable to attack. For this reason, you should not, willy nilly, assign binaries SUID. Only well tested, hardened programs should get that flag (and ping is one of those).
As a matter of conversation, you cannot effectively make interpreted scripts SUID (which is a good thing). I’m honestly not 100% sure what, in the system, blocks it. I believe it’s the kernel, but maybe someone could enlighten me in the comments. The end result is that, regardless of the SUID flag being set, the script runs as the current user.
When you are looking at a directory listing, a file with the SUID bit set has an ‘s’ or an ‘S’ in the column that normally holds an ‘x’. Whether the ‘s’ is upper or lower case depends on whether the execute bit has been set. If it’s set, then the ‘s’ is lowercase. If the execute bit is not set, then it’s upper case. Here’s the example:
msimmons@newcastle:~/test$ touch test
msimmons@newcastle:~/test$ chmod 4755 test
msimmons@newcastle:~/test$ ls -al test
-rwsr-xr-x 1 msimmons enterprise^admins 0 2010-06-10 17:12 test
msimmons@newcastle:~/test$ chmod 4644 test
msimmons@newcastle:~/test$ ls -al test
-rwSr–r– 1 msimmons enterprise^admins 0 2010-06-10 17:12 test
Notice that when the execute bits are set (755), the ‘s’ is lowercase, but when the execute is not set (644), the flag turns to ‘S’.
The Set Group ID (SGID) bit works in a similar way, except that the group permissions it runs with belong to the group that owns it. I don’t find myself using it in that capacity much, but I do have use for the special effects that it has on directories.
The effect that SGID has on directories is that every file and directory created under that directory automatically inherit the group owner. An example is probably the easiest way:
Lets start by touching a file and examining the default owners:
msimmons@newcastle:~/test$ touch myfile
msimmons@newcastle:~/test$ ls -al myfile
-rw-r–r– 1 msimmons enterprise^admins 0 2010-06-10 17:17 myfileAs you can see, the group owning it is my default group, enterprise^admins. Whenever I create files, that’s the group they get assigned to.
Now we’ll make a directory, change ownership of it, add the SGID bit, and take a look:
msimmons@newcastle:~/test$ mkdir mydir
msimmons@newcastle:~/test$ chgrp domain^users mydir
msimmons@newcastle:~/test$ chmod 2755 mydir
msimmons@newcastle:~/test$ ls -ald mydir
drwxr-sr-x 2 msimmons domain^users 4096 2010-06-10 17:18 mydirAs you can see, the SGID bit is set, and the group ownership is ‘domain^users’. Now, lets go into the directory, make a file, and see what happens.
msimmons@newcastle:~/test$ cd mydir
msimmons@newcastle:~/test/mydir$ touch mynewfile
msimmons@newcastle:~/test/mydir$ ls -al mynewfile
-rw-r–r– 1 msimmons domain^users 0 2010-06-10 17:19 mynewfileThere we have it. The file that we created in a directory with the SGID bit inherited the group ownership. But something else happens, too. Lets make a directory and have a look:
msimmons@newcastle:~/test/mydir$ mkdir mysubdir
msimmons@newcastle:~/test/mydir$ ls -ald mysubdir
drwxr-sr-x 2 msimmons domain^users 4096 2010-06-10 17:25 mysubdirNot only did the group ownership change to match, but the SGID bit is set as well. This enables us to set the bit on the parent directory and have the settings affect every directory that’s created. This is ideal for a shared working environment where everyone needs to create files that everyone else can access.
“Sticky Bit” is an interesting term. It can be set on files, but if it is, it’s ignored by Linux. There are other OSes that do use it, though. Instead, it’s very useful on directories.
Normally, files can be removed (or in strict Unix speak, ‘unlinked’) by anyone who has write access, even if they’re not the owner. This normally isn’t a problem. After all, if you can write to it, that means you should be able to erase it. There are times when this isn’t ideal, though, and that’s when the sticky bit comes to the rescue. When a directory has the sticky bit set, only the user who owns the file (or the root user) can remove it. Anyone else can still write to it, but removing it will get the error “rm: cannot remove `file’: Operation not permitted.
You can tell if a file or directory has the sticky bit set if the very last ‘x’ in the ‘others’ column is set to a ‘t’ or a ‘T’. Just like the SUID and SGID flags, you can tell if the underlying bit (in this case, the execute bit) is set by whether the ‘t’ is lower or upper case. If it’s lower case, the execute bit is set. If it’s uppercase, the bit is not set. Example:
msimmons@newcastle:~/test$ touch 1
msimmons@newcastle:~/test$ touch 2
msimmons@newcastle:~/test$ chmod 1001 1
msimmons@newcastle:~/test$ chmod 1000 2
msimmons@newcastle:~/test$ ls -al
total 24
drwxr-xr-x 2 msimmons enterprise^admins 4096 2010-06-10 17:47 .
drwxr-xr-x 171 msimmons enterprise^admins 20480 2010-06-10 16:53 ..
———t 1 msimmons enterprise^admins 0 2010-06-10 17:47 1
———T 1 msimmons enterprise^admins 0 2010-06-10 17:47 2
SUID, SGID, and Sticky Bit Numerics
Interspersed throughout the examples, you probably saw me using 4 digit numeric codes (such as 2755 when we were setting the SGID bit). If you leave off the first of the four bits, ‘chmod’ assumes the first bit is 0, and doesn’t set it (technically, any bits it doesn’t find, it assumes are 0, thus you could make a file
------r--
with a ‘chmod 4′ command). However, when you add that first number, you are instructing chmod to set the SUID, SGID, and Sticky Bit bits.
The breakdown occurs like this:
0 is nothing
1 is sticky bit
2 is SGID
3 is SGID and sticky bit
4 is SUID
5 is SUID and sticky bit
6 is SUID and SGID
7 is SUID, SGID, and sticky bit
Jeez, how could you not have that memorized?
Well, I couldn’t, anyway. And it didn’t click, until today. Those flags are octal, too, but the non-numeric flags are spread out over all three sets of rwx blocks. Maybe I can make it more clear with this snippet:
msimmons@newcastle:/tmp$ touch test
msimmons@newcastle:/tmp$ for PERM in `seq 0 7` ; do echo -n \
" %PERM " ; chmod ${PERM}000 test && ls -l test | awk '{print $1}' ; done
0 ----------
1 ---------T
2 ------S---
3 ------S--T
4 ---S------
5 ---S-----T
6 ---S--S---
7 ---S--S--T
A little bit of explanation is probably in order. First I touch a file. Then, I write a for loop that iterates from 0 to 7, and changes the permissions to 0000, then 1000, then 2000, then 3000, etc etc. It then prints out the permissions on the file at that time (along with the number that is set).
If you follow the pattern, it’s exactly like the ‘rwx’ pattern, with the same numbers. Instead of
rwx --- 421
we have
SST --- 421
The only difference is that the flags are set each in their own “user”, “group”, or “others” column.
Thus is becomes easy to numerically assign SUID, SGID, and Sticky Bit…
If you want a ‘normally’ permissioned directory (rwxr-xr-x), except you want the SGID and Sticky Bit set, you do it like this:
According to the previous table, the SGID is assigned 2, and the Sticky bit is assigned 1. 2+1=3, and the “normal” permissions come out to 755, so our command will be
msimmons@newcastle:~/test$ mkdir dirname
msimmons@newcastle:~/test$ chmod 3755 dirname
msimmons@newcastle:~/test$ ls -ald dirname
drwxr-sr-t 2 msimmons enterprise^admins 4096 2010-06-10 17:55 dirname
There you have it. An easy way to remember the numeric codes for SUID, SGID, and Sticky Bit.
Please comment if you have any questions, if I didn’t explain clearly enough, or if I screwed something up. Thanks!














Posted in





Email me



content rss
June 10th, 2010 at 6:37 pm
[...] This post was mentioned on Twitter by Matt Simmons, Planet SysAd. Planet SysAd said: Standalone Sysadmin: Setting unix file permissions numerically http://bit.ly/agdIPe [...]
June 10th, 2010 at 9:49 pm
Matt, I’ve only ever used SUID and SGID so I just memorized those two. Using the 421 math like with the rwx permissions is pretty awesome though. Time to go set some sticky bits so I can make use of my new-found knowledge!
June 10th, 2010 at 11:24 pm
whats the deal with the group names (domain^users)? is that a byproduct of your ActiveDirectory setup or just a weird syntax you use?
June 11th, 2010 at 5:50 am
I might be wrong but I think the reason you can’t SUID a script is because the script isn’t the thing that’s being executed. It’s the relevant interpreter that gets executed which of course isn’t SUID (unless you are insane).
I had the exact same blind-spot about the octal maths that you did. So cheers for writing this.
June 11th, 2010 at 9:51 am
@neoice
Yes, I’m using Likewise Open to authenticate all of my Linux machines, and the Windows group names come across like that. It’s pretty easy to deal with, except that it makes your lastlog file look insane (because it’s a sparse file):
It’s *not* 89GB ;-)
June 11th, 2010 at 10:43 am
You didn’t mention what happens when you setuid a directory.
(I just did in a round about way :-)
June 11th, 2010 at 10:48 am
Although I have read that SUID on a directory creates all files as the owner of the directory, I have not found that to be the case in my experiments. I might be Doing It Wrong(tm).
June 11th, 2010 at 11:00 am
My latest weak attempt at humour bombed I see :-)
As I understood it, SUID on a directory does nothing. Interestingly, I checked a couple of manuals from my shelf and none of them mention that case.
The only reference I found supporting this was http://www.linuxjournal.com/article/7727?page=0,1
June 11th, 2010 at 11:02 am
It’s either old and not supported (but I can see various use cases), or it’s a bug that never got fixed.
BTW, I see what you did there ;-)
It’s probably one of those things that works on some other Unix that was just ignored. Maybe someone else can clue us in.
June 11th, 2010 at 3:40 pm
Don’t you mean:
“Then, I write a for loop that iterates from 0 to 7, and changes the permissions to 0000, then 1000, then 2000, then 3000, etc etc.”
June 11th, 2010 at 3:57 pm
@Tony
Why yes, yes I did. :-) Thanks! I fixed it.
June 13th, 2010 at 11:18 am
i always wondered if setting rw permissions for everyone was intentionally set as 666
June 16th, 2010 at 4:45 pm
I learned the octal method way back when (starting on a Gould, then on SunOS 4) and only within the last couple of years have I seen the advantages of the nonoctal method for some use cases (in particular, the +X option is really handy for opening up permissions in a tree, as for some chunk of commercial software I’ve installed that’s now ready for more testing or for others to use). But for single files, or even most of the things I do within my home directory, setting permissions with octals is just quicker and easier, even if I’m using a find search to generate the list of things to change.
June 28th, 2010 at 9:12 pm
[...] 640? I highly recommend checking out the excellent StandAlone SysAdmin’s great post on numeric unix permissions[↩] Categories: Sys Admin Tags: Comments (0) Trackbacks (0) Leave a comment [...]
July 9th, 2010 at 12:57 pm
Minor nit: directories are not executable, therefore there’s no such thing as an execute bit on a directory. When x is set and applied to a directory, it means the owner/group/other has _search_ permission. From the man page:
The letters ‘rwxXstugo’ select the new permissions for the affected users: read (r), write (w), execute (or access for directories).
Or maybe the vernacular has changed. 30 years ago we called it the search bit. Pet peeves aside, this article is a good read.