Skip to content

Commit

Permalink
Post 1.7.4 release (#19918)
Browse files Browse the repository at this point in the history
  • Loading branch information
tgross authored Feb 8, 2024
2 parents 2a348ba + 2970690 commit fc26e0c
Show file tree
Hide file tree
Showing 32 changed files with 2,455 additions and 149 deletions.
3 changes: 3 additions & 0 deletions .changelog/19887.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:security
migration: Fixed a bug where archives used for migration were not checked for symlinks that escaped the allocation directory
```
3 changes: 3 additions & 0 deletions .changelog/19888.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:security
template: Fixed a bug where symlinks could force templates to read and write to arbitrary locations (CVE-2024-1329)
```
4 changes: 3 additions & 1 deletion .github/workflows/test-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,9 @@ jobs:
github.com/hashicorp/nomad/drivers/docker \
github.com/hashicorp/nomad/client/lib/fifo \
github.com/hashicorp/nomad/client/logmon \
github.com/hashicorp/nomad/client/allocrunner/taskrunner/template
github.com/hashicorp/nomad/client/allocrunner/taskrunner/template \
github.com/hashicorp/nomad/helper/winappcontainer \
github.com/hashicorp/nomad/helper/winexec
- uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
with:
name: results.xml
Expand Down
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## 1.7.4 (February 08, 2024)

SECURITY:

* deps: Updated runc to 1.1.12 to address CVE-2024-21626 [[GH-19851](https://github.com/hashicorp/nomad/issues/19851)]
* migration: Fixed a bug where archives used for migration were not checked for symlinks that escaped the allocation directory [[GH-19887](https://github.com/hashicorp/nomad/issues/19887)]
* template: Fixed a bug where symlinks could force templates to read and write to arbitrary locations (CVE-2024-1329) [[GH-19888](https://github.com/hashicorp/nomad/issues/19888)]

## 1.7.3 (January 15, 2024)

IMPROVEMENTS:
Expand Down Expand Up @@ -145,6 +153,14 @@ BUG FIXES:
* vault: Fixed a bug where poststop tasks would not get a Vault token [[GH-19268](https://github.com/hashicorp/nomad/issues/19268)]
* vault: Fixed an issue that could cause Nomad to attempt to renew a Vault token that is already expired [[GH-18985](https://github.com/hashicorp/nomad/issues/18985)]

## 1.6.7 (February 08, 2024)

SECURITY:

* deps: Updated runc to 1.1.12 to address CVE-2024-21626 [[GH-19851](https://github.com/hashicorp/nomad/issues/19851)]
* migration: Fixed a bug where archives used for migration were not checked for symlinks that escaped the allocation directory [[GH-19887](https://github.com/hashicorp/nomad/issues/19887)]
* template: Fixed a bug where symlinks could force templates to read and write to arbitrary locations (CVE-2024-1329) [[GH-19888](https://github.com/hashicorp/nomad/issues/19888)]

## 1.6.6 (January 15, 2024)

IMPROVEMENTS:
Expand Down Expand Up @@ -390,6 +406,14 @@ BUG FIXES:
* ui: fixes an issue where the allocations table on child (periodic, parameterized) job pages wouldn't update when accessed via their parent [[GH-17214](https://github.com/hashicorp/nomad/issues/17214)]
* ui: preserve newlines when displaying shown variables in non-json mode [[GH-17343](https://github.com/hashicorp/nomad/issues/17343)]

## 1.5.14 (February 08, 2024)

SECURITY:

* deps: Updated runc to 1.1.12 to address CVE-2024-21626 [[GH-19851](https://github.com/hashicorp/nomad/issues/19851)]
* migration: Fixed a bug where archives used for migration were not checked for symlinks that escaped the allocation directory [[GH-19887](https://github.com/hashicorp/nomad/issues/19887)]
* template: Fixed a bug where symlinks could force templates to read and write to arbitrary locations (CVE-2024-1329) [[GH-19888](https://github.com/hashicorp/nomad/issues/19888)]

## 1.5.13 (January 15, 2024)

IMPROVEMENTS:
Expand Down
2 changes: 1 addition & 1 deletion GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ PROTO_COMPARE_TAG ?= v1.0.3$(if $(findstring ent,$(GO_TAGS)),+ent,)

# LAST_RELEASE is the git sha of the latest release corresponding to this branch. main should have the latest
# published release, and release branches should point to the latest published release in the X.Y release line.
LAST_RELEASE ?= v1.7.3
LAST_RELEASE ?= v1.7.4

default: help

Expand Down
13 changes: 13 additions & 0 deletions client/allocrunner/taskrunner/template/renderer/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1

package renderer

// This package implements a "hidden" command `nomad template-render`, similarly
// to how we implement logmon, getter, docklog, and executor. This package's
// init() function is evaluated before Nomad's top-level main.go gets a chance
// to parse arguments. This bypasses loading in any behaviors other than the
// small bit of code here.
//
// This command and its subcommands `write` and `read` are only invoked by the
// template runner. See the parent package for the callers.
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1

//go:build !windows

package renderer

import (
"fmt"
"os"
"path/filepath"
"syscall"
)

// sandbox is the non-Windows sandbox implementation, which relies on chroot.
// Although chroot is not an appropriate boundary for tasks (implicitly
// untrusted), here the only code that's executing is Nomad itself. Returns the
// new destPath inside the chroot.
func sandbox(sandboxPath, destPath string) (string, error) {

err := syscall.Chroot(sandboxPath)
if err != nil {
// if the user is running in unsupported non-root configuration, we
// can't build the sandbox, but need to handle this gracefully
fmt.Fprintf(os.Stderr, "template-render sandbox %q not available: %v",
sandboxPath, err)
return destPath, nil
}

destPath, err = filepath.Rel(sandboxPath, destPath)
if err != nil {
return "", fmt.Errorf("could not find destination path relative to chroot: %w", err)
}
if !filepath.IsAbs(destPath) {
destPath = "/" + destPath
}

return destPath, nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1

//go:build windows

package renderer

// sandbox is the Windows-specific sandbox implementation. Under Windows,
// symlinks can only be written by the Administrator (including the
// ContainerAdministrator user unfortunately used as the default for Docker). So
// our sandboxing is done by creating an AppContainer in the caller.
func sandbox(_, destPath string) (string, error) {
return destPath, nil
}
152 changes: 152 additions & 0 deletions client/allocrunner/taskrunner/template/renderer/z_template_render.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1

package renderer

import (
"bytes"
"flag"
"fmt"
"io"
"io/fs"
"os"
"strconv"

"github.com/hashicorp/consul-template/renderer"
)

const (
// DefaultFilePerms are the default file permissions for files rendered onto
// disk when a specific file permission has not already been specified.
DefaultFilePerms = 0o644

ExitDidRender = 0
ExitError = 1
ExitWouldRenderButDidnt = 117 // something unmistakeably belonging to Nomad
)

// This init() must be initialized last in package required by the child plugin
// process. It's recommended to avoid any other `init()` or inline any necessary
// calls here. See eeaa95d commit message for more details.
func init() {
if len(os.Args) > 1 && os.Args[1] == "template-render" {

if len(os.Args) <= 3 {
// note: we don't use logger here as any message we send will get
// wrapped by CT's own logger, but it's important to keep Stderr and
// Stdout separate so that "read" has a clean output.
fmt.Fprintln(os.Stderr, `expected "read" or "write" argument`)
}

switch os.Args[2] {
case "read":
err := readTemplate()
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(ExitError)
}
os.Exit(0)

case "write":
result, err := writeTemplate()
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(ExitError)
}

if result.DidRender {
os.Exit(ExitDidRender)
}
if result.WouldRender {
os.Exit(ExitWouldRenderButDidnt)
}
os.Exit(ExitError)
default:
fmt.Fprintln(os.Stderr, `expected "read" or "write" argument`)
os.Exit(ExitError)
}
}
}

func readTemplate() error {
var (
sandboxPath, sourcePath string
err error
)

flags := flag.NewFlagSet("template-render", flag.ExitOnError)
flags.StringVar(&sandboxPath, "sandbox-path", "", "")
flags.StringVar(&sourcePath, "source-path", "", "")
flags.Parse(os.Args[3:])

sourcePath, err = sandbox(sandboxPath, sourcePath) // platform-specific sandboxing
if err != nil {
return fmt.Errorf("failed to sandbox alloc dir %q: %w", sandboxPath, err)
}

f, err := os.Open(sourcePath)
if err != nil {
return fmt.Errorf("failed to open source file %q: %w", sourcePath, err)
}
defer f.Close()

_, err = io.Copy(os.Stdout, f)
return err
}

func writeTemplate() (*renderer.RenderResult, error) {

var (
sandboxPath, destPath, perms, user, group string
)

flags := flag.NewFlagSet("template-render", flag.ExitOnError)
flags.StringVar(&sandboxPath, "sandbox-path", "", "")
flags.StringVar(&destPath, "dest-path", "", "")
flags.StringVar(&perms, "perms", "", "")
flags.StringVar(&user, "user", "", "")
flags.StringVar(&group, "group", "", "")

flags.Parse(os.Args[3:])

contents := new(bytes.Buffer)
_, err := io.Copy(contents, os.Stdin)
if err != nil {
return nil, fmt.Errorf("failed reading template contents: %w", err)
}

destPath, err = sandbox(sandboxPath, destPath) // platform-specific sandboxing
if err != nil {
return nil, fmt.Errorf("failed to sandbox alloc dir %q: %w", sandboxPath, err)
}

// perms must parse into a valid file permission
fileMode := os.FileMode(DefaultFilePerms)
if perms != "" {
fileModeInt, err := strconv.ParseUint(perms, 8, 32)
if err != nil {
return nil, fmt.Errorf(
"Invalid file mode %q: Must be a valid octal number: %w", perms, err)

}
fileMode = fs.FileMode(fileModeInt)
if fileMode.Perm() != fileMode {
return nil, fmt.Errorf(
"Invalid file mode %q: Must be a valid Unix permission: %w", perms, err)
}
}

input := &renderer.RenderInput{
Backup: false,
Contents: contents.Bytes(),
CreateDestDirs: true,
Dry: false,
DryStream: nil,
Path: destPath,
Perms: fileMode,
User: user,
Group: group,
}

return renderer.Render(input)
}
Loading

0 comments on commit fc26e0c

Please sign in to comment.