1 |
On Thu, Jan 18, 2018 at 07:19:59PM -0500, Michael Orlitzky wrote: |
2 |
> Not at all. I'm working this out as I go, so better to speak up if |
3 |
> something looks fishy. |
4 |
> |
5 |
> There are a few risks that I see with the first approach... |
6 |
> |
7 |
> |
8 |
> Risk #1: From what I can tell, the current implementation of checkpath |
9 |
> first creates the path, and then adjusts the ownership and permissions |
10 |
> on it. After /run/foo/bar has been created but before the permissions |
11 |
> and ownership are changed, the "foo" user can replace "bar" with a hard |
12 |
> link (because he owns /run/foo). The lchown/chmod will operate on the |
13 |
> target of that link, and if he's fast enough, then the "foo" user can |
14 |
> use that to take over root's files. (Limited to /run in this example, |
15 |
> but that's beside the point.) |
16 |
> |
17 |
> Maybe that can be avoided. Is there a portable way to atomically create |
18 |
> a file/directory with its ownership and permissions already set? Or is |
19 |
> it possible to operate on the descriptor that you get back when creating |
20 |
> the path? |
21 |
|
22 |
Permissions are set as part of the mkdir/open/mkfifo call, so they are |
23 |
set immediately when the file is created. but ownership is adjusted |
24 |
separately by calling chown/fchown/lchown. |
25 |
|
26 |
At a high level, checkpath looks like this: |
27 |
|
28 |
1. Creating and setting permissions. |
29 |
a. If the file doesn't exist, set the permissions when it is created. |
30 |
b. If the file does exist, only fix the permissions if necessary. |
31 |
c. At this point, the file's permissions are correct. |
32 |
2. setting ownership |
33 |
a. always set the ownership if the file's ownership doesn't match the |
34 |
specified ownership. |
35 |
|
36 |
It looks like we can't use your --as suggestion if we want to be |
37 |
able to create paths in /var/lib and /var/spool that are owned by |
38 |
non-privileged users because of the permissions on those paths. It is |
39 |
possible that service scripts are doing this. |
40 |
|
41 |
Is it worth changing the algorithm to do this instead: |
42 |
|
43 |
0. test for existance by opening a read-only file descriptor to this |
44 |
file. |
45 |
1. Creating the file/directory/fifo. |
46 |
a. If it doesn't exist, create it -- note that I'm not setting |
47 |
permissions with the create call. |
48 |
b. Open a read-only file descriptor that attaches to the newly created |
49 |
file. |
50 |
2. Setting Permissions. |
51 |
a. Fix the permissions of the file if necessary. |
52 |
3. setting ownership |
53 |
a. Set the ownership if it doesn't match the specified ownership. |
54 |
|
55 |
> Risk #2: Instead consider a four-component path /run/foo/bar/baz. If you |
56 |
> start creating those directories with owner "foo", then when you get to |
57 |
> creating "baz", it's possible that "bar" has been replaced by a symlink |
58 |
> somewhere else. |
59 |
|
60 |
It is possible, sure, but the question I would ask is, could this also |
61 |
be a legit situation where a user would want /run/foo/bar to be a |
62 |
symlink to some other location? If it is, there's no way to tell the |
63 |
difference. |
64 |
|
65 |
> Certain tricks exist to avoid that, but I'm not an expert on them and I |
66 |
> don't know how portable or secure they really are. For example, you |
67 |
> might get the descriptor of "bar" and then use openat(dirfd,...) instead |
68 |
> of open(...) to create "baz". |
69 |
> |
70 |
> If both of those can be solved portably, then all you have to worry |
71 |
> about is everything I haven't thought of =) |
72 |
|
73 |
Thoughts? |
74 |
|
75 |
William |