A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://github.com/opencontainers/runc/commit/63c2908164f3a1daea455bf5bcd8d363d70328c7 below:

try to scope MkdirAll to stay inside the rootfs · opencontainers/runc@63c2908 · GitHub

File tree Expand file treeCollapse file tree 3 files changed

+174

-10

lines changed

Filter options

Expand file treeCollapse file tree 3 files changed

+174

-10

lines changed Original file line number Diff line number Diff line change

@@ -313,7 +313,7 @@ func mountCgroupV1(m *configs.Mount, c *mountConfig) error {

313 313

// inside the tmpfs, so we don't want to resolve symlinks).

314 314

subsystemPath := filepath.Join(c.root, b.Destination)

315 315

subsystemName := filepath.Base(b.Destination)

316 -

if err := os.MkdirAll(subsystemPath, 0o755); err != nil {

316 +

if err := utils.MkdirAllInRoot(c.root, subsystemPath, 0o755); err != nil {

317 317

return err

318 318

}

319 319

if err := utils.WithProcfd(c.root, b.Destination, func(dstFd string) error {

@@ -505,15 +505,26 @@ func createMountpoint(rootfs string, m mountEntry) (string, error) {

505 505

return "", fmt.Errorf("%w: file bind mount over rootfs", errRootfsToFile)

506 506

}

507 507

// Make the parent directory.

508 -

if err := os.MkdirAll(filepath.Dir(dest), 0o755); err != nil {

508 +

destDir, destBase := filepath.Split(dest)

509 +

destDirFd, err := utils.MkdirAllInRootOpen(rootfs, destDir, 0o755)

510 +

if err != nil {

509 511

return "", fmt.Errorf("make parent dir of file bind-mount: %w", err)

510 512

}

511 -

// Make the target file.

512 -

f, err := os.OpenFile(dest, os.O_CREATE, 0o755)

513 -

if err != nil {

514 -

return "", fmt.Errorf("create target of file bind-mount: %w", err)

513 +

defer destDirFd.Close()

514 +

// Make the target file. We want to avoid opening any file that is

515 +

// already there because it could be a "bad" file like an invalid

516 +

// device or hung tty that might cause a DoS, so we use mknodat.

517 +

// destBase does not contain any "/" components, and mknodat does

518 +

// not follow trailing symlinks, so we can safely just call mknodat

519 +

// here.

520 +

if err := unix.Mknodat(int(destDirFd.Fd()), destBase, unix.S_IFREG|0o644, 0); err != nil {

521 +

// If we get EEXIST, there was already an inode there and

522 +

// we can consider that a success.

523 +

if !errors.Is(err, unix.EEXIST) {

524 +

err = &os.PathError{Op: "mknod regular file", Path: dest, Err: err}

525 +

return "", fmt.Errorf("create target of file bind-mount: %w", err)

526 +

}

515 527

}

516 -

_ = f.Close()

517 528

// Nothing left to do.

518 529

return dest, nil

519 530

}

@@ -532,7 +543,7 @@ func createMountpoint(rootfs string, m mountEntry) (string, error) {

532 543

}

533 544

}

534 545 535 -

if err := os.MkdirAll(dest, 0o755); err != nil {

546 +

if err := utils.MkdirAllInRoot(rootfs, dest, 0o755); err != nil {

536 547

return "", err

537 548

}

538 549

return dest, nil

@@ -565,7 +576,7 @@ func mountToRootfs(c *mountConfig, m mountEntry) error {

565 576

} else if !fi.IsDir() {

566 577

return fmt.Errorf("filesystem %q must be mounted on ordinary directory", m.Device)

567 578

}

568 -

if err := os.MkdirAll(dest, 0o755); err != nil {

579 +

if err := utils.MkdirAllInRoot(rootfs, dest, 0o755); err != nil {

569 580

return err

570 581

}

571 582

// Selinux kernels do not support labeling of /proc or /sys.

@@ -928,7 +939,7 @@ func createDeviceNode(rootfs string, node *devices.Device, bind bool) error {

928 939

if dest == rootfs {

929 940

return fmt.Errorf("%w: mknod over rootfs", errRootfsToFile)

930 941

}

931 -

if err := os.MkdirAll(filepath.Dir(dest), 0o755); err != nil {

942 +

if err := utils.MkdirAllInRoot(rootfs, filepath.Dir(dest), 0o755); err != nil {

932 943

return err

933 944

}

934 945

if bind {

Original file line number Diff line number Diff line change

@@ -6,7 +6,9 @@ import (

6 6

"fmt"

7 7

"io"

8 8

"os"

9 +

"runtime"

9 10

"strconv"

11 +

"strings"

10 12

"syscall"

11 13

"unsafe"

12 14

@@ -214,3 +216,42 @@ func SetLinuxPersonality(personality int) error {

214 216

}

215 217

return nil

216 218

}

219 + 220 +

func prepareAt(dir *os.File, path string) (int, string) {

221 +

if dir == nil {

222 +

return unix.AT_FDCWD, path

223 +

}

224 + 225 +

// Rather than just filepath.Join-ing path here, do it manually so the

226 +

// error and handle correctly indicate cases like path=".." as being

227 +

// relative to the correct directory. The handle.Name() might end up being

228 +

// wrong but because this is (currently) only used in MkdirAllInRoot, that

229 +

// isn't a problem.

230 +

dirName := dir.Name()

231 +

if !strings.HasSuffix(dirName, "/") {

232 +

dirName += "/"

233 +

}

234 +

fullPath := dirName + path

235 + 236 +

return int(dir.Fd()), fullPath

237 +

}

238 + 239 +

func Openat(dir *os.File, path string, flags int, mode uint32) (*os.File, error) {

240 +

dirFd, fullPath := prepareAt(dir, path)

241 +

fd, err := unix.Openat(dirFd, path, flags, mode)

242 +

if err != nil {

243 +

return nil, &os.PathError{Op: "openat", Path: fullPath, Err: err}

244 +

}

245 +

runtime.KeepAlive(dir)

246 +

return os.NewFile(uintptr(fd), fullPath), nil

247 +

}

248 + 249 +

func Mkdirat(dir *os.File, path string, mode uint32) error {

250 +

dirFd, fullPath := prepareAt(dir, path)

251 +

err := unix.Mkdirat(dirFd, path, mode)

252 +

if err != nil {

253 +

err = &os.PathError{Op: "mkdirat", Path: fullPath, Err: err}

254 +

}

255 +

runtime.KeepAlive(dir)

256 +

return err

257 +

}

Original file line number Diff line number Diff line change

@@ -3,6 +3,7 @@

3 3

package utils

4 4 5 5

import (

6 +

"errors"

6 7

"fmt"

7 8

"math"

8 9

"os"

@@ -13,6 +14,8 @@ import (

13 14

"sync"

14 15

_ "unsafe" // for go:linkname

15 16 17 +

"github.com/opencontainers/runc/libcontainer/system"

18 + 16 19

securejoin "github.com/cyphar/filepath-securejoin"

17 20

"github.com/sirupsen/logrus"

18 21

"golang.org/x/sys/unix"

@@ -275,3 +278,112 @@ func IsLexicallyInRoot(root, path string) bool {

275 278

}

276 279

return strings.HasPrefix(path, root)

277 280

}

281 + 282 +

// MkdirAllInRootOpen attempts to make

283 +

//

284 +

// path, _ := securejoin.SecureJoin(root, unsafePath)

285 +

// os.MkdirAll(path, mode)

286 +

// os.Open(path)

287 +

//

288 +

// safer against attacks where components in the path are changed between

289 +

// SecureJoin returning and MkdirAll (or Open) being called. In particular, we

290 +

// try to detect any symlink components in the path while we are doing the

291 +

// MkdirAll.

292 +

//

293 +

// NOTE: Unlike os.MkdirAll, mode is not Go's os.FileMode, it is the unix mode

294 +

// (the suid/sgid/sticky bits are not the same as for os.FileMode).

295 +

//

296 +

// NOTE: If unsafePath is a subpath of root, we assume that you have already

297 +

// called SecureJoin and so we use the provided path verbatim without resolving

298 +

// any symlinks (this is done in a way that avoids symlink-exchange races).

299 +

// This means that the path also must not contain ".." elements, otherwise an

300 +

// error will occur.

301 +

//

302 +

// This is a somewhat less safe alternative to

303 +

// <https://github.com/cyphar/filepath-securejoin/pull/13>, but it should

304 +

// detect attempts to trick us into creating directories outside of the root.

305 +

// We should migrate to securejoin.MkdirAll once it is merged.

306 +

func MkdirAllInRootOpen(root, unsafePath string, mode uint32) (_ *os.File, Err error) {

307 +

// If the path is already "within" the root, use it verbatim.

308 +

fullPath := unsafePath

309 +

if !IsLexicallyInRoot(root, unsafePath) {

310 +

var err error

311 +

fullPath, err = securejoin.SecureJoin(root, unsafePath)

312 +

if err != nil {

313 +

return nil, err

314 +

}

315 +

}

316 +

subPath, err := filepath.Rel(root, fullPath)

317 +

if err != nil {

318 +

return nil, err

319 +

}

320 + 321 +

// Check for any silly mode bits.

322 +

if mode&^0o7777 != 0 {

323 +

return nil, fmt.Errorf("tried to include non-mode bits in MkdirAll mode: 0o%.3o", mode)

324 +

}

325 + 326 +

currentDir, err := os.OpenFile(root, unix.O_DIRECTORY|unix.O_CLOEXEC, 0)

327 +

if err != nil {

328 +

return nil, fmt.Errorf("open root handle: %w", err)

329 +

}

330 +

defer func() {

331 +

if Err != nil {

332 +

currentDir.Close()

333 +

}

334 +

}()

335 + 336 +

for _, part := range strings.Split(subPath, string(filepath.Separator)) {

337 +

switch part {

338 +

case "", ".":

339 +

// Skip over no-op components.

340 +

continue

341 +

case "..":

342 +

return nil, fmt.Errorf("possible breakout detected: found %q component in SecureJoin subpath %s", part, subPath)

343 +

}

344 + 345 +

nextDir, err := system.Openat(currentDir, part, unix.O_DIRECTORY|unix.O_NOFOLLOW|unix.O_CLOEXEC, 0)

346 +

switch {

347 +

case err == nil:

348 +

// Update the currentDir.

349 +

_ = currentDir.Close()

350 +

currentDir = nextDir

351 + 352 +

case errors.Is(err, unix.ENOTDIR):

353 +

// This might be a symlink or some other random file. Either way,

354 +

// error out.

355 +

return nil, fmt.Errorf("cannot mkdir in %s/%s: %w", currentDir.Name(), part, unix.ENOTDIR)

356 + 357 +

case errors.Is(err, os.ErrNotExist):

358 +

// Luckily, mkdirat will not follow trailing symlinks, so this is

359 +

// safe to do as-is.

360 +

if err := system.Mkdirat(currentDir, part, mode); err != nil {

361 +

return nil, err

362 +

}

363 +

// Open the new directory. There is a race here where an attacker

364 +

// could swap the directory with a different directory, but

365 +

// MkdirAll's fuzzy semantics mean we don't care about that.

366 +

nextDir, err := system.Openat(currentDir, part, unix.O_DIRECTORY|unix.O_NOFOLLOW|unix.O_CLOEXEC, 0)

367 +

if err != nil {

368 +

return nil, fmt.Errorf("open newly created directory: %w", err)

369 +

}

370 +

// Update the currentDir.

371 +

_ = currentDir.Close()

372 +

currentDir = nextDir

373 + 374 +

default:

375 +

return nil, err

376 +

}

377 +

}

378 +

return currentDir, nil

379 +

}

380 + 381 +

// MkdirAllInRoot is a wrapper around MkdirAllInRootOpen which closes the

382 +

// returned handle, for callers that don't need to use it.

383 +

func MkdirAllInRoot(root, unsafePath string, mode uint32) error {

384 +

f, err := MkdirAllInRootOpen(root, unsafePath, mode)

385 +

if err == nil {

386 +

_ = f.Close()

387 +

}

388 +

return err

389 +

}

You can’t perform that action at this time.


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4