SETUID/SETGID not required for changing user
| ... | ... |
@@ -185,15 +185,33 @@ func setupRoute(container *libcontainer.Container) error {
|
| 185 | 185 |
// and working dir, and closes any leaky file descriptors |
| 186 | 186 |
// before execing the command inside the namespace |
| 187 | 187 |
func FinalizeNamespace(container *libcontainer.Container) error {
|
| 188 |
- if err := capabilities.DropCapabilities(container); err != nil {
|
|
| 189 |
- return fmt.Errorf("drop capabilities %s", err)
|
|
| 190 |
- } |
|
| 191 | 188 |
if err := system.CloseFdsFrom(3); err != nil {
|
| 192 | 189 |
return fmt.Errorf("close open file descriptors %s", err)
|
| 193 | 190 |
} |
| 191 |
+ |
|
| 192 |
+ // drop capabilities in bounding set before changing user |
|
| 193 |
+ if err := capabilities.DropBoundingSet(container); err != nil {
|
|
| 194 |
+ return fmt.Errorf("drop bounding set %s", err)
|
|
| 195 |
+ } |
|
| 196 |
+ |
|
| 197 |
+ // preserve existing capabilities while we change users |
|
| 198 |
+ if err := system.SetKeepCaps(); err != nil {
|
|
| 199 |
+ return fmt.Errorf("set keep caps %s", err)
|
|
| 200 |
+ } |
|
| 201 |
+ |
|
| 194 | 202 |
if err := SetupUser(container.User); err != nil {
|
| 195 | 203 |
return fmt.Errorf("setup user %s", err)
|
| 196 | 204 |
} |
| 205 |
+ |
|
| 206 |
+ if err := system.ClearKeepCaps(); err != nil {
|
|
| 207 |
+ return fmt.Errorf("clear keep caps %s", err)
|
|
| 208 |
+ } |
|
| 209 |
+ |
|
| 210 |
+ // drop all other capabilities |
|
| 211 |
+ if err := capabilities.DropCapabilities(container); err != nil {
|
|
| 212 |
+ return fmt.Errorf("drop capabilities %s", err)
|
|
| 213 |
+ } |
|
| 214 |
+ |
|
| 197 | 215 |
if container.WorkingDir != "" {
|
| 198 | 216 |
if err := system.Chdir(container.WorkingDir); err != nil {
|
| 199 | 217 |
return fmt.Errorf("chdir to %s %s", container.WorkingDir, err)
|
| ... | ... |
@@ -9,6 +9,25 @@ import ( |
| 9 | 9 |
|
| 10 | 10 |
const allCapabilityTypes = capability.CAPS | capability.BOUNDS |
| 11 | 11 |
|
| 12 |
+// DropBoundingSet drops the capability bounding set to those specified in the |
|
| 13 |
+// container configuration. |
|
| 14 |
+func DropBoundingSet(container *libcontainer.Container) error {
|
|
| 15 |
+ c, err := capability.NewPid(os.Getpid()) |
|
| 16 |
+ if err != nil {
|
|
| 17 |
+ return err |
|
| 18 |
+ } |
|
| 19 |
+ |
|
| 20 |
+ keep := getEnabledCapabilities(container) |
|
| 21 |
+ c.Clear(capability.BOUNDS) |
|
| 22 |
+ c.Set(capability.BOUNDS, keep...) |
|
| 23 |
+ |
|
| 24 |
+ if err := c.Apply(capability.BOUNDS); err != nil {
|
|
| 25 |
+ return err |
|
| 26 |
+ } |
|
| 27 |
+ |
|
| 28 |
+ return nil |
|
| 29 |
+} |
|
| 30 |
+ |
|
| 12 | 31 |
// DropCapabilities drops all capabilities for the current process expect those specified in the container configuration. |
| 13 | 32 |
func DropCapabilities(container *libcontainer.Container) error {
|
| 14 | 33 |
c, err := capability.NewPid(os.Getpid()) |
| ... | ... |
@@ -135,6 +135,22 @@ func GetParentDeathSignal() (int, error) {
|
| 135 | 135 |
return sig, nil |
| 136 | 136 |
} |
| 137 | 137 |
|
| 138 |
+func SetKeepCaps() error {
|
|
| 139 |
+ if _, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_SET_KEEPCAPS, 1, 0); err != 0 {
|
|
| 140 |
+ return err |
|
| 141 |
+ } |
|
| 142 |
+ |
|
| 143 |
+ return nil |
|
| 144 |
+} |
|
| 145 |
+ |
|
| 146 |
+func ClearKeepCaps() error {
|
|
| 147 |
+ if _, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_SET_KEEPCAPS, 0, 0); err != 0 {
|
|
| 148 |
+ return err |
|
| 149 |
+ } |
|
| 150 |
+ |
|
| 151 |
+ return nil |
|
| 152 |
+} |
|
| 153 |
+ |
|
| 138 | 154 |
func Setctty() error {
|
| 139 | 155 |
if _, _, err := syscall.RawSyscall(syscall.SYS_IOCTL, 0, uintptr(syscall.TIOCSCTTY), 0); err != 0 {
|
| 140 | 156 |
return err |