Drop capabilities in dockerinit instead of with lxc utils, since
libvirt-lxc doesn't support it.
This will also be needed for machine container mode, since dockerinit
needs CAP_SYS_ADMIN to setup /dev/console correctly.
| ... | ... |
@@ -594,6 +594,10 @@ func (container *Container) Start() (err error) {
|
| 594 | 594 |
env = append(env, "TERM=xterm") |
| 595 | 595 |
} |
| 596 | 596 |
|
| 597 |
+ if container.hostConfig.Privileged {
|
|
| 598 |
+ params = append(params, "-privileged") |
|
| 599 |
+ } |
|
| 600 |
+ |
|
| 597 | 601 |
// Init any links between the parent and children |
| 598 | 602 |
runtime := container.runtime |
| 599 | 603 |
|
| ... | ... |
@@ -27,6 +27,8 @@ git_clone github.com/gorilla/context/ 708054d61e5 |
| 27 | 27 |
|
| 28 | 28 |
git_clone github.com/gorilla/mux/ 9b36453141c |
| 29 | 29 |
|
| 30 |
+git_clone github.com/syndtr/gocapability 3454319be2 |
|
| 31 |
+ |
|
| 30 | 32 |
# Docker requires code.google.com/p/go.net/websocket |
| 31 | 33 |
PKG=code.google.com/p/go.net REV=84a4013f96e0 |
| 32 | 34 |
( |
| ... | ... |
@@ -110,18 +110,11 @@ lxc.mount.entry = {{escapeFstabSpaces $realPath}} {{escapeFstabSpaces $ROOTFS}}/
|
| 110 | 110 |
{{end}}
|
| 111 | 111 |
|
| 112 | 112 |
{{if (getHostConfig .).Privileged}}
|
| 113 |
-# retain all capabilities; no lxc.cap.drop line |
|
| 114 | 113 |
{{if (getCapabilities .).AppArmor}}
|
| 115 | 114 |
lxc.aa_profile = unconfined |
| 116 | 115 |
{{else}}
|
| 117 | 116 |
#lxc.aa_profile = unconfined |
| 118 | 117 |
{{end}}
|
| 119 |
-{{else}}
|
|
| 120 |
-# drop linux capabilities (apply mainly to the user root in the container) |
|
| 121 |
-# (Note: 'lxc.cap.keep' is coming soon and should replace this under the |
|
| 122 |
-# security principle 'deny all unless explicitly permitted', see |
|
| 123 |
-# http://sourceforge.net/mailarchive/message.php?msg_id=31054627 ) |
|
| 124 |
-lxc.cap.drop = audit_control audit_write mac_admin mac_override mknod setpcap sys_admin sys_module sys_nice sys_pacct sys_rawio sys_resource sys_time sys_tty_config |
|
| 125 | 118 |
{{end}}
|
| 126 | 119 |
|
| 127 | 120 |
# limits |
| ... | ... |
@@ -6,6 +6,7 @@ import ( |
| 6 | 6 |
"fmt" |
| 7 | 7 |
"github.com/dotcloud/docker/netlink" |
| 8 | 8 |
"github.com/dotcloud/docker/utils" |
| 9 |
+ "github.com/syndtr/gocapability/capability" |
|
| 9 | 10 |
"io/ioutil" |
| 10 | 11 |
"log" |
| 11 | 12 |
"net" |
| ... | ... |
@@ -17,11 +18,12 @@ import ( |
| 17 | 17 |
) |
| 18 | 18 |
|
| 19 | 19 |
type DockerInitArgs struct {
|
| 20 |
- user string |
|
| 21 |
- gateway string |
|
| 22 |
- workDir string |
|
| 23 |
- env []string |
|
| 24 |
- args []string |
|
| 20 |
+ user string |
|
| 21 |
+ gateway string |
|
| 22 |
+ workDir string |
|
| 23 |
+ privileged bool |
|
| 24 |
+ env []string |
|
| 25 |
+ args []string |
|
| 25 | 26 |
} |
| 26 | 27 |
|
| 27 | 28 |
// Setup networking |
| ... | ... |
@@ -82,6 +84,42 @@ func changeUser(args *DockerInitArgs) error {
|
| 82 | 82 |
return nil |
| 83 | 83 |
} |
| 84 | 84 |
|
| 85 |
+func setupCapabilities(args *DockerInitArgs) error {
|
|
| 86 |
+ |
|
| 87 |
+ if args.privileged {
|
|
| 88 |
+ return nil |
|
| 89 |
+ } |
|
| 90 |
+ |
|
| 91 |
+ drop := []capability.Cap{
|
|
| 92 |
+ capability.CAP_SETPCAP, |
|
| 93 |
+ capability.CAP_SYS_MODULE, |
|
| 94 |
+ capability.CAP_SYS_RAWIO, |
|
| 95 |
+ capability.CAP_SYS_PACCT, |
|
| 96 |
+ capability.CAP_SYS_ADMIN, |
|
| 97 |
+ capability.CAP_SYS_NICE, |
|
| 98 |
+ capability.CAP_SYS_RESOURCE, |
|
| 99 |
+ capability.CAP_SYS_TIME, |
|
| 100 |
+ capability.CAP_SYS_TTY_CONFIG, |
|
| 101 |
+ capability.CAP_MKNOD, |
|
| 102 |
+ capability.CAP_AUDIT_WRITE, |
|
| 103 |
+ capability.CAP_AUDIT_CONTROL, |
|
| 104 |
+ capability.CAP_MAC_OVERRIDE, |
|
| 105 |
+ capability.CAP_MAC_ADMIN, |
|
| 106 |
+ } |
|
| 107 |
+ |
|
| 108 |
+ c, err := capability.NewPid(os.Getpid()) |
|
| 109 |
+ if err != nil {
|
|
| 110 |
+ return err |
|
| 111 |
+ } |
|
| 112 |
+ |
|
| 113 |
+ c.Unset(capability.CAPS|capability.BOUNDS, drop...) |
|
| 114 |
+ |
|
| 115 |
+ if err := c.Apply(capability.CAPS | capability.BOUNDS); err != nil {
|
|
| 116 |
+ return err |
|
| 117 |
+ } |
|
| 118 |
+ return nil |
|
| 119 |
+} |
|
| 120 |
+ |
|
| 85 | 121 |
// Clear environment pollution introduced by lxc-start |
| 86 | 122 |
func setupEnv(args *DockerInitArgs) {
|
| 87 | 123 |
os.Clearenv() |
| ... | ... |
@@ -101,6 +139,10 @@ func executeProgram(args *DockerInitArgs) error {
|
| 101 | 101 |
return err |
| 102 | 102 |
} |
| 103 | 103 |
|
| 104 |
+ if err := setupCapabilities(args); err != nil {
|
|
| 105 |
+ return err |
|
| 106 |
+ } |
|
| 107 |
+ |
|
| 104 | 108 |
if err := setupWorkingDirectory(args); err != nil {
|
| 105 | 109 |
return err |
| 106 | 110 |
} |
| ... | ... |
@@ -136,6 +178,7 @@ func SysInit() {
|
| 136 | 136 |
user := flag.String("u", "", "username or uid")
|
| 137 | 137 |
gateway := flag.String("g", "", "gateway address")
|
| 138 | 138 |
workDir := flag.String("w", "", "workdir")
|
| 139 |
+ privileged := flag.Bool("privileged", false, "privileged mode")
|
|
| 139 | 140 |
flag.Parse() |
| 140 | 141 |
|
| 141 | 142 |
// Get env |
| ... | ... |
@@ -149,11 +192,12 @@ func SysInit() {
|
| 149 | 149 |
} |
| 150 | 150 |
|
| 151 | 151 |
args := &DockerInitArgs{
|
| 152 |
- user: *user, |
|
| 153 |
- gateway: *gateway, |
|
| 154 |
- workDir: *workDir, |
|
| 155 |
- env: env, |
|
| 156 |
- args: flag.Args(), |
|
| 152 |
+ user: *user, |
|
| 153 |
+ gateway: *gateway, |
|
| 154 |
+ workDir: *workDir, |
|
| 155 |
+ privileged: *privileged, |
|
| 156 |
+ env: env, |
|
| 157 |
+ args: flag.Args(), |
|
| 157 | 158 |
} |
| 158 | 159 |
|
| 159 | 160 |
if err := executeProgram(args); err != nil {
|
| 160 | 161 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,24 @@ |
| 0 |
+Copyright 2013 Suryandaru Triandana <syndtr@gmail.com> |
|
| 1 |
+All rights reserved. |
|
| 2 |
+ |
|
| 3 |
+Redistribution and use in source and binary forms, with or without |
|
| 4 |
+modification, are permitted provided that the following conditions are |
|
| 5 |
+met: |
|
| 6 |
+ |
|
| 7 |
+ * Redistributions of source code must retain the above copyright |
|
| 8 |
+notice, this list of conditions and the following disclaimer. |
|
| 9 |
+ * Redistributions in binary form must reproduce the above copyright |
|
| 10 |
+notice, this list of conditions and the following disclaimer in the |
|
| 11 |
+documentation and/or other materials provided with the distribution. |
|
| 12 |
+ |
|
| 13 |
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
| 14 |
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
| 15 |
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
| 16 |
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
| 17 |
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
| 18 |
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
| 19 |
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
| 20 |
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
| 21 |
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
| 22 |
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
| 23 |
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 0 | 24 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,71 @@ |
| 0 |
+// Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com> |
|
| 1 |
+// All rights reserved. |
|
| 2 |
+// |
|
| 3 |
+// Use of this source code is governed by a BSD-style license that can be |
|
| 4 |
+// found in the LICENSE file. |
|
| 5 |
+ |
|
| 6 |
+// Package capability provides utilities for manipulating POSIX capabilities. |
|
| 7 |
+package capability |
|
| 8 |
+ |
|
| 9 |
+type Capabilities interface {
|
|
| 10 |
+ // Get check whether a capability present in the given |
|
| 11 |
+ // capabilities set. The 'which' value should be one of EFFECTIVE, |
|
| 12 |
+ // PERMITTED, INHERITABLE or BOUNDING. |
|
| 13 |
+ Get(which CapType, what Cap) bool |
|
| 14 |
+ |
|
| 15 |
+ // Empty check whether all capability bits of the given capabilities |
|
| 16 |
+ // set are zero. The 'which' value should be one of EFFECTIVE, |
|
| 17 |
+ // PERMITTED, INHERITABLE or BOUNDING. |
|
| 18 |
+ Empty(which CapType) bool |
|
| 19 |
+ |
|
| 20 |
+ // Full check whether all capability bits of the given capabilities |
|
| 21 |
+ // set are one. The 'which' value should be one of EFFECTIVE, |
|
| 22 |
+ // PERMITTED, INHERITABLE or BOUNDING. |
|
| 23 |
+ Full(which CapType) bool |
|
| 24 |
+ |
|
| 25 |
+ // Set sets capabilities of the given capabilities sets. The |
|
| 26 |
+ // 'which' value should be one or combination (OR'ed) of EFFECTIVE, |
|
| 27 |
+ // PERMITTED, INHERITABLE or BOUNDING. |
|
| 28 |
+ Set(which CapType, caps ...Cap) |
|
| 29 |
+ |
|
| 30 |
+ // Unset unsets capabilities of the given capabilities sets. The |
|
| 31 |
+ // 'which' value should be one or combination (OR'ed) of EFFECTIVE, |
|
| 32 |
+ // PERMITTED, INHERITABLE or BOUNDING. |
|
| 33 |
+ Unset(which CapType, caps ...Cap) |
|
| 34 |
+ |
|
| 35 |
+ // Fill sets all bits of the given capabilities kind to one. The |
|
| 36 |
+ // 'kind' value should be one or combination (OR'ed) of CAPS or |
|
| 37 |
+ // BOUNDS. |
|
| 38 |
+ Fill(kind CapType) |
|
| 39 |
+ |
|
| 40 |
+ // Clear sets all bits of the given capabilities kind to zero. The |
|
| 41 |
+ // 'kind' value should be one or combination (OR'ed) of CAPS or |
|
| 42 |
+ // BOUNDS. |
|
| 43 |
+ Clear(kind CapType) |
|
| 44 |
+ |
|
| 45 |
+ // String return current capabilities state of the given capabilities |
|
| 46 |
+ // set as string. The 'which' value should be one of EFFECTIVE, |
|
| 47 |
+ // PERMITTED, INHERITABLE or BOUNDING. |
|
| 48 |
+ StringCap(which CapType) string |
|
| 49 |
+ |
|
| 50 |
+ // String return current capabilities state as string. |
|
| 51 |
+ String() string |
|
| 52 |
+ |
|
| 53 |
+ // Load load actual capabilities value. This will overwrite all |
|
| 54 |
+ // outstanding changes. |
|
| 55 |
+ Load() error |
|
| 56 |
+ |
|
| 57 |
+ // Apply apply the capabilities settings, so all changes will take |
|
| 58 |
+ // effect. |
|
| 59 |
+ Apply(kind CapType) error |
|
| 60 |
+} |
|
| 61 |
+ |
|
| 62 |
+// NewPid create new initialized Capabilities object for given pid. |
|
| 63 |
+func NewPid(pid int) (Capabilities, error) {
|
|
| 64 |
+ return newPid(pid) |
|
| 65 |
+} |
|
| 66 |
+ |
|
| 67 |
+// NewFile create new initialized Capabilities object for given named file. |
|
| 68 |
+func NewFile(name string) (Capabilities, error) {
|
|
| 69 |
+ return newFile(name) |
|
| 70 |
+} |
| 0 | 71 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,561 @@ |
| 0 |
+// Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com> |
|
| 1 |
+// All rights reserved. |
|
| 2 |
+// |
|
| 3 |
+// Use of this source code is governed by a BSD-style license that can be |
|
| 4 |
+// found in the LICENSE file. |
|
| 5 |
+ |
|
| 6 |
+package capability |
|
| 7 |
+ |
|
| 8 |
+import ( |
|
| 9 |
+ "bufio" |
|
| 10 |
+ "errors" |
|
| 11 |
+ "fmt" |
|
| 12 |
+ "io" |
|
| 13 |
+ "os" |
|
| 14 |
+ "strings" |
|
| 15 |
+ "syscall" |
|
| 16 |
+) |
|
| 17 |
+ |
|
| 18 |
+var errUnknownVers = errors.New("unknown capability version")
|
|
| 19 |
+ |
|
| 20 |
+const ( |
|
| 21 |
+ linuxCapVer1 = 0x19980330 |
|
| 22 |
+ linuxCapVer2 = 0x20071026 |
|
| 23 |
+ linuxCapVer3 = 0x20080522 |
|
| 24 |
+) |
|
| 25 |
+ |
|
| 26 |
+var capVers uint32 |
|
| 27 |
+ |
|
| 28 |
+func init() {
|
|
| 29 |
+ var hdr capHeader |
|
| 30 |
+ capget(&hdr, nil) |
|
| 31 |
+ capVers = hdr.version |
|
| 32 |
+} |
|
| 33 |
+ |
|
| 34 |
+func mkStringCap(c Capabilities, which CapType) (ret string) {
|
|
| 35 |
+ for i, first := Cap(0), true; i <= CAP_LAST_CAP; i++ {
|
|
| 36 |
+ if !c.Get(which, i) {
|
|
| 37 |
+ continue |
|
| 38 |
+ } |
|
| 39 |
+ if first {
|
|
| 40 |
+ first = false |
|
| 41 |
+ } else {
|
|
| 42 |
+ ret += ", " |
|
| 43 |
+ } |
|
| 44 |
+ ret += i.String() |
|
| 45 |
+ } |
|
| 46 |
+ return |
|
| 47 |
+} |
|
| 48 |
+ |
|
| 49 |
+func mkString(c Capabilities, max CapType) (ret string) {
|
|
| 50 |
+ ret = "{"
|
|
| 51 |
+ for i := CapType(1); i <= max; i <<= 1 {
|
|
| 52 |
+ ret += " " + i.String() + "=\"" |
|
| 53 |
+ if c.Empty(i) {
|
|
| 54 |
+ ret += "empty" |
|
| 55 |
+ } else if c.Full(i) {
|
|
| 56 |
+ ret += "full" |
|
| 57 |
+ } else {
|
|
| 58 |
+ ret += c.StringCap(i) |
|
| 59 |
+ } |
|
| 60 |
+ ret += "\"" |
|
| 61 |
+ } |
|
| 62 |
+ ret += " }" |
|
| 63 |
+ return |
|
| 64 |
+} |
|
| 65 |
+ |
|
| 66 |
+func newPid(pid int) (c Capabilities, err error) {
|
|
| 67 |
+ switch capVers {
|
|
| 68 |
+ case linuxCapVer1: |
|
| 69 |
+ p := new(capsV1) |
|
| 70 |
+ p.hdr.version = capVers |
|
| 71 |
+ p.hdr.pid = pid |
|
| 72 |
+ c = p |
|
| 73 |
+ case linuxCapVer2, linuxCapVer3: |
|
| 74 |
+ p := new(capsV3) |
|
| 75 |
+ p.hdr.version = capVers |
|
| 76 |
+ p.hdr.pid = pid |
|
| 77 |
+ c = p |
|
| 78 |
+ default: |
|
| 79 |
+ err = errUnknownVers |
|
| 80 |
+ return |
|
| 81 |
+ } |
|
| 82 |
+ err = c.Load() |
|
| 83 |
+ if err != nil {
|
|
| 84 |
+ c = nil |
|
| 85 |
+ } |
|
| 86 |
+ return |
|
| 87 |
+} |
|
| 88 |
+ |
|
| 89 |
+type capsV1 struct {
|
|
| 90 |
+ hdr capHeader |
|
| 91 |
+ data capData |
|
| 92 |
+} |
|
| 93 |
+ |
|
| 94 |
+func (c *capsV1) Get(which CapType, what Cap) bool {
|
|
| 95 |
+ if what > 32 {
|
|
| 96 |
+ return false |
|
| 97 |
+ } |
|
| 98 |
+ |
|
| 99 |
+ switch which {
|
|
| 100 |
+ case EFFECTIVE: |
|
| 101 |
+ return (1<<uint(what))&c.data.effective != 0 |
|
| 102 |
+ case PERMITTED: |
|
| 103 |
+ return (1<<uint(what))&c.data.permitted != 0 |
|
| 104 |
+ case INHERITABLE: |
|
| 105 |
+ return (1<<uint(what))&c.data.inheritable != 0 |
|
| 106 |
+ } |
|
| 107 |
+ |
|
| 108 |
+ return false |
|
| 109 |
+} |
|
| 110 |
+ |
|
| 111 |
+func (c *capsV1) getData(which CapType) (ret uint32) {
|
|
| 112 |
+ switch which {
|
|
| 113 |
+ case EFFECTIVE: |
|
| 114 |
+ ret = c.data.effective |
|
| 115 |
+ case PERMITTED: |
|
| 116 |
+ ret = c.data.permitted |
|
| 117 |
+ case INHERITABLE: |
|
| 118 |
+ ret = c.data.inheritable |
|
| 119 |
+ } |
|
| 120 |
+ return |
|
| 121 |
+} |
|
| 122 |
+ |
|
| 123 |
+func (c *capsV1) Empty(which CapType) bool {
|
|
| 124 |
+ return c.getData(which) == 0 |
|
| 125 |
+} |
|
| 126 |
+ |
|
| 127 |
+func (c *capsV1) Full(which CapType) bool {
|
|
| 128 |
+ return (c.getData(which) & 0x7fffffff) == 0x7fffffff |
|
| 129 |
+} |
|
| 130 |
+ |
|
| 131 |
+func (c *capsV1) Set(which CapType, caps ...Cap) {
|
|
| 132 |
+ for _, what := range caps {
|
|
| 133 |
+ if what > 32 {
|
|
| 134 |
+ continue |
|
| 135 |
+ } |
|
| 136 |
+ |
|
| 137 |
+ if which&EFFECTIVE != 0 {
|
|
| 138 |
+ c.data.effective |= 1 << uint(what) |
|
| 139 |
+ } |
|
| 140 |
+ if which&PERMITTED != 0 {
|
|
| 141 |
+ c.data.permitted |= 1 << uint(what) |
|
| 142 |
+ } |
|
| 143 |
+ if which&INHERITABLE != 0 {
|
|
| 144 |
+ c.data.inheritable |= 1 << uint(what) |
|
| 145 |
+ } |
|
| 146 |
+ } |
|
| 147 |
+} |
|
| 148 |
+ |
|
| 149 |
+func (c *capsV1) Unset(which CapType, caps ...Cap) {
|
|
| 150 |
+ for _, what := range caps {
|
|
| 151 |
+ if what > 32 {
|
|
| 152 |
+ continue |
|
| 153 |
+ } |
|
| 154 |
+ |
|
| 155 |
+ if which&EFFECTIVE != 0 {
|
|
| 156 |
+ c.data.effective &= ^(1 << uint(what)) |
|
| 157 |
+ } |
|
| 158 |
+ if which&PERMITTED != 0 {
|
|
| 159 |
+ c.data.permitted &= ^(1 << uint(what)) |
|
| 160 |
+ } |
|
| 161 |
+ if which&INHERITABLE != 0 {
|
|
| 162 |
+ c.data.inheritable &= ^(1 << uint(what)) |
|
| 163 |
+ } |
|
| 164 |
+ } |
|
| 165 |
+} |
|
| 166 |
+ |
|
| 167 |
+func (c *capsV1) Fill(kind CapType) {
|
|
| 168 |
+ if kind&CAPS == CAPS {
|
|
| 169 |
+ c.data.effective = 0x7fffffff |
|
| 170 |
+ c.data.permitted = 0x7fffffff |
|
| 171 |
+ c.data.inheritable = 0 |
|
| 172 |
+ } |
|
| 173 |
+} |
|
| 174 |
+ |
|
| 175 |
+func (c *capsV1) Clear(kind CapType) {
|
|
| 176 |
+ if kind&CAPS == CAPS {
|
|
| 177 |
+ c.data.effective = 0 |
|
| 178 |
+ c.data.permitted = 0 |
|
| 179 |
+ c.data.inheritable = 0 |
|
| 180 |
+ } |
|
| 181 |
+} |
|
| 182 |
+ |
|
| 183 |
+func (c *capsV1) StringCap(which CapType) (ret string) {
|
|
| 184 |
+ return mkStringCap(c, which) |
|
| 185 |
+} |
|
| 186 |
+ |
|
| 187 |
+func (c *capsV1) String() (ret string) {
|
|
| 188 |
+ return mkString(c, BOUNDING) |
|
| 189 |
+} |
|
| 190 |
+ |
|
| 191 |
+func (c *capsV1) Load() (err error) {
|
|
| 192 |
+ return capget(&c.hdr, &c.data) |
|
| 193 |
+} |
|
| 194 |
+ |
|
| 195 |
+func (c *capsV1) Apply(kind CapType) error {
|
|
| 196 |
+ if kind&CAPS == CAPS {
|
|
| 197 |
+ return capset(&c.hdr, &c.data) |
|
| 198 |
+ } |
|
| 199 |
+ return nil |
|
| 200 |
+} |
|
| 201 |
+ |
|
| 202 |
+type capsV3 struct {
|
|
| 203 |
+ hdr capHeader |
|
| 204 |
+ data [2]capData |
|
| 205 |
+ bounds [2]uint32 |
|
| 206 |
+} |
|
| 207 |
+ |
|
| 208 |
+func (c *capsV3) Get(which CapType, what Cap) bool {
|
|
| 209 |
+ var i uint |
|
| 210 |
+ if what > 31 {
|
|
| 211 |
+ i = uint(what) >> 5 |
|
| 212 |
+ what %= 32 |
|
| 213 |
+ } |
|
| 214 |
+ |
|
| 215 |
+ switch which {
|
|
| 216 |
+ case EFFECTIVE: |
|
| 217 |
+ return (1<<uint(what))&c.data[i].effective != 0 |
|
| 218 |
+ case PERMITTED: |
|
| 219 |
+ return (1<<uint(what))&c.data[i].permitted != 0 |
|
| 220 |
+ case INHERITABLE: |
|
| 221 |
+ return (1<<uint(what))&c.data[i].inheritable != 0 |
|
| 222 |
+ case BOUNDING: |
|
| 223 |
+ return (1<<uint(what))&c.bounds[i] != 0 |
|
| 224 |
+ } |
|
| 225 |
+ |
|
| 226 |
+ return false |
|
| 227 |
+} |
|
| 228 |
+ |
|
| 229 |
+func (c *capsV3) getData(which CapType, dest []uint32) {
|
|
| 230 |
+ switch which {
|
|
| 231 |
+ case EFFECTIVE: |
|
| 232 |
+ dest[0] = c.data[0].effective |
|
| 233 |
+ dest[1] = c.data[1].effective |
|
| 234 |
+ case PERMITTED: |
|
| 235 |
+ dest[0] = c.data[0].permitted |
|
| 236 |
+ dest[1] = c.data[1].permitted |
|
| 237 |
+ case INHERITABLE: |
|
| 238 |
+ dest[0] = c.data[0].inheritable |
|
| 239 |
+ dest[1] = c.data[1].inheritable |
|
| 240 |
+ case BOUNDING: |
|
| 241 |
+ dest[0] = c.bounds[0] |
|
| 242 |
+ dest[1] = c.bounds[1] |
|
| 243 |
+ } |
|
| 244 |
+} |
|
| 245 |
+ |
|
| 246 |
+func (c *capsV3) Empty(which CapType) bool {
|
|
| 247 |
+ var data [2]uint32 |
|
| 248 |
+ c.getData(which, data[:]) |
|
| 249 |
+ return data[0] == 0 && data[1] == 0 |
|
| 250 |
+} |
|
| 251 |
+ |
|
| 252 |
+func (c *capsV3) Full(which CapType) bool {
|
|
| 253 |
+ var data [2]uint32 |
|
| 254 |
+ c.getData(which, data[:]) |
|
| 255 |
+ if (data[0] & 0xffffffff) != 0xffffffff {
|
|
| 256 |
+ return false |
|
| 257 |
+ } |
|
| 258 |
+ return (data[1] & capUpperMask) == capUpperMask |
|
| 259 |
+} |
|
| 260 |
+ |
|
| 261 |
+func (c *capsV3) Set(which CapType, caps ...Cap) {
|
|
| 262 |
+ for _, what := range caps {
|
|
| 263 |
+ var i uint |
|
| 264 |
+ if what > 31 {
|
|
| 265 |
+ i = uint(what) >> 5 |
|
| 266 |
+ what %= 32 |
|
| 267 |
+ } |
|
| 268 |
+ |
|
| 269 |
+ if which&EFFECTIVE != 0 {
|
|
| 270 |
+ c.data[i].effective |= 1 << uint(what) |
|
| 271 |
+ } |
|
| 272 |
+ if which&PERMITTED != 0 {
|
|
| 273 |
+ c.data[i].permitted |= 1 << uint(what) |
|
| 274 |
+ } |
|
| 275 |
+ if which&INHERITABLE != 0 {
|
|
| 276 |
+ c.data[i].inheritable |= 1 << uint(what) |
|
| 277 |
+ } |
|
| 278 |
+ if which&BOUNDING != 0 {
|
|
| 279 |
+ c.bounds[i] |= 1 << uint(what) |
|
| 280 |
+ } |
|
| 281 |
+ } |
|
| 282 |
+} |
|
| 283 |
+ |
|
| 284 |
+func (c *capsV3) Unset(which CapType, caps ...Cap) {
|
|
| 285 |
+ for _, what := range caps {
|
|
| 286 |
+ var i uint |
|
| 287 |
+ if what > 31 {
|
|
| 288 |
+ i = uint(what) >> 5 |
|
| 289 |
+ what %= 32 |
|
| 290 |
+ } |
|
| 291 |
+ |
|
| 292 |
+ if which&EFFECTIVE != 0 {
|
|
| 293 |
+ c.data[i].effective &= ^(1 << uint(what)) |
|
| 294 |
+ } |
|
| 295 |
+ if which&PERMITTED != 0 {
|
|
| 296 |
+ c.data[i].permitted &= ^(1 << uint(what)) |
|
| 297 |
+ } |
|
| 298 |
+ if which&INHERITABLE != 0 {
|
|
| 299 |
+ c.data[i].inheritable &= ^(1 << uint(what)) |
|
| 300 |
+ } |
|
| 301 |
+ if which&BOUNDING != 0 {
|
|
| 302 |
+ c.bounds[i] &= ^(1 << uint(what)) |
|
| 303 |
+ } |
|
| 304 |
+ } |
|
| 305 |
+} |
|
| 306 |
+ |
|
| 307 |
+func (c *capsV3) Fill(kind CapType) {
|
|
| 308 |
+ if kind&CAPS == CAPS {
|
|
| 309 |
+ c.data[0].effective = 0xffffffff |
|
| 310 |
+ c.data[0].permitted = 0xffffffff |
|
| 311 |
+ c.data[0].inheritable = 0 |
|
| 312 |
+ c.data[1].effective = 0xffffffff |
|
| 313 |
+ c.data[1].permitted = 0xffffffff |
|
| 314 |
+ c.data[1].inheritable = 0 |
|
| 315 |
+ } |
|
| 316 |
+ |
|
| 317 |
+ if kind&BOUNDS == BOUNDS {
|
|
| 318 |
+ c.bounds[0] = 0xffffffff |
|
| 319 |
+ c.bounds[1] = 0xffffffff |
|
| 320 |
+ } |
|
| 321 |
+} |
|
| 322 |
+ |
|
| 323 |
+func (c *capsV3) Clear(kind CapType) {
|
|
| 324 |
+ if kind&CAPS == CAPS {
|
|
| 325 |
+ c.data[0].effective = 0 |
|
| 326 |
+ c.data[0].permitted = 0 |
|
| 327 |
+ c.data[0].inheritable = 0 |
|
| 328 |
+ c.data[1].effective = 0 |
|
| 329 |
+ c.data[1].permitted = 0 |
|
| 330 |
+ c.data[1].inheritable = 0 |
|
| 331 |
+ } |
|
| 332 |
+ |
|
| 333 |
+ if kind&BOUNDS == BOUNDS {
|
|
| 334 |
+ c.bounds[0] = 0 |
|
| 335 |
+ c.bounds[1] = 0 |
|
| 336 |
+ } |
|
| 337 |
+} |
|
| 338 |
+ |
|
| 339 |
+func (c *capsV3) StringCap(which CapType) (ret string) {
|
|
| 340 |
+ return mkStringCap(c, which) |
|
| 341 |
+} |
|
| 342 |
+ |
|
| 343 |
+func (c *capsV3) String() (ret string) {
|
|
| 344 |
+ return mkString(c, BOUNDING) |
|
| 345 |
+} |
|
| 346 |
+ |
|
| 347 |
+func (c *capsV3) Load() (err error) {
|
|
| 348 |
+ err = capget(&c.hdr, &c.data[0]) |
|
| 349 |
+ if err != nil {
|
|
| 350 |
+ return |
|
| 351 |
+ } |
|
| 352 |
+ |
|
| 353 |
+ f, err := os.Open(fmt.Sprintf("/proc/%d/status", c.hdr.pid))
|
|
| 354 |
+ if err != nil {
|
|
| 355 |
+ return |
|
| 356 |
+ } |
|
| 357 |
+ b := bufio.NewReader(f) |
|
| 358 |
+ for {
|
|
| 359 |
+ line, e := b.ReadString('\n')
|
|
| 360 |
+ if e != nil {
|
|
| 361 |
+ if e != io.EOF {
|
|
| 362 |
+ err = e |
|
| 363 |
+ } |
|
| 364 |
+ break |
|
| 365 |
+ } |
|
| 366 |
+ if strings.HasPrefix(line, "CapB") {
|
|
| 367 |
+ fmt.Sscanf(line[4:], "nd: %08x%08x", &c.bounds[1], &c.bounds[0]) |
|
| 368 |
+ break |
|
| 369 |
+ } |
|
| 370 |
+ } |
|
| 371 |
+ f.Close() |
|
| 372 |
+ |
|
| 373 |
+ return |
|
| 374 |
+} |
|
| 375 |
+ |
|
| 376 |
+func (c *capsV3) Apply(kind CapType) (err error) {
|
|
| 377 |
+ if kind&BOUNDS == BOUNDS {
|
|
| 378 |
+ var data [2]capData |
|
| 379 |
+ err = capget(&c.hdr, &data[0]) |
|
| 380 |
+ if err != nil {
|
|
| 381 |
+ return |
|
| 382 |
+ } |
|
| 383 |
+ if (1<<uint(CAP_SETPCAP))&data[0].effective != 0 {
|
|
| 384 |
+ for i := Cap(0); i <= CAP_LAST_CAP; i++ {
|
|
| 385 |
+ if c.Get(BOUNDING, i) {
|
|
| 386 |
+ continue |
|
| 387 |
+ } |
|
| 388 |
+ err = prctl(syscall.PR_CAPBSET_DROP, uintptr(i), 0, 0, 0) |
|
| 389 |
+ if err != nil {
|
|
| 390 |
+ return |
|
| 391 |
+ } |
|
| 392 |
+ } |
|
| 393 |
+ } |
|
| 394 |
+ } |
|
| 395 |
+ |
|
| 396 |
+ if kind&CAPS == CAPS {
|
|
| 397 |
+ return capset(&c.hdr, &c.data[0]) |
|
| 398 |
+ } |
|
| 399 |
+ |
|
| 400 |
+ return |
|
| 401 |
+} |
|
| 402 |
+ |
|
| 403 |
+func newFile(path string) (c Capabilities, err error) {
|
|
| 404 |
+ c = &capsFile{path: path}
|
|
| 405 |
+ err = c.Load() |
|
| 406 |
+ if err != nil {
|
|
| 407 |
+ c = nil |
|
| 408 |
+ } |
|
| 409 |
+ return |
|
| 410 |
+} |
|
| 411 |
+ |
|
| 412 |
+type capsFile struct {
|
|
| 413 |
+ path string |
|
| 414 |
+ data vfscapData |
|
| 415 |
+} |
|
| 416 |
+ |
|
| 417 |
+func (c *capsFile) Get(which CapType, what Cap) bool {
|
|
| 418 |
+ var i uint |
|
| 419 |
+ if what > 31 {
|
|
| 420 |
+ if c.data.version == 1 {
|
|
| 421 |
+ return false |
|
| 422 |
+ } |
|
| 423 |
+ i = uint(what) >> 5 |
|
| 424 |
+ what %= 32 |
|
| 425 |
+ } |
|
| 426 |
+ |
|
| 427 |
+ switch which {
|
|
| 428 |
+ case EFFECTIVE: |
|
| 429 |
+ return (1<<uint(what))&c.data.effective[i] != 0 |
|
| 430 |
+ case PERMITTED: |
|
| 431 |
+ return (1<<uint(what))&c.data.data[i].permitted != 0 |
|
| 432 |
+ case INHERITABLE: |
|
| 433 |
+ return (1<<uint(what))&c.data.data[i].inheritable != 0 |
|
| 434 |
+ } |
|
| 435 |
+ |
|
| 436 |
+ return false |
|
| 437 |
+} |
|
| 438 |
+ |
|
| 439 |
+func (c *capsFile) getData(which CapType, dest []uint32) {
|
|
| 440 |
+ switch which {
|
|
| 441 |
+ case EFFECTIVE: |
|
| 442 |
+ dest[0] = c.data.effective[0] |
|
| 443 |
+ dest[1] = c.data.effective[1] |
|
| 444 |
+ case PERMITTED: |
|
| 445 |
+ dest[0] = c.data.data[0].permitted |
|
| 446 |
+ dest[1] = c.data.data[1].permitted |
|
| 447 |
+ case INHERITABLE: |
|
| 448 |
+ dest[0] = c.data.data[0].inheritable |
|
| 449 |
+ dest[1] = c.data.data[1].inheritable |
|
| 450 |
+ } |
|
| 451 |
+} |
|
| 452 |
+ |
|
| 453 |
+func (c *capsFile) Empty(which CapType) bool {
|
|
| 454 |
+ var data [2]uint32 |
|
| 455 |
+ c.getData(which, data[:]) |
|
| 456 |
+ return data[0] == 0 && data[1] == 0 |
|
| 457 |
+} |
|
| 458 |
+ |
|
| 459 |
+func (c *capsFile) Full(which CapType) bool {
|
|
| 460 |
+ var data [2]uint32 |
|
| 461 |
+ c.getData(which, data[:]) |
|
| 462 |
+ if c.data.version == 0 {
|
|
| 463 |
+ return (data[0] & 0x7fffffff) == 0x7fffffff |
|
| 464 |
+ } |
|
| 465 |
+ if (data[0] & 0xffffffff) != 0xffffffff {
|
|
| 466 |
+ return false |
|
| 467 |
+ } |
|
| 468 |
+ return (data[1] & capUpperMask) == capUpperMask |
|
| 469 |
+} |
|
| 470 |
+ |
|
| 471 |
+func (c *capsFile) Set(which CapType, caps ...Cap) {
|
|
| 472 |
+ for _, what := range caps {
|
|
| 473 |
+ var i uint |
|
| 474 |
+ if what > 31 {
|
|
| 475 |
+ if c.data.version == 1 {
|
|
| 476 |
+ continue |
|
| 477 |
+ } |
|
| 478 |
+ i = uint(what) >> 5 |
|
| 479 |
+ what %= 32 |
|
| 480 |
+ } |
|
| 481 |
+ |
|
| 482 |
+ if which&EFFECTIVE != 0 {
|
|
| 483 |
+ c.data.effective[i] |= 1 << uint(what) |
|
| 484 |
+ } |
|
| 485 |
+ if which&PERMITTED != 0 {
|
|
| 486 |
+ c.data.data[i].permitted |= 1 << uint(what) |
|
| 487 |
+ } |
|
| 488 |
+ if which&INHERITABLE != 0 {
|
|
| 489 |
+ c.data.data[i].inheritable |= 1 << uint(what) |
|
| 490 |
+ } |
|
| 491 |
+ } |
|
| 492 |
+} |
|
| 493 |
+ |
|
| 494 |
+func (c *capsFile) Unset(which CapType, caps ...Cap) {
|
|
| 495 |
+ for _, what := range caps {
|
|
| 496 |
+ var i uint |
|
| 497 |
+ if what > 31 {
|
|
| 498 |
+ if c.data.version == 1 {
|
|
| 499 |
+ continue |
|
| 500 |
+ } |
|
| 501 |
+ i = uint(what) >> 5 |
|
| 502 |
+ what %= 32 |
|
| 503 |
+ } |
|
| 504 |
+ |
|
| 505 |
+ if which&EFFECTIVE != 0 {
|
|
| 506 |
+ c.data.effective[i] &= ^(1 << uint(what)) |
|
| 507 |
+ } |
|
| 508 |
+ if which&PERMITTED != 0 {
|
|
| 509 |
+ c.data.data[i].permitted &= ^(1 << uint(what)) |
|
| 510 |
+ } |
|
| 511 |
+ if which&INHERITABLE != 0 {
|
|
| 512 |
+ c.data.data[i].inheritable &= ^(1 << uint(what)) |
|
| 513 |
+ } |
|
| 514 |
+ } |
|
| 515 |
+} |
|
| 516 |
+ |
|
| 517 |
+func (c *capsFile) Fill(kind CapType) {
|
|
| 518 |
+ if kind&CAPS == CAPS {
|
|
| 519 |
+ c.data.effective[0] = 0xffffffff |
|
| 520 |
+ c.data.data[0].permitted = 0xffffffff |
|
| 521 |
+ c.data.data[0].inheritable = 0 |
|
| 522 |
+ if c.data.version == 2 {
|
|
| 523 |
+ c.data.effective[1] = 0xffffffff |
|
| 524 |
+ c.data.data[1].permitted = 0xffffffff |
|
| 525 |
+ c.data.data[1].inheritable = 0 |
|
| 526 |
+ } |
|
| 527 |
+ } |
|
| 528 |
+} |
|
| 529 |
+ |
|
| 530 |
+func (c *capsFile) Clear(kind CapType) {
|
|
| 531 |
+ if kind&CAPS == CAPS {
|
|
| 532 |
+ c.data.effective[0] = 0 |
|
| 533 |
+ c.data.data[0].permitted = 0 |
|
| 534 |
+ c.data.data[0].inheritable = 0 |
|
| 535 |
+ if c.data.version == 2 {
|
|
| 536 |
+ c.data.effective[1] = 0 |
|
| 537 |
+ c.data.data[1].permitted = 0 |
|
| 538 |
+ c.data.data[1].inheritable = 0 |
|
| 539 |
+ } |
|
| 540 |
+ } |
|
| 541 |
+} |
|
| 542 |
+ |
|
| 543 |
+func (c *capsFile) StringCap(which CapType) (ret string) {
|
|
| 544 |
+ return mkStringCap(c, which) |
|
| 545 |
+} |
|
| 546 |
+ |
|
| 547 |
+func (c *capsFile) String() (ret string) {
|
|
| 548 |
+ return mkString(c, INHERITABLE) |
|
| 549 |
+} |
|
| 550 |
+ |
|
| 551 |
+func (c *capsFile) Load() (err error) {
|
|
| 552 |
+ return getVfsCap(c.path, &c.data) |
|
| 553 |
+} |
|
| 554 |
+ |
|
| 555 |
+func (c *capsFile) Apply(kind CapType) (err error) {
|
|
| 556 |
+ if kind&CAPS == CAPS {
|
|
| 557 |
+ return setVfsCap(c.path, &c.data) |
|
| 558 |
+ } |
|
| 559 |
+ return |
|
| 560 |
+} |
| 0 | 561 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,19 @@ |
| 0 |
+// Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com> |
|
| 1 |
+// All rights reserved. |
|
| 2 |
+// |
|
| 3 |
+// Use of this source code is governed by a BSD-style license that can be |
|
| 4 |
+// found in the LICENSE file. |
|
| 5 |
+ |
|
| 6 |
+// +build !linux |
|
| 7 |
+ |
|
| 8 |
+package capability |
|
| 9 |
+ |
|
| 10 |
+import "errors" |
|
| 11 |
+ |
|
| 12 |
+func newPid(pid int) (Capabilities, error) {
|
|
| 13 |
+ return nil, errors.New("not supported")
|
|
| 14 |
+} |
|
| 15 |
+ |
|
| 16 |
+func newFile(path string) (Capabilities, error) {
|
|
| 17 |
+ return nil, errors.New("not supported")
|
|
| 18 |
+} |
| 0 | 19 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,83 @@ |
| 0 |
+// Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com> |
|
| 1 |
+// All rights reserved. |
|
| 2 |
+// |
|
| 3 |
+// Use of this source code is governed by a BSD-style license that can be |
|
| 4 |
+// found in the LICENSE file. |
|
| 5 |
+ |
|
| 6 |
+package capability |
|
| 7 |
+ |
|
| 8 |
+import "testing" |
|
| 9 |
+ |
|
| 10 |
+func TestState(t *testing.T) {
|
|
| 11 |
+ testEmpty := func(name string, c Capabilities, whats CapType) {
|
|
| 12 |
+ for i := CapType(1); i <= BOUNDING; i <<= 1 {
|
|
| 13 |
+ if (i&whats) != 0 && !c.Empty(i) {
|
|
| 14 |
+ t.Errorf(name+": capabilities set %q wasn't empty", i) |
|
| 15 |
+ } |
|
| 16 |
+ } |
|
| 17 |
+ } |
|
| 18 |
+ testFull := func(name string, c Capabilities, whats CapType) {
|
|
| 19 |
+ for i := CapType(1); i <= BOUNDING; i <<= 1 {
|
|
| 20 |
+ if (i&whats) != 0 && !c.Full(i) {
|
|
| 21 |
+ t.Errorf(name+": capabilities set %q wasn't full", i) |
|
| 22 |
+ } |
|
| 23 |
+ } |
|
| 24 |
+ } |
|
| 25 |
+ testPartial := func(name string, c Capabilities, whats CapType) {
|
|
| 26 |
+ for i := CapType(1); i <= BOUNDING; i <<= 1 {
|
|
| 27 |
+ if (i&whats) != 0 && (c.Empty(i) || c.Full(i)) {
|
|
| 28 |
+ t.Errorf(name+": capabilities set %q wasn't partial", i) |
|
| 29 |
+ } |
|
| 30 |
+ } |
|
| 31 |
+ } |
|
| 32 |
+ testGet := func(name string, c Capabilities, whats CapType, max Cap) {
|
|
| 33 |
+ for i := CapType(1); i <= BOUNDING; i <<= 1 {
|
|
| 34 |
+ if (i & whats) == 0 {
|
|
| 35 |
+ continue |
|
| 36 |
+ } |
|
| 37 |
+ for j := Cap(0); j <= max; j++ {
|
|
| 38 |
+ if !c.Get(i, j) {
|
|
| 39 |
+ t.Errorf(name+": capability %q wasn't found on %q", j, i) |
|
| 40 |
+ } |
|
| 41 |
+ } |
|
| 42 |
+ } |
|
| 43 |
+ } |
|
| 44 |
+ |
|
| 45 |
+ capf := new(capsFile) |
|
| 46 |
+ capf.data.version = 2 |
|
| 47 |
+ for _, tc := range []struct {
|
|
| 48 |
+ name string |
|
| 49 |
+ c Capabilities |
|
| 50 |
+ sets CapType |
|
| 51 |
+ max Cap |
|
| 52 |
+ }{
|
|
| 53 |
+ {"v1", new(capsV1), EFFECTIVE | PERMITTED, CAP_AUDIT_CONTROL},
|
|
| 54 |
+ {"v3", new(capsV3), EFFECTIVE | PERMITTED | BOUNDING, CAP_LAST_CAP},
|
|
| 55 |
+ {"file_v1", new(capsFile), EFFECTIVE | PERMITTED, CAP_AUDIT_CONTROL},
|
|
| 56 |
+ {"file_v2", capf, EFFECTIVE | PERMITTED, CAP_LAST_CAP},
|
|
| 57 |
+ } {
|
|
| 58 |
+ testEmpty(tc.name, tc.c, tc.sets) |
|
| 59 |
+ tc.c.Fill(CAPS | BOUNDS) |
|
| 60 |
+ testFull(tc.name, tc.c, tc.sets) |
|
| 61 |
+ testGet(tc.name, tc.c, tc.sets, tc.max) |
|
| 62 |
+ tc.c.Clear(CAPS | BOUNDS) |
|
| 63 |
+ testEmpty(tc.name, tc.c, tc.sets) |
|
| 64 |
+ for i := CapType(1); i <= BOUNDING; i <<= 1 {
|
|
| 65 |
+ for j := Cap(0); j <= CAP_LAST_CAP; j++ {
|
|
| 66 |
+ tc.c.Set(i, j) |
|
| 67 |
+ } |
|
| 68 |
+ } |
|
| 69 |
+ testFull(tc.name, tc.c, tc.sets) |
|
| 70 |
+ testGet(tc.name, tc.c, tc.sets, tc.max) |
|
| 71 |
+ for i := CapType(1); i <= BOUNDING; i <<= 1 {
|
|
| 72 |
+ for j := Cap(0); j <= CAP_LAST_CAP; j++ {
|
|
| 73 |
+ tc.c.Unset(i, j) |
|
| 74 |
+ } |
|
| 75 |
+ } |
|
| 76 |
+ testEmpty(tc.name, tc.c, tc.sets) |
|
| 77 |
+ tc.c.Set(PERMITTED, CAP_CHOWN) |
|
| 78 |
+ testPartial(tc.name, tc.c, PERMITTED) |
|
| 79 |
+ tc.c.Clear(CAPS | BOUNDS) |
|
| 80 |
+ testEmpty(tc.name, tc.c, tc.sets) |
|
| 81 |
+ } |
|
| 82 |
+} |
| 0 | 83 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,338 @@ |
| 0 |
+// Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com> |
|
| 1 |
+// All rights reserved. |
|
| 2 |
+// |
|
| 3 |
+// Use of this source code is governed by a BSD-style license that can be |
|
| 4 |
+// found in the LICENSE file. |
|
| 5 |
+ |
|
| 6 |
+package capability |
|
| 7 |
+ |
|
| 8 |
+type CapType uint |
|
| 9 |
+ |
|
| 10 |
+func (c CapType) String() string {
|
|
| 11 |
+ switch c {
|
|
| 12 |
+ case EFFECTIVE: |
|
| 13 |
+ return "effective" |
|
| 14 |
+ case PERMITTED: |
|
| 15 |
+ return "permitted" |
|
| 16 |
+ case INHERITABLE: |
|
| 17 |
+ return "inheritable" |
|
| 18 |
+ case BOUNDING: |
|
| 19 |
+ return "bounding" |
|
| 20 |
+ case CAPS: |
|
| 21 |
+ return "caps" |
|
| 22 |
+ } |
|
| 23 |
+ return "unknown" |
|
| 24 |
+} |
|
| 25 |
+ |
|
| 26 |
+const ( |
|
| 27 |
+ EFFECTIVE CapType = 1 << iota |
|
| 28 |
+ PERMITTED |
|
| 29 |
+ INHERITABLE |
|
| 30 |
+ BOUNDING |
|
| 31 |
+ |
|
| 32 |
+ CAPS = EFFECTIVE | PERMITTED | INHERITABLE |
|
| 33 |
+ BOUNDS = BOUNDING |
|
| 34 |
+) |
|
| 35 |
+ |
|
| 36 |
+type Cap int |
|
| 37 |
+ |
|
| 38 |
+func (c Cap) String() string {
|
|
| 39 |
+ switch c {
|
|
| 40 |
+ case CAP_CHOWN: |
|
| 41 |
+ return "chown" |
|
| 42 |
+ case CAP_DAC_OVERRIDE: |
|
| 43 |
+ return "dac_override" |
|
| 44 |
+ case CAP_DAC_READ_SEARCH: |
|
| 45 |
+ return "dac_read_search" |
|
| 46 |
+ case CAP_FOWNER: |
|
| 47 |
+ return "fowner" |
|
| 48 |
+ case CAP_FSETID: |
|
| 49 |
+ return "fsetid" |
|
| 50 |
+ case CAP_KILL: |
|
| 51 |
+ return "kill" |
|
| 52 |
+ case CAP_SETGID: |
|
| 53 |
+ return "setgid" |
|
| 54 |
+ case CAP_SETUID: |
|
| 55 |
+ return "setuid" |
|
| 56 |
+ case CAP_SETPCAP: |
|
| 57 |
+ return "setpcap" |
|
| 58 |
+ case CAP_LINUX_IMMUTABLE: |
|
| 59 |
+ return "linux_immutable" |
|
| 60 |
+ case CAP_NET_BIND_SERVICE: |
|
| 61 |
+ return "net_bind_service" |
|
| 62 |
+ case CAP_NET_BROADCAST: |
|
| 63 |
+ return "net_broadcast" |
|
| 64 |
+ case CAP_NET_ADMIN: |
|
| 65 |
+ return "net_admin" |
|
| 66 |
+ case CAP_NET_RAW: |
|
| 67 |
+ return "net_raw" |
|
| 68 |
+ case CAP_IPC_LOCK: |
|
| 69 |
+ return "ipc_lock" |
|
| 70 |
+ case CAP_IPC_OWNER: |
|
| 71 |
+ return "ipc_owner" |
|
| 72 |
+ case CAP_SYS_MODULE: |
|
| 73 |
+ return "sys_module" |
|
| 74 |
+ case CAP_SYS_RAWIO: |
|
| 75 |
+ return "sys_rawio" |
|
| 76 |
+ case CAP_SYS_CHROOT: |
|
| 77 |
+ return "sys_chroot" |
|
| 78 |
+ case CAP_SYS_PTRACE: |
|
| 79 |
+ return "sys_ptrace" |
|
| 80 |
+ case CAP_SYS_PACCT: |
|
| 81 |
+ return "sys_psacct" |
|
| 82 |
+ case CAP_SYS_ADMIN: |
|
| 83 |
+ return "sys_admin" |
|
| 84 |
+ case CAP_SYS_BOOT: |
|
| 85 |
+ return "sys_boot" |
|
| 86 |
+ case CAP_SYS_NICE: |
|
| 87 |
+ return "sys_nice" |
|
| 88 |
+ case CAP_SYS_RESOURCE: |
|
| 89 |
+ return "sys_resource" |
|
| 90 |
+ case CAP_SYS_TIME: |
|
| 91 |
+ return "sys_time" |
|
| 92 |
+ case CAP_SYS_TTY_CONFIG: |
|
| 93 |
+ return "sys_tty_config" |
|
| 94 |
+ case CAP_MKNOD: |
|
| 95 |
+ return "mknod" |
|
| 96 |
+ case CAP_LEASE: |
|
| 97 |
+ return "lease" |
|
| 98 |
+ case CAP_AUDIT_WRITE: |
|
| 99 |
+ return "audit_write" |
|
| 100 |
+ case CAP_AUDIT_CONTROL: |
|
| 101 |
+ return "audit_control" |
|
| 102 |
+ case CAP_SETFCAP: |
|
| 103 |
+ return "setfcap" |
|
| 104 |
+ case CAP_MAC_OVERRIDE: |
|
| 105 |
+ return "mac_override" |
|
| 106 |
+ case CAP_MAC_ADMIN: |
|
| 107 |
+ return "mac_admin" |
|
| 108 |
+ case CAP_SYSLOG: |
|
| 109 |
+ return "syslog" |
|
| 110 |
+ case CAP_WAKE_ALARM: |
|
| 111 |
+ return "wake_alarm" |
|
| 112 |
+ case CAP_BLOCK_SUSPEND: |
|
| 113 |
+ return "block_suspend" |
|
| 114 |
+ } |
|
| 115 |
+ return "unknown" |
|
| 116 |
+} |
|
| 117 |
+ |
|
| 118 |
+const ( |
|
| 119 |
+ // POSIX-draft defined capabilities. |
|
| 120 |
+ |
|
| 121 |
+ // In a system with the [_POSIX_CHOWN_RESTRICTED] option defined, this |
|
| 122 |
+ // overrides the restriction of changing file ownership and group |
|
| 123 |
+ // ownership. |
|
| 124 |
+ CAP_CHOWN Cap = 0 |
|
| 125 |
+ |
|
| 126 |
+ // Override all DAC access, including ACL execute access if |
|
| 127 |
+ // [_POSIX_ACL] is defined. Excluding DAC access covered by |
|
| 128 |
+ // CAP_LINUX_IMMUTABLE. |
|
| 129 |
+ CAP_DAC_OVERRIDE Cap = 1 |
|
| 130 |
+ |
|
| 131 |
+ // Overrides all DAC restrictions regarding read and search on files |
|
| 132 |
+ // and directories, including ACL restrictions if [_POSIX_ACL] is |
|
| 133 |
+ // defined. Excluding DAC access covered by CAP_LINUX_IMMUTABLE. |
|
| 134 |
+ CAP_DAC_READ_SEARCH Cap = 2 |
|
| 135 |
+ |
|
| 136 |
+ // Overrides all restrictions about allowed operations on files, where |
|
| 137 |
+ // file owner ID must be equal to the user ID, except where CAP_FSETID |
|
| 138 |
+ // is applicable. It doesn't override MAC and DAC restrictions. |
|
| 139 |
+ CAP_FOWNER Cap = 3 |
|
| 140 |
+ |
|
| 141 |
+ // Overrides the following restrictions that the effective user ID |
|
| 142 |
+ // shall match the file owner ID when setting the S_ISUID and S_ISGID |
|
| 143 |
+ // bits on that file; that the effective group ID (or one of the |
|
| 144 |
+ // supplementary group IDs) shall match the file owner ID when setting |
|
| 145 |
+ // the S_ISGID bit on that file; that the S_ISUID and S_ISGID bits are |
|
| 146 |
+ // cleared on successful return from chown(2) (not implemented). |
|
| 147 |
+ CAP_FSETID Cap = 4 |
|
| 148 |
+ |
|
| 149 |
+ // Overrides the restriction that the real or effective user ID of a |
|
| 150 |
+ // process sending a signal must match the real or effective user ID |
|
| 151 |
+ // of the process receiving the signal. |
|
| 152 |
+ CAP_KILL Cap = 5 |
|
| 153 |
+ |
|
| 154 |
+ // Allows setgid(2) manipulation |
|
| 155 |
+ // Allows setgroups(2) |
|
| 156 |
+ // Allows forged gids on socket credentials passing. |
|
| 157 |
+ CAP_SETGID Cap = 6 |
|
| 158 |
+ |
|
| 159 |
+ // Allows set*uid(2) manipulation (including fsuid). |
|
| 160 |
+ // Allows forged pids on socket credentials passing. |
|
| 161 |
+ CAP_SETUID Cap = 7 |
|
| 162 |
+ |
|
| 163 |
+ // Linux-specific capabilities |
|
| 164 |
+ |
|
| 165 |
+ // Without VFS support for capabilities: |
|
| 166 |
+ // Transfer any capability in your permitted set to any pid, |
|
| 167 |
+ // remove any capability in your permitted set from any pid |
|
| 168 |
+ // With VFS support for capabilities (neither of above, but) |
|
| 169 |
+ // Add any capability from current's capability bounding set |
|
| 170 |
+ // to the current process' inheritable set |
|
| 171 |
+ // Allow taking bits out of capability bounding set |
|
| 172 |
+ // Allow modification of the securebits for a process |
|
| 173 |
+ CAP_SETPCAP Cap = 8 |
|
| 174 |
+ |
|
| 175 |
+ // Allow modification of S_IMMUTABLE and S_APPEND file attributes |
|
| 176 |
+ CAP_LINUX_IMMUTABLE Cap = 9 |
|
| 177 |
+ |
|
| 178 |
+ // Allows binding to TCP/UDP sockets below 1024 |
|
| 179 |
+ // Allows binding to ATM VCIs below 32 |
|
| 180 |
+ CAP_NET_BIND_SERVICE Cap = 10 |
|
| 181 |
+ |
|
| 182 |
+ // Allow broadcasting, listen to multicast |
|
| 183 |
+ CAP_NET_BROADCAST Cap = 11 |
|
| 184 |
+ |
|
| 185 |
+ // Allow interface configuration |
|
| 186 |
+ // Allow administration of IP firewall, masquerading and accounting |
|
| 187 |
+ // Allow setting debug option on sockets |
|
| 188 |
+ // Allow modification of routing tables |
|
| 189 |
+ // Allow setting arbitrary process / process group ownership on |
|
| 190 |
+ // sockets |
|
| 191 |
+ // Allow binding to any address for transparent proxying (also via NET_RAW) |
|
| 192 |
+ // Allow setting TOS (type of service) |
|
| 193 |
+ // Allow setting promiscuous mode |
|
| 194 |
+ // Allow clearing driver statistics |
|
| 195 |
+ // Allow multicasting |
|
| 196 |
+ // Allow read/write of device-specific registers |
|
| 197 |
+ // Allow activation of ATM control sockets |
|
| 198 |
+ CAP_NET_ADMIN Cap = 12 |
|
| 199 |
+ |
|
| 200 |
+ // Allow use of RAW sockets |
|
| 201 |
+ // Allow use of PACKET sockets |
|
| 202 |
+ // Allow binding to any address for transparent proxying (also via NET_ADMIN) |
|
| 203 |
+ CAP_NET_RAW Cap = 13 |
|
| 204 |
+ |
|
| 205 |
+ // Allow locking of shared memory segments |
|
| 206 |
+ // Allow mlock and mlockall (which doesn't really have anything to do |
|
| 207 |
+ // with IPC) |
|
| 208 |
+ CAP_IPC_LOCK Cap = 14 |
|
| 209 |
+ |
|
| 210 |
+ // Override IPC ownership checks |
|
| 211 |
+ CAP_IPC_OWNER Cap = 15 |
|
| 212 |
+ |
|
| 213 |
+ // Insert and remove kernel modules - modify kernel without limit |
|
| 214 |
+ CAP_SYS_MODULE Cap = 16 |
|
| 215 |
+ |
|
| 216 |
+ // Allow ioperm/iopl access |
|
| 217 |
+ // Allow sending USB messages to any device via /proc/bus/usb |
|
| 218 |
+ CAP_SYS_RAWIO Cap = 17 |
|
| 219 |
+ |
|
| 220 |
+ // Allow use of chroot() |
|
| 221 |
+ CAP_SYS_CHROOT Cap = 18 |
|
| 222 |
+ |
|
| 223 |
+ // Allow ptrace() of any process |
|
| 224 |
+ CAP_SYS_PTRACE Cap = 19 |
|
| 225 |
+ |
|
| 226 |
+ // Allow configuration of process accounting |
|
| 227 |
+ CAP_SYS_PACCT Cap = 20 |
|
| 228 |
+ |
|
| 229 |
+ // Allow configuration of the secure attention key |
|
| 230 |
+ // Allow administration of the random device |
|
| 231 |
+ // Allow examination and configuration of disk quotas |
|
| 232 |
+ // Allow setting the domainname |
|
| 233 |
+ // Allow setting the hostname |
|
| 234 |
+ // Allow calling bdflush() |
|
| 235 |
+ // Allow mount() and umount(), setting up new smb connection |
|
| 236 |
+ // Allow some autofs root ioctls |
|
| 237 |
+ // Allow nfsservctl |
|
| 238 |
+ // Allow VM86_REQUEST_IRQ |
|
| 239 |
+ // Allow to read/write pci config on alpha |
|
| 240 |
+ // Allow irix_prctl on mips (setstacksize) |
|
| 241 |
+ // Allow flushing all cache on m68k (sys_cacheflush) |
|
| 242 |
+ // Allow removing semaphores |
|
| 243 |
+ // Used instead of CAP_CHOWN to "chown" IPC message queues, semaphores |
|
| 244 |
+ // and shared memory |
|
| 245 |
+ // Allow locking/unlocking of shared memory segment |
|
| 246 |
+ // Allow turning swap on/off |
|
| 247 |
+ // Allow forged pids on socket credentials passing |
|
| 248 |
+ // Allow setting readahead and flushing buffers on block devices |
|
| 249 |
+ // Allow setting geometry in floppy driver |
|
| 250 |
+ // Allow turning DMA on/off in xd driver |
|
| 251 |
+ // Allow administration of md devices (mostly the above, but some |
|
| 252 |
+ // extra ioctls) |
|
| 253 |
+ // Allow tuning the ide driver |
|
| 254 |
+ // Allow access to the nvram device |
|
| 255 |
+ // Allow administration of apm_bios, serial and bttv (TV) device |
|
| 256 |
+ // Allow manufacturer commands in isdn CAPI support driver |
|
| 257 |
+ // Allow reading non-standardized portions of pci configuration space |
|
| 258 |
+ // Allow DDI debug ioctl on sbpcd driver |
|
| 259 |
+ // Allow setting up serial ports |
|
| 260 |
+ // Allow sending raw qic-117 commands |
|
| 261 |
+ // Allow enabling/disabling tagged queuing on SCSI controllers and sending |
|
| 262 |
+ // arbitrary SCSI commands |
|
| 263 |
+ // Allow setting encryption key on loopback filesystem |
|
| 264 |
+ // Allow setting zone reclaim policy |
|
| 265 |
+ CAP_SYS_ADMIN Cap = 21 |
|
| 266 |
+ |
|
| 267 |
+ // Allow use of reboot() |
|
| 268 |
+ CAP_SYS_BOOT Cap = 22 |
|
| 269 |
+ |
|
| 270 |
+ // Allow raising priority and setting priority on other (different |
|
| 271 |
+ // UID) processes |
|
| 272 |
+ // Allow use of FIFO and round-robin (realtime) scheduling on own |
|
| 273 |
+ // processes and setting the scheduling algorithm used by another |
|
| 274 |
+ // process. |
|
| 275 |
+ // Allow setting cpu affinity on other processes |
|
| 276 |
+ CAP_SYS_NICE Cap = 23 |
|
| 277 |
+ |
|
| 278 |
+ // Override resource limits. Set resource limits. |
|
| 279 |
+ // Override quota limits. |
|
| 280 |
+ // Override reserved space on ext2 filesystem |
|
| 281 |
+ // Modify data journaling mode on ext3 filesystem (uses journaling |
|
| 282 |
+ // resources) |
|
| 283 |
+ // NOTE: ext2 honors fsuid when checking for resource overrides, so |
|
| 284 |
+ // you can override using fsuid too |
|
| 285 |
+ // Override size restrictions on IPC message queues |
|
| 286 |
+ // Allow more than 64hz interrupts from the real-time clock |
|
| 287 |
+ // Override max number of consoles on console allocation |
|
| 288 |
+ // Override max number of keymaps |
|
| 289 |
+ CAP_SYS_RESOURCE Cap = 24 |
|
| 290 |
+ |
|
| 291 |
+ // Allow manipulation of system clock |
|
| 292 |
+ // Allow irix_stime on mips |
|
| 293 |
+ // Allow setting the real-time clock |
|
| 294 |
+ CAP_SYS_TIME Cap = 25 |
|
| 295 |
+ |
|
| 296 |
+ // Allow configuration of tty devices |
|
| 297 |
+ // Allow vhangup() of tty |
|
| 298 |
+ CAP_SYS_TTY_CONFIG Cap = 26 |
|
| 299 |
+ |
|
| 300 |
+ // Allow the privileged aspects of mknod() |
|
| 301 |
+ CAP_MKNOD Cap = 27 |
|
| 302 |
+ |
|
| 303 |
+ // Allow taking of leases on files |
|
| 304 |
+ CAP_LEASE Cap = 28 |
|
| 305 |
+ |
|
| 306 |
+ CAP_AUDIT_WRITE Cap = 29 |
|
| 307 |
+ CAP_AUDIT_CONTROL Cap = 30 |
|
| 308 |
+ CAP_SETFCAP Cap = 31 |
|
| 309 |
+ |
|
| 310 |
+ // Override MAC access. |
|
| 311 |
+ // The base kernel enforces no MAC policy. |
|
| 312 |
+ // An LSM may enforce a MAC policy, and if it does and it chooses |
|
| 313 |
+ // to implement capability based overrides of that policy, this is |
|
| 314 |
+ // the capability it should use to do so. |
|
| 315 |
+ CAP_MAC_OVERRIDE Cap = 32 |
|
| 316 |
+ |
|
| 317 |
+ // Allow MAC configuration or state changes. |
|
| 318 |
+ // The base kernel requires no MAC configuration. |
|
| 319 |
+ // An LSM may enforce a MAC policy, and if it does and it chooses |
|
| 320 |
+ // to implement capability based checks on modifications to that |
|
| 321 |
+ // policy or the data required to maintain it, this is the |
|
| 322 |
+ // capability it should use to do so. |
|
| 323 |
+ CAP_MAC_ADMIN Cap = 33 |
|
| 324 |
+ |
|
| 325 |
+ // Allow configuring the kernel's syslog (printk behaviour) |
|
| 326 |
+ CAP_SYSLOG Cap = 34 |
|
| 327 |
+ |
|
| 328 |
+ // Allow triggering something that will wake the system |
|
| 329 |
+ CAP_WAKE_ALARM Cap = 35 |
|
| 330 |
+ |
|
| 331 |
+ // Allow preventing system suspends |
|
| 332 |
+ CAP_BLOCK_SUSPEND Cap = 36 |
|
| 333 |
+ |
|
| 334 |
+ CAP_LAST_CAP = CAP_BLOCK_SUSPEND |
|
| 335 |
+) |
|
| 336 |
+ |
|
| 337 |
+const capUpperMask = (uint32(1) << (uint(CAP_LAST_CAP) - 31)) - 1 |
| 0 | 338 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,143 @@ |
| 0 |
+// Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com> |
|
| 1 |
+// All rights reserved. |
|
| 2 |
+// |
|
| 3 |
+// Use of this source code is governed by a BSD-style license that can be |
|
| 4 |
+// found in the LICENSE file. |
|
| 5 |
+ |
|
| 6 |
+package capability |
|
| 7 |
+ |
|
| 8 |
+import ( |
|
| 9 |
+ "syscall" |
|
| 10 |
+ "unsafe" |
|
| 11 |
+) |
|
| 12 |
+ |
|
| 13 |
+type capHeader struct {
|
|
| 14 |
+ version uint32 |
|
| 15 |
+ pid int |
|
| 16 |
+} |
|
| 17 |
+ |
|
| 18 |
+type capData struct {
|
|
| 19 |
+ effective uint32 |
|
| 20 |
+ permitted uint32 |
|
| 21 |
+ inheritable uint32 |
|
| 22 |
+} |
|
| 23 |
+ |
|
| 24 |
+func capget(hdr *capHeader, data *capData) (err error) {
|
|
| 25 |
+ _, _, e1 := syscall.Syscall(syscall.SYS_CAPGET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) |
|
| 26 |
+ if e1 != 0 {
|
|
| 27 |
+ err = e1 |
|
| 28 |
+ } |
|
| 29 |
+ return |
|
| 30 |
+} |
|
| 31 |
+ |
|
| 32 |
+func capset(hdr *capHeader, data *capData) (err error) {
|
|
| 33 |
+ _, _, e1 := syscall.Syscall(syscall.SYS_CAPSET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) |
|
| 34 |
+ if e1 != 0 {
|
|
| 35 |
+ err = e1 |
|
| 36 |
+ } |
|
| 37 |
+ return |
|
| 38 |
+} |
|
| 39 |
+ |
|
| 40 |
+func prctl(option int, arg2, arg3, arg4, arg5 uintptr) (err error) {
|
|
| 41 |
+ _, _, e1 := syscall.Syscall6(syscall.SYS_PRCTL, uintptr(option), arg2, arg3, arg4, arg5, 0) |
|
| 42 |
+ if e1 != 0 {
|
|
| 43 |
+ err = e1 |
|
| 44 |
+ } |
|
| 45 |
+ return |
|
| 46 |
+} |
|
| 47 |
+ |
|
| 48 |
+const ( |
|
| 49 |
+ vfsXattrName = "security.capability" |
|
| 50 |
+ |
|
| 51 |
+ vfsCapVerMask = 0xff000000 |
|
| 52 |
+ vfsCapVer1 = 0x01000000 |
|
| 53 |
+ vfsCapVer2 = 0x02000000 |
|
| 54 |
+ |
|
| 55 |
+ vfsCapFlagMask = ^vfsCapVerMask |
|
| 56 |
+ vfsCapFlageffective = 0x000001 |
|
| 57 |
+ |
|
| 58 |
+ vfscapDataSizeV1 = 4 * (1 + 2*1) |
|
| 59 |
+ vfscapDataSizeV2 = 4 * (1 + 2*2) |
|
| 60 |
+) |
|
| 61 |
+ |
|
| 62 |
+type vfscapData struct {
|
|
| 63 |
+ magic uint32 |
|
| 64 |
+ data [2]struct {
|
|
| 65 |
+ permitted uint32 |
|
| 66 |
+ inheritable uint32 |
|
| 67 |
+ } |
|
| 68 |
+ effective [2]uint32 |
|
| 69 |
+ version int8 |
|
| 70 |
+} |
|
| 71 |
+ |
|
| 72 |
+var ( |
|
| 73 |
+ _vfsXattrName *byte |
|
| 74 |
+) |
|
| 75 |
+ |
|
| 76 |
+func init() {
|
|
| 77 |
+ _vfsXattrName, _ = syscall.BytePtrFromString(vfsXattrName) |
|
| 78 |
+} |
|
| 79 |
+ |
|
| 80 |
+func getVfsCap(path string, dest *vfscapData) (err error) {
|
|
| 81 |
+ var _p0 *byte |
|
| 82 |
+ _p0, err = syscall.BytePtrFromString(path) |
|
| 83 |
+ if err != nil {
|
|
| 84 |
+ return |
|
| 85 |
+ } |
|
| 86 |
+ r0, _, e1 := syscall.Syscall6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(dest)), vfscapDataSizeV2, 0, 0) |
|
| 87 |
+ if e1 != 0 {
|
|
| 88 |
+ err = e1 |
|
| 89 |
+ } |
|
| 90 |
+ switch dest.magic & vfsCapVerMask {
|
|
| 91 |
+ case vfsCapVer1: |
|
| 92 |
+ dest.version = 1 |
|
| 93 |
+ if r0 != vfscapDataSizeV1 {
|
|
| 94 |
+ return syscall.EINVAL |
|
| 95 |
+ } |
|
| 96 |
+ dest.data[1].permitted = 0 |
|
| 97 |
+ dest.data[1].inheritable = 0 |
|
| 98 |
+ case vfsCapVer2: |
|
| 99 |
+ dest.version = 2 |
|
| 100 |
+ if r0 != vfscapDataSizeV2 {
|
|
| 101 |
+ return syscall.EINVAL |
|
| 102 |
+ } |
|
| 103 |
+ default: |
|
| 104 |
+ return syscall.EINVAL |
|
| 105 |
+ } |
|
| 106 |
+ if dest.magic&vfsCapFlageffective != 0 {
|
|
| 107 |
+ dest.effective[0] = dest.data[0].permitted | dest.data[0].inheritable |
|
| 108 |
+ dest.effective[1] = dest.data[1].permitted | dest.data[1].inheritable |
|
| 109 |
+ } else {
|
|
| 110 |
+ dest.effective[0] = 0 |
|
| 111 |
+ dest.effective[1] = 0 |
|
| 112 |
+ } |
|
| 113 |
+ return |
|
| 114 |
+} |
|
| 115 |
+ |
|
| 116 |
+func setVfsCap(path string, data *vfscapData) (err error) {
|
|
| 117 |
+ var _p0 *byte |
|
| 118 |
+ _p0, err = syscall.BytePtrFromString(path) |
|
| 119 |
+ if err != nil {
|
|
| 120 |
+ return |
|
| 121 |
+ } |
|
| 122 |
+ var size uintptr |
|
| 123 |
+ if data.version == 1 {
|
|
| 124 |
+ data.magic = vfsCapVer1 |
|
| 125 |
+ size = vfscapDataSizeV1 |
|
| 126 |
+ } else if data.version == 2 {
|
|
| 127 |
+ data.magic = vfsCapVer2 |
|
| 128 |
+ if data.effective[0] != 0 || data.effective[1] != 0 {
|
|
| 129 |
+ data.magic |= vfsCapFlageffective |
|
| 130 |
+ data.data[0].permitted |= data.effective[0] |
|
| 131 |
+ data.data[1].permitted |= data.effective[1] |
|
| 132 |
+ } |
|
| 133 |
+ size = vfscapDataSizeV2 |
|
| 134 |
+ } else {
|
|
| 135 |
+ return syscall.EINVAL |
|
| 136 |
+ } |
|
| 137 |
+ _, _, e1 := syscall.Syscall6(syscall.SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(data)), size, 0, 0) |
|
| 138 |
+ if e1 != 0 {
|
|
| 139 |
+ err = e1 |
|
| 140 |
+ } |
|
| 141 |
+ return |
|
| 142 |
+} |