mirror of
https://github.com/moby/buildkit.git
synced 2026-08-09 01:01:08 +00:00
Merge pull request #3671 from sipsma/fix-merge-file-caps
diffapply: do chown before xattrs
This commit is contained in:
2
go.mod
2
go.mod
@@ -87,6 +87,7 @@ require (
|
||||
google.golang.org/genproto v0.0.0-20230131230820-1c016267d619
|
||||
google.golang.org/grpc v1.52.3
|
||||
google.golang.org/protobuf v1.28.1
|
||||
kernel.org/pub/linux/libs/security/libcap/cap v1.2.67
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -156,4 +157,5 @@ require (
|
||||
golang.org/x/text v0.7.0 // indirect
|
||||
golang.org/x/tools v0.5.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
kernel.org/pub/linux/libs/security/libcap/psx v1.2.67 // indirect
|
||||
)
|
||||
|
||||
4
go.sum
4
go.sum
@@ -1890,6 +1890,10 @@ k8s.io/legacy-cloud-providers v0.17.4/go.mod h1:FikRNoD64ECjkxO36gkDgJeiQWwyZTuB
|
||||
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||
k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
kernel.org/pub/linux/libs/security/libcap/cap v1.2.67 h1:sPQ9qlSNR26fToTKbxe/HDWJlXvBLqGmt84LGCQkOy0=
|
||||
kernel.org/pub/linux/libs/security/libcap/cap v1.2.67/go.mod h1:GkntoBuwffz19qtdFVB+k2NtWNN+yCKnC/Ykv/hMiTU=
|
||||
kernel.org/pub/linux/libs/security/libcap/psx v1.2.67 h1:NxbXJ7pDVq0FKBsqjieT92QDXI2XaqH2HAi4QcCOHt8=
|
||||
kernel.org/pub/linux/libs/security/libcap/psx v1.2.67/go.mod h1:+l6Ee2F59XiJ2I6WR5ObpC1utCQJZ/VLsEbQCD8RG24=
|
||||
modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw=
|
||||
modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
|
||||
modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
|
||||
|
||||
@@ -379,6 +379,18 @@ func (a *applier) applyCopy(ctx context.Context, ca *changeApply) error {
|
||||
return errors.Errorf("unhandled file type %d during merge at path %q", ca.srcStat.Mode&unix.S_IFMT, ca.srcPath)
|
||||
}
|
||||
|
||||
// NOTE: it's important that chown happens before setting xattrs due to the fact that chown will
|
||||
// reset the security.capabilities xattr which results in file capabilities being lost.
|
||||
if err := os.Lchown(ca.dstPath, int(ca.srcStat.Uid), int(ca.srcStat.Gid)); err != nil {
|
||||
return errors.Wrap(err, "failed to chown during apply")
|
||||
}
|
||||
|
||||
if ca.srcStat.Mode&unix.S_IFMT != unix.S_IFLNK {
|
||||
if err := unix.Chmod(ca.dstPath, ca.srcStat.Mode); err != nil {
|
||||
return errors.Wrapf(err, "failed to chmod path %q during apply", ca.dstPath)
|
||||
}
|
||||
}
|
||||
|
||||
if ca.srcPath != "" {
|
||||
xattrs, err := sysx.LListxattr(ca.srcPath)
|
||||
if err != nil {
|
||||
@@ -410,16 +422,6 @@ func (a *applier) applyCopy(ctx context.Context, ca *changeApply) error {
|
||||
}
|
||||
}
|
||||
|
||||
if err := os.Lchown(ca.dstPath, int(ca.srcStat.Uid), int(ca.srcStat.Gid)); err != nil {
|
||||
return errors.Wrap(err, "failed to chown during apply")
|
||||
}
|
||||
|
||||
if ca.srcStat.Mode&unix.S_IFMT != unix.S_IFLNK {
|
||||
if err := unix.Chmod(ca.dstPath, ca.srcStat.Mode); err != nil {
|
||||
return errors.Wrapf(err, "failed to chmod path %q during apply", ca.dstPath)
|
||||
}
|
||||
}
|
||||
|
||||
atimeSpec := unix.Timespec{Sec: ca.srcStat.Atim.Sec, Nsec: ca.srcStat.Atim.Nsec}
|
||||
mtimeSpec := unix.Timespec{Sec: ca.srcStat.Mtim.Sec, Nsec: ca.srcStat.Mtim.Nsec}
|
||||
if ca.srcStat.Mode&unix.S_IFMT != unix.S_IFDIR {
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/require"
|
||||
bolt "go.etcd.io/bbolt"
|
||||
libcap "kernel.org/pub/linux/libs/security/libcap/cap"
|
||||
)
|
||||
|
||||
func newSnapshotter(ctx context.Context, t *testing.T, snapshotterName string) (_ context.Context, _ *mergeSnapshotter, rerr error) {
|
||||
@@ -372,6 +373,41 @@ func TestHardlinks(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMergeFileCapabilities(t *testing.T) {
|
||||
requireRoot(t)
|
||||
for _, snName := range []string{"overlayfs", "native", "native-nohardlink"} {
|
||||
snName := snName
|
||||
t.Run(snName, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctx, sn, err := newSnapshotter(context.Background(), t, snName)
|
||||
require.NoError(t, err)
|
||||
|
||||
setCaps := "cap_net_bind_service=+ep"
|
||||
base1Snap := committedKey(ctx, t, sn, identity.NewID(), "",
|
||||
fstest.CreateFile("hasCaps", []byte("capable"), 0700),
|
||||
fstest.Chown("hasCaps", 1000, 1000),
|
||||
setFileCap("hasCaps", setCaps),
|
||||
)
|
||||
base2Snap := committedKey(ctx, t, sn, identity.NewID(), "",
|
||||
fstest.CreateFile("foo", []byte("bar"), 0600),
|
||||
)
|
||||
|
||||
mergeSnap := mergeKey(ctx, t, sn, identity.NewID(), []Diff{
|
||||
{"", base1Snap.Name},
|
||||
{"", base2Snap.Name},
|
||||
})
|
||||
|
||||
actualCaps := getFileCap(ctx, t, sn, mergeSnap.Name, "hasCaps")
|
||||
require.Equal(t, "cap_net_bind_service=ep", actualCaps)
|
||||
stat := statPath(ctx, t, sn, mergeSnap.Name, "hasCaps")
|
||||
require.EqualValues(t, 1000, stat.Uid)
|
||||
require.EqualValues(t, 1000, stat.Gid)
|
||||
require.EqualValues(t, 0700, stat.Mode&0777)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUsage(t *testing.T) {
|
||||
for _, snName := range []string{"overlayfs", "native", "native-nohardlink"} {
|
||||
snName := snName
|
||||
@@ -559,7 +595,7 @@ func requireMtime(t *testing.T, path string, mtime time.Time) {
|
||||
require.Equal(t, mtime.UnixNano(), stat.Mtim.Nano())
|
||||
}
|
||||
|
||||
func tryStatPath(ctx context.Context, t *testing.T, sn *mergeSnapshotter, key, path string) (st *syscall.Stat_t) {
|
||||
func pathCallback[T any](ctx context.Context, t *testing.T, sn *mergeSnapshotter, key, path string, cb func(t *testing.T, path string) *T) *T {
|
||||
t.Helper()
|
||||
mounts, cleanup := getMounts(ctx, t, sn, key)
|
||||
defer cleanup()
|
||||
@@ -577,24 +613,32 @@ func tryStatPath(ctx context.Context, t *testing.T, sn *mergeSnapshotter, key, p
|
||||
}
|
||||
}
|
||||
if upperdir != "" {
|
||||
st = trySyscallStat(t, filepath.Join(upperdir, path))
|
||||
if st != nil {
|
||||
return st
|
||||
r := cb(t, filepath.Join(upperdir, path))
|
||||
if r != nil {
|
||||
return r
|
||||
}
|
||||
}
|
||||
for _, lowerdir := range lowerdirs {
|
||||
st = trySyscallStat(t, filepath.Join(lowerdir, path))
|
||||
if st != nil {
|
||||
return st
|
||||
r := cb(t, filepath.Join(lowerdir, path))
|
||||
if r != nil {
|
||||
return r
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var r *T
|
||||
withMount(ctx, t, sn, key, func(root string) {
|
||||
st = trySyscallStat(t, filepath.Join(root, path))
|
||||
r = cb(t, filepath.Join(root, path))
|
||||
})
|
||||
return r
|
||||
}
|
||||
|
||||
func tryStatPath(ctx context.Context, t *testing.T, sn *mergeSnapshotter, key, path string) *syscall.Stat_t {
|
||||
t.Helper()
|
||||
return pathCallback(ctx, t, sn, key, path, func(t *testing.T, path string) *syscall.Stat_t {
|
||||
return trySyscallStat(t, path)
|
||||
})
|
||||
return st
|
||||
}
|
||||
|
||||
func statPath(ctx context.Context, t *testing.T, sn *mergeSnapshotter, key, path string) (st *syscall.Stat_t) {
|
||||
@@ -610,3 +654,36 @@ func requireRoot(t *testing.T) {
|
||||
t.Skip("test requires root")
|
||||
}
|
||||
}
|
||||
|
||||
func setFileCap(path string, caps string) fstest.Applier {
|
||||
return applyFn(func(root string) error {
|
||||
path := filepath.Join(root, path)
|
||||
capSet, err := libcap.FromText(caps)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return capSet.SetFile(path)
|
||||
})
|
||||
}
|
||||
|
||||
func getFileCap(ctx context.Context, t *testing.T, sn *mergeSnapshotter, key, path string) string {
|
||||
t.Helper()
|
||||
caps := pathCallback(ctx, t, sn, key, path, func(t *testing.T, path string) *string {
|
||||
t.Helper()
|
||||
capSet, err := libcap.GetFile(path)
|
||||
if err != nil {
|
||||
require.ErrorIs(t, err, os.ErrNotExist)
|
||||
return nil
|
||||
}
|
||||
caps := capSet.String()
|
||||
return &caps
|
||||
})
|
||||
require.NotNil(t, caps)
|
||||
return *caps
|
||||
}
|
||||
|
||||
type applyFn func(root string) error
|
||||
|
||||
func (a applyFn) Apply(root string) error {
|
||||
return a(root)
|
||||
}
|
||||
|
||||
398
vendor/kernel.org/pub/linux/libs/security/libcap/cap/License
generated
vendored
Normal file
398
vendor/kernel.org/pub/linux/libs/security/libcap/cap/License
generated
vendored
Normal file
@@ -0,0 +1,398 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-only */
|
||||
|
||||
Unless otherwise *explicitly* stated, the following text describes the
|
||||
licensed conditions under which the contents of this libcap/cap release
|
||||
may be used and distributed.
|
||||
|
||||
The licensed conditions are one or the other of these two Licenses:
|
||||
|
||||
- BSD 3-clause
|
||||
- GPL v2.0
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
BSD 3-clause:
|
||||
-------------
|
||||
|
||||
Redistribution and use in source and binary forms of libcap/cap, with
|
||||
or without modification, are permitted provided that the following
|
||||
conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain any existing copyright
|
||||
notice, and this entire permission notice in its entirety,
|
||||
including the disclaimer of warranties.
|
||||
|
||||
2. Redistributions in binary form must reproduce all prior and current
|
||||
copyright notices, this list of conditions, and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
3. The name of any author may not be used to endorse or promote
|
||||
products derived from this software without their specific prior
|
||||
written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
GPL v2.0:
|
||||
---------
|
||||
|
||||
ALTERNATIVELY, this product may be distributed under the terms of the
|
||||
GNU General Public License (v2.0 - see below), in which case the
|
||||
provisions of the GNU GPL are required INSTEAD OF the above
|
||||
restrictions. (This clause is necessary due to a potential conflict
|
||||
between the GNU GPL and the restrictions contained in a BSD-style
|
||||
copyright.)
|
||||
|
||||
-------------------------
|
||||
Full text of gpl-2.0.txt:
|
||||
-------------------------
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
10
vendor/kernel.org/pub/linux/libs/security/libcap/cap/README
generated
vendored
Normal file
10
vendor/kernel.org/pub/linux/libs/security/libcap/cap/README
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
Package cap is the libcap API for Linux Capabilities written in
|
||||
Go. The official release announcement site for libcap is:
|
||||
|
||||
https://sites.google.com/site/fullycapable/
|
||||
|
||||
Like libcap, the cap package is distributed with a "you choose"
|
||||
License. Specifically: BSD three clause, or GPL2. See the License
|
||||
file.
|
||||
|
||||
Andrew G. Morgan <morgan@kernel.org>
|
||||
503
vendor/kernel.org/pub/linux/libs/security/libcap/cap/cap.go
generated
vendored
Normal file
503
vendor/kernel.org/pub/linux/libs/security/libcap/cap/cap.go
generated
vendored
Normal file
@@ -0,0 +1,503 @@
|
||||
// Package cap provides all the Linux Capabilities userspace library API
|
||||
// bindings in native Go.
|
||||
//
|
||||
// Capabilities are a feature of the Linux kernel that allow fine
|
||||
// grain permissions to perform privileged operations. Privileged
|
||||
// operations are required to do irregular system level operations
|
||||
// from code. You can read more about how Capabilities are intended to
|
||||
// work here:
|
||||
//
|
||||
// https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/33528.pdf
|
||||
//
|
||||
// This package supports native Go bindings for all the features
|
||||
// described in that paper as well as supporting subsequent changes to
|
||||
// the kernel for other styles of inheritable Capability.
|
||||
//
|
||||
// Some simple things you can do with this package are:
|
||||
//
|
||||
// // Read and display the capabilities of the running process
|
||||
// c := cap.GetProc()
|
||||
// log.Printf("this process has these caps:", c)
|
||||
//
|
||||
// // Drop any privilege a process might have (including for root,
|
||||
// // but note root 'owns' a lot of system files so a cap-limited
|
||||
// // root can still do considerable damage to a running system).
|
||||
// old := cap.GetProc()
|
||||
// empty := cap.NewSet()
|
||||
// if err := empty.SetProc(); err != nil {
|
||||
// log.Fatalf("failed to drop privilege: %q -> %q: %v", old, empty, err)
|
||||
// }
|
||||
// now := cap.GetProc()
|
||||
// if cf, _ := now.Cf(empty); cf != 0 {
|
||||
// log.Fatalf("failed to fully drop privilege: have=%q, wanted=%q", now, empty)
|
||||
// }
|
||||
//
|
||||
// The "cap" package operates with POSIX semantics for security
|
||||
// state. That is all OS threads are kept in sync at all times. The
|
||||
// package "kernel.org/pub/linux/libs/security/libcap/psx" is used to
|
||||
// implement POSIX semantics system calls that manipulate thread state
|
||||
// uniformly over the whole Go (and any CGo linked) process runtime.
|
||||
//
|
||||
// Note, if the Go runtime syscall interface contains the Linux
|
||||
// variant syscall.AllThreadsSyscall() API (it debuted in go1.16 see
|
||||
// https://github.com/golang/go/issues/1435 for its history) then the
|
||||
// "libcap/psx" package will use that to invoke Capability setting
|
||||
// system calls in pure Go binaries. With such an enhanced Go runtime,
|
||||
// to force this behavior, use the CGO_ENABLED=0 environment variable.
|
||||
//
|
||||
// POSIX semantics are more secure than trying to manage privilege at
|
||||
// a thread level when those threads share a common memory image as
|
||||
// they do under Linux: it is trivial to exploit a vulnerability in
|
||||
// one thread of a process to cause execution on any another
|
||||
// thread. So, any imbalance in security state, in such cases will
|
||||
// readily create an opportunity for a privilege escalation
|
||||
// vulnerability.
|
||||
//
|
||||
// POSIX semantics also work well with Go, which deliberately tries to
|
||||
// insulate the user from worrying about the number of OS threads that
|
||||
// are actually running in their program. Indeed, Go can efficiently
|
||||
// launch and manage tens of thousands of concurrent goroutines
|
||||
// without bogging the program or wider system down. It does this by
|
||||
// aggressively migrating idle threads to make progress on unblocked
|
||||
// goroutines. So, inconsistent security state across OS threads can
|
||||
// also lead to program misbehavior.
|
||||
//
|
||||
// The only exception to this process-wide common security state is
|
||||
// the cap.Launcher related functionality. This briefly locks an OS
|
||||
// thread to a goroutine in order to launch another executable - the
|
||||
// robust implementation of this kind of support is quite subtle, so
|
||||
// please read its documentation carefully, if you find that you need
|
||||
// it.
|
||||
//
|
||||
// See https://sites.google.com/site/fullycapable/ for recent updates,
|
||||
// some more complete walk-through examples of ways of using
|
||||
// 'cap.Set's etc and information on how to file bugs.
|
||||
//
|
||||
// Copyright (c) 2019-21 Andrew G. Morgan <morgan@kernel.org>
|
||||
//
|
||||
// The cap and psx packages are licensed with a (you choose) BSD
|
||||
// 3-clause or GPL2. See LICENSE file for details.
|
||||
package cap // import "kernel.org/pub/linux/libs/security/libcap/cap"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sort"
|
||||
"sync"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Value is the type of a single capability (or permission) bit.
|
||||
type Value uint
|
||||
|
||||
// Flag is the type of one of the three Value dimensions held in a
|
||||
// Set. It is also used in the (*IAB).Fill() method for changing the
|
||||
// Bounding and Ambient Vectors.
|
||||
type Flag uint
|
||||
|
||||
// Effective, Permitted, Inheritable are the three Flags of Values
|
||||
// held in a Set.
|
||||
const (
|
||||
Effective Flag = iota
|
||||
Permitted
|
||||
Inheritable
|
||||
)
|
||||
|
||||
// Diff summarizes the result of the (*Set).Cf() function.
|
||||
type Diff uint
|
||||
|
||||
const (
|
||||
effectiveDiff Diff = 1 << Effective
|
||||
permittedDiff Diff = 1 << Permitted
|
||||
inheritableDiff Diff = 1 << Inheritable
|
||||
)
|
||||
|
||||
// String identifies a Flag value by its conventional "e", "p" or "i"
|
||||
// string abbreviation.
|
||||
func (f Flag) String() string {
|
||||
switch f {
|
||||
case Effective:
|
||||
return "e"
|
||||
case Permitted:
|
||||
return "p"
|
||||
case Inheritable:
|
||||
return "i"
|
||||
default:
|
||||
return "<Error>"
|
||||
}
|
||||
}
|
||||
|
||||
// data holds a 32-bit slice of the compressed bitmaps of capability
|
||||
// sets as understood by the kernel.
|
||||
type data [Inheritable + 1]uint32
|
||||
|
||||
// Set is an opaque capabilities container for a set of system
|
||||
// capbilities. It holds individually addressable capability Value's
|
||||
// for the three capability Flag's. See GetFlag() and SetFlag() for
|
||||
// how to adjust them individually, and Clear() and ClearFlag() for
|
||||
// how to do bulk operations.
|
||||
//
|
||||
// For admin tasks associated with managing namespace specific file
|
||||
// capabilities, Set can also support a namespace-root-UID value which
|
||||
// defaults to zero. See GetNSOwner() and SetNSOwner().
|
||||
type Set struct {
|
||||
// mu protects all other members of a Set.
|
||||
mu sync.RWMutex
|
||||
|
||||
// flat holds Flag Value bitmaps for all capabilities
|
||||
// associated with this Set.
|
||||
flat []data
|
||||
|
||||
// Linux specific
|
||||
nsRoot int
|
||||
}
|
||||
|
||||
// Various known kernel magic values.
|
||||
const (
|
||||
kv1 = 0x19980330 // First iteration of process capabilities (32 bits).
|
||||
kv2 = 0x20071026 // First iteration of process and file capabilities (64 bits) - deprecated.
|
||||
kv3 = 0x20080522 // Most recently supported process and file capabilities (64 bits).
|
||||
)
|
||||
|
||||
var (
|
||||
// startUp protects setting of the following values: magic,
|
||||
// words, maxValues.
|
||||
startUp sync.Once
|
||||
|
||||
// magic holds the preferred magic number for the kernel ABI.
|
||||
magic uint32
|
||||
|
||||
// words holds the number of uint32's associated with each
|
||||
// capability Flag for this session.
|
||||
words int
|
||||
|
||||
// maxValues holds the number of bit values that are named by
|
||||
// the running kernel. This is generally expected to match
|
||||
// ValueCount which is autogenerated at packaging time.
|
||||
maxValues uint
|
||||
)
|
||||
|
||||
type header struct {
|
||||
magic uint32
|
||||
pid int32
|
||||
}
|
||||
|
||||
// syscaller is a type for abstracting syscalls. The r* variants are
|
||||
// for reading state, and can be parallelized, the w* variants need to
|
||||
// be serialized so all OS threads can share state.
|
||||
type syscaller struct {
|
||||
r3 func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
|
||||
w3 func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
|
||||
r6 func(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno)
|
||||
w6 func(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno)
|
||||
}
|
||||
|
||||
// caprcall provides a pointer etc wrapper for the system calls
|
||||
// associated with getcap.
|
||||
//go:uintptrescapes
|
||||
func (sc *syscaller) caprcall(call uintptr, h *header, d []data) error {
|
||||
x := uintptr(0)
|
||||
if d != nil {
|
||||
x = uintptr(unsafe.Pointer(&d[0]))
|
||||
}
|
||||
_, _, err := sc.r3(call, uintptr(unsafe.Pointer(h)), x, 0)
|
||||
if err != 0 {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// capwcall provides a pointer etc wrapper for the system calls
|
||||
// associated with setcap.
|
||||
//go:uintptrescapes
|
||||
func (sc *syscaller) capwcall(call uintptr, h *header, d []data) error {
|
||||
x := uintptr(0)
|
||||
if d != nil {
|
||||
x = uintptr(unsafe.Pointer(&d[0]))
|
||||
}
|
||||
_, _, err := sc.w3(call, uintptr(unsafe.Pointer(h)), x, 0)
|
||||
if err != 0 {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// prctlrcall provides a wrapper for the prctl systemcalls that only
|
||||
// read kernel state. There is a limited number of arguments needed
|
||||
// and the caller should use 0 for those not needed.
|
||||
func (sc *syscaller) prctlrcall(prVal, v1, v2 uintptr) (int, error) {
|
||||
r, _, err := sc.r3(syscall.SYS_PRCTL, prVal, v1, v2)
|
||||
if err != 0 {
|
||||
return int(r), err
|
||||
}
|
||||
return int(r), nil
|
||||
}
|
||||
|
||||
// prctlrcall6 provides a wrapper for the prctl systemcalls that only
|
||||
// read kernel state and require 6 arguments - ambient cap API, I'm
|
||||
// looking at you. There is a limited number of arguments needed and
|
||||
// the caller should use 0 for those not needed.
|
||||
func (sc *syscaller) prctlrcall6(prVal, v1, v2, v3, v4, v5 uintptr) (int, error) {
|
||||
r, _, err := sc.r6(syscall.SYS_PRCTL, prVal, v1, v2, v3, v4, v5)
|
||||
if err != 0 {
|
||||
return int(r), err
|
||||
}
|
||||
return int(r), nil
|
||||
}
|
||||
|
||||
// prctlwcall provides a wrapper for the prctl systemcalls that
|
||||
// write/modify kernel state. Where available, these will use the
|
||||
// POSIX semantics fixup system calls. There is a limited number of
|
||||
// arguments needed and the caller should use 0 for those not needed.
|
||||
func (sc *syscaller) prctlwcall(prVal, v1, v2 uintptr) (int, error) {
|
||||
r, _, err := sc.w3(syscall.SYS_PRCTL, prVal, v1, v2)
|
||||
if err != 0 {
|
||||
return int(r), err
|
||||
}
|
||||
return int(r), nil
|
||||
}
|
||||
|
||||
// prctlwcall6 provides a wrapper for the prctl systemcalls that
|
||||
// write/modify kernel state and require 6 arguments - ambient cap
|
||||
// API, I'm looking at you. (Where available, these will use the POSIX
|
||||
// semantics fixup system calls). There is a limited number of
|
||||
// arguments needed and the caller should use 0 for those not needed.
|
||||
func (sc *syscaller) prctlwcall6(prVal, v1, v2, v3, v4, v5 uintptr) (int, error) {
|
||||
r, _, err := sc.w6(syscall.SYS_PRCTL, prVal, v1, v2, v3, v4, v5)
|
||||
if err != 0 {
|
||||
return int(r), err
|
||||
}
|
||||
return int(r), nil
|
||||
}
|
||||
|
||||
// cInit performs the lazy identification of the capability vintage of
|
||||
// the running system.
|
||||
func (sc *syscaller) cInit() {
|
||||
h := &header{
|
||||
magic: kv3,
|
||||
}
|
||||
sc.caprcall(syscall.SYS_CAPGET, h, nil)
|
||||
magic = h.magic
|
||||
switch magic {
|
||||
case kv1:
|
||||
words = 1
|
||||
case kv2, kv3:
|
||||
words = 2
|
||||
default:
|
||||
// Fall back to a known good version.
|
||||
magic = kv3
|
||||
words = 2
|
||||
}
|
||||
// Use the bounding set to evaluate which capabilities exist.
|
||||
maxValues = uint(sort.Search(32*words, func(n int) bool {
|
||||
_, err := GetBound(Value(n))
|
||||
return err != nil
|
||||
}))
|
||||
if maxValues == 0 {
|
||||
// Fall back to using the largest value defined at build time.
|
||||
maxValues = NamedCount
|
||||
}
|
||||
}
|
||||
|
||||
// MaxBits returns the number of kernel-named capabilities discovered
|
||||
// at runtime in the current system.
|
||||
func MaxBits() Value {
|
||||
startUp.Do(multisc.cInit)
|
||||
return Value(maxValues)
|
||||
}
|
||||
|
||||
// NewSet returns an empty capability set.
|
||||
func NewSet() *Set {
|
||||
startUp.Do(multisc.cInit)
|
||||
return &Set{
|
||||
flat: make([]data, words),
|
||||
}
|
||||
}
|
||||
|
||||
// ErrBadSet indicates a nil pointer was used for a *Set, or the
|
||||
// request of the Set is invalid in some way.
|
||||
var ErrBadSet = errors.New("bad capability set")
|
||||
|
||||
// good confirms that c looks valid.
|
||||
func (c *Set) good() error {
|
||||
if c == nil || len(c.flat) == 0 {
|
||||
return ErrBadSet
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Dup returns a copy of the specified capability set.
|
||||
func (c *Set) Dup() (*Set, error) {
|
||||
if err := c.good(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
n := NewSet()
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
copy(n.flat, c.flat)
|
||||
n.nsRoot = c.nsRoot
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// GetPID returns the capability set associated with the target process
|
||||
// id; pid=0 is an alias for current.
|
||||
func GetPID(pid int) (*Set, error) {
|
||||
v := NewSet()
|
||||
if err := multisc.caprcall(syscall.SYS_CAPGET, &header{magic: magic, pid: int32(pid)}, v.flat); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// GetProc returns the capability Set of the current process. If the
|
||||
// kernel is unable to determine the Set associated with the current
|
||||
// process, the function panic()s.
|
||||
func GetProc() *Set {
|
||||
c, err := GetPID(0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// setProc uses syscaller to set process capabilities. Note, c is
|
||||
// either private to or (read) locked by the caller.
|
||||
func (sc *syscaller) setProc(c *Set) error {
|
||||
return sc.capwcall(syscall.SYS_CAPSET, &header{magic: magic}, c.flat)
|
||||
}
|
||||
|
||||
// SetProc attempts to set the capability Set of the current
|
||||
// process. The kernel will perform permission checks and an error
|
||||
// will be returned if the attempt fails. Should the attempt fail
|
||||
// no process capabilities will have been modified.
|
||||
//
|
||||
// Note, the general behavior of this call is to set the
|
||||
// process-shared capabilities. However, when called from a callback
|
||||
// function as part of a (*Launcher).Launch(), the call only sets the
|
||||
// capabilities of the thread being used to perform the launch.
|
||||
func (c *Set) SetProc() error {
|
||||
if err := c.good(); err != nil {
|
||||
return err
|
||||
}
|
||||
state, sc := scwStateSC()
|
||||
defer scwSetState(launchBlocked, state, -1)
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
return sc.setProc(c)
|
||||
}
|
||||
|
||||
// defines from uapi/linux/prctl.h
|
||||
const (
|
||||
prCapBSetRead = 23
|
||||
prCapBSetDrop = 24
|
||||
)
|
||||
|
||||
// GetBound determines if a specific capability is currently part of
|
||||
// the local bounding set. On systems where the bounding set Value is
|
||||
// not present, this function returns an error.
|
||||
func GetBound(val Value) (bool, error) {
|
||||
v, err := multisc.prctlrcall(prCapBSetRead, uintptr(val), 0)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return v > 0, nil
|
||||
}
|
||||
|
||||
//go:uintptrescapes
|
||||
func (sc *syscaller) dropBound(val ...Value) error {
|
||||
for _, v := range val {
|
||||
if _, err := sc.prctlwcall(prCapBSetDrop, uintptr(v), 0); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DropBound attempts to suppress bounding set Values. The kernel will
|
||||
// never allow a bounding set Value bit to be raised once successfully
|
||||
// dropped. However, dropping requires the current process is
|
||||
// sufficiently capable (usually via cap.SETPCAP being raised in the
|
||||
// Effective flag of the process' Set). Note, the drops are performed
|
||||
// in order and if one bounding value cannot be dropped, the function
|
||||
// returns immediately with an error which may leave the system in an
|
||||
// ill-defined state. The caller can determine where things went wrong
|
||||
// using GetBound().
|
||||
func DropBound(val ...Value) error {
|
||||
state, sc := scwStateSC()
|
||||
defer scwSetState(launchBlocked, state, -1)
|
||||
return sc.dropBound(val...)
|
||||
}
|
||||
|
||||
// defines from uapi/linux/prctl.h
|
||||
const (
|
||||
prCapAmbient = 47
|
||||
|
||||
prCapAmbientIsSet = 1
|
||||
prCapAmbientRaise = 2
|
||||
prCapAmbientLower = 3
|
||||
prCapAmbientClearAll = 4
|
||||
)
|
||||
|
||||
// GetAmbient determines if a specific capability is currently part of
|
||||
// the local ambient set. On systems where the ambient set Value is
|
||||
// not present, this function returns an error.
|
||||
func GetAmbient(val Value) (bool, error) {
|
||||
r, err := multisc.prctlrcall6(prCapAmbient, prCapAmbientIsSet, uintptr(val), 0, 0, 0)
|
||||
return r > 0, err
|
||||
}
|
||||
|
||||
//go:uintptrescapes
|
||||
func (sc *syscaller) setAmbient(enable bool, val ...Value) error {
|
||||
dir := uintptr(prCapAmbientLower)
|
||||
if enable {
|
||||
dir = prCapAmbientRaise
|
||||
}
|
||||
for _, v := range val {
|
||||
_, err := sc.prctlwcall6(prCapAmbient, dir, uintptr(v), 0, 0, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetAmbient attempts to set a specific Value bit to the state,
|
||||
// enable. This function will return an error if insufficient
|
||||
// permission is available to perform this task. The settings are
|
||||
// performed in order and the function returns immediately an error is
|
||||
// detected. Use GetAmbient() to unravel where things went
|
||||
// wrong. Note, the cap package manages an abstraction IAB that
|
||||
// captures all three inheritable vectors in a single type. Consider
|
||||
// using that.
|
||||
func SetAmbient(enable bool, val ...Value) error {
|
||||
state, sc := scwStateSC()
|
||||
defer scwSetState(launchBlocked, state, -1)
|
||||
return sc.setAmbient(enable, val...)
|
||||
}
|
||||
|
||||
func (sc *syscaller) resetAmbient() error {
|
||||
var v bool
|
||||
var err error
|
||||
|
||||
for c := Value(0); !v; c++ {
|
||||
if v, err = GetAmbient(c); err != nil {
|
||||
// no non-zero values found.
|
||||
return nil
|
||||
}
|
||||
}
|
||||
_, err = sc.prctlwcall6(prCapAmbient, prCapAmbientClearAll, 0, 0, 0, 0)
|
||||
return err
|
||||
}
|
||||
|
||||
// ResetAmbient attempts to ensure the Ambient set is fully
|
||||
// cleared. It works by first reading the set and if it finds any bits
|
||||
// raised it will attempt a reset. The test before attempting a reset
|
||||
// behavior is a workaround for situations where the Ambient API is
|
||||
// locked, but a reset is not actually needed. No Ambient bit not
|
||||
// already raised in both the Permitted and Inheritable Set is allowed
|
||||
// to be raised by the kernel.
|
||||
func ResetAmbient() error {
|
||||
state, sc := scwStateSC()
|
||||
defer scwSetState(launchBlocked, state, -1)
|
||||
return sc.resetAmbient()
|
||||
}
|
||||
340
vendor/kernel.org/pub/linux/libs/security/libcap/cap/convenience.go
generated
vendored
Normal file
340
vendor/kernel.org/pub/linux/libs/security/libcap/cap/convenience.go
generated
vendored
Normal file
@@ -0,0 +1,340 @@
|
||||
package cap
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// This file contains convenience functions for libcap, to help
|
||||
// users do the right thing with respect to capabilities for
|
||||
// common actions.
|
||||
|
||||
// Secbits capture the prctl settable secure-bits of a process.
|
||||
type Secbits uint
|
||||
|
||||
// SecbitNoRoot etc are the bitmasks associated with the supported
|
||||
// Secbit masks. Source: uapi/linux/securebits.h
|
||||
const (
|
||||
SecbitNoRoot Secbits = 1 << iota
|
||||
SecbitNoRootLocked
|
||||
SecbitNoSetUIDFixup
|
||||
SecbitNoSetUIDFixupLocked
|
||||
SecbitKeepCaps
|
||||
SecbitKeepCapsLocked
|
||||
SecbitNoCapAmbientRaise
|
||||
SecbitNoCapAmbientRaiseLocked
|
||||
)
|
||||
|
||||
const (
|
||||
securedBasicBits = SecbitNoRoot | SecbitNoRootLocked | SecbitNoSetUIDFixup | SecbitNoSetUIDFixupLocked | SecbitKeepCapsLocked
|
||||
securedAmbientBits = securedBasicBits | SecbitNoCapAmbientRaise | SecbitNoCapAmbientRaiseLocked
|
||||
)
|
||||
|
||||
// defines from uapi/linux/prctl.h
|
||||
const (
|
||||
prGetKeepCaps = 7
|
||||
prSetKeepCaps = 8
|
||||
prGetSecureBits = 27
|
||||
prSetSecureBits = 28
|
||||
prSetNoNewPrivs = 38
|
||||
)
|
||||
|
||||
// GetSecbits returns the current setting of the process' Secbits.
|
||||
func GetSecbits() Secbits {
|
||||
v, err := multisc.prctlrcall(prGetSecureBits, 0, 0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return Secbits(v)
|
||||
}
|
||||
|
||||
func (sc *syscaller) setSecbits(s Secbits) error {
|
||||
_, err := sc.prctlwcall(prSetSecureBits, uintptr(s), 0)
|
||||
return err
|
||||
}
|
||||
|
||||
// Set attempts to force the process Secbits to a value. This function
|
||||
// will raise cap.SETPCAP in order to achieve this operation, and will
|
||||
// completely lower the Effective Flag of the process upon returning.
|
||||
func (s Secbits) Set() error {
|
||||
state, sc := scwStateSC()
|
||||
defer scwSetState(launchBlocked, state, -1)
|
||||
return sc.setSecbits(s)
|
||||
}
|
||||
|
||||
// Mode summarizes a complicated secure-bits and capability mode in a
|
||||
// libcap preferred way.
|
||||
type Mode uint
|
||||
|
||||
// ModeUncertain etc are how libcap summarizes security modes
|
||||
// involving capabilities and secure-bits.
|
||||
const (
|
||||
ModeUncertain Mode = iota
|
||||
ModeNoPriv
|
||||
ModePure1EInit
|
||||
ModePure1E
|
||||
ModeHybrid
|
||||
)
|
||||
|
||||
// GetMode assesses the current process state and summarizes it as
|
||||
// a Mode. This function always succeeds. Unfamiliar modes are
|
||||
// declared ModeUncertain.
|
||||
func GetMode() Mode {
|
||||
b := GetSecbits()
|
||||
if b == 0 {
|
||||
return ModeHybrid
|
||||
}
|
||||
if b&securedBasicBits != securedBasicBits {
|
||||
return ModeUncertain
|
||||
}
|
||||
|
||||
for c := Value(0); ; c++ {
|
||||
v, err := GetAmbient(c)
|
||||
if err != nil {
|
||||
if c != 0 && b != securedAmbientBits {
|
||||
return ModeUncertain
|
||||
}
|
||||
break
|
||||
}
|
||||
if v {
|
||||
return ModeUncertain
|
||||
}
|
||||
}
|
||||
|
||||
w := GetProc()
|
||||
e := NewSet()
|
||||
cf, _ := w.Cf(e)
|
||||
|
||||
if cf.Has(Inheritable) {
|
||||
return ModePure1E
|
||||
}
|
||||
if cf.Has(Permitted) || cf.Has(Effective) {
|
||||
return ModePure1EInit
|
||||
}
|
||||
|
||||
for c := Value(0); ; c++ {
|
||||
v, err := GetBound(c)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
if v {
|
||||
return ModePure1EInit
|
||||
}
|
||||
}
|
||||
|
||||
return ModeNoPriv
|
||||
}
|
||||
|
||||
// ErrBadMode is the error returned when an attempt is made to set an
|
||||
// unrecognized libcap security mode.
|
||||
var ErrBadMode = errors.New("unsupported mode")
|
||||
|
||||
func (sc *syscaller) setMode(m Mode) error {
|
||||
w := GetProc()
|
||||
defer func() {
|
||||
w.ClearFlag(Effective)
|
||||
sc.setProc(w)
|
||||
}()
|
||||
|
||||
if err := w.SetFlag(Effective, true, SETPCAP); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := sc.setProc(w); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if m == ModeHybrid {
|
||||
return sc.setSecbits(0)
|
||||
}
|
||||
|
||||
if m == ModeNoPriv || m == ModePure1EInit {
|
||||
w.ClearFlag(Inheritable)
|
||||
} else if m != ModePure1E {
|
||||
return ErrBadMode
|
||||
}
|
||||
|
||||
sb := securedAmbientBits
|
||||
if _, err := GetAmbient(0); err != nil {
|
||||
sb = securedBasicBits
|
||||
} else if err := sc.resetAmbient(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := sc.setSecbits(sb); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if m != ModeNoPriv {
|
||||
return nil
|
||||
}
|
||||
|
||||
for c := Value(0); sc.dropBound(c) == nil; c++ {
|
||||
}
|
||||
w.ClearFlag(Permitted)
|
||||
|
||||
// For good measure.
|
||||
sc.prctlwcall6(prSetNoNewPrivs, 1, 0, 0, 0, 0)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set attempts to enter the specified mode. An attempt is made to
|
||||
// enter the mode, so if you prefer this operation to be a no-op if
|
||||
// entering the same mode, call only if CurrentMode() disagrees with
|
||||
// the desired mode.
|
||||
//
|
||||
// This function will raise cap.SETPCAP in order to achieve this
|
||||
// operation, and will completely lower the Effective Flag of the
|
||||
// process' Set before returning. This function may fail for lack of
|
||||
// permission or because (some of) the Secbits are already locked for
|
||||
// the current process.
|
||||
func (m Mode) Set() error {
|
||||
state, sc := scwStateSC()
|
||||
defer scwSetState(launchBlocked, state, -1)
|
||||
return sc.setMode(m)
|
||||
}
|
||||
|
||||
// String returns the libcap conventional string for this mode.
|
||||
func (m Mode) String() string {
|
||||
switch m {
|
||||
case ModeUncertain:
|
||||
return "UNCERTAIN"
|
||||
case ModeNoPriv:
|
||||
return "NOPRIV"
|
||||
case ModePure1EInit:
|
||||
return "PURE1E_INIT"
|
||||
case ModePure1E:
|
||||
return "PURE1E"
|
||||
case ModeHybrid:
|
||||
return "HYBRID"
|
||||
default:
|
||||
return "UNKNOWN"
|
||||
}
|
||||
}
|
||||
|
||||
func (sc *syscaller) setUID(uid int) error {
|
||||
w := GetProc()
|
||||
defer func() {
|
||||
w.ClearFlag(Effective)
|
||||
sc.setProc(w)
|
||||
}()
|
||||
|
||||
if err := w.SetFlag(Effective, true, SETUID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// these may or may not work depending on whether or not they
|
||||
// are locked. We try them just in case.
|
||||
sc.prctlwcall(prSetKeepCaps, 1, 0)
|
||||
defer sc.prctlwcall(prSetKeepCaps, 0, 0)
|
||||
|
||||
if err := sc.setProc(w); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, _, err := sc.w3(syscall.SYS_SETUID, uintptr(uid), 0, 0); err != 0 {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetUID is a convenience function for robustly setting the UID and
|
||||
// all other variants of UID (EUID etc) to the specified value without
|
||||
// dropping the privilege of the current process. This function will
|
||||
// raise cap.SETUID in order to achieve this operation, and will
|
||||
// completely lower the Effective Flag of the process before
|
||||
// returning. Unlike the traditional method of dropping privilege when
|
||||
// changing from [E]UID=0 to some other UID, this function only can
|
||||
// perform any change of UID if cap.SETUID is available, and this
|
||||
// operation will not alter the Permitted Flag of the process' Set.
|
||||
func SetUID(uid int) error {
|
||||
state, sc := scwStateSC()
|
||||
defer scwSetState(launchBlocked, state, -1)
|
||||
return sc.setUID(uid)
|
||||
}
|
||||
|
||||
//go:uintptrescapes
|
||||
func (sc *syscaller) setGroups(gid int, suppl []int) error {
|
||||
w := GetProc()
|
||||
defer func() {
|
||||
w.ClearFlag(Effective)
|
||||
sc.setProc(w)
|
||||
}()
|
||||
|
||||
if err := w.SetFlag(Effective, true, SETGID); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := sc.setProc(w); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, _, err := sc.w3(syscall.SYS_SETGID, uintptr(gid), 0, 0); err != 0 {
|
||||
return err
|
||||
}
|
||||
if len(suppl) == 0 {
|
||||
if _, _, err := sc.w3(sysSetGroupsVariant, 0, 0, 0); err != 0 {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// On linux gid values are 32-bits.
|
||||
gs := make([]uint32, len(suppl))
|
||||
for i, g := range suppl {
|
||||
gs[i] = uint32(g)
|
||||
}
|
||||
if _, _, err := sc.w3(sysSetGroupsVariant, uintptr(len(suppl)), uintptr(unsafe.Pointer(&gs[0])), 0); err != 0 {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetGroups is a convenience function for robustly setting the GID
|
||||
// and all other variants of GID (EGID etc) to the specified value, as
|
||||
// well as setting all of the supplementary groups. This function will
|
||||
// raise cap.SETGID in order to achieve this operation, and will
|
||||
// completely lower the Effective Flag of the process Set before
|
||||
// returning.
|
||||
func SetGroups(gid int, suppl ...int) error {
|
||||
state, sc := scwStateSC()
|
||||
defer scwSetState(launchBlocked, state, -1)
|
||||
return sc.setGroups(gid, suppl)
|
||||
}
|
||||
|
||||
//go:uintptrescapes
|
||||
|
||||
// Prctlw is a convenience function for performing a syscall.Prctl()
|
||||
// call that executes on all the threads of the process. It is called
|
||||
// Prctlw because it is only appropriate to call this function when it
|
||||
// is writing thread state that the caller wants to set on all OS
|
||||
// threads of the process to observe POSIX semantics when Linux
|
||||
// doesn't natively honor them. (Check prctl documentation for when it
|
||||
// is appropriate to use this vs. a normal syscall.Prctl() call.)
|
||||
func Prctlw(prVal uintptr, args ...uintptr) (int, error) {
|
||||
if n := len(args); n > 5 {
|
||||
return -1, fmt.Errorf("prctl supports up to 5 arguments (not %d)", n)
|
||||
}
|
||||
state, sc := scwStateSC()
|
||||
defer scwSetState(launchBlocked, state, -1)
|
||||
as := make([]uintptr, 5)
|
||||
copy(as, args)
|
||||
return sc.prctlwcall6(prVal, as[0], as[1], as[2], as[3], as[4])
|
||||
}
|
||||
|
||||
//go:uintptrescapes
|
||||
|
||||
// Prctl is a convenience function that performs a syscall.Prctl()
|
||||
// that either reads state using a single OS thread, or performs a
|
||||
// Prctl that is treated as a process wide setting. It is provided for
|
||||
// symmetry reasons, but is equivalent to simply calling the
|
||||
// corresponding syscall function.
|
||||
func Prctl(prVal uintptr, args ...uintptr) (int, error) {
|
||||
if n := len(args); n > 5 {
|
||||
return -1, fmt.Errorf("prctl supports up to 5 arguments (not %d)", n)
|
||||
}
|
||||
as := make([]uintptr, 5)
|
||||
copy(as, args)
|
||||
return singlesc.prctlrcall6(prVal, as[0], as[1], as[2], as[3], as[4])
|
||||
}
|
||||
419
vendor/kernel.org/pub/linux/libs/security/libcap/cap/file.go
generated
vendored
Normal file
419
vendor/kernel.org/pub/linux/libs/security/libcap/cap/file.go
generated
vendored
Normal file
@@ -0,0 +1,419 @@
|
||||
package cap
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// uapi/linux/xattr.h defined.
|
||||
var (
|
||||
xattrNameCaps, _ = syscall.BytePtrFromString("security.capability")
|
||||
)
|
||||
|
||||
// uapi/linux/capability.h defined.
|
||||
const (
|
||||
vfsCapRevisionMask = uint32(0xff000000)
|
||||
vfsCapFlagsMask = ^vfsCapRevisionMask
|
||||
vfsCapFlagsEffective = uint32(1)
|
||||
|
||||
vfsCapRevision1 = uint32(0x01000000)
|
||||
vfsCapRevision2 = uint32(0x02000000)
|
||||
vfsCapRevision3 = uint32(0x03000000)
|
||||
)
|
||||
|
||||
// Data types stored in little-endian order.
|
||||
|
||||
type vfsCaps1 struct {
|
||||
MagicEtc uint32
|
||||
Data [1]struct {
|
||||
Permitted, Inheritable uint32
|
||||
}
|
||||
}
|
||||
|
||||
type vfsCaps2 struct {
|
||||
MagicEtc uint32
|
||||
Data [2]struct {
|
||||
Permitted, Inheritable uint32
|
||||
}
|
||||
}
|
||||
|
||||
type vfsCaps3 struct {
|
||||
MagicEtc uint32
|
||||
Data [2]struct {
|
||||
Permitted, Inheritable uint32
|
||||
}
|
||||
RootID uint32
|
||||
}
|
||||
|
||||
// ErrBadSize indicates the loaded file capability has
|
||||
// an invalid number of bytes in it.
|
||||
var ErrBadSize = errors.New("filecap bad size")
|
||||
|
||||
// ErrBadMagic indicates that the kernel preferred magic number for
|
||||
// capability Set values is not supported by this package. This
|
||||
// generally implies you are using an exceptionally old
|
||||
// "../libcap/cap" package. An upgrade is needed, or failing that see
|
||||
// https://sites.google.com/site/fullycapable/ for how to file a bug.
|
||||
var ErrBadMagic = errors.New("unsupported magic")
|
||||
|
||||
// ErrBadPath indicates a failed attempt to set a file capability on
|
||||
// an irregular (non-executable) file.
|
||||
var ErrBadPath = errors.New("file is not a regular executable")
|
||||
|
||||
// ErrOutOfRange indicates an erroneous value for MinExtFlagSize.
|
||||
var ErrOutOfRange = errors.New("flag length invalid for export")
|
||||
|
||||
// digestFileCap unpacks a file capability and returns it in a *Set
|
||||
// form.
|
||||
func digestFileCap(d []byte, sz int, err error) (*Set, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var raw1 vfsCaps1
|
||||
var raw2 vfsCaps2
|
||||
var raw3 vfsCaps3
|
||||
if sz < binary.Size(raw1) || sz > binary.Size(raw3) {
|
||||
return nil, ErrBadSize
|
||||
}
|
||||
b := bytes.NewReader(d[:sz])
|
||||
var magicEtc uint32
|
||||
if err = binary.Read(b, binary.LittleEndian, &magicEtc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c := NewSet()
|
||||
b.Seek(0, io.SeekStart)
|
||||
switch magicEtc & vfsCapRevisionMask {
|
||||
case vfsCapRevision1:
|
||||
if err = binary.Read(b, binary.LittleEndian, &raw1); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data := raw1.Data[0]
|
||||
c.flat[0][Permitted] = data.Permitted
|
||||
c.flat[0][Inheritable] = data.Inheritable
|
||||
if raw1.MagicEtc&vfsCapFlagsMask == vfsCapFlagsEffective {
|
||||
c.flat[0][Effective] = data.Inheritable | data.Permitted
|
||||
}
|
||||
case vfsCapRevision2:
|
||||
if err = binary.Read(b, binary.LittleEndian, &raw2); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i, data := range raw2.Data {
|
||||
c.flat[i][Permitted] = data.Permitted
|
||||
c.flat[i][Inheritable] = data.Inheritable
|
||||
if raw2.MagicEtc&vfsCapFlagsMask == vfsCapFlagsEffective {
|
||||
c.flat[i][Effective] = data.Inheritable | data.Permitted
|
||||
}
|
||||
}
|
||||
case vfsCapRevision3:
|
||||
if err = binary.Read(b, binary.LittleEndian, &raw3); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i, data := range raw3.Data {
|
||||
c.flat[i][Permitted] = data.Permitted
|
||||
c.flat[i][Inheritable] = data.Inheritable
|
||||
if raw3.MagicEtc&vfsCapFlagsMask == vfsCapFlagsEffective {
|
||||
c.flat[i][Effective] = data.Inheritable | data.Permitted
|
||||
}
|
||||
}
|
||||
c.nsRoot = int(raw3.RootID)
|
||||
default:
|
||||
return nil, ErrBadMagic
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
//go:uintptrescapes
|
||||
|
||||
// GetFd returns the file capabilities of an open (*os.File).Fd().
|
||||
func GetFd(file *os.File) (*Set, error) {
|
||||
var raw3 vfsCaps3
|
||||
d := make([]byte, binary.Size(raw3))
|
||||
sz, _, oErr := multisc.r6(syscall.SYS_FGETXATTR, uintptr(file.Fd()), uintptr(unsafe.Pointer(xattrNameCaps)), uintptr(unsafe.Pointer(&d[0])), uintptr(len(d)), 0, 0)
|
||||
var err error
|
||||
if oErr != 0 {
|
||||
err = oErr
|
||||
}
|
||||
return digestFileCap(d, int(sz), err)
|
||||
}
|
||||
|
||||
//go:uintptrescapes
|
||||
|
||||
// GetFile returns the file capabilities of a named file.
|
||||
func GetFile(path string) (*Set, error) {
|
||||
p, err := syscall.BytePtrFromString(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var raw3 vfsCaps3
|
||||
d := make([]byte, binary.Size(raw3))
|
||||
sz, _, oErr := multisc.r6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(p)), uintptr(unsafe.Pointer(xattrNameCaps)), uintptr(unsafe.Pointer(&d[0])), uintptr(len(d)), 0, 0)
|
||||
if oErr != 0 {
|
||||
err = oErr
|
||||
}
|
||||
return digestFileCap(d, int(sz), err)
|
||||
}
|
||||
|
||||
// GetNSOwner returns the namespace owner UID of the capability Set.
|
||||
func (c *Set) GetNSOwner() (int, error) {
|
||||
if magic < kv3 {
|
||||
return 0, ErrBadMagic
|
||||
}
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
return c.nsRoot, nil
|
||||
}
|
||||
|
||||
// SetNSOwner adds an explicit namespace owner UID to the capability
|
||||
// Set. This is only honored when generating file capabilities, and is
|
||||
// generally for use by a setup process when installing binaries that
|
||||
// use file capabilities to become capable inside a namespace to be
|
||||
// administered by that UID. If capability aware code within that
|
||||
// namespace writes file capabilities without explicitly setting such
|
||||
// a UID, the kernel will fix-up the capabilities to be specific to
|
||||
// that owner. In this way, the kernel prevents filesystem
|
||||
// capabilities from leaking out of that restricted namespace.
|
||||
func (c *Set) SetNSOwner(uid int) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
c.nsRoot = uid
|
||||
}
|
||||
|
||||
// packFileCap transforms a system capability into a VFS form. Because
|
||||
// of the way Linux stores capabilities in the file extended
|
||||
// attributes, the process is a little lossy with respect to effective
|
||||
// bits.
|
||||
func (c *Set) packFileCap() ([]byte, error) {
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
|
||||
var magic uint32
|
||||
switch words {
|
||||
case 1:
|
||||
if c.nsRoot != 0 {
|
||||
return nil, ErrBadSet // nsRoot not supported for single DWORD caps.
|
||||
}
|
||||
magic = vfsCapRevision1
|
||||
case 2:
|
||||
if c.nsRoot == 0 {
|
||||
magic = vfsCapRevision2
|
||||
break
|
||||
}
|
||||
magic = vfsCapRevision3
|
||||
}
|
||||
if magic == 0 {
|
||||
return nil, ErrBadSize
|
||||
}
|
||||
eff := uint32(0)
|
||||
for _, f := range c.flat {
|
||||
eff |= (f[Permitted] | f[Inheritable]) & f[Effective]
|
||||
}
|
||||
if eff != 0 {
|
||||
magic |= vfsCapFlagsEffective
|
||||
}
|
||||
b := new(bytes.Buffer)
|
||||
binary.Write(b, binary.LittleEndian, magic)
|
||||
for _, f := range c.flat {
|
||||
binary.Write(b, binary.LittleEndian, f[Permitted])
|
||||
binary.Write(b, binary.LittleEndian, f[Inheritable])
|
||||
}
|
||||
if c.nsRoot != 0 {
|
||||
binary.Write(b, binary.LittleEndian, c.nsRoot)
|
||||
}
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
//go:uintptrescapes
|
||||
|
||||
// SetFd attempts to set the file capabilities of an open
|
||||
// (*os.File).Fd(). This function can also be used to delete a file's
|
||||
// capabilities, by calling with c = nil.
|
||||
//
|
||||
// Note, Linux does not store the full Effective Flag in the metadata
|
||||
// for the file. Only a single Effective bit is stored in this
|
||||
// metadata. This single bit is non-zero if the Effective Flag has any
|
||||
// overlapping bits with the Permitted or Inheritable Flags of c. This
|
||||
// may appear suboptimal, but the reasoning behind it is sound.
|
||||
// Namely, the purpose of the Effective bit it to support capabability
|
||||
// unaware binaries that will only work if they magically launch with
|
||||
// the needed Values already raised (this bit is sometimes referred to
|
||||
// simply as the 'legacy' bit).
|
||||
//
|
||||
// Historical note: without *full* support for runtime capability
|
||||
// manipulation, as it is provided in this "../libcap/cap" package,
|
||||
// this was previously the only way for Go programs to make use of
|
||||
// file capabilities.
|
||||
//
|
||||
// The preferred way that a binary will actually manipulate its
|
||||
// file-acquired capabilities is to carefully and deliberately use
|
||||
// this package (or libcap, assisted by libpsx, for threaded C/C++
|
||||
// family code).
|
||||
func (c *Set) SetFd(file *os.File) error {
|
||||
if c == nil {
|
||||
if _, _, err := multisc.r6(syscall.SYS_FREMOVEXATTR, uintptr(file.Fd()), uintptr(unsafe.Pointer(xattrNameCaps)), 0, 0, 0, 0); err != 0 {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
d, err := c.packFileCap()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, _, err := multisc.r6(syscall.SYS_FSETXATTR, uintptr(file.Fd()), uintptr(unsafe.Pointer(xattrNameCaps)), uintptr(unsafe.Pointer(&d[0])), uintptr(len(d)), 0, 0); err != 0 {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//go:uintptrescapes
|
||||
|
||||
// SetFile attempts to set the file capabilities of the specified
|
||||
// filename. This function can also be used to delete a file's
|
||||
// capabilities, by calling with c = nil.
|
||||
//
|
||||
// Note, see the comment for SetFd() for some non-obvious behavior of
|
||||
// Linux for the Effective Flag on the modified file.
|
||||
func (c *Set) SetFile(path string) error {
|
||||
fi, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mode := fi.Mode()
|
||||
if mode&os.ModeType != 0 {
|
||||
return ErrBadPath
|
||||
}
|
||||
if mode&os.FileMode(0111) == 0 {
|
||||
return ErrBadPath
|
||||
}
|
||||
p, err := syscall.BytePtrFromString(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c == nil {
|
||||
if _, _, err := multisc.r6(syscall.SYS_REMOVEXATTR, uintptr(unsafe.Pointer(p)), uintptr(unsafe.Pointer(xattrNameCaps)), 0, 0, 0, 0); err != 0 {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
d, err := c.packFileCap()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, _, err := multisc.r6(syscall.SYS_SETXATTR, uintptr(unsafe.Pointer(p)), uintptr(unsafe.Pointer(xattrNameCaps)), uintptr(unsafe.Pointer(&d[0])), uintptr(len(d)), 0, 0); err != 0 {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExtMagic is the 32-bit (little endian) magic for an external
|
||||
// capability set. It can be used to transmit capabilities in binary
|
||||
// format in a Linux portable way. The format is:
|
||||
// <ExtMagic><byte:length><length-bytes*3-of-cap-data>.
|
||||
const ExtMagic = uint32(0x5101c290)
|
||||
|
||||
// Import imports a Set from a byte array where it has been stored in
|
||||
// a portable (lossless) way. That is values exported by
|
||||
// libcap.cap_copy_ext() and Export().
|
||||
func Import(d []byte) (*Set, error) {
|
||||
b := bytes.NewBuffer(d)
|
||||
var m uint32
|
||||
if err := binary.Read(b, binary.LittleEndian, &m); err != nil {
|
||||
return nil, ErrBadSize
|
||||
} else if m != ExtMagic {
|
||||
return nil, ErrBadMagic
|
||||
}
|
||||
var n byte
|
||||
if err := binary.Read(b, binary.LittleEndian, &n); err != nil {
|
||||
return nil, ErrBadSize
|
||||
}
|
||||
c := NewSet()
|
||||
if int(n) > 4*words {
|
||||
return nil, ErrBadSize
|
||||
}
|
||||
f := make([]byte, 3)
|
||||
for i := 0; i < words; i++ {
|
||||
for j := uint(0); n > 0 && j < 4; j++ {
|
||||
n--
|
||||
if x, err := b.Read(f); err != nil || x != 3 {
|
||||
return nil, ErrBadSize
|
||||
}
|
||||
sh := 8 * j
|
||||
c.flat[i][Effective] |= uint32(f[0]) << sh
|
||||
c.flat[i][Permitted] |= uint32(f[1]) << sh
|
||||
c.flat[i][Inheritable] |= uint32(f[2]) << sh
|
||||
}
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// MinExtFlagSize defaults to 8 in order to be equivalent to libcap
|
||||
// defaults. Setting it to zero can generate smaller external
|
||||
// representations. Such smaller representations can be imported by
|
||||
// libcap and the Go package just fine, we just default to the default
|
||||
// libcap representation for legacy reasons.
|
||||
var MinExtFlagSize = uint(8)
|
||||
|
||||
// Export exports a Set into a lossless byte array format where it is
|
||||
// stored in a portable way. Note, any namespace owner in the Set
|
||||
// content is not exported by this function.
|
||||
//
|
||||
// Note, Export() generates exported byte streams that are importable
|
||||
// by libcap.cap_copy_int() as well as Import().
|
||||
func (c *Set) Export() ([]byte, error) {
|
||||
if err := c.good(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if MinExtFlagSize > 255 {
|
||||
return nil, ErrOutOfRange
|
||||
}
|
||||
b := new(bytes.Buffer)
|
||||
binary.Write(b, binary.LittleEndian, ExtMagic)
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
var n = uint(0)
|
||||
for i, f := range c.flat {
|
||||
if nn := 4 * uint(i); nn+4 > n {
|
||||
if u := f[Effective] | f[Permitted] | f[Inheritable]; u != 0 {
|
||||
n = nn
|
||||
for ; u != 0; u >>= 8 {
|
||||
n++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if n < MinExtFlagSize {
|
||||
n = MinExtFlagSize
|
||||
}
|
||||
b.Write([]byte{byte(n)})
|
||||
for _, f := range c.flat {
|
||||
if n == 0 {
|
||||
break
|
||||
}
|
||||
eff, per, inh := f[Effective], f[Permitted], f[Inheritable]
|
||||
for i := 0; n > 0 && i < 4; i++ {
|
||||
n--
|
||||
b.Write([]byte{
|
||||
byte(eff & 0xff),
|
||||
byte(per & 0xff),
|
||||
byte(inh & 0xff),
|
||||
})
|
||||
eff >>= 8
|
||||
per >>= 8
|
||||
inh >>= 8
|
||||
}
|
||||
}
|
||||
for n > 0 {
|
||||
n--
|
||||
b.Write([]byte{0, 0, 0})
|
||||
}
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
271
vendor/kernel.org/pub/linux/libs/security/libcap/cap/flags.go
generated
vendored
Normal file
271
vendor/kernel.org/pub/linux/libs/security/libcap/cap/flags.go
generated
vendored
Normal file
@@ -0,0 +1,271 @@
|
||||
package cap
|
||||
|
||||
import "errors"
|
||||
|
||||
// GetFlag determines if the requested Value is enabled in the
|
||||
// specified Flag of the capability Set.
|
||||
func (c *Set) GetFlag(vec Flag, val Value) (bool, error) {
|
||||
if err := c.good(); err != nil {
|
||||
// Checked this first, because otherwise we are sure
|
||||
// cInit has been called.
|
||||
return false, err
|
||||
}
|
||||
offset, mask, err := bitOf(vec, val)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
return c.flat[offset][vec]&mask != 0, nil
|
||||
}
|
||||
|
||||
// SetFlag sets the requested bits to the indicated enable state. This
|
||||
// function does not perform any security checks, so values can be set
|
||||
// out-of-order. Only when the Set is used to SetProc() etc., will the
|
||||
// bits be checked for validity and permission by the kernel. If the
|
||||
// function returns an error, the Set will not be modified.
|
||||
func (c *Set) SetFlag(vec Flag, enable bool, val ...Value) error {
|
||||
if err := c.good(); err != nil {
|
||||
// Checked this first, because otherwise we are sure
|
||||
// cInit has been called.
|
||||
return err
|
||||
}
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
// Make a backup.
|
||||
replace := make([]uint32, words)
|
||||
for i := range replace {
|
||||
replace[i] = c.flat[i][vec]
|
||||
}
|
||||
var err error
|
||||
for _, v := range val {
|
||||
offset, mask, err2 := bitOf(vec, v)
|
||||
if err2 != nil {
|
||||
err = err2
|
||||
break
|
||||
}
|
||||
if enable {
|
||||
c.flat[offset][vec] |= mask
|
||||
} else {
|
||||
c.flat[offset][vec] &= ^mask
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
// Clean up.
|
||||
for i, bits := range replace {
|
||||
c.flat[i][vec] = bits
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Clear fully clears a capability set.
|
||||
func (c *Set) Clear() error {
|
||||
if err := c.good(); err != nil {
|
||||
return err
|
||||
}
|
||||
// startUp.Do(cInit) is not called here because c cannot be
|
||||
// initialized except via this package and doing that will
|
||||
// perform that call at least once (sic).
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
c.flat = make([]data, words)
|
||||
c.nsRoot = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
// FillFlag copies the from flag values of ref into the to flag of
|
||||
// c. With this function, you can raise all of the permitted values in
|
||||
// the c Set from those in ref with c.Fill(cap.Permitted, ref,
|
||||
// cap.Permitted).
|
||||
func (c *Set) FillFlag(to Flag, ref *Set, from Flag) error {
|
||||
if err := c.good(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ref.good(); err != nil {
|
||||
return err
|
||||
}
|
||||
if to > Inheritable || from > Inheritable {
|
||||
return ErrBadValue
|
||||
}
|
||||
|
||||
// Avoid deadlock by using a copy.
|
||||
if c != ref {
|
||||
var err error
|
||||
ref, err = ref.Dup()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
for i := range c.flat {
|
||||
c.flat[i][to] = ref.flat[i][from]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Fill copies the from flag values into the to flag. With this
|
||||
// function, you can raise all of the permitted values in the
|
||||
// effective flag with c.Fill(cap.Effective, cap.Permitted).
|
||||
func (c *Set) Fill(to, from Flag) error {
|
||||
return c.FillFlag(to, c, from)
|
||||
}
|
||||
|
||||
// ErrBadValue indicates a bad capability value was specified.
|
||||
var ErrBadValue = errors.New("bad capability value")
|
||||
|
||||
// bitOf converts from a Value into the offset and mask for a specific
|
||||
// Value bit in the compressed (kernel ABI) representation of a
|
||||
// capabilities. If the requested bit is unsupported, an error is
|
||||
// returned.
|
||||
func bitOf(vec Flag, val Value) (uint, uint32, error) {
|
||||
if vec > Inheritable || val > Value(words*32) {
|
||||
return 0, 0, ErrBadValue
|
||||
}
|
||||
u := uint(val)
|
||||
return u / 32, uint32(1) << (u % 32), nil
|
||||
}
|
||||
|
||||
// allMask returns the mask of valid bits in the all mask for index.
|
||||
func allMask(index uint) (mask uint32) {
|
||||
if maxValues == 0 {
|
||||
panic("uninitialized package")
|
||||
}
|
||||
base := 32 * uint(index)
|
||||
if maxValues <= base {
|
||||
return
|
||||
}
|
||||
if maxValues >= 32+base {
|
||||
mask = ^mask
|
||||
return
|
||||
}
|
||||
mask = uint32((uint64(1) << (maxValues % 32)) - 1)
|
||||
return
|
||||
}
|
||||
|
||||
// forceFlag sets 'all' capability values (supported by the kernel) of
|
||||
// a specified Flag to enable.
|
||||
func (c *Set) forceFlag(vec Flag, enable bool) error {
|
||||
if err := c.good(); err != nil {
|
||||
return err
|
||||
}
|
||||
if vec > Inheritable {
|
||||
return ErrBadSet
|
||||
}
|
||||
m := uint32(0)
|
||||
if enable {
|
||||
m = ^m
|
||||
}
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
for i := range c.flat {
|
||||
c.flat[i][vec] = m & allMask(uint(i))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ClearFlag clears all the Values associated with the specified Flag.
|
||||
func (c *Set) ClearFlag(vec Flag) error {
|
||||
return c.forceFlag(vec, false)
|
||||
}
|
||||
|
||||
// Cf returns 0 if c and d are identical. A non-zero Diff value
|
||||
// captures a simple macroscopic summary of how they differ. The
|
||||
// (Diff).Has() function can be used to determine how the two
|
||||
// capability sets differ.
|
||||
func (c *Set) Cf(d *Set) (Diff, error) {
|
||||
if err := c.good(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if c == d {
|
||||
return 0, nil
|
||||
}
|
||||
d, err := d.Dup()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
|
||||
var cf Diff
|
||||
for i := 0; i < words; i++ {
|
||||
if c.flat[i][Effective]^d.flat[i][Effective] != 0 {
|
||||
cf |= effectiveDiff
|
||||
}
|
||||
if c.flat[i][Permitted]^d.flat[i][Permitted] != 0 {
|
||||
cf |= permittedDiff
|
||||
}
|
||||
if c.flat[i][Inheritable]^d.flat[i][Inheritable] != 0 {
|
||||
cf |= inheritableDiff
|
||||
}
|
||||
}
|
||||
return cf, nil
|
||||
}
|
||||
|
||||
// Compare returns 0 if c and d are identical in content.
|
||||
//
|
||||
// Deprecated: Replace with (*Set).Cf().
|
||||
//
|
||||
// Example, replace this:
|
||||
//
|
||||
// diff, err := a.Compare(b)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// if diff == 0 {
|
||||
// return nil
|
||||
// }
|
||||
// if diff & (1 << Effective) {
|
||||
// log.Print("a and b difference includes Effective values")
|
||||
// }
|
||||
//
|
||||
// with this:
|
||||
//
|
||||
// diff, err := a.Cf(b)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// if diff == 0 {
|
||||
// return nil
|
||||
// }
|
||||
// if diff.Has(Effective) {
|
||||
// log.Print("a and b difference includes Effective values")
|
||||
// }
|
||||
func (c *Set) Compare(d *Set) (uint, error) {
|
||||
u, err := c.Cf(d)
|
||||
return uint(u), err
|
||||
}
|
||||
|
||||
// Differs processes the result of Compare and determines if the
|
||||
// Flag's components were different.
|
||||
//
|
||||
// Deprecated: Replace with (Diff).Has().
|
||||
//
|
||||
// Example, replace this:
|
||||
//
|
||||
// diff, err := a.Compare(b)
|
||||
// ...
|
||||
// if diff & (1 << Effective) {
|
||||
// ... different effective capabilities ...
|
||||
// }
|
||||
//
|
||||
// with this:
|
||||
//
|
||||
// diff, err := a.Cf(b)
|
||||
// ...
|
||||
// if diff.Has(Effective) {
|
||||
// ... different effective capabilities ...
|
||||
// }
|
||||
func Differs(cf uint, vec Flag) bool {
|
||||
return cf&(1<<vec) != 0
|
||||
}
|
||||
|
||||
// Has processes the Diff result of (*Set).Cf() and determines if the
|
||||
// Flag's components were different in that result.
|
||||
func (cf Diff) Has(vec Flag) bool {
|
||||
return uint(cf)&(1<<vec) != 0
|
||||
}
|
||||
483
vendor/kernel.org/pub/linux/libs/security/libcap/cap/iab.go
generated
vendored
Normal file
483
vendor/kernel.org/pub/linux/libs/security/libcap/cap/iab.go
generated
vendored
Normal file
@@ -0,0 +1,483 @@
|
||||
package cap
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// omask returns the offset and mask for a specific capability.
|
||||
func omask(c Value) (uint, uint32) {
|
||||
u := uint(c)
|
||||
return u >> 5, uint32(1) << (u & 31)
|
||||
}
|
||||
|
||||
// IAB holds a summary of all of the inheritable capability vectors:
|
||||
// Inh, Amb and Bound. The Bound vector is the logical inverse (two's
|
||||
// complement) of the process' Bounding set. That is, raising a Value
|
||||
// in the Bound (think blocked) vector is equivalent to dropping that
|
||||
// Value from the process' Bounding set. This convention is used to
|
||||
// support the empty IAB as being mostly harmless.
|
||||
type IAB struct {
|
||||
mu sync.RWMutex
|
||||
a, i, nb []uint32
|
||||
}
|
||||
|
||||
// Vector enumerates which of the inheritable IAB capability vectors
|
||||
// is being manipulated.
|
||||
type Vector uint
|
||||
|
||||
// Inh, Amb, Bound enumerate the IAB vector components. (Vector) Inh
|
||||
// is equivalent to (Flag) Inheritable. They are named differently for
|
||||
// syntax/type checking reasons.
|
||||
const (
|
||||
Inh Vector = iota
|
||||
Amb
|
||||
Bound
|
||||
)
|
||||
|
||||
// IABDiff holds the non-error result of an (*IAB).Cf()
|
||||
// function call. It can be interpreted with the function
|
||||
// (IABDiff).Has().
|
||||
type IABDiff uint
|
||||
|
||||
// iBits, iBits and bBits track the (semi-)independent parts of an
|
||||
// IABDiff.
|
||||
const (
|
||||
iBits IABDiff = 1 << Inh
|
||||
aBits IABDiff = 1 << Amb
|
||||
bBits IABDiff = 1 << Bound
|
||||
)
|
||||
|
||||
// Has determines if an IAB comparison differs in a specific vector.
|
||||
func (d IABDiff) Has(v Vector) bool {
|
||||
return d&(1<<v) != 0
|
||||
}
|
||||
|
||||
// String identifies a Vector value by its conventional I A or B
|
||||
// string abbreviation.
|
||||
func (v Vector) String() string {
|
||||
switch v {
|
||||
case Inh:
|
||||
return "I"
|
||||
case Amb:
|
||||
return "A"
|
||||
case Bound:
|
||||
return "B"
|
||||
default:
|
||||
return "<Error>"
|
||||
}
|
||||
}
|
||||
|
||||
// NewIAB returns an empty IAB.
|
||||
func NewIAB() *IAB {
|
||||
startUp.Do(multisc.cInit)
|
||||
return &IAB{
|
||||
i: make([]uint32, words),
|
||||
a: make([]uint32, words),
|
||||
nb: make([]uint32, words),
|
||||
}
|
||||
}
|
||||
|
||||
// good confirms the iab looks to be initialized.
|
||||
func (iab *IAB) good() error {
|
||||
if iab == nil || len(iab.i) == 0 || len(iab.i) != words || len(iab.a) != words || len(iab.nb) != words {
|
||||
return ErrBadValue
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Dup returns a duplicate copy of the IAB.
|
||||
func (iab *IAB) Dup() (*IAB, error) {
|
||||
if err := iab.good(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v := NewIAB()
|
||||
iab.mu.RLock()
|
||||
defer iab.mu.RUnlock()
|
||||
copy(v.i, iab.i)
|
||||
copy(v.a, iab.a)
|
||||
copy(v.nb, iab.nb)
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// IABInit allocates a new IAB tuple.
|
||||
//
|
||||
// Deprecated: Replace with NewIAB.
|
||||
//
|
||||
// Example, replace this:
|
||||
//
|
||||
// iab := IABInit()
|
||||
//
|
||||
// with this:
|
||||
//
|
||||
// iab := NewIAB()
|
||||
func IABInit() *IAB {
|
||||
return NewIAB()
|
||||
}
|
||||
|
||||
// IABGetProc summarizes the Inh, Amb and Bound capability vectors of
|
||||
// the current process.
|
||||
func IABGetProc() *IAB {
|
||||
iab := NewIAB()
|
||||
current := GetProc()
|
||||
iab.Fill(Inh, current, Inheritable)
|
||||
for c := MaxBits(); c > 0; {
|
||||
c--
|
||||
offset, mask := omask(c)
|
||||
if a, _ := GetAmbient(c); a {
|
||||
iab.a[offset] |= mask
|
||||
}
|
||||
if b, err := GetBound(c); err == nil && !b {
|
||||
iab.nb[offset] |= mask
|
||||
}
|
||||
}
|
||||
return iab
|
||||
}
|
||||
|
||||
// IABFromText parses a string representing an IAB, as generated
|
||||
// by IAB.String(), to generate an IAB.
|
||||
func IABFromText(text string) (*IAB, error) {
|
||||
iab := NewIAB()
|
||||
if len(text) == 0 {
|
||||
return iab, nil
|
||||
}
|
||||
for _, f := range strings.Split(text, ",") {
|
||||
var i, a, nb bool
|
||||
var j int
|
||||
for j = 0; j < len(f); j++ {
|
||||
switch f[j : j+1] {
|
||||
case "!":
|
||||
nb = true
|
||||
case "^":
|
||||
i = true
|
||||
a = true
|
||||
case "%":
|
||||
i = true
|
||||
default:
|
||||
goto done
|
||||
}
|
||||
}
|
||||
done:
|
||||
c, err := FromName(f[j:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
offset, mask := omask(c)
|
||||
if i || !nb {
|
||||
iab.i[offset] |= mask
|
||||
}
|
||||
if a {
|
||||
iab.a[offset] |= mask
|
||||
}
|
||||
if nb {
|
||||
iab.nb[offset] |= mask
|
||||
}
|
||||
}
|
||||
return iab, nil
|
||||
}
|
||||
|
||||
// String serializes an IAB to a string format.
|
||||
func (iab *IAB) String() string {
|
||||
if err := iab.good(); err != nil {
|
||||
return "<invalid>"
|
||||
}
|
||||
var vs []string
|
||||
iab.mu.RLock()
|
||||
defer iab.mu.RUnlock()
|
||||
for c := Value(0); c < Value(maxValues); c++ {
|
||||
offset, mask := omask(c)
|
||||
i := (iab.i[offset] & mask) != 0
|
||||
a := (iab.a[offset] & mask) != 0
|
||||
nb := (iab.nb[offset] & mask) != 0
|
||||
var cs []string
|
||||
if nb {
|
||||
cs = append(cs, "!")
|
||||
}
|
||||
if a {
|
||||
cs = append(cs, "^")
|
||||
} else if nb && i {
|
||||
cs = append(cs, "%")
|
||||
}
|
||||
if nb || a || i {
|
||||
vs = append(vs, strings.Join(cs, "")+c.String())
|
||||
}
|
||||
}
|
||||
return strings.Join(vs, ",")
|
||||
}
|
||||
|
||||
// iabSetProc uses a syscaller to apply an IAB tuple to the process.
|
||||
// The iab is known to be locked by the caller.
|
||||
func (sc *syscaller) iabSetProc(iab *IAB) (err error) {
|
||||
temp := GetProc()
|
||||
var raising uint32
|
||||
for i := 0; i < words; i++ {
|
||||
newI := iab.i[i]
|
||||
oldIP := temp.flat[i][Inheritable] | temp.flat[i][Permitted]
|
||||
raising |= (newI & ^oldIP) | iab.a[i] | iab.nb[i]
|
||||
temp.flat[i][Inheritable] = newI
|
||||
}
|
||||
working, err2 := temp.Dup()
|
||||
if err2 != nil {
|
||||
err = err2
|
||||
return
|
||||
}
|
||||
if raising != 0 {
|
||||
if err = working.SetFlag(Effective, true, SETPCAP); err != nil {
|
||||
return
|
||||
}
|
||||
if err = sc.setProc(working); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
defer func() {
|
||||
if err2 := sc.setProc(temp); err == nil {
|
||||
err = err2
|
||||
}
|
||||
}()
|
||||
if err = sc.resetAmbient(); err != nil {
|
||||
return
|
||||
}
|
||||
for c := Value(maxValues); c > 0; {
|
||||
c--
|
||||
offset, mask := omask(c)
|
||||
if iab.a[offset]&mask != 0 {
|
||||
err = sc.setAmbient(true, c)
|
||||
}
|
||||
if err == nil && iab.nb[offset]&mask != 0 {
|
||||
err = sc.dropBound(c)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// SetProc attempts to change the Inheritable, Ambient and Bounding
|
||||
// capability vectors of the current process using the content,
|
||||
// iab. The Bounding vector strongly affects the potential for setting
|
||||
// other bits, so this function carefully performs the combined
|
||||
// operation in the most flexible manner.
|
||||
func (iab *IAB) SetProc() error {
|
||||
if err := iab.good(); err != nil {
|
||||
return err
|
||||
}
|
||||
state, sc := scwStateSC()
|
||||
defer scwSetState(launchBlocked, state, -1)
|
||||
iab.mu.RLock()
|
||||
defer iab.mu.RUnlock()
|
||||
return sc.iabSetProc(iab)
|
||||
}
|
||||
|
||||
// GetVector returns the raised state of the specific capability bit
|
||||
// of the indicated vector.
|
||||
func (iab *IAB) GetVector(vec Vector, val Value) (bool, error) {
|
||||
if err := iab.good(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if val >= MaxBits() {
|
||||
return false, ErrBadValue
|
||||
}
|
||||
iab.mu.RLock()
|
||||
defer iab.mu.RUnlock()
|
||||
offset, mask := omask(val)
|
||||
switch vec {
|
||||
case Inh:
|
||||
return (iab.i[offset] & mask) != 0, nil
|
||||
case Amb:
|
||||
return (iab.a[offset] & mask) != 0, nil
|
||||
case Bound:
|
||||
return (iab.nb[offset] & mask) != 0, nil
|
||||
default:
|
||||
return false, ErrBadValue
|
||||
}
|
||||
}
|
||||
|
||||
// SetVector sets all of the vals in the specified vector to the
|
||||
// raised value. Note, the Ambient vector cannot contain values not raised
|
||||
// in the Inh vector, so setting values directly in one vector may have
|
||||
// the side effect of mirroring the value in the other vector to
|
||||
// maintain this constraint. Note, raising a Bound vector bit is
|
||||
// equivalent to lowering the Bounding vector of the process (when
|
||||
// successfully applied with (*IAB).SetProc()).
|
||||
func (iab *IAB) SetVector(vec Vector, raised bool, vals ...Value) error {
|
||||
if err := iab.good(); err != nil {
|
||||
return err
|
||||
}
|
||||
iab.mu.Lock()
|
||||
defer iab.mu.Unlock()
|
||||
for _, val := range vals {
|
||||
if val >= Value(maxValues) {
|
||||
return ErrBadValue
|
||||
}
|
||||
offset, mask := omask(val)
|
||||
switch vec {
|
||||
case Inh:
|
||||
if raised {
|
||||
iab.i[offset] |= mask
|
||||
} else {
|
||||
iab.i[offset] &= ^mask
|
||||
iab.a[offset] &= ^mask
|
||||
}
|
||||
case Amb:
|
||||
if raised {
|
||||
iab.a[offset] |= mask
|
||||
iab.i[offset] |= mask
|
||||
} else {
|
||||
iab.a[offset] &= ^mask
|
||||
}
|
||||
case Bound:
|
||||
if raised {
|
||||
iab.nb[offset] |= mask
|
||||
} else {
|
||||
iab.nb[offset] &= ^mask
|
||||
}
|
||||
default:
|
||||
return ErrBadValue
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Fill fills one of the Inh, Amb and Bound capability vectors from
|
||||
// one of the flag vectors of a Set. Note, filling the Inh vector
|
||||
// will mask the Amb vector, and filling the Amb vector may raise
|
||||
// entries in the Inh vector. Further, when filling the Bound vector,
|
||||
// the bits are inverted from what you might expect - that is lowered
|
||||
// bits from the Set will be raised in the Bound vector.
|
||||
func (iab *IAB) Fill(vec Vector, c *Set, flag Flag) error {
|
||||
if err := iab.good(); err != nil {
|
||||
return err
|
||||
}
|
||||
// work with a copy to avoid potential deadlock.
|
||||
s, err := c.Dup()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
iab.mu.Lock()
|
||||
defer iab.mu.Unlock()
|
||||
for i := 0; i < words; i++ {
|
||||
flat := s.flat[i][flag]
|
||||
switch vec {
|
||||
case Inh:
|
||||
iab.i[i] = flat
|
||||
iab.a[i] &= flat
|
||||
case Amb:
|
||||
iab.a[i] = flat
|
||||
iab.i[i] |= flat
|
||||
case Bound:
|
||||
iab.nb[i] = ^flat
|
||||
default:
|
||||
return ErrBadSet
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Cf compares two IAB values. Its return value is 0 if the compared
|
||||
// tuples are considered identical. The macroscopic differences can be
|
||||
// investigated with (IABDiff).Has().
|
||||
func (iab *IAB) Cf(alt *IAB) (IABDiff, error) {
|
||||
if err := iab.good(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if iab == alt {
|
||||
return 0, nil
|
||||
}
|
||||
// Avoid holding two locks at once.
|
||||
ref, err := alt.Dup()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
iab.mu.RLock()
|
||||
defer iab.mu.RUnlock()
|
||||
|
||||
var cf IABDiff
|
||||
for i := 0; i < words; i++ {
|
||||
if iab.i[i] != ref.i[i] {
|
||||
cf |= iBits
|
||||
}
|
||||
if iab.a[i] != ref.a[i] {
|
||||
cf |= aBits
|
||||
}
|
||||
if iab.nb[i] != ref.nb[i] {
|
||||
cf |= bBits
|
||||
}
|
||||
}
|
||||
return cf, nil
|
||||
}
|
||||
|
||||
// parseHex converts the /proc/*/status string into an array of
|
||||
// uint32s suitable for storage in an IAB structure.
|
||||
func parseHex(hex string, invert bool) []uint32 {
|
||||
if len(hex) != 8*words {
|
||||
// Invalid string
|
||||
return nil
|
||||
}
|
||||
var result []uint32
|
||||
for i := 0; i < words; i++ {
|
||||
upper := 8 * (words - i)
|
||||
raw, err := strconv.ParseUint(hex[upper-8:upper], 16, 32)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if invert {
|
||||
raw = ^raw
|
||||
}
|
||||
bits := allMask(uint(i)) & uint32(raw)
|
||||
result = append(result, bits)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
var procRoot = "/proc"
|
||||
|
||||
// ProcRoot sets the local mount point for the Linux /proc filesystem.
|
||||
// It defaults to "/proc", but might be mounted elsewhere on any given
|
||||
// system. The function returns the previous value of the local mount
|
||||
// point. If the user attempts to set it to "", the value is left
|
||||
// unchanged.
|
||||
func ProcRoot(path string) string {
|
||||
was := procRoot
|
||||
if path != "" {
|
||||
procRoot = path
|
||||
}
|
||||
return was
|
||||
}
|
||||
|
||||
// IABGetPID returns the IAB tuple of a specified process. The kernel
|
||||
// ABI does not support this query via system calls, so the function
|
||||
// works by parsing the /proc/<pid>/status file content.
|
||||
func IABGetPID(pid int) (*IAB, error) {
|
||||
tf := fmt.Sprintf("%s/%d/status", procRoot, pid)
|
||||
d, err := ioutil.ReadFile(tf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iab := &IAB{}
|
||||
for _, line := range strings.Split(string(d), "\n") {
|
||||
if !strings.HasPrefix(line, "Cap") {
|
||||
continue
|
||||
}
|
||||
flavor := line[3:]
|
||||
if strings.HasPrefix(flavor, "Inh:\t") {
|
||||
iab.i = parseHex(line[8:], false)
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(flavor, "Bnd:\t") {
|
||||
iab.nb = parseHex(line[8:], true)
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(flavor, "Amb:\t") {
|
||||
iab.a = parseHex(line[8:], false)
|
||||
continue
|
||||
}
|
||||
}
|
||||
if len(iab.i) != words || len(iab.a) != words || len(iab.nb) != words {
|
||||
return nil, ErrBadValue
|
||||
}
|
||||
return iab, nil
|
||||
}
|
||||
423
vendor/kernel.org/pub/linux/libs/security/libcap/cap/launch.go
generated
vendored
Normal file
423
vendor/kernel.org/pub/linux/libs/security/libcap/cap/launch.go
generated
vendored
Normal file
@@ -0,0 +1,423 @@
|
||||
package cap
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"runtime"
|
||||
"sync"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Launcher holds a configuration for executing an optional callback
|
||||
// function and/or launching a child process with capability state
|
||||
// different from the parent.
|
||||
//
|
||||
// Note, go1.10 is the earliest version of the Go toolchain that can
|
||||
// support this abstraction.
|
||||
type Launcher struct {
|
||||
mu sync.RWMutex
|
||||
|
||||
// Note, path and args must be set, or callbackFn. They cannot
|
||||
// both be empty. In such cases .Launch() will error out.
|
||||
path string
|
||||
args []string
|
||||
env []string
|
||||
|
||||
callbackFn func(pa *syscall.ProcAttr, data interface{}) error
|
||||
|
||||
// The following are only honored when path is non empty.
|
||||
changeUIDs bool
|
||||
uid int
|
||||
|
||||
changeGIDs bool
|
||||
gid int
|
||||
groups []int
|
||||
|
||||
changeMode bool
|
||||
mode Mode
|
||||
|
||||
iab *IAB
|
||||
|
||||
chroot string
|
||||
}
|
||||
|
||||
// NewLauncher returns a new launcher for the specified program path
|
||||
// and args with the specified environment.
|
||||
func NewLauncher(path string, args []string, env []string) *Launcher {
|
||||
return &Launcher{
|
||||
path: path,
|
||||
args: args,
|
||||
env: env,
|
||||
}
|
||||
}
|
||||
|
||||
// FuncLauncher returns a new launcher whose purpose is to only
|
||||
// execute fn in a disposable security context. This is a more bare
|
||||
// bones variant of the more elaborate program launcher returned by
|
||||
// cap.NewLauncher().
|
||||
//
|
||||
// Note, this launcher will fully ignore any overrides provided by the
|
||||
// (*Launcher).SetUID() etc. methods. Should your fn() code want to
|
||||
// run with a different capability state or other privilege, it should
|
||||
// use the cap.*() functions to set them directly. The cap package
|
||||
// will ensure that their effects are limited to the runtime of this
|
||||
// individual function invocation. Warning: executing non-cap.*()
|
||||
// syscall functions may corrupt the state of the program runtime and
|
||||
// lead to unpredictable results.
|
||||
//
|
||||
// The properties of fn are similar to those supplied via
|
||||
// (*Launcher).Callback(fn) method. However, this launcher is bare
|
||||
// bones because, when launching, all privilege management performed
|
||||
// by the fn() is fully discarded when the fn() completes
|
||||
// execution. That is, it does not end by exec()ing some program.
|
||||
func FuncLauncher(fn func(interface{}) error) *Launcher {
|
||||
return &Launcher{
|
||||
callbackFn: func(ignored *syscall.ProcAttr, data interface{}) error {
|
||||
return fn(data)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Callback changes the callback function for Launch() to call before
|
||||
// changing privilege. The only thing that is assumed is that the OS
|
||||
// thread in use to call this callback function at launch time will be
|
||||
// the one that ultimately calls fork to complete the launch of a path
|
||||
// specified executable. Any returned error value of said function
|
||||
// will terminate the launch process.
|
||||
//
|
||||
// A nil fn causes there to be no callback function invoked during a
|
||||
// Launch() sequence - it will remove any pre-existing callback.
|
||||
//
|
||||
// If the non-nil fn requires any effective capabilities in order to
|
||||
// run, they can be raised prior to calling .Launch() or inside the
|
||||
// callback function itself.
|
||||
//
|
||||
// If the specified callback fn should call any "cap" package
|
||||
// functions that change privilege state, these calls will only affect
|
||||
// the launch goroutine itself. While the launch is in progress, other
|
||||
// (non-launch) goroutines will block if they attempt to change
|
||||
// privilege state. These routines will unblock once there are no
|
||||
// in-flight launches.
|
||||
//
|
||||
// Note, the first argument provided to the callback function is the
|
||||
// *syscall.ProcAttr value to be used when a process launch is taking
|
||||
// place. A non-nil structure pointer can be modified by the callback
|
||||
// to enhance the launch. For example, the .Files field can be
|
||||
// overridden to affect how the launched process' stdin/out/err are
|
||||
// handled.
|
||||
//
|
||||
// Further, the 2nd argument to the callback function is provided at
|
||||
// Launch() invocation and can communicate contextual info to and from
|
||||
// the callback and the main process.
|
||||
func (attr *Launcher) Callback(fn func(*syscall.ProcAttr, interface{}) error) {
|
||||
if attr == nil {
|
||||
return
|
||||
}
|
||||
attr.mu.Lock()
|
||||
defer attr.mu.Unlock()
|
||||
attr.callbackFn = fn
|
||||
}
|
||||
|
||||
// SetUID specifies the UID to be used by the launched command.
|
||||
func (attr *Launcher) SetUID(uid int) {
|
||||
if attr == nil {
|
||||
return
|
||||
}
|
||||
attr.mu.Lock()
|
||||
defer attr.mu.Unlock()
|
||||
attr.changeUIDs = true
|
||||
attr.uid = uid
|
||||
}
|
||||
|
||||
// SetGroups specifies the GID and supplementary groups for the
|
||||
// launched command.
|
||||
func (attr *Launcher) SetGroups(gid int, groups []int) {
|
||||
if attr == nil {
|
||||
return
|
||||
}
|
||||
attr.mu.Lock()
|
||||
defer attr.mu.Unlock()
|
||||
attr.changeGIDs = true
|
||||
attr.gid = gid
|
||||
attr.groups = groups
|
||||
}
|
||||
|
||||
// SetMode specifies the libcap Mode to be used by the launched command.
|
||||
func (attr *Launcher) SetMode(mode Mode) {
|
||||
if attr == nil {
|
||||
return
|
||||
}
|
||||
attr.mu.Lock()
|
||||
defer attr.mu.Unlock()
|
||||
attr.changeMode = true
|
||||
attr.mode = mode
|
||||
}
|
||||
|
||||
// SetIAB specifies the IAB capability vectors to be inherited by the
|
||||
// launched command. A nil value means the prevailing vectors of the
|
||||
// parent will be inherited. Note, a duplicate of the provided IAB
|
||||
// tuple is actually stored, so concurrent modification of the iab
|
||||
// value does not affect the launcher.
|
||||
func (attr *Launcher) SetIAB(iab *IAB) {
|
||||
if attr == nil {
|
||||
return
|
||||
}
|
||||
attr.mu.Lock()
|
||||
defer attr.mu.Unlock()
|
||||
attr.iab, _ = iab.Dup()
|
||||
}
|
||||
|
||||
// SetChroot specifies the chroot value to be used by the launched
|
||||
// command. An empty value means no-change from the prevailing value.
|
||||
func (attr *Launcher) SetChroot(root string) {
|
||||
if attr == nil {
|
||||
return
|
||||
}
|
||||
attr.mu.Lock()
|
||||
defer attr.mu.Unlock()
|
||||
attr.chroot = root
|
||||
}
|
||||
|
||||
// lResult is used to get the result from the doomed launcher thread.
|
||||
type lResult struct {
|
||||
// tgid holds the thread group id, which is an alias for the
|
||||
// shared process id of the parent program.
|
||||
tgid int
|
||||
|
||||
// tid holds the tid of the locked launching thread which dies
|
||||
// as the launch completes.
|
||||
tid int
|
||||
|
||||
// pid is the pid of the launched program (path, args). In
|
||||
// the case of a FuncLaunch() this value is zero on success.
|
||||
// pid holds -1 in the case of error.
|
||||
pid int
|
||||
|
||||
// err is nil on success, but otherwise holds the reason the
|
||||
// launch failed.
|
||||
err error
|
||||
}
|
||||
|
||||
// ErrLaunchFailed is returned if a launch was aborted with no more
|
||||
// specific error.
|
||||
var ErrLaunchFailed = errors.New("launch failed")
|
||||
|
||||
// ErrNoLaunch indicates the go runtime available to this binary does
|
||||
// not reliably support launching. See cap.LaunchSupported.
|
||||
var ErrNoLaunch = errors.New("launch not supported")
|
||||
|
||||
// ErrAmbiguousChroot indicates that the Launcher is being used in
|
||||
// addition to a callback supplied Chroot. The former should be used
|
||||
// exclusively for this.
|
||||
var ErrAmbiguousChroot = errors.New("use Launcher for chroot")
|
||||
|
||||
// ErrAmbiguousIDs indicates that the Launcher is being used in
|
||||
// addition to a callback supplied Credentials. The former should be
|
||||
// used exclusively for this.
|
||||
var ErrAmbiguousIDs = errors.New("use Launcher for uids and gids")
|
||||
|
||||
// ErrAmbiguousAmbient indicates that the Launcher is being used in
|
||||
// addition to a callback supplied ambient set and the former should
|
||||
// be used exclusively in a Launch call.
|
||||
var ErrAmbiguousAmbient = errors.New("use Launcher for ambient caps")
|
||||
|
||||
// lName is the name we temporarily give to the launcher thread. Note,
|
||||
// this will likely stick around in the process tree if the Go runtime
|
||||
// is not cleaning up locked launcher OS threads.
|
||||
var lName = []byte("cap-launcher\000")
|
||||
|
||||
// <uapi/linux/prctl.h>
|
||||
const prSetName = 15
|
||||
|
||||
//go:uintptrescapes
|
||||
func launch(result chan<- lResult, attr *Launcher, data interface{}, quit chan<- struct{}) {
|
||||
if quit != nil {
|
||||
defer close(quit)
|
||||
}
|
||||
|
||||
// Thread group ID is the process ID.
|
||||
tgid := syscall.Getpid()
|
||||
|
||||
// This code waits until we are not scheduled on the parent
|
||||
// thread. We will exit this thread once the child has
|
||||
// launched.
|
||||
runtime.LockOSThread()
|
||||
tid := syscall.Gettid()
|
||||
if tid == tgid {
|
||||
// Force the go runtime to find a new thread to run
|
||||
// on. (It is really awkward to have a process'
|
||||
// PID=TID thread in effectively a zombie state. The
|
||||
// Go runtime has support for it, but pstree gives
|
||||
// ugly output since the prSetName value sticks around
|
||||
// after launch completion...
|
||||
//
|
||||
// (Optimize for time to debug by reducing ugly spam
|
||||
// like this.)
|
||||
quit := make(chan struct{})
|
||||
go launch(result, attr, data, quit)
|
||||
|
||||
// Wait for that go routine to complete.
|
||||
<-quit
|
||||
runtime.UnlockOSThread()
|
||||
return
|
||||
}
|
||||
|
||||
// Provide a way to serialize the caller on the thread
|
||||
// completing. This should be done by the one locked tid that
|
||||
// does the ForkExec(). All the other threads have a different
|
||||
// security context.
|
||||
defer close(result)
|
||||
|
||||
// By never releasing the LockOSThread here, we guarantee that
|
||||
// the runtime will terminate the current OS thread once this
|
||||
// function returns.
|
||||
scwSetState(launchIdle, launchActive, tid)
|
||||
|
||||
// Name the launcher thread - transient, but helps to debug if
|
||||
// the callbackFn or something else hangs up.
|
||||
singlesc.prctlrcall(prSetName, uintptr(unsafe.Pointer(&lName[0])), 0)
|
||||
|
||||
var pa *syscall.ProcAttr
|
||||
var err error
|
||||
var needChroot bool
|
||||
|
||||
// Only prepare a non-nil pa value if a path is provided.
|
||||
if attr.path != "" {
|
||||
// By default the following file descriptors are preserved for
|
||||
// the child. The user should modify them in the callback for
|
||||
// stdin/out/err redirection.
|
||||
pa = &syscall.ProcAttr{
|
||||
Files: []uintptr{0, 1, 2},
|
||||
}
|
||||
if len(attr.env) != 0 {
|
||||
pa.Env = attr.env
|
||||
} else {
|
||||
pa.Env = os.Environ()
|
||||
}
|
||||
}
|
||||
|
||||
var pid int
|
||||
if attr.callbackFn != nil {
|
||||
if err = attr.callbackFn(pa, data); err != nil {
|
||||
goto abort
|
||||
}
|
||||
if attr.path == "" {
|
||||
goto abort
|
||||
}
|
||||
}
|
||||
|
||||
if needChroot, err = validatePA(pa, attr.chroot); err != nil {
|
||||
goto abort
|
||||
}
|
||||
if attr.changeUIDs {
|
||||
if err = singlesc.setUID(attr.uid); err != nil {
|
||||
goto abort
|
||||
}
|
||||
}
|
||||
if attr.changeGIDs {
|
||||
if err = singlesc.setGroups(attr.gid, attr.groups); err != nil {
|
||||
goto abort
|
||||
}
|
||||
}
|
||||
if attr.changeMode {
|
||||
if err = singlesc.setMode(attr.mode); err != nil {
|
||||
goto abort
|
||||
}
|
||||
}
|
||||
if attr.iab != nil {
|
||||
// Note, since .iab is a private copy we don't need to
|
||||
// lock it around this call.
|
||||
if err = singlesc.iabSetProc(attr.iab); err != nil {
|
||||
goto abort
|
||||
}
|
||||
}
|
||||
|
||||
if needChroot {
|
||||
c := GetProc()
|
||||
if err = c.SetFlag(Effective, true, SYS_CHROOT); err != nil {
|
||||
goto abort
|
||||
}
|
||||
if err = singlesc.setProc(c); err != nil {
|
||||
goto abort
|
||||
}
|
||||
}
|
||||
pid, err = syscall.ForkExec(attr.path, attr.args, pa)
|
||||
|
||||
abort:
|
||||
if err != nil {
|
||||
pid = -1
|
||||
}
|
||||
result <- lResult{
|
||||
tgid: tgid,
|
||||
tid: tid,
|
||||
pid: pid,
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
|
||||
// pollForThreadExit waits for a thread to terminate. Only after the
|
||||
// thread has safely exited is it safe to resume POSIX semantics
|
||||
// security state mirroring for the rest of the process threads.
|
||||
func (v lResult) pollForThreadExit() {
|
||||
if v.tid == -1 {
|
||||
return
|
||||
}
|
||||
for syscall.Tgkill(v.tgid, v.tid, 0) == nil {
|
||||
runtime.Gosched()
|
||||
}
|
||||
scwSetState(launchActive, launchIdle, v.tid)
|
||||
}
|
||||
|
||||
// Launch performs a callback function and/or new program launch with
|
||||
// a disposable security state. The data object, when not nil, can be
|
||||
// used to communicate with the callback. It can also be used to
|
||||
// return details from the callback function's execution.
|
||||
//
|
||||
// If the attr was created with NewLauncher(), this present function
|
||||
// will return the pid of the launched process, or -1 and a non-nil
|
||||
// error.
|
||||
//
|
||||
// If the attr was created with FuncLauncher(), this present function
|
||||
// will return 0, nil if the callback function exits without
|
||||
// error. Otherwise it will return -1 and the non-nil error of the
|
||||
// callback return value.
|
||||
//
|
||||
// Note, while the disposable security state thread makes some
|
||||
// operations seem more isolated - they are *not securely
|
||||
// isolated*. Launching is inherently violating the POSIX semantics
|
||||
// maintained by the rest of the "libcap/cap" package, so think of
|
||||
// launching as a convenience wrapper around fork()ing.
|
||||
//
|
||||
// Advanced user note: if the caller of this function thinks they know
|
||||
// what they are doing by using runtime.LockOSThread() before invoking
|
||||
// this function, they should understand that the OS thread invoking
|
||||
// (*Launcher).Launch() is *not* guaranteed to be the one used for the
|
||||
// disposable security state to perform the launch. If said caller
|
||||
// needs to run something on the disposable security state thread,
|
||||
// they should do it via the launch callback function mechanism. (The
|
||||
// Go runtime is complicated and this is why this Launch mechanism
|
||||
// provides the optional callback function.)
|
||||
func (attr *Launcher) Launch(data interface{}) (int, error) {
|
||||
if !LaunchSupported {
|
||||
return -1, ErrNoLaunch
|
||||
}
|
||||
if attr == nil {
|
||||
return -1, ErrLaunchFailed
|
||||
}
|
||||
attr.mu.RLock()
|
||||
defer attr.mu.RUnlock()
|
||||
if attr.callbackFn == nil && (attr.path == "" || len(attr.args) == 0) {
|
||||
return -1, ErrLaunchFailed
|
||||
}
|
||||
|
||||
result := make(chan lResult)
|
||||
go launch(result, attr, data, nil)
|
||||
v, ok := <-result
|
||||
if !ok {
|
||||
return -1, ErrLaunchFailed
|
||||
}
|
||||
<-result // blocks until the launch() goroutine exits
|
||||
v.pollForThreadExit()
|
||||
return v.pid, v.err
|
||||
}
|
||||
7
vendor/kernel.org/pub/linux/libs/security/libcap/cap/legacy.go
generated
vendored
Normal file
7
vendor/kernel.org/pub/linux/libs/security/libcap/cap/legacy.go
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
// +build linux,arm linux,386
|
||||
|
||||
package cap
|
||||
|
||||
import "syscall"
|
||||
|
||||
var sysSetGroupsVariant = uintptr(syscall.SYS_SETGROUPS32)
|
||||
8
vendor/kernel.org/pub/linux/libs/security/libcap/cap/modern.go
generated
vendored
Normal file
8
vendor/kernel.org/pub/linux/libs/security/libcap/cap/modern.go
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
// +build linux,!arm
|
||||
// +build linux,!386
|
||||
|
||||
package cap
|
||||
|
||||
import "syscall"
|
||||
|
||||
var sysSetGroupsVariant = uintptr(syscall.SYS_SETGROUPS)
|
||||
436
vendor/kernel.org/pub/linux/libs/security/libcap/cap/names.go
generated
vendored
Normal file
436
vendor/kernel.org/pub/linux/libs/security/libcap/cap/names.go
generated
vendored
Normal file
@@ -0,0 +1,436 @@
|
||||
package cap
|
||||
|
||||
/* ** DO NOT EDIT THIS FILE. IT WAS AUTO-GENERATED BY LIBCAP'S GO BUILDER (mknames.go) ** */
|
||||
|
||||
// NamedCount holds the number of capability values with official
|
||||
// names known at the time this libcap/cap version, was released. The
|
||||
// "../libcap/cap" package is fully able to manipulate higher numbered
|
||||
// capability values by numerical value. However, if you find
|
||||
// cap.NamedCount < cap.MaxBits(), it is probably time to upgrade this
|
||||
// package on your system.
|
||||
//
|
||||
// FWIW the userspace tool '/sbin/capsh' also contains a runtime check
|
||||
// for the condition that libcap is behind the running kernel in this
|
||||
// way.
|
||||
const NamedCount = 41
|
||||
|
||||
// CHOWN etc., are the named capability values of the Linux
|
||||
// kernel. The canonical source for each name is the
|
||||
// "uapi/linux/capabilities.h" file. Some values may not be available
|
||||
// (yet) where the kernel is older. The actual number of capabities
|
||||
// supported by the running kernel can be obtained using the
|
||||
// cap.MaxBits() function.
|
||||
const (
|
||||
// CHOWN allows a process to arbitrarily change the user and
|
||||
// group ownership of a file.
|
||||
CHOWN Value = iota
|
||||
|
||||
// DAC_OVERRIDE allows a process to override of all Discretionary
|
||||
// Access Control (DAC) access, including ACL execute
|
||||
// access. That is read, write or execute files that the
|
||||
// process would otherwise not have access to. This
|
||||
// excludes DAC access covered by cap.LINUX_IMMUTABLE.
|
||||
DAC_OVERRIDE
|
||||
|
||||
// DAC_READ_SEARCH allows a process to override all DAC restrictions
|
||||
// limiting the read and search of files and
|
||||
// directories. This excludes DAC access covered by
|
||||
// cap.LINUX_IMMUTABLE.
|
||||
DAC_READ_SEARCH
|
||||
|
||||
// FOWNER allows a process to perform operations on files, even
|
||||
// where file owner ID should otherwise need be equal to
|
||||
// the UID, except where cap.FSETID is applicable. It
|
||||
// doesn't override MAC and DAC restrictions.
|
||||
FOWNER
|
||||
|
||||
// FSETID allows a process to set the S_ISUID and S_ISUID bits of
|
||||
// the file permissions, even when the process' effective
|
||||
// UID or GID/supplementary GIDs do not match that of the
|
||||
// file.
|
||||
FSETID
|
||||
|
||||
// KILL allows a process to send a kill(2) signal to any other
|
||||
// process - overriding the limitation that there be a
|
||||
// [E]UID match between source and target process.
|
||||
KILL
|
||||
|
||||
// SETGID allows a process to freely manipulate its own GIDs:
|
||||
// - arbitrarily set the GID, EGID, REGID, RESGID values
|
||||
// - arbitrarily set the supplementary GIDs
|
||||
// - allows the forging of GID credentials passed over a
|
||||
// socket
|
||||
SETGID
|
||||
|
||||
// SETUID allows a process to freely manipulate its own UIDs:
|
||||
// - arbitrarily set the UID, EUID, REUID and RESUID
|
||||
// values
|
||||
// - allows the forging of UID credentials passed over a
|
||||
// socket
|
||||
SETUID
|
||||
|
||||
// SETPCAP allows a process to freely manipulate its inheritable
|
||||
// capabilities.
|
||||
//
|
||||
// Linux supports the POSIX.1e Inheritable set, the POXIX.1e (X
|
||||
// vector) known in Linux as the Bounding vector, as well as
|
||||
// the Linux extension Ambient vector.
|
||||
//
|
||||
// This capability permits dropping bits from the Bounding
|
||||
// vector (ie. raising B bits in the libcap IAB
|
||||
// representation). It also permits the process to raise
|
||||
// Ambient vector bits that are both raised in the Permitted
|
||||
// and Inheritable sets of the process. This capability cannot
|
||||
// be used to raise Permitted bits, Effective bits beyond those
|
||||
// already present in the process' permitted set, or
|
||||
// Inheritable bits beyond those present in the Bounding
|
||||
// vector.
|
||||
//
|
||||
// [Historical note: prior to the advent of file capabilities
|
||||
// (2008), this capability was suppressed by default, as its
|
||||
// unsuppressed behavior was not auditable: it could
|
||||
// asynchronously grant its own Permitted capabilities to and
|
||||
// remove capabilities from other processes arbitrarily. The
|
||||
// former leads to undefined behavior, and the latter is better
|
||||
// served by the kill system call.]
|
||||
SETPCAP
|
||||
|
||||
// LINUX_IMMUTABLE allows a process to modify the S_IMMUTABLE and
|
||||
// S_APPEND file attributes.
|
||||
LINUX_IMMUTABLE
|
||||
|
||||
// NET_BIND_SERVICE allows a process to bind to privileged ports:
|
||||
// - TCP/UDP sockets below 1024
|
||||
// - ATM VCIs below 32
|
||||
NET_BIND_SERVICE
|
||||
|
||||
// NET_BROADCAST allows a process to broadcast to the network and to
|
||||
// listen to multicast.
|
||||
NET_BROADCAST
|
||||
|
||||
// NET_ADMIN allows a process to perform network configuration
|
||||
// operations:
|
||||
// - interface configuration
|
||||
// - administration of IP firewall, masquerading and
|
||||
// accounting
|
||||
// - setting debug options on sockets
|
||||
// - modification of routing tables
|
||||
// - setting arbitrary process, and process group
|
||||
// ownership on sockets
|
||||
// - binding to any address for transparent proxying
|
||||
// (this is also allowed via cap.NET_RAW)
|
||||
// - setting TOS (Type of service)
|
||||
// - setting promiscuous mode
|
||||
// - clearing driver statistics
|
||||
// - multicasing
|
||||
// - read/write of device-specific registers
|
||||
// - activation of ATM control sockets
|
||||
NET_ADMIN
|
||||
|
||||
// NET_RAW allows a process to use raw networking:
|
||||
// - RAW sockets
|
||||
// - PACKET sockets
|
||||
// - binding to any address for transparent proxying
|
||||
// (also permitted via cap.NET_ADMIN)
|
||||
NET_RAW
|
||||
|
||||
// IPC_LOCK allows a process to lock shared memory segments for IPC
|
||||
// purposes. Also enables mlock and mlockall system
|
||||
// calls.
|
||||
IPC_LOCK
|
||||
|
||||
// IPC_OWNER allows a process to override IPC ownership checks.
|
||||
IPC_OWNER
|
||||
|
||||
// SYS_MODULE allows a process to initiate the loading and unloading
|
||||
// of kernel modules. This capability can effectively
|
||||
// modify kernel without limit.
|
||||
SYS_MODULE
|
||||
|
||||
// SYS_RAWIO allows a process to perform raw IO:
|
||||
// - permit ioper/iopl access
|
||||
// - permit sending USB messages to any device via
|
||||
// /dev/bus/usb
|
||||
SYS_RAWIO
|
||||
|
||||
// SYS_CHROOT allows a process to perform a chroot syscall to change
|
||||
// the effective root of the process' file system:
|
||||
// redirect to directory "/" to some other location.
|
||||
SYS_CHROOT
|
||||
|
||||
// SYS_PTRACE allows a process to perform a ptrace() of any other
|
||||
// process.
|
||||
SYS_PTRACE
|
||||
|
||||
// SYS_PACCT allows a process to configure process accounting.
|
||||
SYS_PACCT
|
||||
|
||||
// SYS_ADMIN allows a process to perform a somewhat arbitrary
|
||||
// grab-bag of privileged operations. Over time, this
|
||||
// capability should weaken as specific capabilities are
|
||||
// created for subsets of cap.SYS_ADMINs functionality:
|
||||
// - configuration of the secure attention key
|
||||
// - administration of the random device
|
||||
// - examination and configuration of disk quotas
|
||||
// - setting the domainname
|
||||
// - setting the hostname
|
||||
// - calling bdflush()
|
||||
// - mount() and umount(), setting up new SMB connection
|
||||
// - some autofs root ioctls
|
||||
// - nfsservctl
|
||||
// - VM86_REQUEST_IRQ
|
||||
// - to read/write pci config on alpha
|
||||
// - irix_prctl on mips (setstacksize)
|
||||
// - flushing all cache on m68k (sys_cacheflush)
|
||||
// - removing semaphores
|
||||
// - Used instead of cap.CHOWN to "chown" IPC message
|
||||
// queues, semaphores and shared memory
|
||||
// - locking/unlocking of shared memory segment
|
||||
// - turning swap on/off
|
||||
// - forged pids on socket credentials passing
|
||||
// - setting readahead and flushing buffers on block
|
||||
// devices
|
||||
// - setting geometry in floppy driver
|
||||
// - turning DMA on/off in xd driver
|
||||
// - administration of md devices (mostly the above, but
|
||||
// some extra ioctls)
|
||||
// - tuning the ide driver
|
||||
// - access to the nvram device
|
||||
// - administration of apm_bios, serial and bttv (TV)
|
||||
// device
|
||||
// - manufacturer commands in isdn CAPI support driver
|
||||
// - reading non-standardized portions of PCI
|
||||
// configuration space
|
||||
// - DDI debug ioctl on sbpcd driver
|
||||
// - setting up serial ports
|
||||
// - sending raw qic-117 commands
|
||||
// - enabling/disabling tagged queuing on SCSI
|
||||
// controllers and sending arbitrary SCSI commands
|
||||
// - setting encryption key on loopback filesystem
|
||||
// - setting zone reclaim policy
|
||||
SYS_ADMIN
|
||||
|
||||
// SYS_BOOT allows a process to initiate a reboot of the system.
|
||||
SYS_BOOT
|
||||
|
||||
// SYS_NICE allows a process to maipulate the execution priorities
|
||||
// of arbitrary processes:
|
||||
// - those involving different UIDs
|
||||
// - setting their CPU affinity
|
||||
// - alter the FIFO vs. round-robin (realtime)
|
||||
// scheduling for itself and other processes.
|
||||
SYS_NICE
|
||||
|
||||
// SYS_RESOURCE allows a process to adjust resource related parameters
|
||||
// of processes and the system:
|
||||
// - set and override resource limits
|
||||
// - override quota limits
|
||||
// - override the reserved space on ext2 filesystem
|
||||
// (this can also be achieved via cap.FSETID)
|
||||
// - modify the data journaling mode on ext3 filesystem,
|
||||
// which uses journaling resources
|
||||
// - override size restrictions on IPC message queues
|
||||
// - configure more than 64Hz interrupts from the
|
||||
// real-time clock
|
||||
// - override the maximum number of consoles for console
|
||||
// allocation
|
||||
// - override the maximum number of keymaps
|
||||
SYS_RESOURCE
|
||||
|
||||
// SYS_TIME allows a process to perform time manipulation of clocks:
|
||||
// - alter the system clock
|
||||
// - enable irix_stime on MIPS
|
||||
// - set the real-time clock
|
||||
SYS_TIME
|
||||
|
||||
// SYS_TTY_CONFIG allows a process to manipulate tty devices:
|
||||
// - configure tty devices
|
||||
// - perform vhangup() of a tty
|
||||
SYS_TTY_CONFIG
|
||||
|
||||
// MKNOD allows a process to perform privileged operations with
|
||||
// the mknod() system call.
|
||||
MKNOD
|
||||
|
||||
// LEASE allows a process to take leases on files.
|
||||
LEASE
|
||||
|
||||
// AUDIT_WRITE allows a process to write to the audit log via a
|
||||
// unicast netlink socket.
|
||||
AUDIT_WRITE
|
||||
|
||||
// AUDIT_CONTROL allows a process to configure audit logging via a
|
||||
// unicast netlink socket.
|
||||
AUDIT_CONTROL
|
||||
|
||||
// SETFCAP allows a process to set capabilities on files.
|
||||
// Permits a process to uid_map the uid=0 of the
|
||||
// parent user namespace into that of the child
|
||||
// namespace. Also, permits a process to override
|
||||
// securebits locks through user namespace
|
||||
// creation.
|
||||
SETFCAP
|
||||
|
||||
// MAC_OVERRIDE allows a process to override Manditory Access Control
|
||||
// (MAC) access. Not all kernels are configured with a MAC
|
||||
// mechanism, but this is the capability reserved for
|
||||
// overriding them.
|
||||
MAC_OVERRIDE
|
||||
|
||||
// MAC_ADMIN allows a process to configure the Mandatory Access
|
||||
// Control (MAC) policy. Not all kernels are configured
|
||||
// with a MAC enabled, but if they are this capability is
|
||||
// reserved for code to perform administration tasks.
|
||||
MAC_ADMIN
|
||||
|
||||
// SYSLOG allows a process to configure the kernel's syslog
|
||||
// (printk) behavior.
|
||||
SYSLOG
|
||||
|
||||
// WAKE_ALARM allows a process to trigger something that can wake the
|
||||
// system up.
|
||||
WAKE_ALARM
|
||||
|
||||
// BLOCK_SUSPEND allows a process to block system suspends - prevent the
|
||||
// system from entering a lower power state.
|
||||
BLOCK_SUSPEND
|
||||
|
||||
// AUDIT_READ allows a process to read the audit log via a multicast
|
||||
// netlink socket.
|
||||
AUDIT_READ
|
||||
|
||||
// PERFMON allows a process to enable observability of privileged
|
||||
// operations related to performance. The mechanisms
|
||||
// include perf_events, i915_perf and other kernel
|
||||
// subsystems.
|
||||
PERFMON
|
||||
|
||||
// BPF allows a process to manipulate aspects of the kernel
|
||||
// enhanced Berkeley Packet Filter (BPF) system. This is
|
||||
// an execution subsystem of the kernel, that manages BPF
|
||||
// programs. cap.BPF permits a process to:
|
||||
// - create all types of BPF maps
|
||||
// - advanced verifier features:
|
||||
// - indirect variable access
|
||||
// - bounded loops
|
||||
// - BPF to BPF function calls
|
||||
// - scalar precision tracking
|
||||
// - larger complexity limits
|
||||
// - dead code elimination
|
||||
// - potentially other features
|
||||
//
|
||||
// Other capabilities can be used together with cap.BFP to
|
||||
// further manipulate the BPF system:
|
||||
// - cap.PERFMON relaxes the verifier checks as follows:
|
||||
// - BPF programs can use pointer-to-integer
|
||||
// conversions
|
||||
// - speculation attack hardening measures can be
|
||||
// bypassed
|
||||
// - bpf_probe_read to read arbitrary kernel memory is
|
||||
// permitted
|
||||
// - bpf_trace_printk to print the content of kernel
|
||||
// memory
|
||||
// - cap.SYS_ADMIN permits the following:
|
||||
// - use of bpf_probe_write_user
|
||||
// - iteration over the system-wide loaded programs,
|
||||
// maps, links BTFs and convert their IDs to file
|
||||
// descriptors.
|
||||
// - cap.PERFMON is required to load tracing programs.
|
||||
// - cap.NET_ADMIN is required to load networking
|
||||
// programs.
|
||||
BPF
|
||||
|
||||
// CHECKPOINT_RESTORE allows a process to perform checkpoint
|
||||
// and restore operations. Also permits
|
||||
// explicit PID control via clone3() and
|
||||
// also writing to ns_last_pid.
|
||||
CHECKPOINT_RESTORE
|
||||
)
|
||||
|
||||
var names = map[Value]string{
|
||||
CHOWN: "cap_chown",
|
||||
DAC_OVERRIDE: "cap_dac_override",
|
||||
DAC_READ_SEARCH: "cap_dac_read_search",
|
||||
FOWNER: "cap_fowner",
|
||||
FSETID: "cap_fsetid",
|
||||
KILL: "cap_kill",
|
||||
SETGID: "cap_setgid",
|
||||
SETUID: "cap_setuid",
|
||||
SETPCAP: "cap_setpcap",
|
||||
LINUX_IMMUTABLE: "cap_linux_immutable",
|
||||
NET_BIND_SERVICE: "cap_net_bind_service",
|
||||
NET_BROADCAST: "cap_net_broadcast",
|
||||
NET_ADMIN: "cap_net_admin",
|
||||
NET_RAW: "cap_net_raw",
|
||||
IPC_LOCK: "cap_ipc_lock",
|
||||
IPC_OWNER: "cap_ipc_owner",
|
||||
SYS_MODULE: "cap_sys_module",
|
||||
SYS_RAWIO: "cap_sys_rawio",
|
||||
SYS_CHROOT: "cap_sys_chroot",
|
||||
SYS_PTRACE: "cap_sys_ptrace",
|
||||
SYS_PACCT: "cap_sys_pacct",
|
||||
SYS_ADMIN: "cap_sys_admin",
|
||||
SYS_BOOT: "cap_sys_boot",
|
||||
SYS_NICE: "cap_sys_nice",
|
||||
SYS_RESOURCE: "cap_sys_resource",
|
||||
SYS_TIME: "cap_sys_time",
|
||||
SYS_TTY_CONFIG: "cap_sys_tty_config",
|
||||
MKNOD: "cap_mknod",
|
||||
LEASE: "cap_lease",
|
||||
AUDIT_WRITE: "cap_audit_write",
|
||||
AUDIT_CONTROL: "cap_audit_control",
|
||||
SETFCAP: "cap_setfcap",
|
||||
MAC_OVERRIDE: "cap_mac_override",
|
||||
MAC_ADMIN: "cap_mac_admin",
|
||||
SYSLOG: "cap_syslog",
|
||||
WAKE_ALARM: "cap_wake_alarm",
|
||||
BLOCK_SUSPEND: "cap_block_suspend",
|
||||
AUDIT_READ: "cap_audit_read",
|
||||
PERFMON: "cap_perfmon",
|
||||
BPF: "cap_bpf",
|
||||
CHECKPOINT_RESTORE: "cap_checkpoint_restore",
|
||||
}
|
||||
|
||||
var bits = map[string]Value{
|
||||
"cap_chown": CHOWN,
|
||||
"cap_dac_override": DAC_OVERRIDE,
|
||||
"cap_dac_read_search": DAC_READ_SEARCH,
|
||||
"cap_fowner": FOWNER,
|
||||
"cap_fsetid": FSETID,
|
||||
"cap_kill": KILL,
|
||||
"cap_setgid": SETGID,
|
||||
"cap_setuid": SETUID,
|
||||
"cap_setpcap": SETPCAP,
|
||||
"cap_linux_immutable": LINUX_IMMUTABLE,
|
||||
"cap_net_bind_service": NET_BIND_SERVICE,
|
||||
"cap_net_broadcast": NET_BROADCAST,
|
||||
"cap_net_admin": NET_ADMIN,
|
||||
"cap_net_raw": NET_RAW,
|
||||
"cap_ipc_lock": IPC_LOCK,
|
||||
"cap_ipc_owner": IPC_OWNER,
|
||||
"cap_sys_module": SYS_MODULE,
|
||||
"cap_sys_rawio": SYS_RAWIO,
|
||||
"cap_sys_chroot": SYS_CHROOT,
|
||||
"cap_sys_ptrace": SYS_PTRACE,
|
||||
"cap_sys_pacct": SYS_PACCT,
|
||||
"cap_sys_admin": SYS_ADMIN,
|
||||
"cap_sys_boot": SYS_BOOT,
|
||||
"cap_sys_nice": SYS_NICE,
|
||||
"cap_sys_resource": SYS_RESOURCE,
|
||||
"cap_sys_time": SYS_TIME,
|
||||
"cap_sys_tty_config": SYS_TTY_CONFIG,
|
||||
"cap_mknod": MKNOD,
|
||||
"cap_lease": LEASE,
|
||||
"cap_audit_write": AUDIT_WRITE,
|
||||
"cap_audit_control": AUDIT_CONTROL,
|
||||
"cap_setfcap": SETFCAP,
|
||||
"cap_mac_override": MAC_OVERRIDE,
|
||||
"cap_mac_admin": MAC_ADMIN,
|
||||
"cap_syslog": SYSLOG,
|
||||
"cap_wake_alarm": WAKE_ALARM,
|
||||
"cap_block_suspend": BLOCK_SUSPEND,
|
||||
"cap_audit_read": AUDIT_READ,
|
||||
"cap_perfmon": PERFMON,
|
||||
"cap_bpf": BPF,
|
||||
"cap_checkpoint_restore": CHECKPOINT_RESTORE,
|
||||
}
|
||||
33
vendor/kernel.org/pub/linux/libs/security/libcap/cap/oslockluster.go
generated
vendored
Normal file
33
vendor/kernel.org/pub/linux/libs/security/libcap/cap/oslockluster.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
// +build !go1.10
|
||||
|
||||
package cap
|
||||
|
||||
import "syscall"
|
||||
|
||||
// LaunchSupported indicates that is safe to return from a locked OS
|
||||
// Thread and have that OS Thread be terminated by the runtime. The
|
||||
// Launch functionality really needs to rely on the fact that an
|
||||
// excess of runtime.LockOSThread() vs. runtime.UnlockOSThread() calls
|
||||
// in a returning go routine will cause the underlying locked OSThread
|
||||
// to terminate. That feature was added to the Go runtime in version
|
||||
// 1.10.
|
||||
//
|
||||
// See these bugs for the discussion and feature assumed by the code
|
||||
// in this Launch() functionality:
|
||||
//
|
||||
// https://github.com/golang/go/issues/20395
|
||||
// https://github.com/golang/go/issues/20458
|
||||
//
|
||||
// A value of false for this constant causes the Launch functionality
|
||||
// to fail with an error: cap.ErrNoLaunch. If this value is false you
|
||||
// have two choices with respect to the Launch functionality:
|
||||
//
|
||||
// 1) don't use cap.(*Launcher).Launch()
|
||||
// 2) upgrade your Go toolchain to 1.10+ (ie., do this one).
|
||||
const LaunchSupported = false
|
||||
|
||||
// validatePA confirms that the pa.Sys entry is not incompatible with
|
||||
// Launch.
|
||||
func validatePA(pa *syscall.ProcAttr, chroot string) (bool, error) {
|
||||
return false, ErrNoLaunch
|
||||
}
|
||||
51
vendor/kernel.org/pub/linux/libs/security/libcap/cap/oslocks.go
generated
vendored
Normal file
51
vendor/kernel.org/pub/linux/libs/security/libcap/cap/oslocks.go
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
// +build go1.10
|
||||
|
||||
package cap
|
||||
|
||||
import "syscall"
|
||||
|
||||
// LaunchSupported indicates that is safe to return from a locked
|
||||
// OS Thread and have that OS Thread be terminated by the runtime. The
|
||||
// Launch functionality really needs to rely on the fact that an
|
||||
// excess of runtime.LockOSThread() vs. runtime.UnlockOSThread() calls
|
||||
// in a returning go routine will cause the underlying locked OSThread
|
||||
// to terminate. That feature was added to the Go runtime in version
|
||||
// 1.10.
|
||||
//
|
||||
// See these bugs for the discussion and feature assumed by the code
|
||||
// in this Launch() functionality:
|
||||
//
|
||||
// https://github.com/golang/go/issues/20395
|
||||
// https://github.com/golang/go/issues/20458
|
||||
//
|
||||
// A value of false for this constant causes the Launch functionality
|
||||
// to fail with an error: cap.ErrNoLaunch. If this value is false you
|
||||
// have two choices with respect to the Launch functionality:
|
||||
//
|
||||
// 1) don't use cap.(*Launcher).Launch()
|
||||
// 2) upgrade your Go toolchain to 1.10+ (ie., do this one).
|
||||
const LaunchSupported = true
|
||||
|
||||
// validatePA confirms that the pa.Sys entry is not incompatible with
|
||||
// Launch and loads up the chroot value.
|
||||
func validatePA(pa *syscall.ProcAttr, chroot string) (bool, error) {
|
||||
s := pa.Sys
|
||||
if s == nil {
|
||||
if chroot == "" {
|
||||
return false, nil
|
||||
}
|
||||
s = &syscall.SysProcAttr{
|
||||
Chroot: chroot,
|
||||
}
|
||||
pa.Sys = s
|
||||
} else if s.Chroot != "" {
|
||||
return false, ErrAmbiguousChroot
|
||||
}
|
||||
if s.Credential != nil {
|
||||
return false, ErrAmbiguousIDs
|
||||
}
|
||||
if len(s.AmbientCaps) != 0 {
|
||||
return false, ErrAmbiguousAmbient
|
||||
}
|
||||
return s != nil && s.Chroot != "", nil
|
||||
}
|
||||
121
vendor/kernel.org/pub/linux/libs/security/libcap/cap/syscalls.go
generated
vendored
Normal file
121
vendor/kernel.org/pub/linux/libs/security/libcap/cap/syscalls.go
generated
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
package cap
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"kernel.org/pub/linux/libs/security/libcap/psx"
|
||||
)
|
||||
|
||||
// multisc provides syscalls overridable for testing purposes that
|
||||
// support a single kernel security state for all OS threads.
|
||||
// We use this version when we are cgo compiling because
|
||||
// we need to manage the native C pthreads too.
|
||||
var multisc = &syscaller{
|
||||
w3: psx.Syscall3,
|
||||
w6: psx.Syscall6,
|
||||
r3: syscall.RawSyscall,
|
||||
r6: syscall.RawSyscall6,
|
||||
}
|
||||
|
||||
// singlesc provides a single threaded implementation. Users should
|
||||
// take care to ensure the thread is locked and marked nogc.
|
||||
var singlesc = &syscaller{
|
||||
w3: syscall.RawSyscall,
|
||||
w6: syscall.RawSyscall6,
|
||||
r3: syscall.RawSyscall,
|
||||
r6: syscall.RawSyscall6,
|
||||
}
|
||||
|
||||
// launchState is used to track which variant of the write syscalls
|
||||
// should execute.
|
||||
type launchState int
|
||||
|
||||
// these states are used to understand when a launch is in progress.
|
||||
const (
|
||||
launchIdle launchState = iota
|
||||
launchActive
|
||||
launchBlocked
|
||||
)
|
||||
|
||||
// scwMu is used to fully serialize the write system calls. Note, this
|
||||
// would generally not be necessary, but in the case of Launch we get
|
||||
// into a situation where the launching thread is temporarily allowed
|
||||
// to deviate from the kernel state of the rest of the runtime and
|
||||
// allowing other threads to perform w* syscalls will potentially
|
||||
// interfere with the launching process. In pure Go binaries, this
|
||||
// will lead inevitably to a panic when the AllThreadsSyscall
|
||||
// discovers inconsistent thread state.
|
||||
//
|
||||
// scwMu protects scwTIDs and scwState
|
||||
var scwMu sync.Mutex
|
||||
|
||||
// scwTIDs holds the thread IDs of the threads that are executing a
|
||||
// launch it is empty when no launches are occurring.
|
||||
var scwTIDs = make(map[int]bool)
|
||||
|
||||
// scwState captures whether a launch is in progress or not.
|
||||
var scwState = launchIdle
|
||||
|
||||
// scwCond is used to announce when scwState changes to other
|
||||
// goroutines waiting for it to change.
|
||||
var scwCond = sync.NewCond(&scwMu)
|
||||
|
||||
// scwSetState blocks until a launch state change between states from
|
||||
// and to occurs. We use this for more context specific syscaller
|
||||
// use. In the case that the caller is requesting a launchActive ->
|
||||
// launchIdle transition they are declaring that tid is no longer
|
||||
// launching. If another thread is also launching the call will
|
||||
// complete, but the launchState will remain launchActive.
|
||||
func scwSetState(from, to launchState, tid int) {
|
||||
scwMu.Lock()
|
||||
for scwState != from {
|
||||
if scwState == launchActive && from == launchIdle && to == launchActive {
|
||||
break // This "transition" is also allowed.
|
||||
}
|
||||
scwCond.Wait()
|
||||
}
|
||||
if from == launchIdle && to == launchActive {
|
||||
scwTIDs[tid] = true
|
||||
} else if from == launchActive && to == launchIdle {
|
||||
delete(scwTIDs, tid)
|
||||
if len(scwTIDs) != 0 {
|
||||
to = from // not actually idle
|
||||
}
|
||||
}
|
||||
scwState = to
|
||||
scwCond.Broadcast()
|
||||
scwMu.Unlock()
|
||||
}
|
||||
|
||||
// scwStateSC blocks until the current syscaller is available for
|
||||
// writes, and then marks launchBlocked. Use scwSetState to perform
|
||||
// the reverse transition (blocked->returned state value).
|
||||
func scwStateSC() (launchState, *syscaller) {
|
||||
sc := multisc
|
||||
scwMu.Lock()
|
||||
for {
|
||||
if scwState == launchIdle {
|
||||
break
|
||||
}
|
||||
runtime.LockOSThread()
|
||||
if scwState == launchActive && scwTIDs[syscall.Gettid()] {
|
||||
sc = singlesc
|
||||
// note, we don't runtime.UnlockOSThread()
|
||||
// here because we have no reason to ever
|
||||
// allow this thread to return to normal use -
|
||||
// we need it dead before we can return to the
|
||||
// launchIdle state.
|
||||
break
|
||||
}
|
||||
runtime.UnlockOSThread()
|
||||
scwCond.Wait()
|
||||
}
|
||||
old := scwState
|
||||
scwState = launchBlocked
|
||||
scwCond.Broadcast()
|
||||
scwMu.Unlock()
|
||||
|
||||
return old, sc
|
||||
}
|
||||
326
vendor/kernel.org/pub/linux/libs/security/libcap/cap/text.go
generated
vendored
Normal file
326
vendor/kernel.org/pub/linux/libs/security/libcap/cap/text.go
generated
vendored
Normal file
@@ -0,0 +1,326 @@
|
||||
package cap
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// String converts a capability Value into its canonical text
|
||||
// representation.
|
||||
func (v Value) String() string {
|
||||
name, ok := names[v]
|
||||
if ok {
|
||||
return name
|
||||
}
|
||||
// Un-named capabilities are referred to numerically (in decimal).
|
||||
return strconv.Itoa(int(v))
|
||||
}
|
||||
|
||||
// FromName converts a named capability Value to its binary
|
||||
// representation.
|
||||
func FromName(name string) (Value, error) {
|
||||
startUp.Do(multisc.cInit)
|
||||
v, ok := bits[name]
|
||||
if ok {
|
||||
if v >= Value(words*32) {
|
||||
return 0, ErrBadValue
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
i, err := strconv.Atoi(name)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if i >= 0 && i < int(words*32) {
|
||||
return Value(i), nil
|
||||
}
|
||||
return 0, ErrBadValue
|
||||
}
|
||||
|
||||
const (
|
||||
eBin uint = (1 << Effective)
|
||||
pBin = (1 << Permitted)
|
||||
iBin = (1 << Inheritable)
|
||||
)
|
||||
|
||||
var combos = []string{"", "e", "p", "ep", "i", "ei", "ip", "eip"}
|
||||
|
||||
// histo generates a histogram of flag state combinations.
|
||||
// Note: c is locked by or private to the caller.
|
||||
func (c *Set) histo(bins []int, patterns []uint, from, limit Value) uint {
|
||||
for v := from; v < limit; v++ {
|
||||
b := uint(v & 31)
|
||||
u, bit, err := bitOf(0, v)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
x := uint((c.flat[u][Effective]&bit)>>b) * eBin
|
||||
x |= uint((c.flat[u][Permitted]&bit)>>b) * pBin
|
||||
x |= uint((c.flat[u][Inheritable]&bit)>>b) * iBin
|
||||
bins[x]++
|
||||
patterns[uint(v)] = x
|
||||
}
|
||||
// Note, in the loop, we use >= to pick the smallest value for
|
||||
// m with the highest bin value. That is ties break towards
|
||||
// m=0.
|
||||
m := uint(7)
|
||||
for t := m; t > 0; {
|
||||
t--
|
||||
if bins[t] >= bins[m] {
|
||||
m = t
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// String converts a full capability Set into a single short readable
|
||||
// string representation (which may contain spaces). See the
|
||||
// cap.FromText() function for an explanation of its return values.
|
||||
//
|
||||
// Note (*cap.Set).String() may evolve to generate more compact
|
||||
// strings representing the a given Set over time, but it should
|
||||
// maintain compatibility with the libcap:cap_to_text() function for
|
||||
// any given release. Further, it will always be an inverse of
|
||||
// cap.FromText().
|
||||
func (c *Set) String() string {
|
||||
if err := c.good(); err != nil {
|
||||
return "<invalid>"
|
||||
}
|
||||
bins := make([]int, 8)
|
||||
patterns := make([]uint, maxValues)
|
||||
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
|
||||
// Note, in order to have a *Set pointer, startUp.Do(cInit)
|
||||
// must have been called which sets maxValues.
|
||||
m := c.histo(bins, patterns, 0, Value(maxValues))
|
||||
|
||||
// Background state is the most popular of the named bits.
|
||||
vs := []string{"=" + combos[m]}
|
||||
for i := uint(8); i > 0; {
|
||||
i--
|
||||
if i == m || bins[i] == 0 {
|
||||
continue
|
||||
}
|
||||
var list []string
|
||||
for j, p := range patterns {
|
||||
if p != i {
|
||||
continue
|
||||
}
|
||||
list = append(list, Value(j).String())
|
||||
}
|
||||
x := strings.Join(list, ",")
|
||||
var y, z string
|
||||
if cf := i & ^m; cf != 0 {
|
||||
op := "+"
|
||||
if len(vs) == 1 && vs[0] == "=" {
|
||||
// Special case "= foo+..." == "foo=...".
|
||||
// Prefer because it
|
||||
vs = nil
|
||||
op = "="
|
||||
}
|
||||
y = op + combos[cf]
|
||||
}
|
||||
if cf := m & ^i; cf != 0 {
|
||||
z = "-" + combos[cf]
|
||||
}
|
||||
vs = append(vs, x+y+z)
|
||||
}
|
||||
|
||||
// The unnamed bits can only add to the above named ones since
|
||||
// unnamed ones are always defaulted to lowered.
|
||||
uBins := make([]int, 8)
|
||||
uPatterns := make([]uint, 32*words)
|
||||
c.histo(uBins, uPatterns, Value(maxValues), 32*Value(words))
|
||||
for i := uint(7); i > 0; i-- {
|
||||
if uBins[i] == 0 {
|
||||
continue
|
||||
}
|
||||
var list []string
|
||||
for j, p := range uPatterns {
|
||||
if p != i {
|
||||
continue
|
||||
}
|
||||
list = append(list, Value(j).String())
|
||||
}
|
||||
vs = append(vs, strings.Join(list, ",")+"+"+combos[i])
|
||||
}
|
||||
|
||||
return strings.Join(vs, " ")
|
||||
}
|
||||
|
||||
// ErrBadText is returned if the text for a capability set cannot be parsed.
|
||||
var ErrBadText = errors.New("bad text")
|
||||
|
||||
// FromText converts the canonical text representation for a Set into
|
||||
// a freshly allocated Set.
|
||||
//
|
||||
// The format follows the following pattern: a set of space separated
|
||||
// sequences. Each sequence applies over the previous sequence to
|
||||
// build up a Set. The format of a sequence is:
|
||||
//
|
||||
// [comma list of cap_values][[ops][flags]]*
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// "all=ep"
|
||||
// "cap_chown,cap_setuid=ip cap_setuid+e"
|
||||
// "=p cap_setpcap-p+i"
|
||||
//
|
||||
// Here "all" refers to all named capabilities known to the hosting
|
||||
// kernel, and "all" is assumed if no capabilities are listed before
|
||||
// an "=".
|
||||
//
|
||||
// The ops values, "=", "+" and "-" imply "reset and raise", "raise"
|
||||
// and "lower" respectively. The "e", "i" and "p" characters
|
||||
// correspond to the capabilities of the corresponding Flag: "e"
|
||||
// (Effective); "i" (Inheritable); "p" (Permitted).
|
||||
//
|
||||
// This syntax is overspecified and there are many ways of building
|
||||
// the same final Set state. Any sequence that includes a '=' resets
|
||||
// the accumulated state of all Flags ignoring earlier sequences. On
|
||||
// each of the following lines we give three or more examples of ways
|
||||
// to specify a common Set. The last entry on each line is the one
|
||||
// generated by (*cap.Set).String() from that Set.
|
||||
//
|
||||
// "=p all+ei" "all=pie" "=pi all+e" "=eip"
|
||||
//
|
||||
// "cap_setuid=p cap_chown=i" "cap_chown=ip-p" "cap_chown=i"
|
||||
//
|
||||
// "cap_chown=-p" "all=" "cap_setuid=pie-pie" "="
|
||||
//
|
||||
// Note: FromText() is tested at release time to completely match the
|
||||
// import ability of the libcap:cap_from_text() function.
|
||||
func FromText(text string) (*Set, error) {
|
||||
c := NewSet()
|
||||
scanner := bufio.NewScanner(strings.NewReader(text))
|
||||
scanner.Split(bufio.ScanWords)
|
||||
chunks := 0
|
||||
for scanner.Scan() {
|
||||
chunks++
|
||||
|
||||
// Parsing for xxx([-+=][eip]+)+
|
||||
t := scanner.Text()
|
||||
i := strings.IndexAny(t, "=+-")
|
||||
if i < 0 {
|
||||
return nil, ErrBadText
|
||||
}
|
||||
var vs []Value
|
||||
sep := t[i]
|
||||
if vals := t[:i]; vals == "all" {
|
||||
for v := Value(0); v < Value(maxValues); v++ {
|
||||
vs = append(vs, v)
|
||||
}
|
||||
} else if vals != "" {
|
||||
for _, name := range strings.Split(vals, ",") {
|
||||
v, err := FromName(name)
|
||||
if err != nil {
|
||||
return nil, ErrBadText
|
||||
}
|
||||
vs = append(vs, v)
|
||||
}
|
||||
} else if sep != '=' {
|
||||
if vals == "" {
|
||||
// Only "=" supports ""=="all".
|
||||
return nil, ErrBadText
|
||||
}
|
||||
} else if j := i + 1; j+1 < len(t) {
|
||||
switch t[j] {
|
||||
case '+':
|
||||
sep = 'P'
|
||||
i++
|
||||
case '-':
|
||||
sep = 'M'
|
||||
i++
|
||||
}
|
||||
}
|
||||
i++
|
||||
|
||||
// There are 5 ways to set: =, =+, =-, +, -. We call
|
||||
// the 2nd and 3rd of these 'P' and 'M'.
|
||||
|
||||
for {
|
||||
// read [eip]+ setting flags.
|
||||
var fE, fP, fI bool
|
||||
for ok := true; ok && i < len(t); i++ {
|
||||
switch t[i] {
|
||||
case 'e':
|
||||
fE = true
|
||||
case 'i':
|
||||
fI = true
|
||||
case 'p':
|
||||
fP = true
|
||||
default:
|
||||
ok = false
|
||||
}
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !(fE || fI || fP) {
|
||||
if sep != '=' {
|
||||
return nil, ErrBadText
|
||||
}
|
||||
}
|
||||
|
||||
switch sep {
|
||||
case '=', 'P', 'M', '+':
|
||||
if sep != '+' {
|
||||
c.Clear()
|
||||
if sep == 'M' {
|
||||
break
|
||||
}
|
||||
}
|
||||
if keep := len(vs) == 0; keep {
|
||||
if sep != '=' {
|
||||
return nil, ErrBadText
|
||||
}
|
||||
c.forceFlag(Effective, fE)
|
||||
c.forceFlag(Permitted, fP)
|
||||
c.forceFlag(Inheritable, fI)
|
||||
break
|
||||
}
|
||||
// =, + and P for specific values are left.
|
||||
if fE {
|
||||
c.SetFlag(Effective, true, vs...)
|
||||
}
|
||||
if fP {
|
||||
c.SetFlag(Permitted, true, vs...)
|
||||
}
|
||||
if fI {
|
||||
c.SetFlag(Inheritable, true, vs...)
|
||||
}
|
||||
case '-':
|
||||
if fE {
|
||||
c.SetFlag(Effective, false, vs...)
|
||||
}
|
||||
if fP {
|
||||
c.SetFlag(Permitted, false, vs...)
|
||||
}
|
||||
if fI {
|
||||
c.SetFlag(Inheritable, false, vs...)
|
||||
}
|
||||
}
|
||||
|
||||
if i == len(t) {
|
||||
break
|
||||
}
|
||||
|
||||
switch t[i] {
|
||||
case '+', '-':
|
||||
sep = t[i]
|
||||
i++
|
||||
default:
|
||||
return nil, ErrBadText
|
||||
}
|
||||
}
|
||||
}
|
||||
if chunks == 0 {
|
||||
return nil, ErrBadText
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
398
vendor/kernel.org/pub/linux/libs/security/libcap/psx/License
generated
vendored
Normal file
398
vendor/kernel.org/pub/linux/libs/security/libcap/psx/License
generated
vendored
Normal file
@@ -0,0 +1,398 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-only */
|
||||
|
||||
Unless otherwise *explicitly* stated, the following text describes the
|
||||
licensed conditions under which the contents of this libcap/psx release
|
||||
may be used and distributed.
|
||||
|
||||
The licensed conditions are one or the other of these two Licenses:
|
||||
|
||||
- BSD 3-clause
|
||||
- GPL v2.0
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
BSD 3-clause:
|
||||
-------------
|
||||
|
||||
Redistribution and use in source and binary forms of libcap/psx, with
|
||||
or without modification, are permitted provided that the following
|
||||
conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain any existing copyright
|
||||
notice, and this entire permission notice in its entirety,
|
||||
including the disclaimer of warranties.
|
||||
|
||||
2. Redistributions in binary form must reproduce all prior and current
|
||||
copyright notices, this list of conditions, and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
3. The name of any author may not be used to endorse or promote
|
||||
products derived from this software without their specific prior
|
||||
written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
GPL v2.0:
|
||||
---------
|
||||
|
||||
ALTERNATIVELY, this product may be distributed under the terms of the
|
||||
GNU General Public License (v2.0 - see below), in which case the
|
||||
provisions of the GNU GPL are required INSTEAD OF the above
|
||||
restrictions. (This clause is necessary due to a potential conflict
|
||||
between the GNU GPL and the restrictions contained in a BSD-style
|
||||
copyright.)
|
||||
|
||||
-------------------------
|
||||
Full text of gpl-2.0.txt:
|
||||
-------------------------
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
28
vendor/kernel.org/pub/linux/libs/security/libcap/psx/README
generated
vendored
Normal file
28
vendor/kernel.org/pub/linux/libs/security/libcap/psx/README
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
Package "psx" provides an API for invoking system calls in a way that
|
||||
each system call is mirrored on all OS threads of the combined Go/CGo
|
||||
runtime. Since the Go runtime treats OS threads as interchangeable, a
|
||||
feature like this is needed to meaningfully change process privilege
|
||||
(including dropping privilege) in a Go program running on Linux. This
|
||||
package is required by:
|
||||
|
||||
"kernel.org/pub/linux/libs/security/libcap/cap"
|
||||
|
||||
When compiled CGO_ENABLED=0, the functionality requires go1.16+ to
|
||||
build. That release of Go introduced syscall.AllThreadsSyscall*()
|
||||
APIs. When compiled this way, the "psx" package functions
|
||||
psx.Syscall3() and psx.Syscall6() are aliased to
|
||||
syscall.AllThreadsSyscall() and syscall.AllThreadsSyscall6()
|
||||
respectively.
|
||||
|
||||
When compiled CGO_ENABLED=1, the functionality is implemented by C
|
||||
code, [lib]psx, which is distributed with libcap.
|
||||
|
||||
The official release announcement site for libcap and libpsx is:
|
||||
|
||||
https://sites.google.com/site/fullycapable/
|
||||
|
||||
Like libcap/libpsx itself, the "psx" package is distributed with a
|
||||
"you choose" License. Specifically: BSD three clause, or GPL2. See the
|
||||
License file.
|
||||
|
||||
Andrew G. Morgan <morgan@kernel.org>
|
||||
60
vendor/kernel.org/pub/linux/libs/security/libcap/psx/doc.go
generated
vendored
Normal file
60
vendor/kernel.org/pub/linux/libs/security/libcap/psx/doc.go
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
// Package psx provides support for system calls that are run
|
||||
// simultaneously on all threads under Linux.
|
||||
//
|
||||
// This property can be used to work around a historical lack of
|
||||
// native Go support for such a feature. Something that is the subject
|
||||
// of:
|
||||
//
|
||||
// https://github.com/golang/go/issues/1435
|
||||
//
|
||||
// The package works differently depending on whether or not
|
||||
// CGO_ENABLED is 0 or 1.
|
||||
//
|
||||
// In the former case, psx is a low overhead wrapper for the two
|
||||
// native go calls: syscall.AllThreadsSyscall() and
|
||||
// syscall.AllThreadsSyscall6() introduced in go1.16. We provide this
|
||||
// wrapping to minimize client source code changes when compiling with
|
||||
// or without CGo enabled.
|
||||
//
|
||||
// In the latter case, and toolchains prior to go1.16, it works via
|
||||
// CGo wrappers for system call functions that call the C [lib]psx
|
||||
// functions of these names. This ensures that the system calls
|
||||
// execute simultaneously on all the pthreads of the Go (and CGo)
|
||||
// combined runtime.
|
||||
//
|
||||
// With CGo, the psx support works in the following way: the pthread
|
||||
// that is first asked to execute the syscall does so, and determines
|
||||
// if it succeeds or fails. If it fails, it returns immediately
|
||||
// without attempting the syscall on other pthreads. If the initial
|
||||
// attempt succeeds, however, then the runtime is stopped in order for
|
||||
// the same system call to be performed on all the remaining pthreads
|
||||
// of the runtime. Once all pthreads have completed the syscall, the
|
||||
// return codes are those obtained by the first pthread's invocation
|
||||
// of the syscall.
|
||||
//
|
||||
// Note, there is no need to use this variant of syscall where the
|
||||
// syscalls only read state from the kernel. However, since Go's
|
||||
// runtime freely migrates code execution between pthreads, support of
|
||||
// this type is required for any successful attempt to fully drop or
|
||||
// modify the privilege of a running Go program under Linux.
|
||||
//
|
||||
// More info on how Linux privilege works and examples of using this
|
||||
// package can be found here:
|
||||
//
|
||||
// https://sites.google.com/site/fullycapable
|
||||
//
|
||||
// WARNING: For older go toolchains (prior to go1.15), correct
|
||||
// compilation of this package may require an extra workaround step:
|
||||
//
|
||||
// The workaround is to build with the following CGO_LDFLAGS_ALLOW in
|
||||
// effect (here the syntax is that of bash for defining an environment
|
||||
// variable):
|
||||
//
|
||||
// export CGO_LDFLAGS_ALLOW="-Wl,-?-wrap[=,][^-.@][^,]*"
|
||||
//
|
||||
//
|
||||
// Copyright (c) 2019,20 Andrew G. Morgan <morgan@kernel.org>
|
||||
//
|
||||
// The psx package is licensed with a (you choose) BSD 3-clause or
|
||||
// GPL2. See LICENSE file for details.
|
||||
package psx // import "kernel.org/pub/linux/libs/security/libcap/psx"
|
||||
765
vendor/kernel.org/pub/linux/libs/security/libcap/psx/psx.c
generated
vendored
Normal file
765
vendor/kernel.org/pub/linux/libs/security/libcap/psx/psx.c
generated
vendored
Normal file
@@ -0,0 +1,765 @@
|
||||
/*
|
||||
* Copyright (c) 2019-21 Andrew G Morgan <morgan@kernel.org>
|
||||
*
|
||||
* This file contains a collection of routines that perform thread
|
||||
* synchronization to ensure that a whole process is running as a
|
||||
* single privilege entity - independent of the number of pthreads.
|
||||
*
|
||||
* The whole file would be unnecessary if glibc exported an explicit
|
||||
* psx_syscall()-like function that leveraged the nptl:setxid
|
||||
* mechanism to synchronize thread state over the whole process.
|
||||
*/
|
||||
#undef _POSIX_C_SOURCE
|
||||
#define _POSIX_C_SOURCE 199309L
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include "psx_syscall.h"
|
||||
|
||||
#ifdef _PSX_DEBUG_MEMORY
|
||||
|
||||
static void *_psx_calloc(const char *file, const int line,
|
||||
size_t nmemb, size_t size) {
|
||||
void *ptr = calloc(nmemb, size);
|
||||
fprintf(stderr, "psx:%d:%s:%d: calloc(%ld, %ld) -> %p\n", gettid(),
|
||||
file, line, (long int)nmemb, (long int)size, ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void _psx_free(const char *file, const int line, void *ptr) {
|
||||
fprintf(stderr, "psx:%d:%s:%d: free(%p)\n", gettid(), file, line, ptr);
|
||||
return free(ptr);
|
||||
}
|
||||
|
||||
#define calloc(a, b) _psx_calloc(__FILE__, __LINE__, a, b)
|
||||
#define free(a) _psx_free(__FILE__, __LINE__, a)
|
||||
|
||||
#endif /* def _PSX_DEBUG_MEMORY */
|
||||
|
||||
/*
|
||||
* psx_load_syscalls() can be weakly defined in dependent libraries to
|
||||
* provide a mechanism for a library to optionally leverage this psx
|
||||
* mechanism. Specifically, when libcap calls psx_load_sycalls() it
|
||||
* provides a weakly declared default that maps its system calls to
|
||||
* the regular system call functions. However, when linked with psx,
|
||||
* this function here overrides the syscalls to be the psx ones.
|
||||
*/
|
||||
void psx_load_syscalls(long int (**syscall_fn)(long int,
|
||||
long int, long int, long int),
|
||||
long int (**syscall6_fn)(long int,
|
||||
long int, long int, long int,
|
||||
long int, long int, long int))
|
||||
{
|
||||
*syscall_fn = psx_syscall3;
|
||||
*syscall6_fn = psx_syscall6;
|
||||
}
|
||||
|
||||
/*
|
||||
* type to keep track of registered threads.
|
||||
*/
|
||||
typedef struct registered_thread_s {
|
||||
struct registered_thread_s *next, *prev;
|
||||
pthread_t thread;
|
||||
pthread_mutex_t mu;
|
||||
int pending;
|
||||
int gone;
|
||||
long int retval;
|
||||
pid_t tid;
|
||||
} registered_thread_t;
|
||||
|
||||
static pthread_once_t psx_tracker_initialized = PTHREAD_ONCE_INIT;
|
||||
|
||||
typedef enum {
|
||||
_PSX_IDLE = 0,
|
||||
_PSX_SETUP = 1,
|
||||
_PSX_SYSCALL = 2,
|
||||
_PSX_CREATE = 3,
|
||||
_PSX_INFORK = 4,
|
||||
_PSX_EXITING = 5,
|
||||
} psx_tracker_state_t;
|
||||
|
||||
/*
|
||||
* This global structure holds the global coordination state for
|
||||
* libcap's psx_posix_syscall() support.
|
||||
*/
|
||||
static struct psx_tracker_s {
|
||||
int has_forked;
|
||||
|
||||
pthread_mutex_t state_mu;
|
||||
pthread_cond_t cond; /* this is only used to wait on 'state' changes */
|
||||
psx_tracker_state_t state;
|
||||
int initialized;
|
||||
int psx_sig;
|
||||
psx_sensitivity_t sensitivity;
|
||||
|
||||
struct {
|
||||
long syscall_nr;
|
||||
long arg1, arg2, arg3, arg4, arg5, arg6;
|
||||
int six;
|
||||
int active;
|
||||
} cmd;
|
||||
|
||||
struct sigaction sig_action;
|
||||
struct sigaction chained_action;
|
||||
registered_thread_t *root;
|
||||
} psx_tracker;
|
||||
|
||||
/*
|
||||
* psx_action_key is used for thread local storage of the thread's
|
||||
* registration.
|
||||
*/
|
||||
pthread_key_t psx_action_key;
|
||||
|
||||
/*
|
||||
* psx_do_registration called locked and creates a tracker entry for
|
||||
* the current thread with a TLS specific key pointing at the threads
|
||||
* specific tracker.
|
||||
*/
|
||||
static void *psx_do_registration(void) {
|
||||
registered_thread_t *node = calloc(1, sizeof(registered_thread_t));
|
||||
if (node == NULL) {
|
||||
perror("unable to register psx handler");
|
||||
_exit(1);
|
||||
}
|
||||
pthread_mutex_init(&node->mu, NULL);
|
||||
node->thread = pthread_self();
|
||||
pthread_setspecific(psx_action_key, node);
|
||||
node->next = psx_tracker.root;
|
||||
if (node->next) {
|
||||
node->next->prev = node;
|
||||
}
|
||||
psx_tracker.root = node;
|
||||
return node;
|
||||
}
|
||||
|
||||
/*
|
||||
* psx_posix_syscall_actor performs the system call on the targeted
|
||||
* thread and signals it is no longer pending.
|
||||
*/
|
||||
static void psx_posix_syscall_actor(int signum, siginfo_t *info, void *ignore) {
|
||||
/* bail early if this isn't something we recognize */
|
||||
if (signum != psx_tracker.psx_sig || !psx_tracker.cmd.active ||
|
||||
info == NULL || info->si_code != SI_TKILL || info->si_pid != getpid()) {
|
||||
if (psx_tracker.chained_action.sa_sigaction != 0) {
|
||||
psx_tracker.chained_action.sa_sigaction(signum, info, ignore);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
long int retval;
|
||||
if (!psx_tracker.cmd.six) {
|
||||
retval = syscall(psx_tracker.cmd.syscall_nr,
|
||||
psx_tracker.cmd.arg1,
|
||||
psx_tracker.cmd.arg2,
|
||||
psx_tracker.cmd.arg3);
|
||||
} else {
|
||||
retval = syscall(psx_tracker.cmd.syscall_nr,
|
||||
psx_tracker.cmd.arg1,
|
||||
psx_tracker.cmd.arg2,
|
||||
psx_tracker.cmd.arg3,
|
||||
psx_tracker.cmd.arg4,
|
||||
psx_tracker.cmd.arg5,
|
||||
psx_tracker.cmd.arg6);
|
||||
}
|
||||
|
||||
/*
|
||||
* This handler can only be called on registered threads which
|
||||
* have had this specific defined at start-up. (But see the
|
||||
* subsequent test.)
|
||||
*/
|
||||
registered_thread_t *ref = pthread_getspecific(psx_action_key);
|
||||
if (ref) {
|
||||
pthread_mutex_lock(&ref->mu);
|
||||
ref->pending = 0;
|
||||
ref->retval = retval;
|
||||
ref->tid = syscall(SYS_gettid);
|
||||
pthread_mutex_unlock(&ref->mu);
|
||||
} /*
|
||||
* else thread must be dying and its psx_action_key has already
|
||||
* been cleaned up.
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* Some forward declarations for the initialization
|
||||
* psx_syscall_start() routine.
|
||||
*/
|
||||
static void _psx_cleanup(void);
|
||||
static void _psx_prepare_fork(void);
|
||||
static void _psx_fork_completed(void);
|
||||
static void _psx_forked_child(void);
|
||||
int __wrap_pthread_create(pthread_t *thread, const pthread_attr_t *attr,
|
||||
void *(*start_routine) (void *), void *arg);
|
||||
|
||||
/*
|
||||
* psx requires this function to be provided by the linkage wrapping.
|
||||
*/
|
||||
extern int __real_pthread_create(pthread_t *thread, const pthread_attr_t *attr,
|
||||
void *(*start_routine) (void *), void *arg);
|
||||
|
||||
/*
|
||||
* psx_confirm_sigaction reconfirms that the psx handler is the first
|
||||
* handler to respond to the psx signal. It assumes that
|
||||
* psx_tracker.psx_sig has been set.
|
||||
*/
|
||||
static void psx_confirm_sigaction(void) {
|
||||
sigset_t mask, orig;
|
||||
struct sigaction existing_sa;
|
||||
|
||||
/*
|
||||
* Block interrupts while potentially rewriting the handler.
|
||||
*/
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, psx_tracker.psx_sig);
|
||||
sigprocmask(SIG_BLOCK, &mask, &orig);
|
||||
|
||||
sigaction(psx_tracker.psx_sig, NULL, &existing_sa);
|
||||
if (existing_sa.sa_sigaction != psx_posix_syscall_actor) {
|
||||
memcpy(&psx_tracker.chained_action, &existing_sa, sizeof(struct sigaction));
|
||||
psx_tracker.sig_action.sa_sigaction = psx_posix_syscall_actor;
|
||||
sigemptyset(&psx_tracker.sig_action.sa_mask);
|
||||
psx_tracker.sig_action.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESTART;
|
||||
sigaction(psx_tracker.psx_sig, &psx_tracker.sig_action, NULL);
|
||||
}
|
||||
|
||||
sigprocmask(SIG_SETMASK, &orig, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* psx_syscall_start initializes the subsystem including initializing
|
||||
* the mutex.
|
||||
*/
|
||||
static void psx_syscall_start(void) {
|
||||
pthread_mutex_init(&psx_tracker.state_mu, NULL);
|
||||
pthread_cond_init(&psx_tracker.cond, NULL);
|
||||
pthread_key_create(&psx_action_key, NULL);
|
||||
pthread_atfork(_psx_prepare_fork, _psx_fork_completed, _psx_forked_child);
|
||||
|
||||
/*
|
||||
* All sorts of things are assumed by Linux and glibc and/or musl
|
||||
* about signal handlers and which can be blocked. Go has its own
|
||||
* idiosyncrasies too. We tried SIGRTMAX until
|
||||
*
|
||||
* https://bugzilla.kernel.org/show_bug.cgi?id=210533
|
||||
*
|
||||
* Our current strategy is to aggressively intercept SIGSYS.
|
||||
*/
|
||||
psx_tracker.psx_sig = SIGSYS;
|
||||
|
||||
psx_confirm_sigaction();
|
||||
psx_do_registration(); /* register the main thread. */
|
||||
atexit(_psx_cleanup);
|
||||
|
||||
psx_tracker.initialized = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the only way this library globally locks. Note, this is not
|
||||
* to be confused with psx_sig (interrupt) blocking - which is
|
||||
* performed around thread creation and when the signal handler is
|
||||
* being confirmed.
|
||||
*/
|
||||
static void psx_lock(void)
|
||||
{
|
||||
pthread_once(&psx_tracker_initialized, psx_syscall_start);
|
||||
pthread_mutex_lock(&psx_tracker.state_mu);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the only way this library unlocks.
|
||||
*/
|
||||
static void psx_unlock(void)
|
||||
{
|
||||
pthread_mutex_unlock(&psx_tracker.state_mu);
|
||||
}
|
||||
|
||||
/*
|
||||
* under lock perform a state transition. Changing state is generally
|
||||
* done via this function. However, there is a single exception in
|
||||
* _psx_cleanup().
|
||||
*/
|
||||
static void psx_new_state(psx_tracker_state_t was, psx_tracker_state_t is)
|
||||
{
|
||||
psx_lock();
|
||||
while (psx_tracker.state != was) {
|
||||
pthread_cond_wait(&psx_tracker.cond, &psx_tracker.state_mu);
|
||||
}
|
||||
psx_tracker.state = is;
|
||||
if (is == _PSX_IDLE) {
|
||||
/* only announce newly idle states since that is all we wait for */
|
||||
pthread_cond_signal(&psx_tracker.cond);
|
||||
}
|
||||
psx_unlock();
|
||||
}
|
||||
|
||||
long int psx_syscall3(long int syscall_nr,
|
||||
long int arg1, long int arg2, long int arg3) {
|
||||
return psx_syscall(syscall_nr, arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
long int psx_syscall6(long int syscall_nr,
|
||||
long int arg1, long int arg2, long int arg3,
|
||||
long int arg4, long int arg5, long int arg6) {
|
||||
return psx_syscall(syscall_nr, arg1, arg2, arg3, arg4, arg5, arg6);
|
||||
}
|
||||
|
||||
static void _psx_prepare_fork(void) {
|
||||
/*
|
||||
* obtain global lock - we don't want any syscalls while the fork
|
||||
* is occurring since it may interfere with the preparation for
|
||||
* the fork.
|
||||
*/
|
||||
psx_new_state(_PSX_IDLE, _PSX_INFORK);
|
||||
}
|
||||
|
||||
static void _psx_fork_completed(void) {
|
||||
/*
|
||||
* The only way we can get here is if state is _PSX_INFORK and was
|
||||
* previously _PSX_IDLE. Now that the fork has completed, the
|
||||
* parent can continue as if it hadn't happened - the forked child
|
||||
* does not tie its security state to that of the parent process
|
||||
* and threads.
|
||||
*
|
||||
* We don't strictly need to change the psx_tracker.state since we
|
||||
* hold the mutex over the fork, but we do to make deadlock
|
||||
* debugging easier.
|
||||
*/
|
||||
psx_new_state(_PSX_INFORK, _PSX_IDLE);
|
||||
}
|
||||
|
||||
static void _psx_forked_child(void) {
|
||||
/*
|
||||
* The only way we can get here is if state is _PSX_INFORK and was
|
||||
* previously _PSX_IDLE. However, none of the registered threads
|
||||
* exist in this newly minted child process, so we have to reset
|
||||
* the tracking structure to avoid any confusion. We also scuttle
|
||||
* any chance of the PSX API working on more than one thread in
|
||||
* the child by leaving the state as _PSX_INFORK. We do support
|
||||
* all psx_syscall()s by reverting to them being direct in the
|
||||
* fork()ed child.
|
||||
*
|
||||
* We do this because the glibc man page for fork() suggests that
|
||||
* only a subset of things will work post fork(). Specifically,
|
||||
* only a "async-signal-safe functions (see signal-safety(7))
|
||||
* until such time as it calls execve(2)" can be relied upon. That
|
||||
* man page suggests that you can't expect mutexes to work: "not
|
||||
* async-signal-safe because it uses pthread_mutex_lock(3)
|
||||
* internally.".
|
||||
*/
|
||||
registered_thread_t *next, *old_root;
|
||||
old_root = psx_tracker.root;
|
||||
psx_tracker.root = NULL;
|
||||
|
||||
psx_tracker.has_forked = 1;
|
||||
|
||||
for (; old_root; old_root = next) {
|
||||
next = old_root->next;
|
||||
memset(old_root, 0, sizeof(*old_root));
|
||||
free(old_root);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* called locked to unregister a node from the tracker.
|
||||
*/
|
||||
static void psx_do_unregister(registered_thread_t *node) {
|
||||
if (psx_tracker.root == node) {
|
||||
psx_tracker.root = node->next;
|
||||
}
|
||||
if (node->next) {
|
||||
node->next->prev = node->prev;
|
||||
}
|
||||
if (node->prev) {
|
||||
node->prev->next = node->next;
|
||||
}
|
||||
pthread_mutex_destroy(&node->mu);
|
||||
memset(node, 0, sizeof(*node));
|
||||
free(node);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
void *(*fn)(void *);
|
||||
void *arg;
|
||||
sigset_t sigbits;
|
||||
} psx_starter_t;
|
||||
|
||||
/*
|
||||
* _psx_exiting is used to cleanup the node for the thread on its exit
|
||||
* path. This is needed for musl libc:
|
||||
*
|
||||
* https://bugzilla.kernel.org/show_bug.cgi?id=208477
|
||||
*
|
||||
* and likely wise for glibc too:
|
||||
*
|
||||
* https://sourceware.org/bugzilla/show_bug.cgi?id=12889
|
||||
*/
|
||||
static void _psx_exiting(void *node) {
|
||||
/*
|
||||
* Until we are in the _PSX_EXITING state, we must not block the
|
||||
* psx_sig interrupt for this dying thread. That is, until this
|
||||
* exiting thread can set ref->gone to 1, this dying thread is
|
||||
* still participating in the psx syscall distribution.
|
||||
*
|
||||
* See https://github.com/golang/go/issues/42494 for a situation
|
||||
* where this code is called with psx_tracker.psx_sig blocked.
|
||||
*/
|
||||
sigset_t sigbit, orig_sigbits;
|
||||
sigemptyset(&sigbit);
|
||||
pthread_sigmask(SIG_UNBLOCK, &sigbit, &orig_sigbits);
|
||||
sigaddset(&sigbit, psx_tracker.psx_sig);
|
||||
pthread_sigmask(SIG_UNBLOCK, &sigbit, NULL);
|
||||
|
||||
/*
|
||||
* With psx_tracker.psx_sig unblocked we can wait until this
|
||||
* thread can enter the _PSX_EXITING state.
|
||||
*/
|
||||
psx_new_state(_PSX_IDLE, _PSX_EXITING);
|
||||
|
||||
/*
|
||||
* We now indicate that this thread is no longer participating in
|
||||
* the psx mechanism.
|
||||
*/
|
||||
registered_thread_t *ref = node;
|
||||
pthread_mutex_lock(&ref->mu);
|
||||
ref->gone = 1;
|
||||
pthread_mutex_unlock(&ref->mu);
|
||||
|
||||
/*
|
||||
* At this point, we can restore the calling sigmask to whatever
|
||||
* the caller thought was appropriate for a dying thread to have.
|
||||
*/
|
||||
pthread_sigmask(SIG_SETMASK, &orig_sigbits, NULL);
|
||||
|
||||
/*
|
||||
* Allow the rest of the psx system to carry on as per normal.
|
||||
*/
|
||||
psx_new_state(_PSX_EXITING, _PSX_IDLE);
|
||||
}
|
||||
|
||||
/*
|
||||
* _psx_start_fn is a trampoline for the intended start function, it
|
||||
* is called blocked (_PSX_CREATE), but releases the block before
|
||||
* calling starter->fn. Before releasing the block, the TLS specific
|
||||
* attributes are initialized for use by the interrupt handler under
|
||||
* the psx mutex, so it doesn't race with an interrupt received by
|
||||
* this thread and the interrupt handler does not need to poll for
|
||||
* that specific attribute to be present (which is problematic during
|
||||
* thread shutdown).
|
||||
*/
|
||||
static void *_psx_start_fn(void *data) {
|
||||
void *node = psx_do_registration();
|
||||
|
||||
psx_new_state(_PSX_CREATE, _PSX_IDLE);
|
||||
|
||||
psx_starter_t *starter = data;
|
||||
pthread_sigmask(SIG_SETMASK, &starter->sigbits, NULL);
|
||||
void *(*fn)(void *) = starter->fn;
|
||||
void *arg = starter->arg;
|
||||
|
||||
memset(data, 0, sizeof(*starter));
|
||||
free(data);
|
||||
|
||||
void *ret;
|
||||
|
||||
pthread_cleanup_push(_psx_exiting, node);
|
||||
ret = fn(arg);
|
||||
pthread_cleanup_pop(1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* __wrap_pthread_create is the wrapped destination of all regular
|
||||
* pthread_create calls.
|
||||
*/
|
||||
int __wrap_pthread_create(pthread_t *thread, const pthread_attr_t *attr,
|
||||
void *(*start_routine) (void *), void *arg) {
|
||||
psx_starter_t *starter = calloc(1, sizeof(psx_starter_t));
|
||||
if (starter == NULL) {
|
||||
perror("failed at thread creation");
|
||||
exit(1);
|
||||
}
|
||||
starter->fn = start_routine;
|
||||
starter->arg = arg;
|
||||
/*
|
||||
* Until we are in the _PSX_IDLE state and locked, we must not
|
||||
* block the psx_sig interrupt for this parent thread. Arrange
|
||||
* that parent thread and newly created one can restore signal
|
||||
* mask.
|
||||
*/
|
||||
sigset_t sigbit, orig_sigbits;
|
||||
sigemptyset(&sigbit);
|
||||
pthread_sigmask(SIG_UNBLOCK, &sigbit, &starter->sigbits);
|
||||
sigaddset(&sigbit, psx_tracker.psx_sig);
|
||||
pthread_sigmask(SIG_UNBLOCK, &sigbit, &orig_sigbits);
|
||||
|
||||
psx_new_state(_PSX_IDLE, _PSX_CREATE);
|
||||
|
||||
/*
|
||||
* until the child thread has been blessed with its own TLS
|
||||
* specific attribute(s) we prevent either the parent thread or
|
||||
* the new one from experiencing a PSX interrupt.
|
||||
*/
|
||||
pthread_sigmask(SIG_BLOCK, &sigbit, NULL);
|
||||
|
||||
int ret = __real_pthread_create(thread, attr, _psx_start_fn, starter);
|
||||
if (ret == -1) {
|
||||
psx_new_state(_PSX_CREATE, _PSX_IDLE);
|
||||
memset(starter, 0, sizeof(*starter));
|
||||
free(starter);
|
||||
} /* else unlock happens in _psx_start_fn */
|
||||
|
||||
/* the parent can once again receive psx interrupt signals */
|
||||
pthread_sigmask(SIG_SETMASK, &orig_sigbits, NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* __psx_immediate_syscall does one syscall using the current
|
||||
* process.
|
||||
*/
|
||||
static long int __psx_immediate_syscall(long int syscall_nr,
|
||||
int count, long int *arg) {
|
||||
psx_tracker.cmd.syscall_nr = syscall_nr;
|
||||
psx_tracker.cmd.arg1 = count > 0 ? arg[0] : 0;
|
||||
psx_tracker.cmd.arg2 = count > 1 ? arg[1] : 0;
|
||||
psx_tracker.cmd.arg3 = count > 2 ? arg[2] : 0;
|
||||
|
||||
if (count > 3) {
|
||||
psx_tracker.cmd.six = 1;
|
||||
psx_tracker.cmd.arg4 = arg[3];
|
||||
psx_tracker.cmd.arg5 = count > 4 ? arg[4] : 0;
|
||||
psx_tracker.cmd.arg6 = count > 5 ? arg[5] : 0;
|
||||
return syscall(syscall_nr,
|
||||
psx_tracker.cmd.arg1,
|
||||
psx_tracker.cmd.arg2,
|
||||
psx_tracker.cmd.arg3,
|
||||
psx_tracker.cmd.arg4,
|
||||
psx_tracker.cmd.arg5,
|
||||
psx_tracker.cmd.arg6);
|
||||
}
|
||||
|
||||
psx_tracker.cmd.six = 0;
|
||||
return syscall(syscall_nr, psx_tracker.cmd.arg1,
|
||||
psx_tracker.cmd.arg2, psx_tracker.cmd.arg3);
|
||||
}
|
||||
|
||||
/*
|
||||
* __psx_syscall performs the syscall on the current thread and if no
|
||||
* error is detected it ensures that the syscall is also performed on
|
||||
* all (other) registered threads. The return code is the value for
|
||||
* the first invocation. It uses a trick to figure out how many
|
||||
* arguments the user has supplied. The other half of the trick is
|
||||
* provided by the macro psx_syscall() in the <sys/psx_syscall.h>
|
||||
* file. The trick is the 7th optional argument (8th over all) to
|
||||
* __psx_syscall is the count of arguments supplied to psx_syscall.
|
||||
*
|
||||
* User:
|
||||
* psx_syscall(nr, a, b);
|
||||
* Expanded by macro to:
|
||||
* __psx_syscall(nr, a, b, 6, 5, 4, 3, 2, 1, 0);
|
||||
* The eighth arg is now ------------------------------------^
|
||||
*/
|
||||
long int __psx_syscall(long int syscall_nr, ...) {
|
||||
long int arg[7];
|
||||
int i;
|
||||
|
||||
va_list aptr;
|
||||
va_start(aptr, syscall_nr);
|
||||
for (i = 0; i < 7; i++) {
|
||||
arg[i] = va_arg(aptr, long int);
|
||||
}
|
||||
va_end(aptr);
|
||||
|
||||
int count = arg[6];
|
||||
if (count < 0 || count > 6) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (psx_tracker.has_forked) {
|
||||
return __psx_immediate_syscall(syscall_nr, count, arg);
|
||||
}
|
||||
|
||||
psx_new_state(_PSX_IDLE, _PSX_SETUP);
|
||||
psx_confirm_sigaction();
|
||||
|
||||
long int ret;
|
||||
|
||||
ret = __psx_immediate_syscall(syscall_nr, count, arg);
|
||||
if (ret == -1 || !psx_tracker.initialized) {
|
||||
psx_new_state(_PSX_SETUP, _PSX_IDLE);
|
||||
goto defer;
|
||||
}
|
||||
|
||||
int restore_errno = errno;
|
||||
|
||||
psx_new_state(_PSX_SETUP, _PSX_SYSCALL);
|
||||
psx_tracker.cmd.active = 1;
|
||||
|
||||
pthread_t self = pthread_self();
|
||||
registered_thread_t *next = NULL, *ref;
|
||||
|
||||
psx_lock();
|
||||
for (ref = psx_tracker.root; ref; ref = next) {
|
||||
next = ref->next;
|
||||
if (ref->thread == self) {
|
||||
continue;
|
||||
}
|
||||
pthread_mutex_lock(&ref->mu);
|
||||
ref->pending = 1;
|
||||
int gone = ref->gone;
|
||||
if (!gone) {
|
||||
gone = pthread_kill(ref->thread, psx_tracker.psx_sig) != 0;
|
||||
}
|
||||
pthread_mutex_unlock(&ref->mu);
|
||||
if (!gone) {
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* need to remove invalid thread id from linked list
|
||||
*/
|
||||
psx_do_unregister(ref);
|
||||
}
|
||||
psx_unlock();
|
||||
|
||||
int mismatch = 0;
|
||||
for (;;) {
|
||||
int waiting = 0;
|
||||
psx_lock();
|
||||
for (ref = psx_tracker.root; ref; ref = next) {
|
||||
next = ref->next;
|
||||
if (ref->thread == self) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&ref->mu);
|
||||
int pending = ref->pending;
|
||||
int gone = ref->gone;
|
||||
if (!gone) {
|
||||
if (pending) {
|
||||
gone = (pthread_kill(ref->thread, 0) != 0);
|
||||
} else {
|
||||
mismatch |= (ref->retval != ret);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&ref->mu);
|
||||
if (!gone) {
|
||||
waiting += pending;
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* need to remove invalid thread id from linked list
|
||||
*/
|
||||
psx_do_unregister(ref);
|
||||
}
|
||||
psx_unlock();
|
||||
if (!waiting) {
|
||||
break;
|
||||
}
|
||||
sched_yield();
|
||||
}
|
||||
|
||||
psx_tracker.cmd.active = 0;
|
||||
if (mismatch) {
|
||||
psx_lock();
|
||||
switch (psx_tracker.sensitivity) {
|
||||
case PSX_IGNORE:
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "psx_syscall result differs.\n");
|
||||
if (psx_tracker.cmd.six) {
|
||||
fprintf(stderr, "trap:%ld a123456=[%ld,%ld,%ld,%ld,%ld,%ld]\n",
|
||||
psx_tracker.cmd.syscall_nr,
|
||||
psx_tracker.cmd.arg1,
|
||||
psx_tracker.cmd.arg2,
|
||||
psx_tracker.cmd.arg3,
|
||||
psx_tracker.cmd.arg4,
|
||||
psx_tracker.cmd.arg5,
|
||||
psx_tracker.cmd.arg6);
|
||||
} else {
|
||||
fprintf(stderr, "trap:%ld a123=[%ld,%ld,%ld]\n",
|
||||
psx_tracker.cmd.syscall_nr,
|
||||
psx_tracker.cmd.arg1,
|
||||
psx_tracker.cmd.arg2,
|
||||
psx_tracker.cmd.arg3);
|
||||
}
|
||||
fprintf(stderr, "results:");
|
||||
for (ref = psx_tracker.root; ref; ref = next) {
|
||||
next = ref->next;
|
||||
if (ref->thread == self) {
|
||||
continue;
|
||||
}
|
||||
if (ret != ref->retval) {
|
||||
fprintf(stderr, " %d={%ld}", ref->tid, ref->retval);
|
||||
}
|
||||
}
|
||||
fprintf(stderr, " wanted={%ld}\n", ret);
|
||||
if (psx_tracker.sensitivity == PSX_WARNING) {
|
||||
break;
|
||||
}
|
||||
pthread_kill(self, SIGSYS);
|
||||
}
|
||||
psx_unlock();
|
||||
}
|
||||
errno = restore_errno;
|
||||
psx_new_state(_PSX_SYSCALL, _PSX_IDLE);
|
||||
|
||||
defer:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* _psx_cleanup its called when the program exits. It is used to free
|
||||
* any memory used by the thread tracker.
|
||||
*/
|
||||
static void _psx_cleanup(void) {
|
||||
registered_thread_t *ref, *next;
|
||||
|
||||
/*
|
||||
* We enter the exiting state. Unlike exiting a single thread we
|
||||
* never leave this state since this cleanup is only done at
|
||||
* program exit.
|
||||
*/
|
||||
psx_lock();
|
||||
while (psx_tracker.state != _PSX_IDLE && psx_tracker.state != _PSX_INFORK) {
|
||||
pthread_cond_wait(&psx_tracker.cond, &psx_tracker.state_mu);
|
||||
}
|
||||
psx_tracker.state = _PSX_EXITING;
|
||||
psx_unlock();
|
||||
|
||||
for (ref = psx_tracker.root; ref; ref = next) {
|
||||
next = ref->next;
|
||||
psx_do_unregister(ref);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Change the PSX sensitivity level. If the threads appear to have
|
||||
* diverged in behavior, this can cause the library to notify the
|
||||
* user.
|
||||
*/
|
||||
int psx_set_sensitivity(psx_sensitivity_t level) {
|
||||
if (level < PSX_IGNORE || level > PSX_ERROR) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
psx_lock();
|
||||
psx_tracker.sensitivity = level;
|
||||
psx_unlock();
|
||||
return 0;
|
||||
}
|
||||
35
vendor/kernel.org/pub/linux/libs/security/libcap/psx/psx.go
generated
vendored
Normal file
35
vendor/kernel.org/pub/linux/libs/security/libcap/psx/psx.go
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
// +build linux,!cgo
|
||||
// +build go1.16
|
||||
|
||||
package psx // import "kernel.org/pub/linux/libs/security/libcap/psx"
|
||||
|
||||
import "syscall"
|
||||
|
||||
// Documentation for these functions are provided in the psx_cgo.go
|
||||
// file.
|
||||
|
||||
//go:uintptrescapes
|
||||
|
||||
// Syscall3 performs a 3 argument syscall. Syscall3 differs from
|
||||
// syscall.[Raw]Syscall() insofar as it is simultaneously executed on
|
||||
// every thread of the combined Go and CGo runtimes. It works
|
||||
// differently depending on whether CGO_ENABLED is 1 or 0 at compile
|
||||
// time.
|
||||
//
|
||||
// If CGO_ENABLED=1 it uses the libpsx function C.psx_syscall3().
|
||||
//
|
||||
// If CGO_ENABLED=0 it redirects to the go1.16+
|
||||
// syscall.AllThreadsSyscall() function.
|
||||
func Syscall3(syscallnr, arg1, arg2, arg3 uintptr) (uintptr, uintptr, syscall.Errno) {
|
||||
return syscall.AllThreadsSyscall(syscallnr, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
//go:uintptrescapes
|
||||
|
||||
// Syscall6 performs a 6 argument syscall on every thread of the
|
||||
// combined Go and CGo runtimes. Other than the number of syscall
|
||||
// arguments, its behavior is identical to that of Syscall3() - see
|
||||
// above for the full documentation.
|
||||
func Syscall6(syscallnr, arg1, arg2, arg3, arg4, arg5, arg6 uintptr) (uintptr, uintptr, syscall.Errno) {
|
||||
return syscall.AllThreadsSyscall6(syscallnr, arg1, arg2, arg3, arg4, arg5, arg6)
|
||||
}
|
||||
91
vendor/kernel.org/pub/linux/libs/security/libcap/psx/psx_cgo.go
generated
vendored
Normal file
91
vendor/kernel.org/pub/linux/libs/security/libcap/psx/psx_cgo.go
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
// +build linux,cgo
|
||||
|
||||
package psx // import "kernel.org/pub/linux/libs/security/libcap/psx"
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"sync"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// #cgo LDFLAGS: -lpthread -Wl,-wrap,pthread_create
|
||||
//
|
||||
// #include <errno.h>
|
||||
// #include "psx_syscall.h"
|
||||
//
|
||||
// long __errno_too(long set_errno) {
|
||||
// long v = errno;
|
||||
// if (set_errno >= 0) {
|
||||
// errno = set_errno;
|
||||
// }
|
||||
// return v;
|
||||
// }
|
||||
import "C"
|
||||
|
||||
// setErrno returns the current C.errno value and, if v >= 0, sets the
|
||||
// CGo errno for a random pthread to value v. If you want some
|
||||
// consistency, this needs to be called from runtime.LockOSThread()
|
||||
// code. This function is only defined for testing purposes. The psx.c
|
||||
// code should properly handle the case that a non-zero errno is saved
|
||||
// and restored independently of what these Syscall[36]() functions
|
||||
// observe.
|
||||
func setErrno(v int) int {
|
||||
return int(C.__errno_too(C.long(v)))
|
||||
}
|
||||
|
||||
var makeFatal sync.Once
|
||||
|
||||
// forceFatal configures the psx_syscall mechanism to PSX_ERROR.
|
||||
func forceFatal() {
|
||||
makeFatal.Do(func() {
|
||||
C.psx_set_sensitivity(C.PSX_ERROR)
|
||||
})
|
||||
}
|
||||
|
||||
//go:uintptrescapes
|
||||
|
||||
// Syscall3 performs a 3 argument syscall. Syscall3 differs from
|
||||
// syscall.[Raw]Syscall() insofar as it is simultaneously executed on
|
||||
// every thread of the combined Go and CGo runtimes. It works
|
||||
// differently depending on whether CGO_ENABLED is 1 or 0 at compile
|
||||
// time.
|
||||
//
|
||||
// If CGO_ENABLED=1 it uses the libpsx function C.psx_syscall3().
|
||||
//
|
||||
// If CGO_ENABLED=0 it redirects to the go1.16+
|
||||
// syscall.AllThreadsSyscall() function.
|
||||
func Syscall3(syscallnr, arg1, arg2, arg3 uintptr) (uintptr, uintptr, syscall.Errno) {
|
||||
forceFatal()
|
||||
// We lock to the OSThread here because we may need errno to
|
||||
// be the one for this thread.
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
v := C.psx_syscall3(C.long(syscallnr), C.long(arg1), C.long(arg2), C.long(arg3))
|
||||
var errno syscall.Errno
|
||||
if v < 0 {
|
||||
errno = syscall.Errno(C.__errno_too(-1))
|
||||
}
|
||||
return uintptr(v), uintptr(v), errno
|
||||
}
|
||||
|
||||
//go:uintptrescapes
|
||||
|
||||
// Syscall6 performs a 6 argument syscall on every thread of the
|
||||
// combined Go and CGo runtimes. Other than the number of syscall
|
||||
// arguments, its behavior is identical to that of Syscall3() - see
|
||||
// above for the full documentation.
|
||||
func Syscall6(syscallnr, arg1, arg2, arg3, arg4, arg5, arg6 uintptr) (uintptr, uintptr, syscall.Errno) {
|
||||
forceFatal()
|
||||
// We lock to the OSThread here because we may need errno to
|
||||
// be the one for this thread.
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
v := C.psx_syscall6(C.long(syscallnr), C.long(arg1), C.long(arg2), C.long(arg3), C.long(arg4), C.long(arg5), C.long(arg6))
|
||||
var errno syscall.Errno
|
||||
if v < 0 {
|
||||
errno = syscall.Errno(C.__errno_too(-1))
|
||||
}
|
||||
return uintptr(v), uintptr(v), errno
|
||||
}
|
||||
95
vendor/kernel.org/pub/linux/libs/security/libcap/psx/psx_syscall.h
generated
vendored
Normal file
95
vendor/kernel.org/pub/linux/libs/security/libcap/psx/psx_syscall.h
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Andrew G. Morgan <morgan@kernel.org>
|
||||
*
|
||||
* This header, and the -lpsx library, provide a number of things to
|
||||
* support POSIX semantics for syscalls associated with the pthread
|
||||
* library. Linking this code is tricky and is done as follows:
|
||||
*
|
||||
* ld ... -lpsx -lpthread --wrap=pthread_create
|
||||
* or, gcc ... -lpsx -lpthread -Wl,-wrap,pthread_create
|
||||
*
|
||||
* glibc provides a subset of this functionality natively through the
|
||||
* nptl:setxid mechanism and could implement psx_syscall() directly
|
||||
* using that style of functionality but, as of 2019-11-30, the setxid
|
||||
* mechanism is limited to 9 specific set*() syscalls that do not
|
||||
* support the syscall6 API (needed for prctl functions and the ambient
|
||||
* capabilities set for example).
|
||||
*/
|
||||
|
||||
#ifndef _SYS_PSX_SYSCALL_H
|
||||
#define _SYS_PSX_SYSCALL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
/*
|
||||
* psx_syscall performs the specified syscall on all psx registered
|
||||
* threads. The mechanism by which this occurs is much less efficient
|
||||
* than a standard system call on Linux, so it should only be used
|
||||
* when POSIX semantics are required to change process relevant
|
||||
* security state.
|
||||
*
|
||||
* Glibc has native support for POSIX semantics on setgroups() and the
|
||||
* 8 set*[gu]id() functions. So, there is no need to use psx_syscall()
|
||||
* for these calls. This call exists for all the other system calls
|
||||
* that need to maintain parity on all pthreads of a program.
|
||||
*
|
||||
* Some macrology is used to allow the caller to provide only as many
|
||||
* arguments as needed, thus psx_syscall() cannot be used as a
|
||||
* function pointer. For those situations, we define psx_syscall3()
|
||||
* and psx_syscall6().
|
||||
*/
|
||||
#define psx_syscall(syscall_nr, ...) \
|
||||
__psx_syscall(syscall_nr, __VA_ARGS__, (long int) 6, (long int) 5, \
|
||||
(long int) 4, (long int) 3, (long int) 2, \
|
||||
(long int) 1, (long int) 0)
|
||||
long int __psx_syscall(long int syscall_nr, ...);
|
||||
long int psx_syscall3(long int syscall_nr,
|
||||
long int arg1, long int arg2, long int arg3);
|
||||
long int psx_syscall6(long int syscall_nr,
|
||||
long int arg1, long int arg2, long int arg3,
|
||||
long int arg4, long int arg5, long int arg6);
|
||||
|
||||
/*
|
||||
* This function should be used by systems to obtain pointers to the
|
||||
* two syscall functions provided by the PSX library. A linkage trick
|
||||
* is to define this function as weak in a library that can optionally
|
||||
* use libpsx and then, should the caller link -lpsx, that library can
|
||||
* implicitly use these POSIX semantics syscalls. See libcap for an
|
||||
* example of this usage.
|
||||
*/
|
||||
void psx_load_syscalls(long int (**syscall_fn)(long int,
|
||||
long int, long int, long int),
|
||||
long int (**syscall6_fn)(long int,
|
||||
long int, long int, long int,
|
||||
long int, long int, long int));
|
||||
|
||||
/*
|
||||
* psx_sensitivity_t holds the level of paranoia for non-POSIX syscall
|
||||
* behavior. The default is PSX_IGNORE: which is best effort - no
|
||||
* enforcement; PSX_WARNING will dump to stderr a warning when a
|
||||
* syscall's results differ; PSX_ERROR will dump info as per
|
||||
* PSX_WARNING and generate a SIGSYS. The current mode can be set with
|
||||
* psx_set_sensitivity().
|
||||
*/
|
||||
typedef enum {
|
||||
PSX_IGNORE = 0,
|
||||
PSX_WARNING = 1,
|
||||
PSX_ERROR = 2,
|
||||
} psx_sensitivity_t;
|
||||
|
||||
/*
|
||||
* psx_set_sensitivity sets the current sensitivity of the PSX
|
||||
* mechanism. The function returns 0 on success and -1 if the
|
||||
* requested level is invalid.
|
||||
*/
|
||||
int psx_set_sensitivity(psx_sensitivity_t level);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SYS_PSX_SYSCALL_H */
|
||||
6
vendor/modules.txt
vendored
6
vendor/modules.txt
vendored
@@ -988,3 +988,9 @@ google.golang.org/protobuf/types/pluginpb
|
||||
# gopkg.in/yaml.v3 v3.0.1
|
||||
## explicit
|
||||
gopkg.in/yaml.v3
|
||||
# kernel.org/pub/linux/libs/security/libcap/cap v1.2.67
|
||||
## explicit; go 1.11
|
||||
kernel.org/pub/linux/libs/security/libcap/cap
|
||||
# kernel.org/pub/linux/libs/security/libcap/psx v1.2.67
|
||||
## explicit; go 1.11
|
||||
kernel.org/pub/linux/libs/security/libcap/psx
|
||||
|
||||
Reference in New Issue
Block a user