Browse code

Use real root with 0701 perms

Various dirs in /var/lib/docker contain data that needs to be mounted
into a container. For this reason, these dirs are set to be owned by the
remapped root user, otherwise there can be permissions issues.
However, this uneccessarily exposes these dirs to an unprivileged user
on the host.

Instead, set the ownership of these dirs to the real root (or rather the
UID/GID of dockerd) with 0701 permissions, which allows the remapped
root to enter the directories but not read/write to them.
The remapped root needs to enter these dirs so the container's rootfs
can be configured... e.g. to mount /etc/resolve.conf.

This prevents an unprivileged user from having read/write access to
these dirs on the host.
The flip side of this is now any user can enter these directories.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>

Brian Goff authored on 2020/10/07 04:43:24
Showing 12 changed files
... ...
@@ -466,5 +466,5 @@ func (daemon *Daemon) setupContainerMountsRoot(c *container.Container) error {
466 466
 	if err != nil {
467 467
 		return err
468 468
 	}
469
-	return idtools.MkdirAllAndChown(p, 0700, daemon.idMapping.RootPair())
469
+	return idtools.MkdirAllAndChown(p, 0701, idtools.CurrentIdentity())
470 470
 }
... ...
@@ -211,12 +211,10 @@ func (daemon *Daemon) create(opts createOpts) (retC *container.Container, retErr
211 211
 	}
212 212
 	ctr.RWLayer = rwLayer
213 213
 
214
-	rootIDs := daemon.idMapping.RootPair()
215
-
216
-	if err := idtools.MkdirAndChown(ctr.Root, 0700, rootIDs); err != nil {
214
+	if err := idtools.MkdirAndChown(ctr.Root, 0701, idtools.CurrentIdentity()); err != nil {
217 215
 		return nil, err
218 216
 	}
219
-	if err := idtools.MkdirAndChown(ctr.CheckpointDir(), 0700, rootIDs); err != nil {
217
+	if err := idtools.MkdirAndChown(ctr.CheckpointDir(), 0700, idtools.CurrentIdentity()); err != nil {
220 218
 		return nil, err
221 219
 	}
222 220
 
... ...
@@ -861,7 +861,7 @@ func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.S
861 861
 	}
862 862
 
863 863
 	daemonRepo := filepath.Join(config.Root, "containers")
864
-	if err := idtools.MkdirAllAndChown(daemonRepo, 0700, rootIDs); err != nil {
864
+	if err := idtools.MkdirAllAndChown(daemonRepo, 0701, idtools.CurrentIdentity()); err != nil {
865 865
 		return nil, err
866 866
 	}
867 867
 
... ...
@@ -1196,7 +1196,7 @@ func setupRemappedRoot(config *config.Config) (*idtools.IdentityMapping, error)
1196 1196
 	return &idtools.IdentityMapping{}, nil
1197 1197
 }
1198 1198
 
1199
-func setupDaemonRoot(config *config.Config, rootDir string, rootIdentity idtools.Identity) error {
1199
+func setupDaemonRoot(config *config.Config, rootDir string, remappedRoot idtools.Identity) error {
1200 1200
 	config.Root = rootDir
1201 1201
 	// the docker root metadata directory needs to have execute permissions for all users (g+x,o+x)
1202 1202
 	// so that syscalls executing as non-root, operating on subdirectories of the graph root
... ...
@@ -1221,10 +1221,16 @@ func setupDaemonRoot(config *config.Config, rootDir string, rootIdentity idtools
1221 1221
 	// a new subdirectory with ownership set to the remapped uid/gid (so as to allow
1222 1222
 	// `chdir()` to work for containers namespaced to that uid/gid)
1223 1223
 	if config.RemappedRoot != "" {
1224
-		config.Root = filepath.Join(rootDir, fmt.Sprintf("%d.%d", rootIdentity.UID, rootIdentity.GID))
1224
+		id := idtools.CurrentIdentity()
1225
+		// First make sure the current root dir has the correct perms.
1226
+		if err := idtools.MkdirAllAndChown(config.Root, 0701, id); err != nil {
1227
+			return errors.Wrapf(err, "could not create or set daemon root permissions: %s", config.Root)
1228
+		}
1229
+
1230
+		config.Root = filepath.Join(rootDir, fmt.Sprintf("%d.%d", remappedRoot.UID, remappedRoot.GID))
1225 1231
 		logrus.Debugf("Creating user namespaced daemon root: %s", config.Root)
1226 1232
 		// Create the root directory if it doesn't exist
1227
-		if err := idtools.MkdirAllAndChown(config.Root, 0700, rootIdentity); err != nil {
1233
+		if err := idtools.MkdirAllAndChown(config.Root, 0701, id); err != nil {
1228 1234
 			return fmt.Errorf("Cannot create daemon root: %s: %v", config.Root, err)
1229 1235
 		}
1230 1236
 		// we also need to verify that any pre-existing directories in the path to
... ...
@@ -1237,7 +1243,7 @@ func setupDaemonRoot(config *config.Config, rootDir string, rootIdentity idtools
1237 1237
 			if dirPath == "/" {
1238 1238
 				break
1239 1239
 			}
1240
-			if !idtools.CanAccess(dirPath, rootIdentity) {
1240
+			if !idtools.CanAccess(dirPath, remappedRoot) {
1241 1241
 				return fmt.Errorf("a subdirectory in your graphroot path (%s) restricts access to the remapped root uid/gid; please fix by allowing 'o+x' permissions on existing directories", config.Root)
1242 1242
 			}
1243 1243
 		}
... ...
@@ -129,18 +129,15 @@ func Init(root string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
129 129
 		locker:    locker.New(),
130 130
 	}
131 131
 
132
-	rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps)
133
-	if err != nil {
134
-		return nil, err
135
-	}
132
+	currentID := idtools.CurrentIdentity()
136 133
 	// Create the root aufs driver dir
137
-	if err := idtools.MkdirAllAndChown(root, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
134
+	if err := idtools.MkdirAllAndChown(root, 0701, currentID); err != nil {
138 135
 		return nil, err
139 136
 	}
140 137
 
141 138
 	// Populate the dir structure
142 139
 	for _, p := range paths {
143
-		if err := idtools.MkdirAllAndChown(path.Join(root, p), 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
140
+		if err := idtools.MkdirAllAndChown(path.Join(root, p), 0701, currentID); err != nil {
144 141
 			return nil, err
145 142
 		}
146 143
 	}
... ...
@@ -70,11 +70,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
70 70
 		return nil, graphdriver.ErrPrerequisites
71 71
 	}
72 72
 
73
-	rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps)
74
-	if err != nil {
75
-		return nil, err
76
-	}
77
-	if err := idtools.MkdirAllAndChown(home, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
73
+	if err := idtools.MkdirAllAndChown(home, 0701, idtools.CurrentIdentity()); err != nil {
78 74
 		return nil, err
79 75
 	}
80 76
 
... ...
@@ -525,7 +521,7 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
525 525
 	if err != nil {
526 526
 		return err
527 527
 	}
528
-	if err := idtools.MkdirAllAndChown(subvolumes, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
528
+	if err := idtools.MkdirAllAndChown(subvolumes, 0701, idtools.CurrentIdentity()); err != nil {
529 529
 		return err
530 530
 	}
531 531
 	if parent == "" {
... ...
@@ -560,7 +556,7 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
560 560
 		if err := d.setStorageSize(path.Join(subvolumes, id), driver); err != nil {
561 561
 			return err
562 562
 		}
563
-		if err := idtools.MkdirAllAndChown(quotas, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
563
+		if err := idtools.MkdirAllAndChown(quotas, 0700, idtools.CurrentIdentity()); err != nil {
564 564
 			return err
565 565
 		}
566 566
 		if err := ioutil.WriteFile(path.Join(quotas, id), []byte(fmt.Sprint(driver.options.size)), 0644); err != nil {
... ...
@@ -88,12 +88,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
88 88
 		return nil, graphdriver.ErrNotSupported
89 89
 	}
90 90
 
91
-	rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps)
92
-	if err != nil {
93
-		return nil, err
94
-	}
95
-	// Create the driver home dir
96
-	if err := idtools.MkdirAllAndChown(path.Join(home, linkDir), 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
91
+	if err := idtools.MkdirAllAndChown(path.Join(home, linkDir), 0701, idtools.CurrentIdentity()); err != nil {
97 92
 		return nil, err
98 93
 	}
99 94
 
... ...
@@ -178,10 +173,11 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts) (retErr
178 178
 	}
179 179
 	root := idtools.Identity{UID: rootUID, GID: rootGID}
180 180
 
181
-	if err := idtools.MkdirAllAndChown(path.Dir(dir), 0700, root); err != nil {
181
+	currentID := idtools.CurrentIdentity()
182
+	if err := idtools.MkdirAllAndChown(path.Dir(dir), 0701, currentID); err != nil {
182 183
 		return err
183 184
 	}
184
-	if err := idtools.MkdirAndChown(dir, 0700, root); err != nil {
185
+	if err := idtools.MkdirAndChown(dir, 0701, currentID); err != nil {
185 186
 		return err
186 187
 	}
187 188
 
... ...
@@ -215,7 +211,7 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts) (retErr
215 215
 		return nil
216 216
 	}
217 217
 
218
-	if err := idtools.MkdirAndChown(path.Join(dir, workDirName), 0700, root); err != nil {
218
+	if err := idtools.MkdirAndChown(path.Join(dir, workDirName), 0701, currentID); err != nil {
219 219
 		return err
220 220
 	}
221 221
 
... ...
@@ -156,12 +156,8 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
156 156
 		logrus.WithField("storage-driver", "overlay").Warn(overlayutils.ErrDTypeNotSupported("overlay", backingFs))
157 157
 	}
158 158
 
159
-	rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps)
160
-	if err != nil {
161
-		return nil, err
162
-	}
163 159
 	// Create the driver home dir
164
-	if err := idtools.MkdirAllAndChown(home, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
160
+	if err := idtools.MkdirAllAndChown(home, 0701, idtools.CurrentIdentity()); err != nil {
165 161
 		return nil, err
166 162
 	}
167 163
 
... ...
@@ -265,10 +261,11 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) (retErr
265 265
 	}
266 266
 	root := idtools.Identity{UID: rootUID, GID: rootGID}
267 267
 
268
-	if err := idtools.MkdirAllAndChown(path.Dir(dir), 0700, root); err != nil {
268
+	currentID := idtools.CurrentIdentity()
269
+	if err := idtools.MkdirAllAndChown(path.Dir(dir), 0701, currentID); err != nil {
269 270
 		return err
270 271
 	}
271
-	if err := idtools.MkdirAndChown(dir, 0700, root); err != nil {
272
+	if err := idtools.MkdirAndChown(dir, 0701, currentID); err != nil {
272 273
 		return err
273 274
 	}
274 275
 
... ...
@@ -281,6 +278,7 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) (retErr
281 281
 
282 282
 	// Toplevel images are just a "root" dir
283 283
 	if parent == "" {
284
+		// This must be 0755 otherwise unprivileged users will in the container will not be able to read / in the container
284 285
 		return idtools.MkdirAndChown(path.Join(dir, "root"), 0755, root)
285 286
 	}
286 287
 
... ...
@@ -301,7 +299,7 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) (retErr
301 301
 		if err := idtools.MkdirAndChown(path.Join(dir, "work"), 0700, root); err != nil {
302 302
 			return err
303 303
 		}
304
-		return ioutil.WriteFile(path.Join(dir, "lower-id"), []byte(parent), 0666)
304
+		return ioutil.WriteFile(path.Join(dir, "lower-id"), []byte(parent), 0600)
305 305
 	}
306 306
 
307 307
 	// Otherwise, copy the upper and the lower-id from the parent
... ...
@@ -311,7 +309,7 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) (retErr
311 311
 		return err
312 312
 	}
313 313
 
314
-	if err := ioutil.WriteFile(path.Join(dir, "lower-id"), lowerID, 0666); err != nil {
314
+	if err := ioutil.WriteFile(path.Join(dir, "lower-id"), lowerID, 0600); err != nil {
315 315
 		return err
316 316
 	}
317 317
 
... ...
@@ -165,12 +165,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
165 165
 		logger.Warn(overlayutils.ErrDTypeNotSupported("overlay2", backingFs))
166 166
 	}
167 167
 
168
-	rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps)
169
-	if err != nil {
170
-		return nil, err
171
-	}
172
-	// Create the driver home dir
173
-	if err := idtools.MkdirAllAndChown(path.Join(home, linkDir), 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
168
+	if err := idtools.MkdirAllAndChown(path.Join(home, linkDir), 0701, idtools.CurrentIdentity()); err != nil {
174 169
 		return nil, err
175 170
 	}
176 171
 
... ...
@@ -339,11 +334,12 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts) (retErr
339 339
 		return err
340 340
 	}
341 341
 	root := idtools.Identity{UID: rootUID, GID: rootGID}
342
+	current := idtools.CurrentIdentity()
342 343
 
343
-	if err := idtools.MkdirAllAndChown(path.Dir(dir), 0700, root); err != nil {
344
+	if err := idtools.MkdirAllAndChown(path.Dir(dir), 0701, current); err != nil {
344 345
 		return err
345 346
 	}
346
-	if err := idtools.MkdirAndChown(dir, 0700, root); err != nil {
347
+	if err := idtools.MkdirAndChown(dir, 0701, current); err != nil {
347 348
 		return err
348 349
 	}
349 350
 
... ...
@@ -38,8 +38,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
38 38
 		return nil, err
39 39
 	}
40 40
 
41
-	rootIDs := d.idMapping.RootPair()
42
-	if err := idtools.MkdirAllAndChown(home, 0700, rootIDs); err != nil {
41
+	if err := idtools.MkdirAllAndChown(home, 0701, idtools.CurrentIdentity()); err != nil {
43 42
 		return nil, err
44 43
 	}
45 44
 
... ...
@@ -141,7 +140,7 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
141 141
 func (d *Driver) create(id, parent string, size uint64) error {
142 142
 	dir := d.dir(id)
143 143
 	rootIDs := d.idMapping.RootPair()
144
-	if err := idtools.MkdirAllAndChown(filepath.Dir(dir), 0700, rootIDs); err != nil {
144
+	if err := idtools.MkdirAllAndChown(filepath.Dir(dir), 0701, idtools.CurrentIdentity()); err != nil {
145 145
 		return err
146 146
 	}
147 147
 	if err := idtools.MkdirAndChown(dir, 0755, rootIDs); err != nil {
... ...
@@ -104,11 +104,7 @@ func Init(base string, opt []string, uidMaps, gidMaps []idtools.IDMap) (graphdri
104 104
 		return nil, fmt.Errorf("BUG: zfs get all -t filesystem -rHp '%s' should contain '%s'", options.fsName, options.fsName)
105 105
 	}
106 106
 
107
-	rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps)
108
-	if err != nil {
109
-		return nil, fmt.Errorf("Failed to get root uid/guid: %v", err)
110
-	}
111
-	if err := idtools.MkdirAllAndChown(base, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
107
+	if err := idtools.MkdirAllAndChown(base, 0701, idtools.CurrentIdentity()); err != nil {
112 108
 		return nil, fmt.Errorf("Failed to create '%s': %v", base, err)
113 109
 	}
114 110
 
... ...
@@ -50,7 +50,7 @@ type activeMount struct {
50 50
 func New(scope string, rootIdentity idtools.Identity) (*Root, error) {
51 51
 	rootDirectory := filepath.Join(scope, volumesPathName)
52 52
 
53
-	if err := idtools.MkdirAllAndChown(rootDirectory, 0700, rootIdentity); err != nil {
53
+	if err := idtools.MkdirAllAndChown(rootDirectory, 0701, idtools.CurrentIdentity()); err != nil {
54 54
 		return nil, err
55 55
 	}
56 56
 
... ...
@@ -153,8 +153,15 @@ func (r *Root) Create(name string, opts map[string]string) (volume.Volume, error
153 153
 	}
154 154
 
155 155
 	path := r.DataPath(name)
156
+	volRoot := filepath.Dir(path)
157
+	// Root dir does not need to be accessed by the remapped root
158
+	if err := idtools.MkdirAllAndChown(volRoot, 0701, idtools.CurrentIdentity()); err != nil {
159
+		return nil, errors.Wrapf(errdefs.System(err), "error while creating volume root path '%s'", volRoot)
160
+	}
161
+
162
+	// Remapped root does need access to the data path
156 163
 	if err := idtools.MkdirAllAndChown(path, 0755, r.rootIdentity); err != nil {
157
-		return nil, errors.Wrapf(errdefs.System(err), "error while creating volume path '%s'", path)
164
+		return nil, errors.Wrapf(errdefs.System(err), "error while creating volume data path '%s'", path)
158 165
 	}
159 166
 
160 167
 	var err error