* Add support for ssh commit signing * Split out ssh verification to separate file * Show ssh key fingerprint on commit page * Update sshsig lib * Make sure we verify against correct namespace * Add ssh public key verification via ssh signatures When adding a public ssh key also validate that this user actually owns the key by signing a token with the private key. * Remove some gpg references and make verify key optional * Fix spaces indentation * Update options/locale/locale_en-US.ini Co-authored-by: Gusted <williamzijl7@hotmail.com> * Update templates/user/settings/keys_ssh.tmpl Co-authored-by: Gusted <williamzijl7@hotmail.com> * Update options/locale/locale_en-US.ini Co-authored-by: Gusted <williamzijl7@hotmail.com> * Update options/locale/locale_en-US.ini Co-authored-by: Gusted <williamzijl7@hotmail.com> * Update models/ssh_key_commit_verification.go Co-authored-by: Gusted <williamzijl7@hotmail.com> * Reword ssh/gpg_key_success message * Change Badsignature to NoKeyFound * Add sign/verify tests * Fix upstream api changes to user_model User * Match exact on SSH signature * Fix code review remarks Co-authored-by: Gusted <williamzijl7@hotmail.com> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Co-authored-by: techknowlogick <techknowlogick@gitea.io>tags/v1.16.0-rc1
@@ -11,6 +11,7 @@ require ( | |||
gitea.com/go-chi/captcha v0.0.0-20211013065431-70641c1a35d5 | |||
gitea.com/go-chi/session v0.0.0-20211013065435-7d334f340c09 | |||
gitea.com/lunny/levelqueue v0.4.1 | |||
github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121 | |||
github.com/Microsoft/go-winio v0.5.0 // indirect | |||
github.com/NYTimes/gziphandler v1.1.1 | |||
github.com/ProtonMail/go-crypto v0.0.0-20210705153151-cc34b1f6908b // indirect | |||
@@ -121,10 +122,10 @@ require ( | |||
go.uber.org/atomic v1.9.0 // indirect | |||
go.uber.org/multierr v1.7.0 // indirect | |||
go.uber.org/zap v1.19.0 // indirect | |||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 | |||
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d | |||
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 | |||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 | |||
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 | |||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf | |||
golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1 | |||
golang.org/x/text v0.3.7 | |||
golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6 // indirect | |||
golang.org/x/tools v0.1.0 |
@@ -54,6 +54,8 @@ gitea.com/lunny/levelqueue v0.4.1 h1:RZ+AFx5gBsZuyqCvofhAkPQ9uaVDPJnsULoJZIYaJNw | |||
gitea.com/lunny/levelqueue v0.4.1/go.mod h1:HBqmLbz56JWpfEGG0prskAV97ATNRoj5LDmPicD22hU= | |||
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s= | |||
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU= | |||
github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121 h1:r3qt8PCHnfjOv9PN3H+XXKmDA1dfFMIN1AislhlA/ps= | |||
github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121/go.mod h1:Ock8XgA7pvULhIaHGAk/cDnRfNrF9Jey81nPcc403iU= | |||
github.com/6543/go-version v1.3.1 h1:HvOp+Telns7HWJ2Xo/05YXQSB2bE0WmVgbHqwMPZT4U= | |||
github.com/6543/go-version v1.3.1/go.mod h1:oqFAHCwtLVUTLdhQmVZWYvaHXTdsbB4SY85at64SQEo= | |||
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c h1:/IBSNwUN8+eKzUzbJPqhK839ygXJ82sde8x3ogr6R28= | |||
@@ -1261,6 +1263,8 @@ golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5 | |||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= | |||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= | |||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= | |||
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 h1:/pEO3GD/ABYAjuakUS6xSEmmlyVS4kxBNkeA9tLJiTI= | |||
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= | |||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= | |||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= | |||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= | |||
@@ -1355,6 +1359,8 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx | |||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= | |||
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d h1:LO7XpTYMwTqxjLcGWPijK3vRXg1aWdlNOVOHRq45d7c= | |||
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= | |||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= | |||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= | |||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= | |||
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= | |||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= | |||
@@ -1462,6 +1468,8 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc | |||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | |||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k= | |||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | |||
golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1 h1:kwrAHlwJ0DUBZwQ238v+Uod/3eZ8B2K5rYsUHBQvzmI= | |||
golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | |||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= | |||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= | |||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= |
@@ -246,3 +246,19 @@ func IsErrDeployKeyNameAlreadyUsed(err error) bool { | |||
func (err ErrDeployKeyNameAlreadyUsed) Error() string { | |||
return fmt.Sprintf("public key with name already exists [repo_id: %d, name: %s]", err.RepoID, err.Name) | |||
} | |||
// ErrSSHInvalidTokenSignature represents a "ErrSSHInvalidTokenSignature" kind of error. | |||
type ErrSSHInvalidTokenSignature struct { | |||
Wrapped error | |||
Fingerprint string | |||
} | |||
// IsErrSSHInvalidTokenSignature checks if an error is a ErrSSHInvalidTokenSignature. | |||
func IsErrSSHInvalidTokenSignature(err error) bool { | |||
_, ok := err.(ErrSSHInvalidTokenSignature) | |||
return ok | |||
} | |||
func (err ErrSSHInvalidTokenSignature) Error() string { | |||
return "the provided signature does not sign the token with the provided key" | |||
} |
@@ -49,6 +49,7 @@ type CommitVerification struct { | |||
CommittingUser *user_model.User | |||
SigningEmail string | |||
SigningKey *GPGKey | |||
SigningSSHKey *PublicKey | |||
TrustStatus string | |||
} | |||
@@ -122,6 +123,11 @@ func ParseCommitWithSignature(c *git.Commit) *CommitVerification { | |||
} | |||
} | |||
// If this a SSH signature handle it differently | |||
if strings.HasPrefix(c.Signature.Signature, "-----BEGIN SSH SIGNATURE-----") { | |||
return ParseCommitWithSSHSignature(c, committer) | |||
} | |||
// Parsing signature | |||
sig, err := extractSignature(c.Signature.Signature) | |||
if err != nil { // Skipping failed to extract sign | |||
@@ -487,28 +493,31 @@ func CalculateTrustStatus(verification *CommitVerification, repoTrustModel repo_ | |||
return | |||
} | |||
var isMember bool | |||
if keyMap != nil { | |||
var has bool | |||
isMember, has = (*keyMap)[verification.SigningKey.KeyID] | |||
if !has { | |||
// Check we actually have a GPG SigningKey | |||
if verification.SigningKey != nil { | |||
var isMember bool | |||
if keyMap != nil { | |||
var has bool | |||
isMember, has = (*keyMap)[verification.SigningKey.KeyID] | |||
if !has { | |||
isMember, err = isCodeReader(verification.SigningUser) | |||
(*keyMap)[verification.SigningKey.KeyID] = isMember | |||
} | |||
} else { | |||
isMember, err = isCodeReader(verification.SigningUser) | |||
(*keyMap)[verification.SigningKey.KeyID] = isMember | |||
} | |||
} else { | |||
isMember, err = isCodeReader(verification.SigningUser) | |||
} | |||
if !isMember { | |||
verification.TrustStatus = "untrusted" | |||
if verification.CommittingUser.ID != verification.SigningUser.ID { | |||
// The committing user and the signing user are not the same | |||
// This should be marked as questionable unless the signing user is a collaborator/team member etc. | |||
if !isMember { | |||
verification.TrustStatus = "untrusted" | |||
if verification.CommittingUser.ID != verification.SigningUser.ID { | |||
// The committing user and the signing user are not the same | |||
// This should be marked as questionable unless the signing user is a collaborator/team member etc. | |||
verification.TrustStatus = "unmatched" | |||
} | |||
} else if repoTrustModel == repo_model.CollaboratorCommitterTrustModel && verification.CommittingUser.ID != verification.SigningUser.ID { | |||
// The committing user and the signing user are not the same and our trustmodel states that they must match | |||
verification.TrustStatus = "unmatched" | |||
} | |||
} else if repoTrustModel == repo_model.CollaboratorCommitterTrustModel && verification.CommittingUser.ID != verification.SigningUser.ID { | |||
// The committing user and the signing user are not the same and our trustmodel states that they must match | |||
verification.TrustStatus = "unmatched" | |||
} | |||
return |
@@ -50,6 +50,7 @@ type PublicKey struct { | |||
UpdatedUnix timeutil.TimeStamp `xorm:"updated"` | |||
HasRecentActivity bool `xorm:"-"` | |||
HasUsed bool `xorm:"-"` | |||
Verified bool `xorm:"NOT NULL DEFAULT false"` | |||
} | |||
func init() { |
@@ -0,0 +1,77 @@ | |||
// Copyright 2021 The Gitea Authors. All rights reserved. | |||
// Use of this source code is governed by a MIT-style | |||
// license that can be found in the LICENSE file. | |||
package asymkey | |||
import ( | |||
"bytes" | |||
"fmt" | |||
"strings" | |||
"code.gitea.io/gitea/models/db" | |||
user_model "code.gitea.io/gitea/models/user" | |||
"code.gitea.io/gitea/modules/git" | |||
"code.gitea.io/gitea/modules/log" | |||
"github.com/42wim/sshsig" | |||
) | |||
// ParseCommitWithSSHSignature check if signature is good against keystore. | |||
func ParseCommitWithSSHSignature(c *git.Commit, committer *user_model.User) *CommitVerification { | |||
// Now try to associate the signature with the committer, if present | |||
if committer.ID != 0 { | |||
keys, err := ListPublicKeys(committer.ID, db.ListOptions{}) | |||
if err != nil { // Skipping failed to get ssh keys of user | |||
log.Error("ListPublicKeys: %v", err) | |||
return &CommitVerification{ | |||
CommittingUser: committer, | |||
Verified: false, | |||
Reason: "gpg.error.failed_retrieval_gpg_keys", | |||
} | |||
} | |||
committerEmailAddresses, err := user_model.GetEmailAddresses(committer.ID) | |||
if err != nil { | |||
log.Error("GetEmailAddresses: %v", err) | |||
} | |||
activated := false | |||
for _, e := range committerEmailAddresses { | |||
if e.IsActivated && strings.EqualFold(e.Email, c.Committer.Email) { | |||
activated = true | |||
break | |||
} | |||
} | |||
for _, k := range keys { | |||
if k.Verified && activated { | |||
commitVerification := verifySSHCommitVerification(c.Signature.Signature, c.Signature.Payload, k, committer, committer, c.Committer.Email) | |||
if commitVerification != nil { | |||
return commitVerification | |||
} | |||
} | |||
} | |||
} | |||
return &CommitVerification{ | |||
CommittingUser: committer, | |||
Verified: false, | |||
Reason: NoKeyFound, | |||
} | |||
} | |||
func verifySSHCommitVerification(sig, payload string, k *PublicKey, committer, signer *user_model.User, email string) *CommitVerification { | |||
if err := sshsig.Verify(bytes.NewBuffer([]byte(payload)), []byte(sig), []byte(k.Content), "git"); err != nil { | |||
return nil | |||
} | |||
return &CommitVerification{ // Everything is ok | |||
CommittingUser: committer, | |||
Verified: true, | |||
Reason: fmt.Sprintf("%s / %s", signer.Name, k.Fingerprint), | |||
SigningUser: signer, | |||
SigningSSHKey: k, | |||
SigningEmail: email, | |||
} | |||
} |
@@ -6,11 +6,16 @@ | |||
package asymkey | |||
import ( | |||
"bytes" | |||
"io/ioutil" | |||
"os/exec" | |||
"path/filepath" | |||
"strings" | |||
"testing" | |||
"code.gitea.io/gitea/modules/setting" | |||
"github.com/42wim/sshsig" | |||
"github.com/stretchr/testify/assert" | |||
) | |||
@@ -185,3 +190,309 @@ func Test_calcFingerprint(t *testing.T) { | |||
}) | |||
} | |||
} | |||
var ( | |||
// Generated with "ssh-keygen -C test@rekor.dev -f id_rsa" | |||
sshPrivateKey = `-----BEGIN OPENSSH PRIVATE KEY----- | |||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn | |||
NhAAAAAwEAAQAAAYEA16H5ImoRO7mr41r8Z8JFBdu6jIM+6XU8M0r9F81RuhLYqzr9zw1n | |||
LeGCqFxPXNBKm8ZyH2BCsBHsbXbwe85IMHM3SUh8X/9fI0Lpi5/xbqAproFUpNR+UJYv6s | |||
8AaWk5zpN1rmpBrqGFJfGQKJCioDiiwNGmSdVkUNmQmYIANxJMDWYmNe8vUOh6nYEHB+lz | |||
fGgDAAzVSXTACW994UkSY47AD05swU4rIT/JWA6BkUrEhO//F0QQhFeROCPJiPRhJXGcFf | |||
9SicffJqR/ELzM1zNYnRXMD0bbdTUwDrIcIFFNBbtcfJVOUUCGumSlt+qjUC7y8cvwbHAu | |||
wf5nS6baA7P6LfTYplF2XIAkdWtkN6O1ouoyIHICXMlddDW2vNaJeEXTeKjx51WSM7qPnQ | |||
ZKsBtwjLQeEY/OPkIvu88lNNYSD63qMUA12msohjwVFCIgJVvYLIrkViczZ7t3L7lgy1X0 | |||
CJI4e1roOfM/r9jTieyDHchEYpZYcw3L1R2qtePlAAAFiHdJQKl3SUCpAAAAB3NzaC1yc2 | |||
EAAAGBANeh+SJqETu5q+Na/GfCRQXbuoyDPul1PDNK/RfNUboS2Ks6/c8NZy3hgqhcT1zQ | |||
SpvGch9gQrAR7G128HvOSDBzN0lIfF//XyNC6Yuf8W6gKa6BVKTUflCWL+rPAGlpOc6Tda | |||
5qQa6hhSXxkCiQoqA4osDRpknVZFDZkJmCADcSTA1mJjXvL1Doep2BBwfpc3xoAwAM1Ul0 | |||
wAlvfeFJEmOOwA9ObMFOKyE/yVgOgZFKxITv/xdEEIRXkTgjyYj0YSVxnBX/UonH3yakfx | |||
C8zNczWJ0VzA9G23U1MA6yHCBRTQW7XHyVTlFAhrpkpbfqo1Au8vHL8GxwLsH+Z0um2gOz | |||
+i302KZRdlyAJHVrZDejtaLqMiByAlzJXXQ1trzWiXhF03io8edVkjO6j50GSrAbcIy0Hh | |||
GPzj5CL7vPJTTWEg+t6jFANdprKIY8FRQiICVb2CyK5FYnM2e7dy+5YMtV9AiSOHta6Dnz | |||
P6/Y04nsgx3IRGKWWHMNy9UdqrXj5QAAAAMBAAEAAAGAJyaOcFQnuttUPRxY9ZHNLGofrc | |||
Fqm8KgYoO7/iVWMF2Zn0U/rec2E5t9OIpCEozy7uOR9uZoVUV70sgkk6X5b2qL4C9b/aYF | |||
JQbSFnq8wCQuTTPIJYE7SfBq1Mwuu/TR/RLC7B74u/cxkJkSXnscO9Dso+ussH0hEJjf6y | |||
8yUM1up4Qjbel2gs8i7BPwLdySDkVoPgsWcpbTAyOODGhTAWZ6soy/rD1AEXJeYTGJDtMv | |||
aR+WBihig1TO1g2RWt9bqqiG7PIlljd3ZsjSSU5y3t6ZN/8j5keKD032EtxbZB0WFD3Ar4 | |||
FbFwlW+urb2MQ0JyNKOio3nhdjolXYkJa+C6LXdaaml/8BhMR1eLoMe8nS45w76o8mdJWX | |||
wsirB8tvjCLY0QBXgGv/1DTsKu/wEFCW2/Y0e50gF7pHAlYFNmKDcgI9OyORRYhFbV4D82 | |||
fI8JLQ42ZJkS/0t6xQma8WC88pbHGEuVSB6CE/p25fyYRX+UPTQ79tWFvLV4kNQAaBAAAA | |||
wEvyd6H8ePyBXImg8JzGxthufB0eXSfZBrabjf6e6bR2ivpJsHmB64gbMkV6MFV7EWYX1B | |||
wYPQxf4gA2Ez7aJvDtfE7uV6pa0WJS3hW1+be8DHEftmLSbTy/TEvDujNb2gqoi7uWQXWJ | |||
yYWZlYO65r1a6HucryQ8+78fTuTRbZALO43vNGz0oXH1hPSddkcbNAhZTsD0rQKNwqVTe5 | |||
wl+6Cduy/CQwjHLYrY73MyWy1Vh1LXhAdGMPnWZwGIu/dnkgAAAMEA9KuaoGnfnLQkrjeR | |||
tO4RCRS2quNRvm4L6i4vHgTDsYtoSlR1ujge7SGOOmIPS4XVjZN5zzCOA7+EDVnuz3WWmx | |||
hmkjpG1YxzmJGaWoYdeo3a6UgJtisfMp8eUKqjJT1mhsCliCWtaOQNRoQieDQmgwZzSX/v | |||
ZiGsOIKa6cR37eKvOJSjVrHsAUzdtYrmi8P2gvAUFWyzXobAtpzHcWrwWkOEIm04G0OGXb | |||
J46hfIX3f45E5EKXvFzexGgVOD2I7hAAAAwQDhniYAizfW9YfG7UJWekkl42xMP7Cb8b0W | |||
SindSIuE8bFTukV1yxbmNZp/f0pKvn/DWc2n0I0bwSGZpy8BCY46RKKB2DYQavY/tGcC1N | |||
AynKuvbtWs11A0mTXmq3WwHVXQDozMwJ2nnHpm0UHspPuHqkYpurlP+xoFsocaQ9QwITyp | |||
lL4qHtXBEzaT8okkcGZBHdSx3gk4TzCsEDOP7ZZPLq42lpKMK10zFPTMd0maXtJDYKU/b4 | |||
gAATvvPoylyYUAAAAOdGVzdEByZWtvci5kZXYBAgMEBQ== | |||
-----END OPENSSH PRIVATE KEY----- | |||
` | |||
sshPublicKey = `ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDXofkiahE7uavjWvxnwkUF27qMgz7pdTwzSv0XzVG6EtirOv3PDWct4YKoXE9c0EqbxnIfYEKwEextdvB7zkgwczdJSHxf/18jQumLn/FuoCmugVSk1H5Qli/qzwBpaTnOk3WuakGuoYUl8ZAokKKgOKLA0aZJ1WRQ2ZCZggA3EkwNZiY17y9Q6HqdgQcH6XN8aAMADNVJdMAJb33hSRJjjsAPTmzBTishP8lYDoGRSsSE7/8XRBCEV5E4I8mI9GElcZwV/1KJx98mpH8QvMzXM1idFcwPRtt1NTAOshwgUU0Fu1x8lU5RQIa6ZKW36qNQLvLxy/BscC7B/mdLptoDs/ot9NimUXZcgCR1a2Q3o7Wi6jIgcgJcyV10Nba81ol4RdN4qPHnVZIzuo+dBkqwG3CMtB4Rj84+Qi+7zyU01hIPreoxQDXaayiGPBUUIiAlW9gsiuRWJzNnu3cvuWDLVfQIkjh7Wug58z+v2NOJ7IMdyERillhzDcvVHaq14+U= test@rekor.dev | |||
` | |||
// Generated with "ssh-keygen -C other-test@rekor.dev -f id_rsa" | |||
otherSSHPrivateKey = `-----BEGIN OPENSSH PRIVATE KEY----- | |||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn | |||
NhAAAAAwEAAQAAAYEAw/WCSWC9TEvCQOwO+T68EvNa3OSIv1Y0+sT8uSvyjPyEO0+p0t8C | |||
g/zy67vOxiQpU5jN6MItjXAjMmeCm8GKMt6gk+cDoaAev/ZfjuzSL7RayExpmhBleh2X3G | |||
KLkkXF9ABFNchlTqSLOZiEjDoNpbFv16KT1sE6CqW8DjxXQkQk9JK65hLH+BxeWMNCEJVa | |||
Cma4X04aJmC7zJAi5yGeeT0SKVqMohavF90O6XiYFCQHuwXPPyHfocqgudmXnozz+6D6ax | |||
JKZMwQsNp3WKumOjlzWnxBCCB1l2jN6Rag8aJ2277iMFXRwjTL/8jaEsW4KkysDf0GjV2/ | |||
iqbr0q5b0arDYbv7CrGBR+uH0wGz/Zog1x5iZANObhZULpDrLVJidEMc27HXBb7PMsNDy7 | |||
BGYRB1yc0d0y83p8mUqvOlWSArxn1WnAZO04pAgTrclrhEh4ZXOkn2Sn82eu3DpQ8inkol | |||
Y4IfnhIfbOIeemoUNq1tOUquhow9GLRM6INieHLBAAAFkPPnA1jz5wNYAAAAB3NzaC1yc2 | |||
EAAAGBAMP1gklgvUxLwkDsDvk+vBLzWtzkiL9WNPrE/Lkr8oz8hDtPqdLfAoP88uu7zsYk | |||
KVOYzejCLY1wIzJngpvBijLeoJPnA6GgHr/2X47s0i+0WshMaZoQZXodl9xii5JFxfQART | |||
XIZU6kizmYhIw6DaWxb9eik9bBOgqlvA48V0JEJPSSuuYSx/gcXljDQhCVWgpmuF9OGiZg | |||
u8yQIuchnnk9EilajKIWrxfdDul4mBQkB7sFzz8h36HKoLnZl56M8/ug+msSSmTMELDad1 | |||
irpjo5c1p8QQggdZdozekWoPGidtu+4jBV0cI0y//I2hLFuCpMrA39Bo1dv4qm69KuW9Gq | |||
w2G7+wqxgUfrh9MBs/2aINceYmQDTm4WVC6Q6y1SYnRDHNux1wW+zzLDQ8uwRmEQdcnNHd | |||
MvN6fJlKrzpVkgK8Z9VpwGTtOKQIE63Ja4RIeGVzpJ9kp/Nnrtw6UPIp5KJWOCH54SH2zi | |||
HnpqFDatbTlKroaMPRi0TOiDYnhywQAAAAMBAAEAAAGAYycx4oEhp55Zz1HijblxnsEmQ8 | |||
kbbH1pV04fdm7HTxFis0Qu8PVIp5JxNFiWWunnQ1Z5MgI23G9WT+XST4+RpwXBCLWGv9xu | |||
UsGOPpqUC/FdUiZf9MXBIxYgRjJS3xORA1KzsnAQ2sclb2I+B1pEl4d9yQWJesvQ25xa2H | |||
Utzej/LgWkrk/ogSGRl6ZNImj/421wc0DouGyP+gUgtATt0/jT3LrlmAqUVCXVqssLYH2O | |||
r9JTuGUibBJEW2W/c0lsM0jaHa5bGAdL3nhDuF1Q6KFB87mZoNw8c2znYoTzQ3FyWtIEZI | |||
V/9oWrkS7V6242SKSR9tJoEzK0jtrKC/FZwBiI4hPcwoqY6fZbT1701i/n50xWEfEUOLVm | |||
d6VqNKyAbIaZIPN0qfZuD+xdrHuM3V6k/rgFxGl4XTrp/N4AsruiQs0nRQKNTw3fHE0zPq | |||
UTxSeMvjywRCepxhBFCNh8NHydapclHtEPEGdTVHohL3krJehstPO/IuRyKLfSVtL1AAAA | |||
wQCmGA8k+uW6mway9J3jp8mlMhhp3DCX6DAcvalbA/S5OcqMyiTM3c/HD5OJ6OYFDldcqu | |||
MPEgLRL2HfxL29LsbQSzjyOIrfp5PLJlo70P5lXS8u2QPbo4/KQJmQmsIX18LDyU2zRtNA | |||
C2WfBiHSZV+guLhmHms9S5gQYKt2T5OnY/W0tmnInx9lmFCMC+XKS1iSQ2o433IrtCPQJp | |||
IXZd59OQpO9QjJABgJIDtXxFIXt45qpXduDPJuggrhg81stOwAAADBAPX73u/CY+QUPts+ | |||
LV185Z4mZ2y+qu2ZMCAU3BnpHktGZZ1vFN1Xq9o8KdnuPZ+QJRdO8eKMWpySqrIdIbTYLm | |||
9nXmVH0uNECIEAvdU+wgKeR+BSHxCRVuTF4YSygmNadgH/z+oRWLgOblGo2ywFBoXsIAKQ | |||
paNu1MFGRUmhz67+dcpkkBUDRU9loAgBKexMo8D9vkR0YiHLOUjCrtmEZRNm0YRZt0gQhD | |||
ZSD1fOH0fZDcCVNpGP2zqAKos4EGLnkwAAAMEAy/AuLtPKA2u9oCA8e18ZnuQRAi27FBVU | |||
rU2D7bMg1eS0IakG8v0gE9K6WdYzyArY1RoKB3ZklK5VmJ1cOcWc2x3Ejc5jcJgc8cC6lZ | |||
wwjpE8HfWL1kIIYgPdcexqFc+l6MdgH6QMKU3nLg1LsM4v5FEldtk/2dmnw620xnFfstpF | |||
VxSZNdKrYfM/v9o6sRaDRqSfH1dG8BvkUxPznTAF+JDxBENcKXYECcq9f6dcl1w5IEnNTD | |||
Wry/EKQvgvOUjbAAAAFG90aGVyLXRlc3RAcmVrb3IuZGV2AQIDBAUG | |||
-----END OPENSSH PRIVATE KEY----- | |||
` | |||
otherSSHPublicKey = `ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDD9YJJYL1MS8JA7A75PrwS81rc5Ii/VjT6xPy5K/KM/IQ7T6nS3wKD/PLru87GJClTmM3owi2NcCMyZ4KbwYoy3qCT5wOhoB6/9l+O7NIvtFrITGmaEGV6HZfcYouSRcX0AEU1yGVOpIs5mISMOg2lsW/XopPWwToKpbwOPFdCRCT0krrmEsf4HF5Yw0IQlVoKZrhfThomYLvMkCLnIZ55PRIpWoyiFq8X3Q7peJgUJAe7Bc8/Id+hyqC52ZeejPP7oPprEkpkzBCw2ndYq6Y6OXNafEEIIHWXaM3pFqDxonbbvuIwVdHCNMv/yNoSxbgqTKwN/QaNXb+KpuvSrlvRqsNhu/sKsYFH64fTAbP9miDXHmJkA05uFlQukOstUmJ0QxzbsdcFvs8yw0PLsEZhEHXJzR3TLzenyZSq86VZICvGfVacBk7TikCBOtyWuESHhlc6SfZKfzZ67cOlDyKeSiVjgh+eEh9s4h56ahQ2rW05Sq6GjD0YtEzog2J4csE= other-test@rekor.dev | |||
` | |||
// Generated with ssh-keygen -C test@rekor.dev -t ed25519 -f id_ed25519 | |||
ed25519PrivateKey = `-----BEGIN OPENSSH PRIVATE KEY----- | |||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW | |||
QyNTUxOQAAACBB45zRHxPPFtabwS3Vd6Lb9vMe+tIHZj2qN5VQ+bgLfQAAAJgyRa3cMkWt | |||
3AAAAAtzc2gtZWQyNTUxOQAAACBB45zRHxPPFtabwS3Vd6Lb9vMe+tIHZj2qN5VQ+bgLfQ | |||
AAAED7y4N/DsVnRQiBZNxEWdsJ9RmbranvtQ3X9jnb6gFed0HjnNEfE88W1pvBLdV3otv2 | |||
8x760gdmPao3lVD5uAt9AAAADnRlc3RAcmVrb3IuZGV2AQIDBAUGBw== | |||
-----END OPENSSH PRIVATE KEY----- | |||
` | |||
ed25519PublicKey = `ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEHjnNEfE88W1pvBLdV3otv28x760gdmPao3lVD5uAt9 test@rekor.dev | |||
` | |||
) | |||
func TestFromOpenSSH(t *testing.T) { | |||
for _, tt := range []struct { | |||
name string | |||
pub string | |||
priv string | |||
}{ | |||
{ | |||
name: "rsa", | |||
pub: sshPublicKey, | |||
priv: sshPrivateKey, | |||
}, | |||
{ | |||
name: "ed25519", | |||
pub: ed25519PublicKey, | |||
priv: ed25519PrivateKey, | |||
}, | |||
} { | |||
if _, err := exec.LookPath("ssh-keygen"); err != nil { | |||
t.Skip("skip TestFromOpenSSH: missing ssh-keygen in PATH") | |||
} | |||
t.Run(tt.name, func(t *testing.T) { | |||
tt := tt | |||
// Test that a signature from the cli can validate here. | |||
td := t.TempDir() | |||
data := []byte("hello, ssh world") | |||
dataPath := write(t, []byte(data), td, "data") | |||
privPath := write(t, []byte(tt.priv), td, "id") | |||
write(t, []byte(tt.pub), td, "id.pub") | |||
sigPath := dataPath + ".sig" | |||
run(t, nil, "ssh-keygen", "-Y", "sign", "-n", "file", "-f", privPath, dataPath) | |||
sigBytes, err := ioutil.ReadFile(sigPath) | |||
if err != nil { | |||
t.Fatal(err) | |||
} | |||
if err := sshsig.Verify(bytes.NewReader(data), sigBytes, []byte(tt.pub), "file"); err != nil { | |||
t.Error(err) | |||
} | |||
// It should not verify if we check against another public key | |||
if err := sshsig.Verify(bytes.NewReader(data), sigBytes, []byte(otherSSHPublicKey), "file"); err == nil { | |||
t.Error("expected error with incorrect key") | |||
} | |||
// It should not verify if the data is tampered | |||
if err := sshsig.Verify(strings.NewReader("bad data"), sigBytes, []byte(sshPublicKey), "file"); err == nil { | |||
t.Error("expected error with incorrect data") | |||
} | |||
}) | |||
} | |||
} | |||
func TestToOpenSSH(t *testing.T) { | |||
for _, tt := range []struct { | |||
name string | |||
pub string | |||
priv string | |||
}{ | |||
{ | |||
name: "rsa", | |||
pub: sshPublicKey, | |||
priv: sshPrivateKey, | |||
}, | |||
{ | |||
name: "ed25519", | |||
pub: ed25519PublicKey, | |||
priv: ed25519PrivateKey, | |||
}, | |||
} { | |||
if _, err := exec.LookPath("ssh-keygen"); err != nil { | |||
t.Skip("skip TestToOpenSSH: missing ssh-keygen in PATH") | |||
} | |||
t.Run(tt.name, func(t *testing.T) { | |||
tt := tt | |||
// Test that a signature from here can validate in the CLI. | |||
td := t.TempDir() | |||
data := []byte("hello, ssh world") | |||
write(t, []byte(data), td, "data") | |||
armored, err := sshsig.Sign([]byte(tt.priv), bytes.NewReader(data), "file") | |||
if err != nil { | |||
t.Fatal(err) | |||
} | |||
sigPath := write(t, []byte(armored), td, "oursig") | |||
// Create an allowed_signers file with two keys to check against. | |||
allowedSigner := "test@rekor.dev " + tt.pub + "\n" | |||
allowedSigner += "othertest@rekor.dev " + otherSSHPublicKey + "\n" | |||
allowedSigners := write(t, []byte(allowedSigner), td, "allowed_signer") | |||
// We use the correct principal here so it should work. | |||
run(t, data, "ssh-keygen", "-Y", "verify", "-f", allowedSigners, | |||
"-I", "test@rekor.dev", "-n", "file", "-s", sigPath) | |||
// Just to be sure, check against the other public key as well. | |||
runErr(t, data, "ssh-keygen", "-Y", "verify", "-f", allowedSigners, | |||
"-I", "othertest@rekor.dev", "-n", "file", "-s", sigPath) | |||
// It should error if we run it against other data | |||
data = []byte("other data!") | |||
runErr(t, data, "ssh-keygen", "-Y", "check-novalidate", "-n", "file", "-s", sigPath) | |||
}) | |||
} | |||
} | |||
func TestRoundTrip(t *testing.T) { | |||
data := []byte("my good data to be signed!") | |||
// Create one extra signature for all the tests. | |||
otherSig, err := sshsig.Sign([]byte(otherSSHPrivateKey), bytes.NewReader(data), "file") | |||
if err != nil { | |||
t.Fatal(err) | |||
} | |||
for _, tt := range []struct { | |||
name string | |||
pub string | |||
priv string | |||
}{ | |||
{ | |||
name: "rsa", | |||
pub: sshPublicKey, | |||
priv: sshPrivateKey, | |||
}, | |||
{ | |||
name: "ed25519", | |||
pub: ed25519PublicKey, | |||
priv: ed25519PrivateKey, | |||
}, | |||
} { | |||
t.Run(tt.name, func(t *testing.T) { | |||
tt := tt | |||
sig, err := sshsig.Sign([]byte(tt.priv), bytes.NewReader(data), "file") | |||
if err != nil { | |||
t.Fatal(err) | |||
} | |||
// Check the signature against that data and public key | |||
if err := sshsig.Verify(bytes.NewReader(data), sig, []byte(tt.pub), "file"); err != nil { | |||
t.Error(err) | |||
} | |||
// Now check it against invalid data. | |||
if err := sshsig.Verify(strings.NewReader("invalid data!"), sig, []byte(tt.pub), "file"); err == nil { | |||
t.Error("expected error!") | |||
} | |||
// Now check it against the wrong key. | |||
if err := sshsig.Verify(bytes.NewReader(data), sig, []byte(otherSSHPublicKey), "file"); err == nil { | |||
t.Error("expected error!") | |||
} | |||
// Now check it against an invalid signature data. | |||
if err := sshsig.Verify(bytes.NewReader(data), []byte("invalid signature!"), []byte(tt.pub), "file"); err == nil { | |||
t.Error("expected error!") | |||
} | |||
// Once more, use the wrong signature and check it against the original (wrong public key) | |||
if err := sshsig.Verify(bytes.NewReader(data), otherSig, []byte(tt.pub), "file"); err == nil { | |||
t.Error("expected error!") | |||
} | |||
// It should work against the correct public key. | |||
if err := sshsig.Verify(bytes.NewReader(data), otherSig, []byte(otherSSHPublicKey), "file"); err != nil { | |||
t.Error(err) | |||
} | |||
}) | |||
} | |||
} | |||
func write(t *testing.T, d []byte, fp ...string) string { | |||
p := filepath.Join(fp...) | |||
if err := ioutil.WriteFile(p, d, 0o600); err != nil { | |||
t.Fatal(err) | |||
} | |||
return p | |||
} | |||
func run(t *testing.T, stdin []byte, args ...string) { | |||
t.Helper() | |||
/* #nosec */ | |||
cmd := exec.Command(args[0], args[1:]...) | |||
cmd.Stdin = bytes.NewReader(stdin) | |||
out, err := cmd.CombinedOutput() | |||
t.Logf("cmd %v: %s", cmd, string(out)) | |||
if err != nil { | |||
t.Fatal(err) | |||
} | |||
} | |||
func runErr(t *testing.T, stdin []byte, args ...string) { | |||
t.Helper() | |||
/* #nosec */ | |||
cmd := exec.Command(args[0], args[1:]...) | |||
cmd.Stdin = bytes.NewReader(stdin) | |||
out, err := cmd.CombinedOutput() | |||
t.Logf("cmd %v: %s", cmd, string(out)) | |||
if err == nil { | |||
t.Fatal("expected error") | |||
} | |||
} |
@@ -0,0 +1,49 @@ | |||
// Copyright 2021 The Gitea Authors. All rights reserved. | |||
// Use of this source code is governed by a MIT-style | |||
// license that can be found in the LICENSE file. | |||
package asymkey | |||
import ( | |||
"bytes" | |||
"code.gitea.io/gitea/models/db" | |||
"code.gitea.io/gitea/modules/log" | |||
"github.com/42wim/sshsig" | |||
) | |||
// VerifySSHKey marks a SSH key as verified | |||
func VerifySSHKey(ownerID int64, fingerprint, token, signature string) (string, error) { | |||
ctx, committer, err := db.TxContext() | |||
if err != nil { | |||
return "", err | |||
} | |||
defer committer.Close() | |||
key := new(PublicKey) | |||
has, err := db.GetEngine(ctx).Where("owner_id = ? AND fingerprint = ?", ownerID, fingerprint).Get(key) | |||
if err != nil { | |||
return "", err | |||
} else if !has { | |||
return "", ErrKeyNotExist{} | |||
} | |||
if err := sshsig.Verify(bytes.NewBuffer([]byte(token)), []byte(signature), []byte(key.Content), "gitea"); err != nil { | |||
log.Error("Unable to validate token signature. Error: %v", err) | |||
return "", ErrSSHInvalidTokenSignature{ | |||
Fingerprint: key.Fingerprint, | |||
} | |||
} | |||
key.Verified = true | |||
if _, err := db.GetEngine(ctx).ID(key.ID).Cols("verified").Update(key); err != nil { | |||
return "", err | |||
} | |||
if err := committer.Commit(); err != nil { | |||
return "", err | |||
} | |||
return key.Fingerprint, nil | |||
} |
@@ -361,6 +361,8 @@ var migrations = []Migration{ | |||
NewMigration("Create key/value table for user settings", createUserSettingsTable), | |||
// v203 -> v204 | |||
NewMigration("Add Sorting to ProjectIssue table", addProjectIssueSorting), | |||
// v204 -> v205 | |||
NewMigration("Add key is verified to ssh key", addSSHKeyIsVerified), | |||
} | |||
// GetCurrentDBVersion returns the current db version |
@@ -21,5 +21,4 @@ func createUserSettingsTable(x *xorm.Engine) error { | |||
return fmt.Errorf("sync2: %v", err) | |||
} | |||
return nil | |||
} |
@@ -0,0 +1,15 @@ | |||
// Copyright 2021 The Gitea Authors. All rights reserved. | |||
// Use of this source code is governed by a MIT-style | |||
// license that can be found in the LICENSE file. | |||
package migrations | |||
import "xorm.io/xorm" | |||
func addSSHKeyIsVerified(x *xorm.Engine) error { | |||
type PublicKey struct { | |||
Verified bool `xorm:"NOT NULL DEFAULT false"` | |||
} | |||
return x.Sync(new(PublicKey)) | |||
} |
@@ -629,7 +629,18 @@ gpg_token_help = You can generate a signature using: | |||
gpg_token_code = echo "%s" | gpg -a --default-key %s --detach-sig | |||
gpg_token_signature = Armored GPG signature | |||
key_signature_gpg_placeholder = Begins with '-----BEGIN PGP SIGNATURE-----' | |||
verify_gpg_key_success = The GPG key '%s' has been verified. | |||
verify_gpg_key_success = GPG key '%s' has been verified. | |||
ssh_key_verified=Verified Key | |||
ssh_key_verified_long=Key has been verified with a token and can be used to verify commits matching any activated email addresses for this user. | |||
ssh_key_verify=Verify | |||
ssh_invalid_token_signature = The provided SSH key, signature or token do not match or token is out-of-date. | |||
ssh_token_required = You must provide a signature for the below token | |||
ssh_token = Token | |||
ssh_token_help = You can generate a signature using: | |||
ssh_token_code = echo -n "%s" | ssh-keygen -Y sign -n gitea -f /path_to_your_pubkey | |||
ssh_token_signature = Armored SSH signature | |||
key_signature_ssh_placeholder = Begins with '-----BEGIN SSH SIGNATURE-----' | |||
verify_ssh_key_success = SSH key '%s' has been verified. | |||
subkeys = Subkeys | |||
key_id = Key ID | |||
key_name = Key Name | |||
@@ -1084,6 +1095,7 @@ commits.signed_by = Signed by | |||
commits.signed_by_untrusted_user = Signed by untrusted user | |||
commits.signed_by_untrusted_user_unmatched = Signed by untrusted user who does not match committer | |||
commits.gpg_key_id = GPG Key ID | |||
commits.ssh_key_fingerprint = SSH Key Fingerprint | |||
ext_issues = Ext. Issues | |||
ext_issues.desc = Link to an external issue tracker. |
@@ -184,6 +184,28 @@ func KeysPost(ctx *context.Context) { | |||
} | |||
ctx.Flash.Success(ctx.Tr("settings.add_key_success", form.Title)) | |||
ctx.Redirect(setting.AppSubURL + "/user/settings/keys") | |||
case "verify_ssh": | |||
token := asymkey_model.VerificationToken(ctx.User, 1) | |||
lastToken := asymkey_model.VerificationToken(ctx.User, 0) | |||
fingerprint, err := asymkey_model.VerifySSHKey(ctx.User.ID, form.Fingerprint, token, form.Signature) | |||
if err != nil && asymkey_model.IsErrSSHInvalidTokenSignature(err) { | |||
fingerprint, err = asymkey_model.VerifySSHKey(ctx.User.ID, form.Fingerprint, lastToken, form.Signature) | |||
} | |||
if err != nil { | |||
ctx.Data["HasSSHVerifyError"] = true | |||
switch { | |||
case asymkey_model.IsErrSSHInvalidTokenSignature(err): | |||
loadKeysData(ctx) | |||
ctx.Data["Err_Signature"] = true | |||
ctx.Data["Fingerprint"] = err.(asymkey_model.ErrSSHInvalidTokenSignature).Fingerprint | |||
ctx.RenderWithErr(ctx.Tr("settings.ssh_invalid_token_signature"), tplSettingsKeys, &form) | |||
default: | |||
ctx.ServerError("VerifySSH", err) | |||
} | |||
} | |||
ctx.Flash.Success(ctx.Tr("settings.verify_ssh_key_success", fingerprint)) | |||
ctx.Redirect(setting.AppSubURL + "/user/settings/keys") | |||
default: | |||
ctx.Flash.Warning("Function not implemented") | |||
@@ -268,4 +290,5 @@ func loadKeysData(ctx *context.Context) { | |||
ctx.Data["Principals"] = principals | |||
ctx.Data["VerifyingID"] = ctx.FormString("verify_gpg") | |||
ctx.Data["VerifyingFingerprint"] = ctx.FormString("verify_ssh") | |||
} |
@@ -349,12 +349,13 @@ func (f *AddOpenIDForm) Validate(req *http.Request, errs binding.Errors) binding | |||
// AddKeyForm form for adding SSH/GPG key | |||
type AddKeyForm struct { | |||
Type string `binding:"OmitEmpty"` | |||
Title string `binding:"Required;MaxSize(50)"` | |||
Content string `binding:"Required"` | |||
Signature string `binding:"OmitEmpty"` | |||
KeyID string `binding:"OmitEmpty"` | |||
IsWritable bool | |||
Type string `binding:"OmitEmpty"` | |||
Title string `binding:"Required;MaxSize(50)"` | |||
Content string `binding:"Required"` | |||
Signature string `binding:"OmitEmpty"` | |||
KeyID string `binding:"OmitEmpty"` | |||
Fingerprint string `binding:"OmitEmpty"` | |||
IsWritable bool | |||
} | |||
// Validate validates the fields |
@@ -109,17 +109,32 @@ | |||
{{if .Verification.Verified}} | |||
{{if ne .Verification.SigningUser.ID 0}} | |||
{{svg "octicon-shield-check" 16 "mr-3"}} | |||
<span class="ui text mr-3">{{.i18n.Tr "repo.commits.gpg_key_id"}}:</span> | |||
{{.Verification.SigningKey.KeyID}} | |||
{{if .Verification.SigningSSHKey}} | |||
<span class="ui text mr-3">{{.i18n.Tr "repo.commits.ssh_key_fingerprint"}}:</span> | |||
{{.Verification.SigningSSHKey.Fingerprint}} | |||
{{else}} | |||
<span class="ui text mr-3">{{.i18n.Tr "repo.commits.gpg_key_id"}}:</span> | |||
{{.Verification.SigningKey.KeyID}} | |||
{{end}} | |||
{{else}} | |||
{{svg "octicon-shield-lock" 16 "mr-3"}} | |||
<span class="ui text mr-3 tooltip" data-content="{{.i18n.Tr "gpg.default_key"}}">{{.i18n.Tr "repo.commits.gpg_key_id"}}:</span> | |||
{{.Verification.SigningKey.KeyID}} | |||
{{if .Verification.SigningSSHKey}} | |||
<span class="ui text mr-3 tooltip" data-content="{{.i18n.Tr "gpg.default_key"}}">{{.i18n.Tr "repo.commits.ssh_key_fingerprint"}}:</span> | |||
{{.Verification.SigningSSHKey.Fingerprint}} | |||
{{else}} | |||
<span class="ui text mr-3 tooltip" data-content="{{.i18n.Tr "gpg.default_key"}}">{{.i18n.Tr "repo.commits.gpg_key_id"}}:</span> | |||
{{.Verification.SigningKey.KeyID}} | |||
{{end}} | |||
{{end}} | |||
{{else if .Verification.Warning}} | |||
{{svg "octicon-shield" 16 "mr-3"}} | |||
<span class="ui text mr-3">{{.i18n.Tr "repo.commits.gpg_key_id"}}:</span> | |||
{{.Verification.SigningKey.KeyID}} | |||
{{if .Verification.SigningSSHKey}} | |||
<span class="ui text mr-3">{{.i18n.Tr "repo.commits.ssh_key_fingerprint"}}:</span> | |||
{{.Verification.SigningSSHKey.Fingerprint}} | |||
{{else}} | |||
<span class="ui text mr-3">{{.i18n.Tr "repo.commits.gpg_key_id"}}:</span> | |||
{{.Verification.SigningKey.KeyID}} | |||
{{end}} | |||
{{else}} | |||
{{if .Verification.SigningKey}} | |||
{{if ne .Verification.SigningKey.KeyID ""}} | |||
@@ -128,6 +143,13 @@ | |||
{{.Verification.SigningKey.KeyID}} | |||
{{end}} | |||
{{end}} | |||
{{if .Verification.SigningSSHKey}} | |||
{{if ne .Verification.SigningSSHKey.Fingerprint ""}} | |||
{{svg "octicon-shield" 16 "mr-3"}} | |||
<span class="ui text mr-3">{{.i18n.Tr "repo.commits.ssh_key_fingerprint"}}:</span> | |||
{{.Verification.SigningSSHKey.Fingerprint}} | |||
{{end}} | |||
{{end}} | |||
{{end}} | |||
</div> | |||
</div> |
@@ -41,11 +41,18 @@ | |||
<button class="ui red tiny button delete-button{{if index $.ExternalKeys $index}} disabled{{end}}" data-modal-id="delete-ssh" data-url="{{$.Link}}/delete?type=ssh" data-id="{{.ID}}"{{if index $.ExternalKeys $index}} title="{{$.i18n.Tr "settings.ssh_externally_managed"}}"{{end}}> | |||
{{$.i18n.Tr "settings.delete_key"}} | |||
</button> | |||
{{if and (not .Verified) (ne $.VerifyingFingerprint .Fingerprint)}} | |||
<a class="ui blue tiny show-panel button" href="{{$.Link}}?verify_ssh={{.Fingerprint}}">{{$.i18n.Tr "settings.ssh_key_verify"}}</a> | |||
{{end}} | |||
</div> | |||
<div class="left floated content"> | |||
<span class="{{if .HasRecentActivity}}green{{end}}" {{if .HasRecentActivity}}data-content="{{$.i18n.Tr "settings.key_state_desc"}}" data-variation="inverted tiny"{{end}}>{{svg "octicon-key" 32}}</span> | |||
</div> | |||
<div class="content"> | |||
{{if .Verified}} | |||
<span class="tooltip" data-content="{{$.i18n.Tr "settings.ssh_key_verified_long"}}">{{svg "octicon-shield-check"}} <strong>{{$.i18n.Tr "settings.ssh_key_verified"}}</strong></span> | |||
{{end}} | |||
<strong>{{.Name}}</strong> | |||
<div class="print meta"> | |||
{{.Fingerprint}} | |||
@@ -55,6 +62,37 @@ | |||
</div> | |||
</div> | |||
</div> | |||
{{if and (not .Verified) (eq $.VerifyingFingerprint .Fingerprint)}} | |||
<div class="ui segment"> | |||
<h4>{{$.i18n.Tr "settings.ssh_token_required"}}</h4> | |||
<form class="ui form{{if $.HasSSHVerifyError}} error{{end}}" action="{{$.Link}}" method="post"> | |||
{{$.CsrfTokenHtml}} | |||
<input type="hidden" name="title" value="none"> | |||
<input type="hidden" name="content" value="{{.Content}}"> | |||
<input type="hidden" name="fingerprint" value="{{.Fingerprint}}"> | |||
<div class="field"> | |||
<label for="token">{{$.i18n.Tr "settings.ssh_token"}}</label> | |||
<input readonly="" value="{{$.TokenToSign}}"> | |||
<div class="help"> | |||
<p>{{$.i18n.Tr "settings.ssh_token_help"}}</p> | |||
<p><code>{{$.i18n.Tr "settings.ssh_token_code" $.TokenToSign}}</code></p> | |||
</div> | |||
<br> | |||
</div> | |||
<div class="field"> | |||
<label for="signature">{{$.i18n.Tr "settings.ssh_token_signature"}}</label> | |||
<textarea id="ssh-key-signature" name="signature" placeholder="{{$.i18n.Tr "settings.key_signature_ssh_placeholder"}}" required>{{$.signature}}</textarea> | |||
</div> | |||
<input name="type" type="hidden" value="verify_ssh"> | |||
<button class="ui green button"> | |||
{{$.i18n.Tr "settings.ssh_key_verify"}} | |||
</button> | |||
<a class="ui red button" href="{{$.Link}}"> | |||
{{$.i18n.Tr "settings.cancel"}} | |||
</a> | |||
</form> | |||
</div> | |||
{{end}} | |||
{{end}} | |||
</div> | |||
</div> |
@@ -0,0 +1,201 @@ | |||
Apache License | |||
Version 2.0, January 2004 | |||
http://www.apache.org/licenses/ | |||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | |||
1. Definitions. | |||
"License" shall mean the terms and conditions for use, reproduction, | |||
and distribution as defined by Sections 1 through 9 of this document. | |||
"Licensor" shall mean the copyright owner or entity authorized by | |||
the copyright owner that is granting the License. | |||
"Legal Entity" shall mean the union of the acting entity and all | |||
other entities that control, are controlled by, or are under common | |||
control with that entity. For the purposes of this definition, | |||
"control" means (i) the power, direct or indirect, to cause the | |||
direction or management of such entity, whether by contract or | |||
otherwise, or (ii) ownership of fifty percent (50%) or more of the | |||
outstanding shares, or (iii) beneficial ownership of such entity. | |||
"You" (or "Your") shall mean an individual or Legal Entity | |||
exercising permissions granted by this License. | |||
"Source" form shall mean the preferred form for making modifications, | |||
including but not limited to software source code, documentation | |||
source, and configuration files. | |||
"Object" form shall mean any form resulting from mechanical | |||
transformation or translation of a Source form, including but | |||
not limited to compiled object code, generated documentation, | |||
and conversions to other media types. | |||
"Work" shall mean the work of authorship, whether in Source or | |||
Object form, made available under the License, as indicated by a | |||
copyright notice that is included in or attached to the work | |||
(an example is provided in the Appendix below). | |||
"Derivative Works" shall mean any work, whether in Source or Object | |||
form, that is based on (or derived from) the Work and for which the | |||
editorial revisions, annotations, elaborations, or other modifications | |||
represent, as a whole, an original work of authorship. For the purposes | |||
of this License, Derivative Works shall not include works that remain | |||
separable from, or merely link (or bind by name) to the interfaces of, | |||
the Work and Derivative Works thereof. | |||
"Contribution" shall mean any work of authorship, including | |||
the original version of the Work and any modifications or additions | |||
to that Work or Derivative Works thereof, that is intentionally | |||
submitted to Licensor for inclusion in the Work by the copyright owner | |||
or by an individual or Legal Entity authorized to submit on behalf of | |||
the copyright owner. For the purposes of this definition, "submitted" | |||
means any form of electronic, verbal, or written communication sent | |||
to the Licensor or its representatives, including but not limited to | |||
communication on electronic mailing lists, source code control systems, | |||
and issue tracking systems that are managed by, or on behalf of, the | |||
Licensor for the purpose of discussing and improving the Work, but | |||
excluding communication that is conspicuously marked or otherwise | |||
designated in writing by the copyright owner as "Not a Contribution." | |||
"Contributor" shall mean Licensor and any individual or Legal Entity | |||
on behalf of whom a Contribution has been received by Licensor and | |||
subsequently incorporated within the Work. | |||
2. Grant of Copyright License. Subject to the terms and conditions of | |||
this License, each Contributor hereby grants to You a perpetual, | |||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable | |||
copyright license to reproduce, prepare Derivative Works of, | |||
publicly display, publicly perform, sublicense, and distribute the | |||
Work and such Derivative Works in Source or Object form. | |||
3. Grant of Patent License. Subject to the terms and conditions of | |||
this License, each Contributor hereby grants to You a perpetual, | |||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable | |||
(except as stated in this section) patent license to make, have made, | |||
use, offer to sell, sell, import, and otherwise transfer the Work, | |||
where such license applies only to those patent claims licensable | |||
by such Contributor that are necessarily infringed by their | |||
Contribution(s) alone or by combination of their Contribution(s) | |||
with the Work to which such Contribution(s) was submitted. If You | |||
institute patent litigation against any entity (including a | |||
cross-claim or counterclaim in a lawsuit) alleging that the Work | |||
or a Contribution incorporated within the Work constitutes direct | |||
or contributory patent infringement, then any patent licenses | |||
granted to You under this License for that Work shall terminate | |||
as of the date such litigation is filed. | |||
4. Redistribution. You may reproduce and distribute copies of the | |||
Work or Derivative Works thereof in any medium, with or without | |||
modifications, and in Source or Object form, provided that You | |||
meet the following conditions: | |||
(a) You must give any other recipients of the Work or | |||
Derivative Works a copy of this License; and | |||
(b) You must cause any modified files to carry prominent notices | |||
stating that You changed the files; and | |||
(c) You must retain, in the Source form of any Derivative Works | |||
that You distribute, all copyright, patent, trademark, and | |||
attribution notices from the Source form of the Work, | |||
excluding those notices that do not pertain to any part of | |||
the Derivative Works; and | |||
(d) If the Work includes a "NOTICE" text file as part of its | |||
distribution, then any Derivative Works that You distribute must | |||
include a readable copy of the attribution notices contained | |||
within such NOTICE file, excluding those notices that do not | |||
pertain to any part of the Derivative Works, in at least one | |||
of the following places: within a NOTICE text file distributed | |||
as part of the Derivative Works; within the Source form or | |||
documentation, if provided along with the Derivative Works; or, | |||
within a display generated by the Derivative Works, if and | |||
wherever such third-party notices normally appear. The contents | |||
of the NOTICE file are for informational purposes only and | |||
do not modify the License. You may add Your own attribution | |||
notices within Derivative Works that You distribute, alongside | |||
or as an addendum to the NOTICE text from the Work, provided | |||
that such additional attribution notices cannot be construed | |||
as modifying the License. | |||
You may add Your own copyright statement to Your modifications and | |||
may provide additional or different license terms and conditions | |||
for use, reproduction, or distribution of Your modifications, or | |||
for any such Derivative Works as a whole, provided Your use, | |||
reproduction, and distribution of the Work otherwise complies with | |||
the conditions stated in this License. | |||
5. Submission of Contributions. Unless You explicitly state otherwise, | |||
any Contribution intentionally submitted for inclusion in the Work | |||
by You to the Licensor shall be under the terms and conditions of | |||
this License, without any additional terms or conditions. | |||
Notwithstanding the above, nothing herein shall supersede or modify | |||
the terms of any separate license agreement you may have executed | |||
with Licensor regarding such Contributions. | |||
6. Trademarks. This License does not grant permission to use the trade | |||
names, trademarks, service marks, or product names of the Licensor, | |||
except as required for reasonable and customary use in describing the | |||
origin of the Work and reproducing the content of the NOTICE file. | |||
7. Disclaimer of Warranty. Unless required by applicable law or | |||
agreed to in writing, Licensor provides the Work (and each | |||
Contributor provides its Contributions) on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | |||
implied, including, without limitation, any warranties or conditions | |||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | |||
PARTICULAR PURPOSE. You are solely responsible for determining the | |||
appropriateness of using or redistributing the Work and assume any | |||
risks associated with Your exercise of permissions under this License. | |||
8. Limitation of Liability. In no event and under no legal theory, | |||
whether in tort (including negligence), contract, or otherwise, | |||
unless required by applicable law (such as deliberate and grossly | |||
negligent acts) or agreed to in writing, shall any Contributor be | |||
liable to You for damages, including any direct, indirect, special, | |||
incidental, or consequential damages of any character arising as a | |||
result of this License or out of the use or inability to use the | |||
Work (including but not limited to damages for loss of goodwill, | |||
work stoppage, computer failure or malfunction, or any and all | |||
other commercial damages or losses), even if such Contributor | |||
has been advised of the possibility of such damages. | |||
9. Accepting Warranty or Additional Liability. While redistributing | |||
the Work or Derivative Works thereof, You may choose to offer, | |||
and charge a fee for, acceptance of support, warranty, indemnity, | |||
or other liability obligations and/or rights consistent with this | |||
License. However, in accepting such obligations, You may act only | |||
on Your own behalf and on Your sole responsibility, not on behalf | |||
of any other Contributor, and only if You agree to indemnify, | |||
defend, and hold each Contributor harmless for any liability | |||
incurred by, or claims asserted against, such Contributor by reason | |||
of your accepting any such warranty or additional liability. | |||
END OF TERMS AND CONDITIONS | |||
APPENDIX: How to apply the Apache License to your work. | |||
To apply the Apache License to your work, attach the following | |||
boilerplate notice, with the fields enclosed by brackets "[]" | |||
replaced with your own identifying information. (Don't include | |||
the brackets!) The text should be enclosed in the appropriate | |||
comment syntax for the file format. We also recommend that a | |||
file or class name and description of purpose be included on the | |||
same "printed page" as the copyright notice for easier | |||
identification within third-party archives. | |||
Copyright [yyyy] [name of copyright owner] | |||
Licensed under the Apache License, Version 2.0 (the "License"); | |||
you may not use this file except in compliance with the License. | |||
You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. |
@@ -0,0 +1,82 @@ | |||
# Armored ssh signatures in go | |||
[![Go Reference](https://pkg.go.dev/badge/github.com/42wim/sshsig.svg)](https://pkg.go.dev/github.com/42wim/sshsig#section-documentation) | |||
Package sshsig implements signing/verifying armored SSH signatures. | |||
You can use this package to sign data and verify signatures using your ssh private keys or your ssh agent. | |||
It gives the same output as using `ssh-keygen`, eg when signing `ssh-keygen -Y sign -f keyfile -n namespace data` | |||
This code is based upon work by <https://github.com/sigstore/rekor> | |||
References: <https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.sshsig> | |||
You can find some examples on how to use this library on: <https://pkg.go.dev/github.com/42wim/sshsig#pkg-examples> | |||
## Examples | |||
```golang | |||
package main | |||
import ( | |||
"bytes" | |||
"fmt" | |||
"net" | |||
"os" | |||
"github.com/42wim/sshsig" | |||
"golang.org/x/crypto/ssh/agent" | |||
) | |||
func ExampleSignWithAgent() { | |||
// This example will panic when you don't have a ssh-agent running. | |||
conn, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")) | |||
if err != nil { | |||
panic(err) | |||
} | |||
ag := agent.NewClient(conn) | |||
// This public key must match in your agent (use `ssh-add -L` to get the public key) | |||
pubkey := []byte(`ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAo3D7CGN01tTYY/dLKXEv8RxRyxa32c51X0uKMhnMab wim@localhost`) | |||
// | |||
data := []byte("hello world") | |||
res, err := sshsig.SignWithAgent(pubkey, ag, bytes.NewBuffer(data), "file") | |||
if err != nil { | |||
panic(err) | |||
} | |||
fmt.Println(string(res)) | |||
} | |||
func ExampleSign() { | |||
privkey := []byte(`-----BEGIN OPENSSH PRIVATE KEY----- | |||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW | |||
QyNTUxOQAAACCOjP6i4Pm/pYAAmpAMNZ6xrbHl9RW8xdul6kzIWuKMMAAAAIhoQm34aEJt | |||
+AAAAAtzc2gtZWQyNTUxOQAAACCOjP6i4Pm/pYAAmpAMNZ6xrbHl9RW8xdul6kzIWuKMMA | |||
AAAEBfIl93TLj6qHeg37GnPuZ00h8OVv1mzlhy0rhuO4Y0do6M/qLg+b+lgACakAw1nrGt | |||
seX1FbzF26XqTMha4owwAAAAAAECAwQF | |||
-----END OPENSSH PRIVATE KEY-----`) | |||
data := []byte("hello world") | |||
res, err := sshsig.Sign(privkey, bytes.NewBuffer(data), "file") | |||
if err != nil { | |||
panic(err) | |||
} | |||
fmt.Println(string(res)) | |||
// Output: | |||
// -----BEGIN SSH SIGNATURE----- | |||
// U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgjoz+ouD5v6WAAJqQDDWesa2x5f | |||
// UVvMXbpepMyFrijDAAAAAEZmlsZQAAAAAAAAAGc2hhNTEyAAAAUwAAAAtzc2gtZWQyNTUx | |||
// OQAAAEBeu9Z+vLxBORysiqEbTzJP0EZKG0/aE5HpTtvimjQS6mHZCAGFg+kimNatBE0Y1j | |||
// gS4pfD73TlML1SyB5lb/YO | |||
// -----END SSH SIGNATURE----- | |||
} | |||
func main() { | |||
ExampleSign() | |||
} | |||
``` |
@@ -0,0 +1,11 @@ | |||
/* | |||
Package sshsig implements signing/verifying armored SSH signatures. | |||
You can use this package to sign data and verify signatures using your ssh private keys or your ssh agent. | |||
It gives the same output as using `ssh-keygen`, eg when signing `ssh-keygen -Y sign -f keyfile -n namespace data` | |||
This code is based upon work by https://github.com/sigstore/rekor | |||
References: | |||
- https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.sshsig | |||
*/ | |||
package sshsig |
@@ -0,0 +1,95 @@ | |||
// Modified by 42wim | |||
// | |||
// Copyright 2021 The Sigstore Authors. | |||
// | |||
// Licensed under the Apache License, Version 2.0 (the "License"); | |||
// you may not use this file except in compliance with the License. | |||
// You may obtain a copy of the License at | |||
// | |||
// http://www.apache.org/licenses/LICENSE-2.0 | |||
// | |||
// Unless required by applicable law or agreed to in writing, software | |||
// distributed under the License is distributed on an "AS IS" BASIS, | |||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
// See the License for the specific language governing permissions and | |||
// limitations under the License. | |||
package sshsig | |||
import ( | |||
"errors" | |||
"fmt" | |||
"github.com/42wim/sshsig/pem" | |||
"golang.org/x/crypto/ssh" | |||
) | |||
const ( | |||
pemType = "SSH SIGNATURE" | |||
) | |||
// Armored returns the signature in an armored format. | |||
func Armor(s *ssh.Signature, p ssh.PublicKey, ns string) []byte { | |||
sig := WrappedSig{ | |||
Version: 1, | |||
PublicKey: string(p.Marshal()), | |||
Namespace: ns, | |||
HashAlgorithm: defaultHashAlgorithm, | |||
Signature: string(ssh.Marshal(s)), | |||
} | |||
copy(sig.MagicHeader[:], magicHeader) | |||
enc := pem.EncodeToMemory(&pem.Block{ | |||
Type: pemType, | |||
Bytes: ssh.Marshal(sig), | |||
}) | |||
return enc | |||
} | |||
// Decode parses an armored signature. | |||
func Decode(b []byte) (*Signature, error) { | |||
pemBlock, _ := pem.Decode(b) | |||
if pemBlock == nil { | |||
return nil, errors.New("unable to decode pem file") | |||
} | |||
if pemBlock.Type != pemType { | |||
return nil, fmt.Errorf("wrong pem block type: %s. Expected SSH-SIGNATURE", pemBlock.Type) | |||
} | |||
// Now we unmarshal it into the Signature block | |||
sig := WrappedSig{} | |||
if err := ssh.Unmarshal(pemBlock.Bytes, &sig); err != nil { | |||
return nil, err | |||
} | |||
if sig.Version != 1 { | |||
return nil, fmt.Errorf("unsupported signature version: %d", sig.Version) | |||
} | |||
if string(sig.MagicHeader[:]) != magicHeader { | |||
return nil, fmt.Errorf("invalid magic header: %s", sig.MagicHeader[:]) | |||
} | |||
if _, ok := supportedHashAlgorithms[sig.HashAlgorithm]; !ok { | |||
return nil, fmt.Errorf("unsupported hash algorithm: %s", sig.HashAlgorithm) | |||
} | |||
// Now we can unpack the Signature and PublicKey blocks | |||
sshSig := ssh.Signature{} | |||
if err := ssh.Unmarshal([]byte(sig.Signature), &sshSig); err != nil { | |||
return nil, err | |||
} | |||
// TODO: check the format here (should be rsa-sha512) | |||
pk, err := ssh.ParsePublicKey([]byte(sig.PublicKey)) | |||
if err != nil { | |||
return nil, err | |||
} | |||
return &Signature{ | |||
signature: &sshSig, | |||
pk: pk, | |||
hashAlg: sig.HashAlgorithm, | |||
}, nil | |||
} |
@@ -0,0 +1,7 @@ | |||
module github.com/42wim/sshsig | |||
go 1.17 | |||
require golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 | |||
require golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1 // indirect |
@@ -0,0 +1,12 @@ | |||
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 h1:/pEO3GD/ABYAjuakUS6xSEmmlyVS4kxBNkeA9tLJiTI= | |||
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= | |||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= | |||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | |||
golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1 h1:kwrAHlwJ0DUBZwQ238v+Uod/3eZ8B2K5rYsUHBQvzmI= | |||
golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | |||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= | |||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | |||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | |||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
@@ -0,0 +1,346 @@ | |||
// Modified by 42wim | |||
// | |||
// Copyright 2009 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
// Package pem implements the PEM data encoding, which originated in Privacy | |||
// Enhanced Mail. The most common use of PEM encoding today is in TLS keys and | |||
// certificates. See RFC 1421. | |||
package pem | |||
import ( | |||
"bytes" | |||
"encoding/base64" | |||
"errors" | |||
"io" | |||
"sort" | |||
"strings" | |||
) | |||
// A Block represents a PEM encoded structure. | |||
// | |||
// The encoded form is: | |||
// -----BEGIN Type----- | |||
// Headers | |||
// base64-encoded Bytes | |||
// -----END Type----- | |||
// where Headers is a possibly empty sequence of Key: Value lines. | |||
type Block struct { | |||
Type string // The type, taken from the preamble (i.e. "RSA PRIVATE KEY"). | |||
Headers map[string]string // Optional headers. | |||
Bytes []byte // The decoded bytes of the contents. Typically a DER encoded ASN.1 structure. | |||
} | |||
// getLine results the first \r\n or \n delineated line from the given byte | |||
// array. The line does not include trailing whitespace or the trailing new | |||
// line bytes. The remainder of the byte array (also not including the new line | |||
// bytes) is also returned and this will always be smaller than the original | |||
// argument. | |||
func getLine(data []byte) (line, rest []byte) { | |||
i := bytes.IndexByte(data, '\n') | |||
var j int | |||
if i < 0 { | |||
i = len(data) | |||
j = i | |||
} else { | |||
j = i + 1 | |||
if i > 0 && data[i-1] == '\r' { | |||
i-- | |||
} | |||
} | |||
return bytes.TrimRight(data[0:i], " \t"), data[j:] | |||
} | |||
// removeSpacesAndTabs returns a copy of its input with all spaces and tabs | |||
// removed, if there were any. Otherwise, the input is returned unchanged. | |||
// | |||
// The base64 decoder already skips newline characters, so we don't need to | |||
// filter them out here. | |||
func removeSpacesAndTabs(data []byte) []byte { | |||
if !bytes.ContainsAny(data, " \t") { | |||
// Fast path; most base64 data within PEM contains newlines, but | |||
// no spaces nor tabs. Skip the extra alloc and work. | |||
return data | |||
} | |||
result := make([]byte, len(data)) | |||
n := 0 | |||
for _, b := range data { | |||
if b == ' ' || b == '\t' { | |||
continue | |||
} | |||
result[n] = b | |||
n++ | |||
} | |||
return result[0:n] | |||
} | |||
var ( | |||
pemStart = []byte("\n-----BEGIN ") | |||
pemEnd = []byte("\n-----END ") | |||
pemEndOfLine = []byte("-----") | |||
) | |||
// Decode will find the next PEM formatted block (certificate, private key | |||
// etc) in the input. It returns that block and the remainder of the input. If | |||
// no PEM data is found, p is nil and the whole of the input is returned in | |||
// rest. | |||
func Decode(data []byte) (p *Block, rest []byte) { | |||
// pemStart begins with a newline. However, at the very beginning of | |||
// the byte array, we'll accept the start string without it. | |||
rest = data | |||
if bytes.HasPrefix(data, pemStart[1:]) { | |||
rest = rest[len(pemStart)-1 : len(data)] | |||
} else if i := bytes.Index(data, pemStart); i >= 0 { | |||
rest = rest[i+len(pemStart) : len(data)] | |||
} else { | |||
return nil, data | |||
} | |||
typeLine, rest := getLine(rest) | |||
if !bytes.HasSuffix(typeLine, pemEndOfLine) { | |||
return decodeError(data, rest) | |||
} | |||
typeLine = typeLine[0 : len(typeLine)-len(pemEndOfLine)] | |||
p = &Block{ | |||
Headers: make(map[string]string), | |||
Type: string(typeLine), | |||
} | |||
for { | |||
// This loop terminates because getLine's second result is | |||
// always smaller than its argument. | |||
if len(rest) == 0 { | |||
return nil, data | |||
} | |||
line, next := getLine(rest) | |||
i := bytes.IndexByte(line, ':') | |||
if i == -1 { | |||
break | |||
} | |||
// TODO(agl): need to cope with values that spread across lines. | |||
key, val := line[:i], line[i+1:] | |||
key = bytes.TrimSpace(key) | |||
val = bytes.TrimSpace(val) | |||
p.Headers[string(key)] = string(val) | |||
rest = next | |||
} | |||
var endIndex, endTrailerIndex int | |||
// If there were no headers, the END line might occur | |||
// immediately, without a leading newline. | |||
if len(p.Headers) == 0 && bytes.HasPrefix(rest, pemEnd[1:]) { | |||
endIndex = 0 | |||
endTrailerIndex = len(pemEnd) - 1 | |||
} else { | |||
endIndex = bytes.Index(rest, pemEnd) | |||
endTrailerIndex = endIndex + len(pemEnd) | |||
} | |||
if endIndex < 0 { | |||
return decodeError(data, rest) | |||
} | |||
// After the "-----" of the ending line, there should be the same type | |||
// and then a final five dashes. | |||
endTrailer := rest[endTrailerIndex:] | |||
endTrailerLen := len(typeLine) + len(pemEndOfLine) | |||
if len(endTrailer) < endTrailerLen { | |||
return decodeError(data, rest) | |||
} | |||
restOfEndLine := endTrailer[endTrailerLen:] | |||
endTrailer = endTrailer[:endTrailerLen] | |||
if !bytes.HasPrefix(endTrailer, typeLine) || | |||
!bytes.HasSuffix(endTrailer, pemEndOfLine) { | |||
return decodeError(data, rest) | |||
} | |||
// The line must end with only whitespace. | |||
if s, _ := getLine(restOfEndLine); len(s) != 0 { | |||
return decodeError(data, rest) | |||
} | |||
base64Data := removeSpacesAndTabs(rest[:endIndex]) | |||
p.Bytes = make([]byte, base64.StdEncoding.DecodedLen(len(base64Data))) | |||
n, err := base64.StdEncoding.Decode(p.Bytes, base64Data) | |||
if err != nil { | |||
return decodeError(data, rest) | |||
} | |||
p.Bytes = p.Bytes[:n] | |||
// the -1 is because we might have only matched pemEnd without the | |||
// leading newline if the PEM block was empty. | |||
_, rest = getLine(rest[endIndex+len(pemEnd)-1:]) | |||
return | |||
} | |||
func decodeError(data, rest []byte) (*Block, []byte) { | |||
// If we get here then we have rejected a likely looking, but | |||
// ultimately invalid PEM block. We need to start over from a new | |||
// position. We have consumed the preamble line and will have consumed | |||
// any lines which could be header lines. However, a valid preamble | |||
// line is not a valid header line, therefore we cannot have consumed | |||
// the preamble line for the any subsequent block. Thus, we will always | |||
// find any valid block, no matter what bytes precede it. | |||
// | |||
// For example, if the input is | |||
// | |||
// -----BEGIN MALFORMED BLOCK----- | |||
// junk that may look like header lines | |||
// or data lines, but no END line | |||
// | |||
// -----BEGIN ACTUAL BLOCK----- | |||
// realdata | |||
// -----END ACTUAL BLOCK----- | |||
// | |||
// we've failed to parse using the first BEGIN line | |||
// and now will try again, using the second BEGIN line. | |||
p, rest := Decode(rest) | |||
if p == nil { | |||
rest = data | |||
} | |||
return p, rest | |||
} | |||
// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.sshsig#L20-L21 | |||
// Should be on 76 chars, but strangely enough ssh breaks on 70 | |||
const pemLineLength = 70 | |||
type lineBreaker struct { | |||
line [pemLineLength]byte | |||
used int | |||
out io.Writer | |||
} | |||
var nl = []byte{'\n'} | |||
func (l *lineBreaker) Write(b []byte) (n int, err error) { | |||
if l.used+len(b) < pemLineLength { | |||
copy(l.line[l.used:], b) | |||
l.used += len(b) | |||
return len(b), nil | |||
} | |||
n, err = l.out.Write(l.line[0:l.used]) | |||
if err != nil { | |||
return | |||
} | |||
excess := pemLineLength - l.used | |||
l.used = 0 | |||
n, err = l.out.Write(b[0:excess]) | |||
if err != nil { | |||
return | |||
} | |||
n, err = l.out.Write(nl) | |||
if err != nil { | |||
return | |||
} | |||
return l.Write(b[excess:]) | |||
} | |||
func (l *lineBreaker) Close() (err error) { | |||
if l.used > 0 { | |||
_, err = l.out.Write(l.line[0:l.used]) | |||
if err != nil { | |||
return | |||
} | |||
_, err = l.out.Write(nl) | |||
} | |||
return | |||
} | |||
func writeHeader(out io.Writer, k, v string) error { | |||
_, err := out.Write([]byte(k + ": " + v + "\n")) | |||
return err | |||
} | |||
// Encode writes the PEM encoding of b to out. | |||
func Encode(out io.Writer, b *Block) error { | |||
// Check for invalid block before writing any output. | |||
for k := range b.Headers { | |||
if strings.Contains(k, ":") { | |||
return errors.New("pem: cannot encode a header key that contains a colon") | |||
} | |||
} | |||
// All errors below are relayed from underlying io.Writer, | |||
// so it is now safe to write data. | |||
if _, err := out.Write(pemStart[1:]); err != nil { | |||
return err | |||
} | |||
if _, err := out.Write([]byte(b.Type + "-----\n")); err != nil { | |||
return err | |||
} | |||
if len(b.Headers) > 0 { | |||
const procType = "Proc-Type" | |||
h := make([]string, 0, len(b.Headers)) | |||
hasProcType := false | |||
for k := range b.Headers { | |||
if k == procType { | |||
hasProcType = true | |||
continue | |||
} | |||
h = append(h, k) | |||
} | |||
// The Proc-Type header must be written first. | |||
// See RFC 1421, section 4.6.1.1 | |||
if hasProcType { | |||
if err := writeHeader(out, procType, b.Headers[procType]); err != nil { | |||
return err | |||
} | |||
} | |||
// For consistency of output, write other headers sorted by key. | |||
sort.Strings(h) | |||
for _, k := range h { | |||
if err := writeHeader(out, k, b.Headers[k]); err != nil { | |||
return err | |||
} | |||
} | |||
if _, err := out.Write(nl); err != nil { | |||
return err | |||
} | |||
} | |||
var breaker lineBreaker | |||
breaker.out = out | |||
b64 := base64.NewEncoder(base64.StdEncoding, &breaker) | |||
if _, err := b64.Write(b.Bytes); err != nil { | |||
return err | |||
} | |||
b64.Close() | |||
breaker.Close() | |||
if _, err := out.Write(pemEnd[1:]); err != nil { | |||
return err | |||
} | |||
_, err := out.Write([]byte(b.Type + "-----\n")) | |||
return err | |||
} | |||
// EncodeToMemory returns the PEM encoding of b. | |||
// | |||
// If b has invalid headers and cannot be encoded, | |||
// EncodeToMemory returns nil. If it is important to | |||
// report details about this error case, use Encode instead. | |||
func EncodeToMemory(b *Block) []byte { | |||
var buf bytes.Buffer | |||
if err := Encode(&buf, b); err != nil { | |||
return nil | |||
} | |||
return buf.Bytes() | |||
} |
@@ -0,0 +1,169 @@ | |||
// Modifications by 42wim | |||
// | |||
// Copyright 2021 The Sigstore Authors. | |||
// | |||
// Licensed under the Apache License, Version 2.0 (the "License"); | |||
// you may not use this file except in compliance with the License. | |||
// You may obtain a copy of the License at | |||
// | |||
// http://www.apache.org/licenses/LICENSE-2.0 | |||
// | |||
// Unless required by applicable law or agreed to in writing, software | |||
// distributed under the License is distributed on an "AS IS" BASIS, | |||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
// See the License for the specific language governing permissions and | |||
// limitations under the License. | |||
package sshsig | |||
import ( | |||
"crypto/rand" | |||
"crypto/sha256" | |||
"crypto/sha512" | |||
"errors" | |||
"hash" | |||
"io" | |||
"golang.org/x/crypto/ssh" | |||
"golang.org/x/crypto/ssh/agent" | |||
) | |||
// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.sshsig#L81 | |||
type MessageWrapper struct { | |||
Namespace string | |||
Reserved string | |||
HashAlgorithm string | |||
Hash string | |||
} | |||
// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.sshsig#L34 | |||
type WrappedSig struct { | |||
MagicHeader [6]byte | |||
Version uint32 | |||
PublicKey string | |||
Namespace string | |||
Reserved string | |||
HashAlgorithm string | |||
Signature string | |||
} | |||
const ( | |||
magicHeader = "SSHSIG" | |||
defaultHashAlgorithm = "sha512" | |||
) | |||
var supportedHashAlgorithms = map[string]func() hash.Hash{ | |||
"sha256": sha256.New, | |||
"sha512": sha512.New, | |||
} | |||
func wrapData(m io.Reader, ns string) ([]byte, error) { | |||
hf := sha512.New() | |||
if _, err := io.Copy(hf, m); err != nil { | |||
return nil, err | |||
} | |||
mh := hf.Sum(nil) | |||
sp := MessageWrapper{ | |||
Namespace: ns, | |||
HashAlgorithm: defaultHashAlgorithm, | |||
Hash: string(mh), | |||
} | |||
dataMessageWrapper := ssh.Marshal(sp) | |||
dataMessageWrapper = append([]byte(magicHeader), dataMessageWrapper...) | |||
return dataMessageWrapper, nil | |||
} | |||
func sign(s ssh.AlgorithmSigner, m io.Reader, ns string) (*ssh.Signature, error) { | |||
dataMessageWrapper, err := wrapData(m, ns) | |||
if err != nil { | |||
return nil, err | |||
} | |||
// ssh-rsa is not supported for RSA keys: | |||
// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.sshsig#L71 | |||
// We can use the default value of "" for other key types though. | |||
algo := "" | |||
if s.PublicKey().Type() == ssh.KeyAlgoRSA { | |||
algo = ssh.SigAlgoRSASHA2512 | |||
} | |||
return s.SignWithAlgorithm(rand.Reader, dataMessageWrapper, algo) | |||
} | |||
func signAgent(pk ssh.PublicKey, ag agent.Agent, m io.Reader, ns string) (*ssh.Signature, error) { | |||
dataMessageWrapper, err := wrapData(m, ns) | |||
if err != nil { | |||
return nil, err | |||
} | |||
var sigFlag agent.SignatureFlags | |||
if pk.Type() == ssh.KeyAlgoRSA { | |||
sigFlag = agent.SignatureFlagRsaSha512 | |||
} | |||
agExt, ok := ag.(agent.ExtendedAgent) | |||
if !ok { | |||
return nil, errors.New("couldn't cast to ExtendedAgent") | |||
} | |||
return agExt.SignWithFlags(pk, dataMessageWrapper, sigFlag) | |||
} | |||
// SignWithAgent asks the ssh Agent to sign the data with the signer matching the given publicKey and returns an armored signature. | |||
// The purpose of the namespace value is to specify a unambiguous | |||
// interpretation domain for the signature, e.g. file signing. | |||
// This prevents cross-protocol attacks caused by signatures | |||
// intended for one intended domain being accepted in another. | |||
// If empty, the default is "file". | |||
// This can be compared with `ssh-keygen -Y sign -f keyfile -n namespace data` | |||
func SignWithAgent(publicKey []byte, ag agent.Agent, data io.Reader, namespace string) ([]byte, error) { | |||
pk, _, _, _, err := ssh.ParseAuthorizedKey(publicKey) | |||
if err != nil { | |||
return nil, err | |||
} | |||
if namespace == "" { | |||
namespace = defaultNamespace | |||
} | |||
sig, err := signAgent(pk, ag, data, namespace) | |||
if err != nil { | |||
return nil, err | |||
} | |||
armored := Armor(sig, pk, namespace) | |||
return armored, nil | |||
} | |||
// Sign signs the data with the given private key in PEM format and returns an armored signature. | |||
// The purpose of the namespace value is to specify a unambiguous | |||
// interpretation domain for the signature, e.g. file signing. | |||
// This prevents cross-protocol attacks caused by signatures | |||
// intended for one intended domain being accepted in another. | |||
// If empty, the default is "file". | |||
// This can be compared with `ssh-keygen -Y sign -f keyfile -n namespace data` | |||
func Sign(pemBytes []byte, data io.Reader, namespace string) ([]byte, error) { | |||
s, err := ssh.ParsePrivateKey(pemBytes) | |||
if err != nil { | |||
return nil, err | |||
} | |||
as, ok := s.(ssh.AlgorithmSigner) | |||
if !ok { | |||
return nil, err | |||
} | |||
if namespace == "" { | |||
namespace = defaultNamespace | |||
} | |||
sig, err := sign(as, data, namespace) | |||
if err != nil { | |||
return nil, err | |||
} | |||
armored := Armor(sig, s.PublicKey(), namespace) | |||
return armored, nil | |||
} |
@@ -0,0 +1,29 @@ | |||
// modified by 42wim | |||
// | |||
// Copyright 2021 The Sigstore Authors. | |||
// | |||
// Licensed under the Apache License, Version 2.0 (the "License"); | |||
// you may not use this file except in compliance with the License. | |||
// You may obtain a copy of the License at | |||
// | |||
// http://www.apache.org/licenses/LICENSE-2.0 | |||
// | |||
// Unless required by applicable law or agreed to in writing, software | |||
// distributed under the License is distributed on an "AS IS" BASIS, | |||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
// See the License for the specific language governing permissions and | |||
// limitations under the License. | |||
package sshsig | |||
import ( | |||
"golang.org/x/crypto/ssh" | |||
) | |||
type Signature struct { | |||
signature *ssh.Signature | |||
pk ssh.PublicKey | |||
hashAlg string | |||
} | |||
const defaultNamespace = "file" |
@@ -0,0 +1,56 @@ | |||
// | |||
// Copyright 2021 The Sigstore Authors. | |||
// | |||
// Licensed under the Apache License, Version 2.0 (the "License"); | |||
// you may not use this file except in compliance with the License. | |||
// You may obtain a copy of the License at | |||
// | |||
// http://www.apache.org/licenses/LICENSE-2.0 | |||
// | |||
// Unless required by applicable law or agreed to in writing, software | |||
// distributed under the License is distributed on an "AS IS" BASIS, | |||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
// See the License for the specific language governing permissions and | |||
// limitations under the License. | |||
package sshsig | |||
import ( | |||
"io" | |||
"golang.org/x/crypto/ssh" | |||
) | |||
// Verify verifies the signature of the given data and the armored signature using the given public key and the namespace. | |||
// If the namespace is empty, the default namespace (file) is used. | |||
func Verify(message io.Reader, armoredSignature []byte, publicKey []byte, namespace string) error { | |||
if namespace == "" { | |||
namespace = defaultNamespace | |||
} | |||
decodedSignature, err := Decode(armoredSignature) | |||
if err != nil { | |||
return err | |||
} | |||
desiredPk, _, _, _, err := ssh.ParseAuthorizedKey(publicKey) | |||
if err != nil { | |||
return err | |||
} | |||
// Hash the message so we can verify it against the signature. | |||
h := supportedHashAlgorithms[decodedSignature.hashAlg]() | |||
if _, err := io.Copy(h, message); err != nil { | |||
return err | |||
} | |||
hm := h.Sum(nil) | |||
toVerify := MessageWrapper{ | |||
Namespace: namespace, | |||
HashAlgorithm: decodedSignature.hashAlg, | |||
Hash: string(hm), | |||
} | |||
signedMessage := ssh.Marshal(toVerify) | |||
signedMessage = append([]byte(magicHeader), signedMessage...) | |||
return desiredPk.Verify(signedMessage, decodedSignature.signature) | |||
} |
@@ -15,7 +15,7 @@ | |||
// used with a fixed key in order to generate one-time keys from an nonce. | |||
// However, in this package AES isn't used and the one-time key is specified | |||
// directly. | |||
package poly1305 // import "golang.org/x/crypto/poly1305" | |||
package poly1305 | |||
import "crypto/subtle" | |||
@@ -18,7 +18,7 @@ | |||
// value. These limbs are, for the most part, zero extended and | |||
// placed into 64-bit vector register elements. Each vector | |||
// register is 128-bits wide and so holds 2 of these elements. | |||
// Using 26-bit limbs allows us plenty of headroom to accomodate | |||
// Using 26-bit limbs allows us plenty of headroom to accommodate | |||
// accumulations before and after multiplication without | |||
// overflowing either 32-bits (before multiplication) or 64-bits | |||
// (after multiplication). |
@@ -14,7 +14,7 @@ import ( | |||
"time" | |||
) | |||
// These constants from [PROTOCOL.certkeys] represent the algorithm names | |||
// These constants from [PROTOCOL.certkeys] represent the key algorithm names | |||
// for certificate types supported by this package. | |||
const ( | |||
CertAlgoRSAv01 = "ssh-rsa-cert-v01@openssh.com" | |||
@@ -27,6 +27,14 @@ const ( | |||
CertAlgoSKED25519v01 = "sk-ssh-ed25519-cert-v01@openssh.com" | |||
) | |||
// These constants from [PROTOCOL.certkeys] represent additional signature | |||
// algorithm names for certificate types supported by this package. | |||
const ( | |||
CertSigAlgoRSAv01 = "ssh-rsa-cert-v01@openssh.com" | |||
CertSigAlgoRSASHA2256v01 = "rsa-sha2-256-cert-v01@openssh.com" | |||
CertSigAlgoRSASHA2512v01 = "rsa-sha2-512-cert-v01@openssh.com" | |||
) | |||
// Certificate types distinguish between host and user | |||
// certificates. The values can be set in the CertType field of | |||
// Certificate. | |||
@@ -423,6 +431,12 @@ func (c *Certificate) SignCert(rand io.Reader, authority Signer) error { | |||
} | |||
c.SignatureKey = authority.PublicKey() | |||
if v, ok := authority.(AlgorithmSigner); ok { | |||
if v.PublicKey().Type() == KeyAlgoRSA { | |||
authority = &rsaSigner{v, SigAlgoRSASHA2512} | |||
} | |||
} | |||
sig, err := authority.Sign(rand, c.bytesForSigning()) | |||
if err != nil { | |||
return err | |||
@@ -431,8 +445,14 @@ func (c *Certificate) SignCert(rand io.Reader, authority Signer) error { | |||
return nil | |||
} | |||
// certAlgoNames includes a mapping from signature algorithms to the | |||
// corresponding certificate signature algorithm. When a key type (such | |||
// as ED25516) is associated with only one algorithm, the KeyAlgo | |||
// constant is used instead of the SigAlgo. | |||
var certAlgoNames = map[string]string{ | |||
KeyAlgoRSA: CertAlgoRSAv01, | |||
SigAlgoRSA: CertSigAlgoRSAv01, | |||
SigAlgoRSASHA2256: CertSigAlgoRSASHA2256v01, | |||
SigAlgoRSASHA2512: CertSigAlgoRSASHA2512v01, | |||
KeyAlgoDSA: CertAlgoDSAv01, | |||
KeyAlgoECDSA256: CertAlgoECDSA256v01, | |||
KeyAlgoECDSA384: CertAlgoECDSA384v01, |
@@ -18,7 +18,7 @@ import ( | |||
"io/ioutil" | |||
"golang.org/x/crypto/chacha20" | |||
"golang.org/x/crypto/poly1305" | |||
"golang.org/x/crypto/internal/poly1305" | |||
) | |||
const ( |
@@ -115,12 +115,25 @@ func (c *connection) clientHandshake(dialAddress string, config *ClientConfig) e | |||
// verifyHostKeySignature verifies the host key obtained in the key | |||
// exchange. | |||
func verifyHostKeySignature(hostKey PublicKey, result *kexResult) error { | |||
func verifyHostKeySignature(hostKey PublicKey, algo string, result *kexResult) error { | |||
sig, rest, ok := parseSignatureBody(result.Signature) | |||
if len(rest) > 0 || !ok { | |||
return errors.New("ssh: signature parse error") | |||
} | |||
// For keys, underlyingAlgo is exactly algo. For certificates, | |||
// we have to look up the underlying key algorithm that SSH | |||
// uses to evaluate signatures. | |||
underlyingAlgo := algo | |||
for sigAlgo, certAlgo := range certAlgoNames { | |||
if certAlgo == algo { | |||
underlyingAlgo = sigAlgo | |||
} | |||
} | |||
if sig.Format != underlyingAlgo { | |||
return fmt.Errorf("ssh: invalid signature algorithm %q, expected %q", sig.Format, underlyingAlgo) | |||
} | |||
return hostKey.Verify(result.H, sig) | |||
} | |||
@@ -69,11 +69,13 @@ var preferredKexAlgos = []string{ | |||
// supportedHostKeyAlgos specifies the supported host-key algorithms (i.e. methods | |||
// of authenticating servers) in preference order. | |||
var supportedHostKeyAlgos = []string{ | |||
CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, | |||
CertSigAlgoRSASHA2512v01, CertSigAlgoRSASHA2256v01, | |||
CertSigAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, | |||
CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoED25519v01, | |||
KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, | |||
KeyAlgoRSA, KeyAlgoDSA, | |||
SigAlgoRSASHA2512, SigAlgoRSASHA2256, | |||
SigAlgoRSA, KeyAlgoDSA, | |||
KeyAlgoED25519, | |||
} | |||
@@ -90,16 +92,20 @@ var supportedCompressions = []string{compressionNone} | |||
// hashFuncs keeps the mapping of supported algorithms to their respective | |||
// hashes needed for signature verification. | |||
var hashFuncs = map[string]crypto.Hash{ | |||
KeyAlgoRSA: crypto.SHA1, | |||
KeyAlgoDSA: crypto.SHA1, | |||
KeyAlgoECDSA256: crypto.SHA256, | |||
KeyAlgoECDSA384: crypto.SHA384, | |||
KeyAlgoECDSA521: crypto.SHA512, | |||
CertAlgoRSAv01: crypto.SHA1, | |||
CertAlgoDSAv01: crypto.SHA1, | |||
CertAlgoECDSA256v01: crypto.SHA256, | |||
CertAlgoECDSA384v01: crypto.SHA384, | |||
CertAlgoECDSA521v01: crypto.SHA512, | |||
SigAlgoRSA: crypto.SHA1, | |||
SigAlgoRSASHA2256: crypto.SHA256, | |||
SigAlgoRSASHA2512: crypto.SHA512, | |||
KeyAlgoDSA: crypto.SHA1, | |||
KeyAlgoECDSA256: crypto.SHA256, | |||
KeyAlgoECDSA384: crypto.SHA384, | |||
KeyAlgoECDSA521: crypto.SHA512, | |||
CertSigAlgoRSAv01: crypto.SHA1, | |||
CertSigAlgoRSASHA2256v01: crypto.SHA256, | |||
CertSigAlgoRSASHA2512v01: crypto.SHA512, | |||
CertAlgoDSAv01: crypto.SHA1, | |||
CertAlgoECDSA256v01: crypto.SHA256, | |||
CertAlgoECDSA384v01: crypto.SHA384, | |||
CertAlgoECDSA521v01: crypto.SHA512, | |||
} | |||
// unexpectedMessageError results when the SSH message that we received didn't |
@@ -457,8 +457,15 @@ func (t *handshakeTransport) sendKexInit() error { | |||
if len(t.hostKeys) > 0 { | |||
for _, k := range t.hostKeys { | |||
msg.ServerHostKeyAlgos = append( | |||
msg.ServerHostKeyAlgos, k.PublicKey().Type()) | |||
algo := k.PublicKey().Type() | |||
switch algo { | |||
case KeyAlgoRSA: | |||
msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, []string{SigAlgoRSASHA2512, SigAlgoRSASHA2256, SigAlgoRSA}...) | |||
case CertAlgoRSAv01: | |||
msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, []string{CertSigAlgoRSASHA2512v01, CertSigAlgoRSASHA2256v01, CertSigAlgoRSAv01}...) | |||
default: | |||
msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, algo) | |||
} | |||
} | |||
} else { | |||
msg.ServerHostKeyAlgos = t.hostKeyAlgorithms | |||
@@ -614,8 +621,22 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error { | |||
func (t *handshakeTransport) server(kex kexAlgorithm, algs *algorithms, magics *handshakeMagics) (*kexResult, error) { | |||
var hostKey Signer | |||
for _, k := range t.hostKeys { | |||
if algs.hostKey == k.PublicKey().Type() { | |||
kt := k.PublicKey().Type() | |||
if kt == algs.hostKey { | |||
hostKey = k | |||
} else if signer, ok := k.(AlgorithmSigner); ok { | |||
// Some signature algorithms don't show up as key types | |||
// so we have to manually check for a compatible host key. | |||
switch kt { | |||
case KeyAlgoRSA: | |||
if algs.hostKey == SigAlgoRSASHA2256 || algs.hostKey == SigAlgoRSASHA2512 { | |||
hostKey = &rsaSigner{signer, algs.hostKey} | |||
} | |||
case CertAlgoRSAv01: | |||
if algs.hostKey == CertSigAlgoRSASHA2256v01 || algs.hostKey == CertSigAlgoRSASHA2512v01 { | |||
hostKey = &rsaSigner{signer, certToPrivAlgo(algs.hostKey)} | |||
} | |||
} | |||
} | |||
} | |||
@@ -634,7 +655,7 @@ func (t *handshakeTransport) client(kex kexAlgorithm, algs *algorithms, magics * | |||
return nil, err | |||
} | |||
if err := verifyHostKeySignature(hostKey, result); err != nil { | |||
if err := verifyHostKeySignature(hostKey, algs.hostKey, result); err != nil { | |||
return nil, err | |||
} | |||
@@ -939,6 +939,15 @@ func newDSAPrivateKey(key *dsa.PrivateKey) (Signer, error) { | |||
return &dsaPrivateKey{key}, nil | |||
} | |||
type rsaSigner struct { | |||
AlgorithmSigner | |||
defaultAlgorithm string | |||
} | |||
func (s *rsaSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { | |||
return s.AlgorithmSigner.SignWithAlgorithm(rand, data, s.defaultAlgorithm) | |||
} | |||
type wrappedSigner struct { | |||
signer crypto.Signer | |||
pubKey PublicKey |
@@ -284,7 +284,7 @@ func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error) | |||
func isAcceptableAlgo(algo string) bool { | |||
switch algo { | |||
case KeyAlgoRSA, KeyAlgoDSA, KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, KeyAlgoSKECDSA256, KeyAlgoED25519, KeyAlgoSKED25519, | |||
case SigAlgoRSA, SigAlgoRSASHA2256, SigAlgoRSASHA2512, KeyAlgoDSA, KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, KeyAlgoSKECDSA256, KeyAlgoED25519, KeyAlgoSKED25519, | |||
CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoSKECDSA256v01, CertAlgoED25519v01, CertAlgoSKED25519v01: | |||
return true | |||
} |
@@ -0,0 +1,14 @@ | |||
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. | |||
// Copyright 2021 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build go1.18 | |||
// +build go1.18 | |||
package idna | |||
// Transitional processing is disabled by default in Go 1.18. | |||
// https://golang.org/issue/47510 | |||
const transitionalLookup = false |
@@ -59,10 +59,10 @@ type Option func(*options) | |||
// Transitional sets a Profile to use the Transitional mapping as defined in UTS | |||
// #46. This will cause, for example, "ß" to be mapped to "ss". Using the | |||
// transitional mapping provides a compromise between IDNA2003 and IDNA2008 | |||
// compatibility. It is used by most browsers when resolving domain names. This | |||
// compatibility. It is used by some browsers when resolving domain names. This | |||
// option is only meaningful if combined with MapForLookup. | |||
func Transitional(transitional bool) Option { | |||
return func(o *options) { o.transitional = true } | |||
return func(o *options) { o.transitional = transitional } | |||
} | |||
// VerifyDNSLength sets whether a Profile should fail if any of the IDN parts | |||
@@ -284,7 +284,7 @@ var ( | |||
punycode = &Profile{} | |||
lookup = &Profile{options{ | |||
transitional: true, | |||
transitional: transitionalLookup, | |||
useSTD3Rules: true, | |||
checkHyphens: true, | |||
checkJoiners: true, |
@@ -58,10 +58,10 @@ type Option func(*options) | |||
// Transitional sets a Profile to use the Transitional mapping as defined in UTS | |||
// #46. This will cause, for example, "ß" to be mapped to "ss". Using the | |||
// transitional mapping provides a compromise between IDNA2003 and IDNA2008 | |||
// compatibility. It is used by most browsers when resolving domain names. This | |||
// compatibility. It is used by some browsers when resolving domain names. This | |||
// option is only meaningful if combined with MapForLookup. | |||
func Transitional(transitional bool) Option { | |||
return func(o *options) { o.transitional = true } | |||
return func(o *options) { o.transitional = transitional } | |||
} | |||
// VerifyDNSLength sets whether a Profile should fail if any of the IDN parts |
@@ -0,0 +1,12 @@ | |||
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. | |||
// Copyright 2021 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build !go1.18 | |||
// +build !go1.18 | |||
package idna | |||
const transitionalLookup = true |
@@ -49,6 +49,7 @@ func decode(encoded string) (string, error) { | |||
} | |||
} | |||
i, n, bias := int32(0), initialN, initialBias | |||
overflow := false | |||
for pos < len(encoded) { | |||
oldI, w := i, int32(1) | |||
for k := base; ; k += base { | |||
@@ -60,29 +61,32 @@ func decode(encoded string) (string, error) { | |||
return "", punyError(encoded) | |||
} | |||
pos++ | |||
i += digit * w | |||
if i < 0 { | |||
i, overflow = madd(i, digit, w) | |||
if overflow { | |||
return "", punyError(encoded) | |||
} | |||
t := k - bias | |||
if t < tmin { | |||
if k <= bias { | |||
t = tmin | |||
} else if t > tmax { | |||
} else if k >= bias+tmax { | |||
t = tmax | |||
} | |||
if digit < t { | |||
break | |||
} | |||
w *= base - t | |||
if w >= math.MaxInt32/base { | |||
w, overflow = madd(0, w, base-t) | |||
if overflow { | |||
return "", punyError(encoded) | |||
} | |||
} | |||
if len(output) >= 1024 { | |||
return "", punyError(encoded) | |||
} | |||
x := int32(len(output) + 1) | |||
bias = adapt(i-oldI, x, oldI == 0) | |||
n += i / x | |||
i %= x | |||
if n > utf8.MaxRune || len(output) >= 1024 { | |||
if n < 0 || n > utf8.MaxRune { | |||
return "", punyError(encoded) | |||
} | |||
output = append(output, 0) | |||
@@ -115,6 +119,7 @@ func encode(prefix, s string) (string, error) { | |||
if b > 0 { | |||
output = append(output, '-') | |||
} | |||
overflow := false | |||
for remaining != 0 { | |||
m := int32(0x7fffffff) | |||
for _, r := range s { | |||
@@ -122,8 +127,8 @@ func encode(prefix, s string) (string, error) { | |||
m = r | |||
} | |||
} | |||
delta += (m - n) * (h + 1) | |||
if delta < 0 { | |||
delta, overflow = madd(delta, m-n, h+1) | |||
if overflow { | |||
return "", punyError(s) | |||
} | |||
n = m | |||
@@ -141,9 +146,9 @@ func encode(prefix, s string) (string, error) { | |||
q := delta | |||
for k := base; ; k += base { | |||
t := k - bias | |||
if t < tmin { | |||
if k <= bias { | |||
t = tmin | |||
} else if t > tmax { | |||
} else if k >= bias+tmax { | |||
t = tmax | |||
} | |||
if q < t { | |||
@@ -164,6 +169,15 @@ func encode(prefix, s string) (string, error) { | |||
return string(output), nil | |||
} | |||
// madd computes a + (b * c), detecting overflow. | |||
func madd(a, b, c int32) (next int32, overflow bool) { | |||
p := int64(b) * int64(c) | |||
if p > math.MaxInt32-int64(a) { | |||
return 0, true | |||
} | |||
return a + int32(p), false | |||
} | |||
func decodeDigit(x byte) (digit int32, ok bool) { | |||
switch { | |||
case '0' <= x && x <= '9': |
@@ -2,6 +2,7 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build darwin && go1.12 | |||
// +build darwin,go1.12 | |||
// This exists solely so we can linkname in symbols from syscall. |
@@ -90,9 +90,10 @@ func archInit() { | |||
osSupportsAVX = isSet(1, eax) && isSet(2, eax) | |||
if runtime.GOOS == "darwin" { | |||
// Check darwin commpage for AVX512 support. Necessary because: | |||
// https://github.com/apple/darwin-xnu/blob/0a798f6738bc1db01281fc08ae024145e84df927/osfmk/i386/fpu.c#L175-L201 | |||
osSupportsAVX512 = osSupportsAVX && darwinSupportsAVX512() | |||
// Darwin doesn't save/restore AVX-512 mask registers correctly across signal handlers. | |||
// Since users can't rely on mask register contents, let's not advertise AVX-512 support. | |||
// See issue 49233. | |||
osSupportsAVX512 = false | |||
} else { | |||
// Check if OPMASK and ZMM registers have OS support. | |||
osSupportsAVX512 = osSupportsAVX && isSet(5, eax) && isSet(6, eax) && isSet(7, eax) |
@@ -26,27 +26,3 @@ TEXT ·xgetbv(SB),NOSPLIT,$0-8 | |||
MOVL AX, eax+0(FP) | |||
MOVL DX, edx+4(FP) | |||
RET | |||
// func darwinSupportsAVX512() bool | |||
TEXT ·darwinSupportsAVX512(SB), NOSPLIT, $0-1 | |||
MOVB $0, ret+0(FP) // default to false | |||
#ifdef GOOS_darwin // return if not darwin | |||
#ifdef GOARCH_amd64 // return if not amd64 | |||
// These values from: | |||
// https://github.com/apple/darwin-xnu/blob/xnu-4570.1.46/osfmk/i386/cpu_capabilities.h | |||
#define commpage64_base_address 0x00007fffffe00000 | |||
#define commpage64_cpu_capabilities64 (commpage64_base_address+0x010) | |||
#define commpage64_version (commpage64_base_address+0x01E) | |||
#define hasAVX512F 0x0000004000000000 | |||
MOVQ $commpage64_version, BX | |||
CMPW (BX), $13 // cpu_capabilities64 undefined in versions < 13 | |||
JL no_avx512 | |||
MOVQ $commpage64_cpu_capabilities64, BX | |||
MOVQ $hasAVX512F, CX | |||
TESTQ (BX), CX | |||
JZ no_avx512 | |||
MOVB $1, ret+0(FP) | |||
no_avx512: | |||
#endif | |||
#endif | |||
RET |
@@ -149,7 +149,7 @@ To add a constant, add the header that includes it to the appropriate variable. | |||
Then, edit the regex (if necessary) to match the desired constant. Avoid making | |||
the regex too broad to avoid matching unintended constants. | |||
### mkmerge.go | |||
### internal/mkmerge | |||
This program is used to extract duplicate const, func, and type declarations | |||
from the generated architecture-specific files listed below, and merge these |
@@ -50,7 +50,7 @@ if [[ "$GOOS" = "linux" ]]; then | |||
# Use the Docker-based build system | |||
# Files generated through docker (use $cmd so you can Ctl-C the build or run) | |||
$cmd docker build --tag generate:$GOOS $GOOS | |||
$cmd docker run --interactive --tty --volume $(cd -- "$(dirname -- "$0")" && /bin/pwd):/build generate:$GOOS | |||
$cmd docker run --interactive --tty --volume $(cd -- "$(dirname -- "$0")/.." && /bin/pwd):/build generate:$GOOS | |||
exit | |||
fi | |||
@@ -54,7 +54,7 @@ includes_AIX=' | |||
includes_Darwin=' | |||
#define _DARWIN_C_SOURCE | |||
#define KERNEL | |||
#define KERNEL 1 | |||
#define _DARWIN_USE_64_BIT_INODE | |||
#define __APPLE_USE_RFC_3542 | |||
#include <stdint.h> | |||
@@ -75,6 +75,7 @@ includes_Darwin=' | |||
#include <sys/utsname.h> | |||
#include <sys/wait.h> | |||
#include <sys/xattr.h> | |||
#include <sys/vsock.h> | |||
#include <net/bpf.h> | |||
#include <net/if.h> | |||
#include <net/if_types.h> | |||
@@ -82,6 +83,9 @@ includes_Darwin=' | |||
#include <netinet/in.h> | |||
#include <netinet/ip.h> | |||
#include <termios.h> | |||
// for backwards compatibility because moved TIOCREMOTE to Kernel.framework after MacOSX12.0.sdk. | |||
#define TIOCREMOTE 0x80047469 | |||
' | |||
includes_DragonFly=' | |||
@@ -229,11 +233,13 @@ struct ltchars { | |||
#include <linux/input.h> | |||
#include <linux/kexec.h> | |||
#include <linux/keyctl.h> | |||
#include <linux/landlock.h> | |||
#include <linux/loop.h> | |||
#include <linux/lwtunnel.h> | |||
#include <linux/magic.h> | |||
#include <linux/memfd.h> | |||
#include <linux/module.h> | |||
#include <linux/mount.h> | |||
#include <linux/netfilter/nfnetlink.h> | |||
#include <linux/netlink.h> | |||
#include <linux/net_namespace.h> | |||
@@ -465,7 +471,6 @@ ccflags="$@" | |||
$2 !~ /^EQUIV_/ && | |||
$2 !~ /^EXPR_/ && | |||
$2 !~ /^EVIOC/ && | |||
$2 !~ /^EV_/ && | |||
$2 ~ /^E[A-Z0-9_]+$/ || | |||
$2 ~ /^B[0-9_]+$/ || | |||
$2 ~ /^(OLD|NEW)DEV$/ || | |||
@@ -497,6 +502,7 @@ ccflags="$@" | |||
$2 ~ /^O?XTABS$/ || | |||
$2 ~ /^TC[IO](ON|OFF)$/ || | |||
$2 ~ /^IN_/ || | |||
$2 ~ /^LANDLOCK_/ || | |||
$2 ~ /^LOCK_(SH|EX|NB|UN)$/ || | |||
$2 ~ /^LO_(KEY|NAME)_SIZE$/ || | |||
$2 ~ /^LOOP_(CLR|CTL|GET|SET)_/ || | |||
@@ -515,7 +521,7 @@ ccflags="$@" | |||
$2 ~ /^HW_MACHINE$/ || | |||
$2 ~ /^SYSCTL_VERS/ || | |||
$2 !~ "MNT_BITS" && | |||
$2 ~ /^(MS|MNT|UMOUNT)_/ || | |||
$2 ~ /^(MS|MNT|MOUNT|UMOUNT)_/ || | |||
$2 ~ /^NS_GET_/ || | |||
$2 ~ /^TUN(SET|GET|ATTACH|DETACH)/ || | |||
$2 ~ /^(O|F|[ES]?FD|NAME|S|PTRACE|PT|TFD)_/ || |
@@ -34,3 +34,52 @@ func ParseUnixCredentials(m *SocketControlMessage) (*Ucred, error) { | |||
ucred := *(*Ucred)(unsafe.Pointer(&m.Data[0])) | |||
return &ucred, nil | |||
} | |||
// PktInfo4 encodes Inet4Pktinfo into a socket control message of type IP_PKTINFO. | |||
func PktInfo4(info *Inet4Pktinfo) []byte { | |||
b := make([]byte, CmsgSpace(SizeofInet4Pktinfo)) | |||
h := (*Cmsghdr)(unsafe.Pointer(&b[0])) | |||
h.Level = SOL_IP | |||
h.Type = IP_PKTINFO | |||
h.SetLen(CmsgLen(SizeofInet4Pktinfo)) | |||
*(*Inet4Pktinfo)(h.data(0)) = *info | |||
return b | |||
} | |||
// PktInfo6 encodes Inet6Pktinfo into a socket control message of type IPV6_PKTINFO. | |||
func PktInfo6(info *Inet6Pktinfo) []byte { | |||
b := make([]byte, CmsgSpace(SizeofInet6Pktinfo)) | |||
h := (*Cmsghdr)(unsafe.Pointer(&b[0])) | |||
h.Level = SOL_IPV6 | |||
h.Type = IPV6_PKTINFO | |||
h.SetLen(CmsgLen(SizeofInet6Pktinfo)) | |||
*(*Inet6Pktinfo)(h.data(0)) = *info | |||
return b | |||
} | |||
// ParseOrigDstAddr decodes a socket control message containing the original | |||
// destination address. To receive such a message the IP_RECVORIGDSTADDR or | |||
// IPV6_RECVORIGDSTADDR option must be enabled on the socket. | |||
func ParseOrigDstAddr(m *SocketControlMessage) (Sockaddr, error) { | |||
switch { | |||
case m.Header.Level == SOL_IP && m.Header.Type == IP_ORIGDSTADDR: | |||
pp := (*RawSockaddrInet4)(unsafe.Pointer(&m.Data[0])) | |||
sa := new(SockaddrInet4) | |||
p := (*[2]byte)(unsafe.Pointer(&pp.Port)) | |||
sa.Port = int(p[0])<<8 + int(p[1]) | |||
sa.Addr = pp.Addr | |||
return sa, nil | |||
case m.Header.Level == SOL_IPV6 && m.Header.Type == IPV6_ORIGDSTADDR: | |||
pp := (*RawSockaddrInet6)(unsafe.Pointer(&m.Data[0])) | |||
sa := new(SockaddrInet6) | |||
p := (*[2]byte)(unsafe.Pointer(&pp.Port)) | |||
sa.Port = int(p[0])<<8 + int(p[1]) | |||
sa.ZoneId = pp.Scope_id | |||
sa.Addr = pp.Addr | |||
return sa, nil | |||
default: | |||
return nil, EINVAL | |||
} | |||
} |
@@ -70,9 +70,7 @@ func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) { | |||
p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port)) | |||
p[0] = byte(sa.Port >> 8) | |||
p[1] = byte(sa.Port) | |||
for i := 0; i < len(sa.Addr); i++ { | |||
sa.raw.Addr[i] = sa.Addr[i] | |||
} | |||
sa.raw.Addr = sa.Addr | |||
return unsafe.Pointer(&sa.raw), SizeofSockaddrInet4, nil | |||
} | |||
@@ -85,9 +83,7 @@ func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) { | |||
p[0] = byte(sa.Port >> 8) | |||
p[1] = byte(sa.Port) | |||
sa.raw.Scope_id = sa.ZoneId | |||
for i := 0; i < len(sa.Addr); i++ { | |||
sa.raw.Addr[i] = sa.Addr[i] | |||
} | |||
sa.raw.Addr = sa.Addr | |||
return unsafe.Pointer(&sa.raw), SizeofSockaddrInet6, nil | |||
} | |||
@@ -261,9 +257,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { | |||
sa := new(SockaddrInet4) | |||
p := (*[2]byte)(unsafe.Pointer(&pp.Port)) | |||
sa.Port = int(p[0])<<8 + int(p[1]) | |||
for i := 0; i < len(sa.Addr); i++ { | |||
sa.Addr[i] = pp.Addr[i] | |||
} | |||
sa.Addr = pp.Addr | |||
return sa, nil | |||
case AF_INET6: | |||
@@ -272,9 +266,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { | |||
p := (*[2]byte)(unsafe.Pointer(&pp.Port)) | |||
sa.Port = int(p[0])<<8 + int(p[1]) | |||
sa.ZoneId = pp.Scope_id | |||
for i := 0; i < len(sa.Addr); i++ { | |||
sa.Addr[i] = pp.Addr[i] | |||
} | |||
sa.Addr = pp.Addr | |||
return sa, nil | |||
} | |||
return nil, EAFNOSUPPORT | |||
@@ -385,6 +377,11 @@ func (w WaitStatus) TrapCause() int { return -1 } | |||
//sys fcntl(fd int, cmd int, arg int) (val int, err error) | |||
//sys fsyncRange(fd int, how int, start int64, length int64) (err error) = fsync_range | |||
func Fsync(fd int) error { | |||
return fsyncRange(fd, O_SYNC, 0, 0) | |||
} | |||
/* | |||
* Direct access | |||
*/ | |||
@@ -401,7 +398,6 @@ func (w WaitStatus) TrapCause() int { return -1 } | |||
//sys Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) | |||
//sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) | |||
//sys Fdatasync(fd int) (err error) | |||
//sys Fsync(fd int) (err error) | |||
// readdir_r | |||
//sysnb Getpgid(pid int) (pgid int, err error) | |||
@@ -163,9 +163,7 @@ func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) { | |||
p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port)) | |||
p[0] = byte(sa.Port >> 8) | |||
p[1] = byte(sa.Port) | |||
for i := 0; i < len(sa.Addr); i++ { | |||
sa.raw.Addr[i] = sa.Addr[i] | |||
} | |||
sa.raw.Addr = sa.Addr | |||
return unsafe.Pointer(&sa.raw), _Socklen(sa.raw.Len), nil | |||
} | |||
@@ -179,9 +177,7 @@ func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) { | |||
p[0] = byte(sa.Port >> 8) | |||
p[1] = byte(sa.Port) | |||
sa.raw.Scope_id = sa.ZoneId | |||
for i := 0; i < len(sa.Addr); i++ { | |||
sa.raw.Addr[i] = sa.Addr[i] | |||
} | |||
sa.raw.Addr = sa.Addr | |||
return unsafe.Pointer(&sa.raw), _Socklen(sa.raw.Len), nil | |||
} | |||
@@ -210,9 +206,7 @@ func (sa *SockaddrDatalink) sockaddr() (unsafe.Pointer, _Socklen, error) { | |||
sa.raw.Nlen = sa.Nlen | |||
sa.raw.Alen = sa.Alen | |||
sa.raw.Slen = sa.Slen | |||
for i := 0; i < len(sa.raw.Data); i++ { | |||
sa.raw.Data[i] = sa.Data[i] | |||
} | |||
sa.raw.Data = sa.Data | |||
return unsafe.Pointer(&sa.raw), SizeofSockaddrDatalink, nil | |||
} | |||
@@ -228,9 +222,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { | |||
sa.Nlen = pp.Nlen | |||
sa.Alen = pp.Alen | |||
sa.Slen = pp.Slen | |||
for i := 0; i < len(sa.Data); i++ { | |||
sa.Data[i] = pp.Data[i] | |||
} | |||
sa.Data = pp.Data | |||
return sa, nil | |||
case AF_UNIX: | |||
@@ -262,9 +254,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { | |||
sa := new(SockaddrInet4) | |||
p := (*[2]byte)(unsafe.Pointer(&pp.Port)) | |||
sa.Port = int(p[0])<<8 + int(p[1]) | |||
for i := 0; i < len(sa.Addr); i++ { | |||
sa.Addr[i] = pp.Addr[i] | |||
} | |||
sa.Addr = pp.Addr | |||
return sa, nil | |||
case AF_INET6: | |||
@@ -273,9 +263,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { | |||
p := (*[2]byte)(unsafe.Pointer(&pp.Port)) | |||
sa.Port = int(p[0])<<8 + int(p[1]) | |||
sa.ZoneId = pp.Scope_id | |||
for i := 0; i < len(sa.Addr); i++ { | |||
sa.Addr[i] = pp.Addr[i] | |||
} | |||
sa.Addr = pp.Addr | |||
return sa, nil | |||
} | |||
return anyToSockaddrGOOS(fd, rsa) |
@@ -48,6 +48,30 @@ func (sa *SockaddrCtl) sockaddr() (unsafe.Pointer, _Socklen, error) { | |||
return unsafe.Pointer(&sa.raw), SizeofSockaddrCtl, nil | |||
} | |||
// SockaddrVM implements the Sockaddr interface for AF_VSOCK type sockets. | |||
// SockaddrVM provides access to Darwin VM sockets: a mechanism that enables | |||
// bidirectional communication between a hypervisor and its guest virtual | |||
// machines. | |||
type SockaddrVM struct { | |||
// CID and Port specify a context ID and port address for a VM socket. | |||
// Guests have a unique CID, and hosts may have a well-known CID of: | |||
// - VMADDR_CID_HYPERVISOR: refers to the hypervisor process. | |||
// - VMADDR_CID_LOCAL: refers to local communication (loopback). | |||
// - VMADDR_CID_HOST: refers to other processes on the host. | |||
CID uint32 | |||
Port uint32 | |||
raw RawSockaddrVM | |||
} | |||
func (sa *SockaddrVM) sockaddr() (unsafe.Pointer, _Socklen, error) { | |||
sa.raw.Len = SizeofSockaddrVM | |||
sa.raw.Family = AF_VSOCK | |||
sa.raw.Port = sa.Port | |||
sa.raw.Cid = sa.CID | |||
return unsafe.Pointer(&sa.raw), SizeofSockaddrVM, nil | |||
} | |||
func anyToSockaddrGOOS(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { | |||
switch rsa.Addr.Family { | |||
case AF_SYSTEM: | |||
@@ -58,6 +82,13 @@ func anyToSockaddrGOOS(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { | |||
sa.Unit = pp.Sc_unit | |||
return sa, nil | |||
} | |||
case AF_VSOCK: | |||
pp := (*RawSockaddrVM)(unsafe.Pointer(rsa)) | |||
sa := &SockaddrVM{ | |||
CID: pp.Cid, | |||
Port: pp.Port, | |||
} | |||
return sa, nil | |||
} | |||
return nil, EAFNOSUPPORT | |||
} | |||
@@ -399,8 +430,25 @@ func GetsockoptXucred(fd, level, opt int) (*Xucred, error) { | |||
return x, err | |||
} | |||
func SysctlKinfoProcSlice(name string) ([]KinfoProc, error) { | |||
mib, err := sysctlmib(name) | |||
func SysctlKinfoProc(name string, args ...int) (*KinfoProc, error) { | |||
mib, err := sysctlmib(name, args...) | |||
if err != nil { | |||
return nil, err | |||
} | |||
var kinfo KinfoProc | |||
n := uintptr(SizeofKinfoProc) | |||
if err := sysctl(mib, (*byte)(unsafe.Pointer(&kinfo)), &n, nil, 0); err != nil { | |||
return nil, err | |||
} | |||
if n != SizeofKinfoProc { | |||
return nil, EIO | |||
} | |||
return &kinfo, nil | |||
} | |||
func SysctlKinfoProcSlice(name string, args ...int) ([]KinfoProc, error) { | |||
mib, err := sysctlmib(name, args...) | |||
if err != nil { | |||
return nil, err | |||
} | |||
@@ -433,6 +481,11 @@ func SysctlKinfoProcSlice(name string) ([]KinfoProc, error) { | |||
//sys sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) | |||
//sys shmat(id int, addr uintptr, flag int) (ret uintptr, err error) | |||
//sys shmctl(id int, cmd int, buf *SysvShmDesc) (result int, err error) | |||
//sys shmdt(addr uintptr) (err error) | |||
//sys shmget(key int, size int, flag int) (id int, err error) | |||
/* | |||
* Exposed directly | |||
*/ | |||
@@ -590,10 +643,6 @@ func SysctlKinfoProcSlice(name string) ([]KinfoProc, error) { | |||
// Msgget | |||
// Msgsnd | |||
// Msgrcv | |||
// Shmat | |||
// Shmctl | |||
// Shmdt | |||
// Shmget | |||
// Shm_open | |||
// Shm_unlink | |||
// Sem_open |
@@ -162,6 +162,14 @@ func (l *Lifreq) GetLifruInt() int { | |||
return *(*int)(unsafe.Pointer(&l.Lifru[0])) | |||
} | |||
func (l *Lifreq) SetLifruUint(d uint) { | |||
*(*uint)(unsafe.Pointer(&l.Lifru[0])) = d | |||
} | |||
func (l *Lifreq) GetLifruUint() uint { | |||
return *(*uint)(unsafe.Pointer(&l.Lifru[0])) | |||
} | |||
func IoctlLifreq(fd int, req uint, l *Lifreq) error { | |||
return ioctl(fd, req, uintptr(unsafe.Pointer(l))) | |||
} |
@@ -13,7 +13,6 @@ package unix | |||
import ( | |||
"encoding/binary" | |||
"runtime" | |||
"syscall" | |||
"unsafe" | |||
) | |||
@@ -38,6 +37,13 @@ func Creat(path string, mode uint32) (fd int, err error) { | |||
return Open(path, O_CREAT|O_WRONLY|O_TRUNC, mode) | |||
} | |||
func EpollCreate(size int) (fd int, err error) { | |||
if size <= 0 { | |||
return -1, EINVAL | |||
} | |||
return EpollCreate1(0) | |||
} | |||
//sys FanotifyInit(flags uint, event_f_flags uint) (fd int, err error) | |||
//sys fanotifyMark(fd int, flags uint, mask uint64, dirFd int, pathname *byte) (err error) | |||
@@ -66,6 +72,10 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { | |||
return fchmodat(dirfd, path, mode) | |||
} | |||
func InotifyInit() (fd int, err error) { | |||
return InotifyInit1(0) | |||
} | |||
//sys ioctl(fd int, req uint, arg uintptr) (err error) = SYS_IOCTL | |||
//sys ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) = SYS_IOCTL | |||
@@ -109,6 +119,23 @@ func Openat2(dirfd int, path string, how *OpenHow) (fd int, err error) { | |||
return openat2(dirfd, path, how, SizeofOpenHow) | |||
} | |||
func Pipe(p []int) error { | |||
return Pipe2(p, 0) | |||
} | |||
//sysnb pipe2(p *[2]_C_int, flags int) (err error) | |||
func Pipe2(p []int, flags int) error { | |||
if len(p) != 2 { | |||
return EINVAL | |||
} | |||
var pp [2]_C_int | |||
err := pipe2(&pp, flags) | |||
p[0] = int(pp[0]) | |||
p[1] = int(pp[1]) | |||
return err | |||
} | |||
//sys ppoll(fds *PollFd, nfds int, timeout *Timespec, sigmask *Sigset_t) (n int, err error) | |||
func Ppoll(fds []PollFd, timeout *Timespec, sigmask *Sigset_t) (n int, err error) { | |||
@@ -118,6 +145,15 @@ func Ppoll(fds []PollFd, timeout *Timespec, sigmask *Sigset_t) (n int, err error | |||
return ppoll(&fds[0], len(fds), timeout, sigmask) | |||
} | |||
func Poll(fds []PollFd, timeout int) (n int, err error) { | |||
var ts *Timespec | |||
if timeout >= 0 { | |||
ts = new(Timespec) | |||
*ts = NsecToTimespec(int64(timeout) * 1e6) | |||
} | |||
return Ppoll(fds, ts, nil) | |||
} | |||
//sys Readlinkat(dirfd int, path string, buf []byte) (n int, err error) | |||
func Readlink(path string, buf []byte) (n int, err error) { | |||
@@ -168,27 +204,7 @@ func Utimes(path string, tv []Timeval) error { | |||
//sys utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) | |||
func UtimesNano(path string, ts []Timespec) error { | |||
if ts == nil { | |||
err := utimensat(AT_FDCWD, path, nil, 0) | |||
if err != ENOSYS { | |||
return err | |||
} | |||
return utimes(path, nil) | |||
} | |||
if len(ts) != 2 { | |||
return EINVAL | |||
} | |||
err := utimensat(AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0) | |||
if err != ENOSYS { | |||
return err | |||
} | |||
// If the utimensat syscall isn't available (utimensat was added to Linux | |||
// in 2.6.22, Released, 8 July 2007) then fall back to utimes | |||
var tv [2]Timeval | |||
for i := 0; i < 2; i++ { | |||
tv[i] = NsecToTimeval(TimespecToNsec(ts[i])) | |||
} | |||
return utimes(path, (*[2]Timeval)(unsafe.Pointer(&tv[0]))) | |||
return UtimesNanoAt(AT_FDCWD, path, ts, 0) | |||
} | |||
func UtimesNanoAt(dirfd int, path string, ts []Timespec, flags int) error { | |||
@@ -356,9 +372,7 @@ func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) { | |||
p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port)) | |||
p[0] = byte(sa.Port >> 8) | |||
p[1] = byte(sa.Port) | |||
for i := 0; i < len(sa.Addr); i++ { | |||
sa.raw.Addr[i] = sa.Addr[i] | |||
} | |||
sa.raw.Addr = sa.Addr | |||
return unsafe.Pointer(&sa.raw), SizeofSockaddrInet4, nil | |||
} | |||
@@ -371,9 +385,7 @@ func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) { | |||
p[0] = byte(sa.Port >> 8) | |||
p[1] = byte(sa.Port) | |||
sa.raw.Scope_id = sa.ZoneId | |||
for i := 0; i < len(sa.Addr); i++ { | |||
sa.raw.Addr[i] = sa.Addr[i] | |||
} | |||
sa.raw.Addr = sa.Addr | |||
return unsafe.Pointer(&sa.raw), SizeofSockaddrInet6, nil | |||
} | |||
@@ -422,9 +434,7 @@ func (sa *SockaddrLinklayer) sockaddr() (unsafe.Pointer, _Socklen, error) { | |||
sa.raw.Hatype = sa.Hatype | |||
sa.raw.Pkttype = sa.Pkttype | |||
sa.raw.Halen = sa.Halen | |||
for i := 0; i < len(sa.Addr); i++ { | |||
sa.raw.Addr[i] = sa.Addr[i] | |||
} | |||
sa.raw.Addr = sa.Addr | |||
return unsafe.Pointer(&sa.raw), SizeofSockaddrLinklayer, nil | |||
} | |||
@@ -839,12 +849,10 @@ func (sa *SockaddrTIPC) sockaddr() (unsafe.Pointer, _Socklen, error) { | |||
if sa.Addr == nil { | |||
return nil, 0, EINVAL | |||
} | |||
sa.raw.Family = AF_TIPC | |||
sa.raw.Scope = int8(sa.Scope) | |||
sa.raw.Addrtype = sa.Addr.tipcAddrtype() | |||
sa.raw.Addr = sa.Addr.tipcAddr() | |||
return unsafe.Pointer(&sa.raw), SizeofSockaddrTIPC, nil | |||
} | |||
@@ -858,9 +866,7 @@ type SockaddrL2TPIP struct { | |||
func (sa *SockaddrL2TPIP) sockaddr() (unsafe.Pointer, _Socklen, error) { | |||
sa.raw.Family = AF_INET | |||
sa.raw.Conn_id = sa.ConnId | |||
for i := 0; i < len(sa.Addr); i++ { | |||
sa.raw.Addr[i] = sa.Addr[i] | |||
} | |||
sa.raw.Addr = sa.Addr | |||
return unsafe.Pointer(&sa.raw), SizeofSockaddrL2TPIP, nil | |||
} | |||
@@ -876,9 +882,7 @@ func (sa *SockaddrL2TPIP6) sockaddr() (unsafe.Pointer, _Socklen, error) { | |||
sa.raw.Family = AF_INET6 | |||
sa.raw.Conn_id = sa.ConnId | |||
sa.raw.Scope_id = sa.ZoneId | |||
for i := 0; i < len(sa.Addr); i++ { | |||
sa.raw.Addr[i] = sa.Addr[i] | |||
} | |||
sa.raw.Addr = sa.Addr | |||
return unsafe.Pointer(&sa.raw), SizeofSockaddrL2TPIP6, nil | |||
} | |||
@@ -974,9 +978,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { | |||
sa.Hatype = pp.Hatype | |||
sa.Pkttype = pp.Pkttype | |||
sa.Halen = pp.Halen | |||
for i := 0; i < len(sa.Addr); i++ { | |||
sa.Addr[i] = pp.Addr[i] | |||
} | |||
sa.Addr = pp.Addr | |||
return sa, nil | |||
case AF_UNIX: | |||
@@ -1015,18 +1017,14 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { | |||
pp := (*RawSockaddrL2TPIP)(unsafe.Pointer(rsa)) | |||
sa := new(SockaddrL2TPIP) | |||
sa.ConnId = pp.Conn_id | |||
for i := 0; i < len(sa.Addr); i++ { | |||
sa.Addr[i] = pp.Addr[i] | |||
} | |||
sa.Addr = pp.Addr | |||
return sa, nil | |||
default: | |||
pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa)) | |||
sa := new(SockaddrInet4) | |||
p := (*[2]byte)(unsafe.Pointer(&pp.Port)) | |||
sa.Port = int(p[0])<<8 + int(p[1]) | |||
for i := 0; i < len(sa.Addr); i++ { | |||
sa.Addr[i] = pp.Addr[i] | |||
} | |||
sa.Addr = pp.Addr | |||
return sa, nil | |||
} | |||
@@ -1042,9 +1040,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { | |||
sa := new(SockaddrL2TPIP6) | |||
sa.ConnId = pp.Conn_id | |||
sa.ZoneId = pp.Scope_id | |||
for i := 0; i < len(sa.Addr); i++ { | |||
sa.Addr[i] = pp.Addr[i] | |||
} | |||
sa.Addr = pp.Addr | |||
return sa, nil | |||
default: | |||
pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa)) | |||
@@ -1052,9 +1048,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { | |||
p := (*[2]byte)(unsafe.Pointer(&pp.Port)) | |||
sa.Port = int(p[0])<<8 + int(p[1]) | |||
sa.ZoneId = pp.Scope_id | |||
for i := 0; i < len(sa.Addr); i++ { | |||
sa.Addr[i] = pp.Addr[i] | |||
} | |||
sa.Addr = pp.Addr | |||
return sa, nil | |||
} | |||
@@ -1229,11 +1223,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { | |||
func Accept(fd int) (nfd int, sa Sockaddr, err error) { | |||
var rsa RawSockaddrAny | |||
var len _Socklen = SizeofSockaddrAny | |||
// Try accept4 first for Android, then try accept for kernel older than 2.6.28 | |||
nfd, err = accept4(fd, &rsa, &len, 0) | |||
if err == ENOSYS { | |||
nfd, err = accept(fd, &rsa, &len) | |||
} | |||
if err != nil { | |||
return | |||
} | |||
@@ -1785,6 +1775,16 @@ func Mount(source string, target string, fstype string, flags uintptr, data stri | |||
return mount(source, target, fstype, flags, datap) | |||
} | |||
//sys mountSetattr(dirfd int, pathname string, flags uint, attr *MountAttr, size uintptr) (err error) = SYS_MOUNT_SETATTR | |||
// MountSetattr is a wrapper for mount_setattr(2). | |||
// https://man7.org/linux/man-pages/man2/mount_setattr.2.html | |||
// | |||
// Requires kernel >= 5.12. | |||
func MountSetattr(dirfd int, pathname string, flags uint, attr *MountAttr) error { | |||
return mountSetattr(dirfd, pathname, flags, attr, unsafe.Sizeof(*attr)) | |||
} | |||
func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { | |||
if raceenabled { | |||
raceReleaseMerge(unsafe.Pointer(&ioSync)) | |||
@@ -1816,11 +1816,7 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err e | |||
//sys Dup(oldfd int) (fd int, err error) | |||
func Dup2(oldfd, newfd int) error { | |||
// Android O and newer blocks dup2; riscv and arm64 don't implement dup2. | |||
if runtime.GOOS == "android" || runtime.GOARCH == "riscv64" || runtime.GOARCH == "arm64" { | |||
return Dup3(oldfd, newfd, 0) | |||
} | |||
return dup2(oldfd, newfd) | |||
return Dup3(oldfd, newfd, 0) | |||
} | |||
//sys Dup3(oldfd int, newfd int, flags int) (err error) | |||
@@ -2308,6 +2304,14 @@ type RemoteIovec struct { | |||
//sys ProcessVMReadv(pid int, localIov []Iovec, remoteIov []RemoteIovec, flags uint) (n int, err error) = SYS_PROCESS_VM_READV | |||
//sys ProcessVMWritev(pid int, localIov []Iovec, remoteIov []RemoteIovec, flags uint) (n int, err error) = SYS_PROCESS_VM_WRITEV | |||
//sys PidfdOpen(pid int, flags int) (fd int, err error) = SYS_PIDFD_OPEN | |||
//sys PidfdGetfd(pidfd int, targetfd int, flags int) (fd int, err error) = SYS_PIDFD_GETFD | |||
//sys shmat(id int, addr uintptr, flag int) (ret uintptr, err error) | |||
//sys shmctl(id int, cmd int, buf *SysvShmDesc) (result int, err error) | |||
//sys shmdt(addr uintptr) (err error) | |||
//sys shmget(key int, size int, flag int) (id int, err error) | |||
/* | |||
* Unimplemented | |||
*/ | |||
@@ -2389,10 +2393,6 @@ type RemoteIovec struct { | |||
// SetRobustList | |||
// SetThreadArea | |||
// SetTidAddress | |||
// Shmat | |||
// Shmctl | |||
// Shmdt | |||
// Shmget | |||
// Sigaltstack | |||
// Swapoff | |||
// Swapon |
@@ -19,36 +19,8 @@ func setTimeval(sec, usec int64) Timeval { | |||
return Timeval{Sec: int32(sec), Usec: int32(usec)} | |||
} | |||
//sysnb pipe(p *[2]_C_int) (err error) | |||
func Pipe(p []int) (err error) { | |||
if len(p) != 2 { | |||
return EINVAL | |||
} | |||
var pp [2]_C_int | |||
err = pipe(&pp) | |||
p[0] = int(pp[0]) | |||
p[1] = int(pp[1]) | |||
return | |||
} | |||
//sysnb pipe2(p *[2]_C_int, flags int) (err error) | |||
func Pipe2(p []int, flags int) (err error) { | |||
if len(p) != 2 { | |||
return EINVAL | |||
} | |||
var pp [2]_C_int | |||
err = pipe2(&pp, flags) | |||
p[0] = int(pp[0]) | |||
p[1] = int(pp[1]) | |||
return | |||
} | |||
// 64-bit file system and 32-bit uid calls | |||
// (386 default is 32-bit file system and 16-bit uid). | |||
//sys dup2(oldfd int, newfd int) (err error) | |||
//sysnb EpollCreate(size int) (fd int, err error) | |||
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) | |||
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64_64 | |||
//sys Fchown(fd int, uid int, gid int) (err error) = SYS_FCHOWN32 | |||
@@ -59,7 +31,6 @@ func Pipe2(p []int, flags int) (err error) { | |||
//sysnb Geteuid() (euid int) = SYS_GETEUID32 | |||
//sysnb Getgid() (gid int) = SYS_GETGID32 | |||
//sysnb Getuid() (uid int) = SYS_GETUID32 | |||
//sysnb InotifyInit() (fd int, err error) | |||
//sys Ioperm(from int, num int, on int) (err error) | |||
//sys Iopl(level int) (err error) | |||
//sys Lchown(path string, uid int, gid int) (err error) = SYS_LCHOWN32 | |||
@@ -381,12 +352,3 @@ func (cmsg *Cmsghdr) SetLen(length int) { | |||
func (rsa *RawSockaddrNFCLLCP) SetServiceNameLen(length int) { | |||
rsa.Service_name_len = uint32(length) | |||
} | |||
//sys poll(fds *PollFd, nfds int, timeout int) (n int, err error) | |||
func Poll(fds []PollFd, timeout int) (n int, err error) { | |||
if len(fds) == 0 { | |||
return poll(nil, 0, timeout) | |||
} | |||
return poll(&fds[0], len(fds), timeout) | |||
} |
@@ -7,8 +7,6 @@ | |||
package unix | |||
//sys dup2(oldfd int, newfd int) (err error) | |||
//sysnb EpollCreate(size int) (fd int, err error) | |||
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) | |||
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64 | |||
//sys Fchown(fd int, uid int, gid int) (err error) | |||
@@ -21,17 +19,6 @@ package unix | |||
//sysnb Getgid() (gid int) | |||
//sysnb Getrlimit(resource int, rlim *Rlimit) (err error) | |||
//sysnb Getuid() (uid int) | |||
//sysnb inotifyInit() (fd int, err error) | |||
func InotifyInit() (fd int, err error) { | |||
// First try inotify_init1, because Android's seccomp policy blocks the latter. | |||
fd, err = InotifyInit1(0) | |||
if err == ENOSYS { | |||
fd, err = inotifyInit() | |||
} | |||
return | |||
} | |||
//sys Ioperm(from int, num int, on int) (err error) | |||
//sys Iopl(level int) (err error) | |||
//sys Lchown(path string, uid int, gid int) (err error) | |||
@@ -126,32 +113,6 @@ func setTimeval(sec, usec int64) Timeval { | |||
return Timeval{Sec: sec, Usec: usec} | |||
} | |||
//sysnb pipe(p *[2]_C_int) (err error) | |||
func Pipe(p []int) (err error) { | |||
if len(p) != 2 { | |||
return EINVAL | |||
} | |||
var pp [2]_C_int | |||
err = pipe(&pp) | |||
p[0] = int(pp[0]) | |||
p[1] = int(pp[1]) | |||
return | |||
} | |||
//sysnb pipe2(p *[2]_C_int, flags int) (err error) | |||
func Pipe2(p []int, flags int) (err error) { | |||
if len(p) != 2 { | |||
return EINVAL | |||
} | |||
var pp [2]_C_int | |||
err = pipe2(&pp, flags) | |||
p[0] = int(pp[0]) | |||
p[1] = int(pp[1]) | |||
return | |||
} | |||
func (r *PtraceRegs) PC() uint64 { return r.Rip } | |||
func (r *PtraceRegs) SetPC(pc uint64) { r.Rip = pc } | |||
@@ -176,15 +137,6 @@ func (rsa *RawSockaddrNFCLLCP) SetServiceNameLen(length int) { | |||
rsa.Service_name_len = uint64(length) | |||
} | |||
//sys poll(fds *PollFd, nfds int, timeout int) (n int, err error) | |||
func Poll(fds []PollFd, timeout int) (n int, err error) { | |||
if len(fds) == 0 { | |||
return poll(nil, 0, timeout) | |||
} | |||
return poll(&fds[0], len(fds), timeout) | |||
} | |||
//sys kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, flags int) (err error) | |||
func KexecFileLoad(kernelFd int, initrdFd int, cmdline string, flags int) error { |
@@ -19,36 +19,6 @@ func setTimeval(sec, usec int64) Timeval { | |||
return Timeval{Sec: int32(sec), Usec: int32(usec)} | |||
} | |||
//sysnb pipe(p *[2]_C_int) (err error) | |||
func Pipe(p []int) (err error) { | |||
if len(p) != 2 { | |||
return EINVAL | |||
} | |||
var pp [2]_C_int | |||
// Try pipe2 first for Android O, then try pipe for kernel 2.6.23. | |||
err = pipe2(&pp, 0) | |||
if err == ENOSYS { | |||
err = pipe(&pp) | |||
} | |||
p[0] = int(pp[0]) | |||
p[1] = int(pp[1]) | |||
return | |||
} | |||
//sysnb pipe2(p *[2]_C_int, flags int) (err error) | |||
func Pipe2(p []int, flags int) (err error) { | |||
if len(p) != 2 { | |||
return EINVAL | |||
} | |||
var pp [2]_C_int | |||
err = pipe2(&pp, flags) | |||
p[0] = int(pp[0]) | |||
p[1] = int(pp[1]) | |||
return | |||
} | |||
func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { | |||
newoffset, errno := seek(fd, offset, whence) | |||
if errno != 0 { | |||
@@ -76,8 +46,6 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { | |||
// 64-bit file system and 32-bit uid calls | |||
// (16-bit uid calls are not always supported in newer kernels) | |||
//sys dup2(oldfd int, newfd int) (err error) | |||
//sysnb EpollCreate(size int) (fd int, err error) | |||
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) | |||
//sys Fchown(fd int, uid int, gid int) (err error) = SYS_FCHOWN32 | |||
//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64 | |||
@@ -86,7 +54,6 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { | |||
//sysnb Geteuid() (euid int) = SYS_GETEUID32 | |||
//sysnb Getgid() (gid int) = SYS_GETGID32 | |||
//sysnb Getuid() (uid int) = SYS_GETUID32 | |||
//sysnb InotifyInit() (fd int, err error) | |||
//sys Lchown(path string, uid int, gid int) (err error) = SYS_LCHOWN32 | |||
//sys Listen(s int, n int) (err error) | |||
//sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64 | |||
@@ -260,15 +227,6 @@ func (rsa *RawSockaddrNFCLLCP) SetServiceNameLen(length int) { | |||
rsa.Service_name_len = uint32(length) | |||
} | |||
//sys poll(fds *PollFd, nfds int, timeout int) (n int, err error) | |||
func Poll(fds []PollFd, timeout int) (n int, err error) { | |||
if len(fds) == 0 { | |||
return poll(nil, 0, timeout) | |||
} | |||
return poll(&fds[0], len(fds), timeout) | |||
} | |||
//sys armSyncFileRange(fd int, flags int, off int64, n int64) (err error) = SYS_ARM_SYNC_FILE_RANGE | |||
func SyncFileRange(fd int, off int64, n int64, flags int) error { |
@@ -9,13 +9,6 @@ package unix | |||
import "unsafe" | |||
func EpollCreate(size int) (fd int, err error) { | |||
if size <= 0 { | |||
return -1, EINVAL | |||
} | |||
return EpollCreate1(0) | |||
} | |||
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) = SYS_EPOLL_PWAIT | |||
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64 | |||
//sys Fchown(fd int, uid int, gid int) (err error) | |||
@@ -145,30 +138,6 @@ func utimes(path string, tv *[2]Timeval) (err error) { | |||
return utimensat(AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0) | |||
} | |||
func Pipe(p []int) (err error) { | |||
if len(p) != 2 { | |||
return EINVAL | |||
} | |||
var pp [2]_C_int | |||
err = pipe2(&pp, 0) | |||
p[0] = int(pp[0]) | |||
p[1] = int(pp[1]) | |||
return | |||
} | |||
//sysnb pipe2(p *[2]_C_int, flags int) (err error) | |||
func Pipe2(p []int, flags int) (err error) { | |||
if len(p) != 2 { | |||
return EINVAL | |||
} | |||
var pp [2]_C_int | |||
err = pipe2(&pp, flags) | |||
p[0] = int(pp[0]) | |||
p[1] = int(pp[1]) | |||
return | |||
} | |||
// Getrlimit prefers the prlimit64 system call. See issue 38604. | |||
func Getrlimit(resource int, rlim *Rlimit) error { | |||
err := Prlimit(0, resource, nil, rlim) | |||
@@ -211,31 +180,11 @@ func (rsa *RawSockaddrNFCLLCP) SetServiceNameLen(length int) { | |||
rsa.Service_name_len = uint64(length) | |||
} | |||
func InotifyInit() (fd int, err error) { | |||
return InotifyInit1(0) | |||
} | |||
// dup2 exists because func Dup3 in syscall_linux.go references | |||
// it in an unreachable path. dup2 isn't available on arm64. | |||
func dup2(oldfd int, newfd int) error | |||
func Pause() error { | |||
_, err := ppoll(nil, 0, nil, nil) | |||
return err | |||
} | |||
func Poll(fds []PollFd, timeout int) (n int, err error) { | |||
var ts *Timespec | |||
if timeout >= 0 { | |||
ts = new(Timespec) | |||
*ts = NsecToTimespec(int64(timeout) * 1e6) | |||
} | |||
if len(fds) == 0 { | |||
return ppoll(nil, 0, ts, nil) | |||
} | |||
return ppoll(&fds[0], len(fds), ts, nil) | |||
} | |||
//sys kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, flags int) (err error) | |||
func KexecFileLoad(kernelFd int, initrdFd int, cmdline string, flags int) error { |
@@ -8,8 +8,6 @@ | |||
package unix | |||
//sys dup2(oldfd int, newfd int) (err error) | |||
//sysnb EpollCreate(size int) (fd int, err error) | |||
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) | |||
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64 | |||
//sys Fchown(fd int, uid int, gid int) (err error) | |||
@@ -94,30 +92,6 @@ func setTimeval(sec, usec int64) Timeval { | |||
return Timeval{Sec: sec, Usec: usec} | |||
} | |||
func Pipe(p []int) (err error) { | |||
if len(p) != 2 { | |||
return EINVAL | |||
} | |||
var pp [2]_C_int | |||
err = pipe2(&pp, 0) | |||
p[0] = int(pp[0]) | |||
p[1] = int(pp[1]) | |||
return | |||
} | |||
//sysnb pipe2(p *[2]_C_int, flags int) (err error) | |||
func Pipe2(p []int, flags int) (err error) { | |||
if len(p) != 2 { | |||
return EINVAL | |||
} | |||
var pp [2]_C_int | |||
err = pipe2(&pp, flags) | |||
p[0] = int(pp[0]) | |||
p[1] = int(pp[1]) | |||
return | |||
} | |||
func Ioperm(from int, num int, on int) (err error) { | |||
return ENOSYS | |||
} | |||
@@ -220,16 +194,3 @@ func (cmsg *Cmsghdr) SetLen(length int) { | |||
func (rsa *RawSockaddrNFCLLCP) SetServiceNameLen(length int) { | |||
rsa.Service_name_len = uint64(length) | |||
} | |||
func InotifyInit() (fd int, err error) { | |||
return InotifyInit1(0) | |||
} | |||
//sys poll(fds *PollFd, nfds int, timeout int) (n int, err error) | |||
func Poll(fds []PollFd, timeout int) (n int, err error) { | |||
if len(fds) == 0 { | |||
return poll(nil, 0, timeout) | |||
} | |||
return poll(&fds[0], len(fds), timeout) | |||
} |
@@ -15,8 +15,6 @@ import ( | |||
func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) | |||
//sys dup2(oldfd int, newfd int) (err error) | |||
//sysnb EpollCreate(size int) (fd int, err error) | |||
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) | |||
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64 | |||
//sys Fchown(fd int, uid int, gid int) (err error) | |||
@@ -60,7 +58,6 @@ func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, | |||
//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error) | |||
//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error) | |||
//sysnb InotifyInit() (fd int, err error) | |||
//sys Ioperm(from int, num int, on int) (err error) | |||
//sys Iopl(level int) (err error) | |||
@@ -113,29 +110,6 @@ func setTimeval(sec, usec int64) Timeval { | |||
return Timeval{Sec: int32(sec), Usec: int32(usec)} | |||
} | |||
//sysnb pipe2(p *[2]_C_int, flags int) (err error) | |||
func Pipe2(p []int, flags int) (err error) { | |||
if len(p) != 2 { | |||
return EINVAL | |||
} | |||
var pp [2]_C_int | |||
err = pipe2(&pp, flags) | |||
p[0] = int(pp[0]) | |||
p[1] = int(pp[1]) | |||
return | |||
} | |||
//sysnb pipe() (p1 int, p2 int, err error) | |||
func Pipe(p []int) (err error) { | |||
if len(p) != 2 { | |||
return EINVAL | |||
} | |||
p[0], p[1], err = pipe() | |||
return | |||
} | |||
//sys mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, err error) | |||
func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) { | |||
@@ -232,12 +206,3 @@ func (cmsg *Cmsghdr) SetLen(length int) { | |||
func (rsa *RawSockaddrNFCLLCP) SetServiceNameLen(length int) { | |||
rsa.Service_name_len = uint32(length) | |||
} | |||
//sys poll(fds *PollFd, nfds int, timeout int) (n int, err error) | |||
func Poll(fds []PollFd, timeout int) (n int, err error) { | |||
if len(fds) == 0 { | |||
return poll(nil, 0, timeout) | |||
} | |||
return poll(&fds[0], len(fds), timeout) | |||
} |
@@ -12,8 +12,6 @@ import ( | |||
"unsafe" | |||
) | |||
//sys dup2(oldfd int, newfd int) (err error) | |||
//sysnb EpollCreate(size int) (fd int, err error) | |||
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) | |||
//sys Fchown(fd int, uid int, gid int) (err error) | |||
//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64 | |||
@@ -23,7 +21,6 @@ import ( | |||
//sysnb Geteuid() (euid int) | |||
//sysnb Getgid() (gid int) | |||
//sysnb Getuid() (uid int) | |||
//sysnb InotifyInit() (fd int, err error) | |||
//sys Ioperm(from int, num int, on int) (err error) | |||
//sys Iopl(level int) (err error) | |||
//sys Lchown(path string, uid int, gid int) (err error) | |||
@@ -218,41 +215,6 @@ func (rsa *RawSockaddrNFCLLCP) SetServiceNameLen(length int) { | |||
rsa.Service_name_len = uint32(length) | |||
} | |||
//sysnb pipe(p *[2]_C_int) (err error) | |||
func Pipe(p []int) (err error) { | |||
if len(p) != 2 { | |||
return EINVAL | |||
} | |||
var pp [2]_C_int | |||
err = pipe(&pp) | |||
p[0] = int(pp[0]) | |||
p[1] = int(pp[1]) | |||
return | |||
} | |||
//sysnb pipe2(p *[2]_C_int, flags int) (err error) | |||
func Pipe2(p []int, flags int) (err error) { | |||
if len(p) != 2 { | |||
return EINVAL | |||
} | |||
var pp [2]_C_int | |||
err = pipe2(&pp, flags) | |||
p[0] = int(pp[0]) | |||
p[1] = int(pp[1]) | |||
return | |||
} | |||
//sys poll(fds *PollFd, nfds int, timeout int) (n int, err error) | |||
func Poll(fds []PollFd, timeout int) (n int, err error) { | |||
if len(fds) == 0 { | |||
return poll(nil, 0, timeout) | |||
} | |||
return poll(&fds[0], len(fds), timeout) | |||
} | |||
//sys syncFileRange2(fd int, flags int, off int64, n int64) (err error) = SYS_SYNC_FILE_RANGE2 | |||
func SyncFileRange(fd int, off int64, n int64, flags int) error { |
@@ -8,8 +8,6 @@ | |||
package unix | |||
//sys dup2(oldfd int, newfd int) (err error) | |||
//sysnb EpollCreate(size int) (fd int, err error) | |||
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) | |||
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64 | |||
//sys Fchown(fd int, uid int, gid int) (err error) | |||
@@ -22,7 +20,6 @@ package unix | |||
//sysnb Getgid() (gid int) | |||
//sysnb Getrlimit(resource int, rlim *Rlimit) (err error) = SYS_UGETRLIMIT | |||
//sysnb Getuid() (uid int) | |||
//sysnb InotifyInit() (fd int, err error) | |||
//sys Ioperm(from int, num int, on int) (err error) | |||
//sys Iopl(level int) (err error) | |||
//sys Lchown(path string, uid int, gid int) (err error) | |||
@@ -104,41 +101,6 @@ func (rsa *RawSockaddrNFCLLCP) SetServiceNameLen(length int) { | |||
rsa.Service_name_len = uint64(length) | |||
} | |||
//sysnb pipe(p *[2]_C_int) (err error) | |||
func Pipe(p []int) (err error) { | |||
if len(p) != 2 { | |||
return EINVAL | |||
} | |||
var pp [2]_C_int | |||
err = pipe(&pp) | |||
p[0] = int(pp[0]) | |||
p[1] = int(pp[1]) | |||
return | |||
} | |||
//sysnb pipe2(p *[2]_C_int, flags int) (err error) | |||
func Pipe2(p []int, flags int) (err error) { | |||
if len(p) != 2 { | |||
return EINVAL | |||
} | |||
var pp [2]_C_int | |||
err = pipe2(&pp, flags) | |||
p[0] = int(pp[0]) | |||
p[1] = int(pp[1]) | |||
return | |||
} | |||
//sys poll(fds *PollFd, nfds int, timeout int) (n int, err error) | |||
func Poll(fds []PollFd, timeout int) (n int, err error) { | |||
if len(fds) == 0 { | |||
return poll(nil, 0, timeout) | |||
} | |||
return poll(&fds[0], len(fds), timeout) | |||
} | |||
//sys syncFileRange2(fd int, flags int, off int64, n int64) (err error) = SYS_SYNC_FILE_RANGE2 | |||
func SyncFileRange(fd int, off int64, n int64, flags int) error { |
@@ -9,13 +9,6 @@ package unix | |||
import "unsafe" | |||
func EpollCreate(size int) (fd int, err error) { | |||
if size <= 0 { | |||
return -1, EINVAL | |||
} | |||
return EpollCreate1(0) | |||
} | |||
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) = SYS_EPOLL_PWAIT | |||
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64 | |||
//sys Fchown(fd int, uid int, gid int) (err error) | |||
@@ -144,30 +137,6 @@ func utimes(path string, tv *[2]Timeval) (err error) { | |||
return utimensat(AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0) | |||
} | |||
func Pipe(p []int) (err error) { | |||
if len(p) != 2 { | |||
return EINVAL | |||
} | |||
var pp [2]_C_int | |||
err = pipe2(&pp, 0) | |||
p[0] = int(pp[0]) | |||
p[1] = int(pp[1]) | |||
return | |||
} | |||
//sysnb pipe2(p *[2]_C_int, flags int) (err error) | |||
func Pipe2(p []int, flags int) (err error) { | |||
if len(p) != 2 { | |||
return EINVAL | |||
} | |||
var pp [2]_C_int | |||
err = pipe2(&pp, flags) | |||
p[0] = int(pp[0]) | |||
p[1] = int(pp[1]) | |||
return | |||
} | |||
func (r *PtraceRegs) PC() uint64 { return r.Pc } | |||
func (r *PtraceRegs) SetPC(pc uint64) { r.Pc = pc } | |||
@@ -192,27 +161,11 @@ func (rsa *RawSockaddrNFCLLCP) SetServiceNameLen(length int) { | |||
rsa.Service_name_len = uint64(length) | |||
} | |||
func InotifyInit() (fd int, err error) { | |||
return InotifyInit1(0) | |||
} | |||
func Pause() error { | |||
_, err := ppoll(nil, 0, nil, nil) | |||
return err | |||
} | |||
func Poll(fds []PollFd, timeout int) (n int, err error) { | |||
var ts *Timespec | |||
if timeout >= 0 { | |||
ts = new(Timespec) | |||
*ts = NsecToTimespec(int64(timeout) * 1e6) | |||
} | |||
if len(fds) == 0 { | |||
return ppoll(nil, 0, ts, nil) | |||
} | |||
return ppoll(&fds[0], len(fds), ts, nil) | |||
} | |||
func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { | |||
return Renameat2(olddirfd, oldpath, newdirfd, newpath, 0) | |||
} | |||
@@ -229,7 +182,3 @@ func KexecFileLoad(kernelFd int, initrdFd int, cmdline string, flags int) error | |||
} | |||
return kexecFileLoad(kernelFd, initrdFd, cmdlineLen, cmdline, flags) | |||
} | |||
// dup2 exists because func Dup3 in syscall_linux.go references | |||
// it in an unreachable path. dup2 isn't available on arm64. | |||
func dup2(oldfd int, newfd int) error |
@@ -11,8 +11,6 @@ import ( | |||
"unsafe" | |||
) | |||
//sys dup2(oldfd int, newfd int) (err error) | |||
//sysnb EpollCreate(size int) (fd int, err error) | |||
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) | |||
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64 | |||
//sys Fchown(fd int, uid int, gid int) (err error) | |||
@@ -25,7 +23,6 @@ import ( | |||
//sysnb Getgid() (gid int) | |||
//sysnb Getrlimit(resource int, rlim *Rlimit) (err error) | |||
//sysnb Getuid() (uid int) | |||
//sysnb InotifyInit() (fd int, err error) | |||
//sys Lchown(path string, uid int, gid int) (err error) | |||
//sys Lstat(path string, stat *Stat_t) (err error) | |||
//sys Pause() (err error) | |||
@@ -77,30 +74,6 @@ func setTimeval(sec, usec int64) Timeval { | |||
return Timeval{Sec: sec, Usec: usec} | |||
} | |||
//sysnb pipe2(p *[2]_C_int, flags int) (err error) | |||
func Pipe(p []int) (err error) { | |||
if len(p) != 2 { | |||
return EINVAL | |||
} | |||
var pp [2]_C_int | |||
err = pipe2(&pp, 0) // pipe2 is the same as pipe when flags are set to 0. | |||
p[0] = int(pp[0]) | |||
p[1] = int(pp[1]) | |||
return | |||
} | |||
func Pipe2(p []int, flags int) (err error) { | |||
if len(p) != 2 { | |||
return EINVAL | |||
} | |||
var pp [2]_C_int | |||
err = pipe2(&pp, flags) | |||
p[0] = int(pp[0]) | |||
p[1] = int(pp[1]) | |||
return | |||
} | |||
func Ioperm(from int, num int, on int) (err error) { | |||
return ENOSYS | |||
} | |||
@@ -324,15 +297,6 @@ func Shutdown(s, how int) error { | |||
return nil | |||
} | |||
//sys poll(fds *PollFd, nfds int, timeout int) (n int, err error) | |||
func Poll(fds []PollFd, timeout int) (n int, err error) { | |||
if len(fds) == 0 { | |||
return poll(nil, 0, timeout) | |||
} | |||
return poll(&fds[0], len(fds), timeout) | |||
} | |||
//sys kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, flags int) (err error) | |||
func KexecFileLoad(kernelFd int, initrdFd int, cmdline string, flags int) error { |
@@ -9,7 +9,6 @@ package unix | |||
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) | |||
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64 | |||
//sys dup2(oldfd int, newfd int) (err error) | |||
//sys Fchown(fd int, uid int, gid int) (err error) | |||
//sys Fstat(fd int, stat *Stat_t) (err error) | |||
//sys Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64 | |||
@@ -20,7 +19,6 @@ package unix | |||
//sysnb Getgid() (gid int) | |||
//sysnb Getrlimit(resource int, rlim *Rlimit) (err error) | |||
//sysnb Getuid() (uid int) | |||
//sysnb InotifyInit() (fd int, err error) | |||
//sys Lchown(path string, uid int, gid int) (err error) | |||
//sys Listen(s int, n int) (err error) | |||
//sys Lstat(path string, stat *Stat_t) (err error) | |||
@@ -119,38 +117,3 @@ func (cmsg *Cmsghdr) SetLen(length int) { | |||
func (rsa *RawSockaddrNFCLLCP) SetServiceNameLen(length int) { | |||
rsa.Service_name_len = uint64(length) | |||
} | |||
//sysnb pipe(p *[2]_C_int) (err error) | |||
func Pipe(p []int) (err error) { | |||
if len(p) != 2 { | |||
return EINVAL | |||
} | |||
var pp [2]_C_int | |||
err = pipe(&pp) | |||
p[0] = int(pp[0]) | |||
p[1] = int(pp[1]) | |||
return | |||
} | |||
//sysnb pipe2(p *[2]_C_int, flags int) (err error) | |||
func Pipe2(p []int, flags int) (err error) { | |||
if len(p) != 2 { | |||
return EINVAL | |||
} | |||
var pp [2]_C_int | |||
err = pipe2(&pp, flags) | |||
p[0] = int(pp[0]) | |||
p[1] = int(pp[1]) | |||
return | |||
} | |||
//sys poll(fds *PollFd, nfds int, timeout int) (n int, err error) | |||
func Poll(fds []PollFd, timeout int) (n int, err error) { | |||
if len(fds) == 0 { | |||
return poll(nil, 0, timeout) | |||
} | |||
return poll(&fds[0], len(fds), timeout) | |||
} |
@@ -92,9 +92,7 @@ func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) { | |||
p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port)) | |||
p[0] = byte(sa.Port >> 8) | |||
p[1] = byte(sa.Port) | |||
for i := 0; i < len(sa.Addr); i++ { | |||
sa.raw.Addr[i] = sa.Addr[i] | |||
} | |||
sa.raw.Addr = sa.Addr | |||
return unsafe.Pointer(&sa.raw), SizeofSockaddrInet4, nil | |||
} | |||
@@ -107,9 +105,7 @@ func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) { | |||
p[0] = byte(sa.Port >> 8) | |||
p[1] = byte(sa.Port) | |||
sa.raw.Scope_id = sa.ZoneId | |||
for i := 0; i < len(sa.Addr); i++ { | |||
sa.raw.Addr[i] = sa.Addr[i] | |||
} | |||
sa.raw.Addr = sa.Addr | |||
return unsafe.Pointer(&sa.raw), SizeofSockaddrInet6, nil | |||
} | |||
@@ -417,9 +413,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { | |||
sa := new(SockaddrInet4) | |||
p := (*[2]byte)(unsafe.Pointer(&pp.Port)) | |||
sa.Port = int(p[0])<<8 + int(p[1]) | |||
for i := 0; i < len(sa.Addr); i++ { | |||
sa.Addr[i] = pp.Addr[i] | |||
} | |||
sa.Addr = pp.Addr | |||
return sa, nil | |||
case AF_INET6: | |||
@@ -428,9 +422,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { | |||
p := (*[2]byte)(unsafe.Pointer(&pp.Port)) | |||
sa.Port = int(p[0])<<8 + int(p[1]) | |||
sa.ZoneId = pp.Scope_id | |||
for i := 0; i < len(sa.Addr); i++ { | |||
sa.Addr[i] = pp.Addr[i] | |||
} | |||
sa.Addr = pp.Addr | |||
return sa, nil | |||
} | |||
return nil, EAFNOSUPPORT |
@@ -67,9 +67,7 @@ func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) { | |||
p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port)) | |||
p[0] = byte(sa.Port >> 8) | |||
p[1] = byte(sa.Port) | |||
for i := 0; i < len(sa.Addr); i++ { | |||
sa.raw.Addr[i] = sa.Addr[i] | |||
} | |||
sa.raw.Addr = sa.Addr | |||
return unsafe.Pointer(&sa.raw), _Socklen(sa.raw.Len), nil | |||
} | |||
@@ -83,9 +81,7 @@ func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) { | |||
p[0] = byte(sa.Port >> 8) | |||
p[1] = byte(sa.Port) | |||
sa.raw.Scope_id = sa.ZoneId | |||
for i := 0; i < len(sa.Addr); i++ { | |||
sa.raw.Addr[i] = sa.Addr[i] | |||
} | |||
sa.raw.Addr = sa.Addr | |||
return unsafe.Pointer(&sa.raw), _Socklen(sa.raw.Len), nil | |||
} | |||
@@ -144,9 +140,7 @@ func anyToSockaddr(_ int, rsa *RawSockaddrAny) (Sockaddr, error) { | |||
sa := new(SockaddrInet4) | |||
p := (*[2]byte)(unsafe.Pointer(&pp.Port)) | |||
sa.Port = int(p[0])<<8 + int(p[1]) | |||
for i := 0; i < len(sa.Addr); i++ { | |||
sa.Addr[i] = pp.Addr[i] | |||
} | |||
sa.Addr = pp.Addr | |||
return sa, nil | |||
case AF_INET6: | |||
@@ -155,9 +149,7 @@ func anyToSockaddr(_ int, rsa *RawSockaddrAny) (Sockaddr, error) { | |||
p := (*[2]byte)(unsafe.Pointer(&pp.Port)) | |||
sa.Port = int(p[0])<<8 + int(p[1]) | |||
sa.ZoneId = pp.Scope_id | |||
for i := 0; i < len(sa.Addr); i++ { | |||
sa.Addr[i] = pp.Addr[i] | |||
} | |||
sa.Addr = pp.Addr | |||
return sa, nil | |||
} | |||
return nil, EAFNOSUPPORT |
@@ -0,0 +1,21 @@ | |||
// Copyright 2021 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build linux | |||
// +build linux | |||
package unix | |||
import "runtime" | |||
// SysvShmCtl performs control operations on the shared memory segment | |||
// specified by id. | |||
func SysvShmCtl(id, cmd int, desc *SysvShmDesc) (result int, err error) { | |||
if runtime.GOARCH == "arm" || | |||
runtime.GOARCH == "mips64" || runtime.GOARCH == "mips64le" { | |||
cmd |= ipc_64 | |||
} | |||
return shmctl(id, cmd, desc) | |||
} |
@@ -0,0 +1,61 @@ | |||
// Copyright 2021 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build (darwin && !ios) || linux | |||
// +build darwin,!ios linux | |||
package unix | |||
import ( | |||
"unsafe" | |||
"golang.org/x/sys/internal/unsafeheader" | |||
) | |||
// SysvShmAttach attaches the Sysv shared memory segment associated with the | |||
// shared memory identifier id. | |||
func SysvShmAttach(id int, addr uintptr, flag int) ([]byte, error) { | |||
addr, errno := shmat(id, addr, flag) | |||
if errno != nil { | |||
return nil, errno | |||
} | |||
// Retrieve the size of the shared memory to enable slice creation | |||
var info SysvShmDesc | |||
_, err := SysvShmCtl(id, IPC_STAT, &info) | |||
if err != nil { | |||
// release the shared memory if we can't find the size | |||
// ignoring error from shmdt as there's nothing sensible to return here | |||
shmdt(addr) | |||
return nil, err | |||
} | |||
// Use unsafe to convert addr into a []byte. | |||
// TODO: convert to unsafe.Slice once we can assume Go 1.17 | |||
var b []byte | |||
hdr := (*unsafeheader.Slice)(unsafe.Pointer(&b)) | |||
hdr.Data = unsafe.Pointer(addr) | |||
hdr.Cap = int(info.Segsz) | |||
hdr.Len = int(info.Segsz) | |||
return b, nil | |||
} | |||
// SysvShmDetach unmaps the shared memory slice returned from SysvShmAttach. | |||
// | |||
// It is not safe to use the slice after calling this function. | |||
func SysvShmDetach(data []byte) error { | |||
if len(data) == 0 { | |||
return EINVAL | |||
} | |||
return shmdt(uintptr(unsafe.Pointer(&data[0]))) | |||
} | |||
// SysvShmGet returns the Sysv shared memory identifier associated with key. | |||
// If the IPC_CREAT flag is specified a new segment is created. | |||
func SysvShmGet(key, size, flag int) (id int, err error) { | |||
return shmget(key, size, flag) | |||
} |
@@ -0,0 +1,14 @@ | |||
// Copyright 2021 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build darwin && !ios | |||
// +build darwin,!ios | |||
package unix | |||
// SysvShmCtl performs control operations on the shared memory segment | |||
// specified by id. | |||
func SysvShmCtl(id, cmd int, desc *SysvShmDesc) (result int, err error) { | |||
return shmctl(id, cmd, desc) | |||
} |
@@ -1,4 +1,4 @@ | |||
// Code generated by mkmerge.go; DO NOT EDIT. | |||
// Code generated by mkmerge; DO NOT EDIT. | |||
//go:build linux | |||
// +build linux | |||
@@ -116,6 +116,7 @@ const ( | |||
ARPHRD_LAPB = 0x204 | |||
ARPHRD_LOCALTLK = 0x305 | |||
ARPHRD_LOOPBACK = 0x304 | |||
ARPHRD_MCTP = 0x122 | |||
ARPHRD_METRICOM = 0x17 | |||
ARPHRD_NETLINK = 0x338 | |||
ARPHRD_NETROM = 0x0 | |||
@@ -231,6 +232,8 @@ const ( | |||
BPF_PSEUDO_FUNC = 0x4 | |||
BPF_PSEUDO_KFUNC_CALL = 0x2 | |||
BPF_PSEUDO_MAP_FD = 0x1 | |||
BPF_PSEUDO_MAP_IDX = 0x5 | |||
BPF_PSEUDO_MAP_IDX_VALUE = 0x6 | |||
BPF_PSEUDO_MAP_VALUE = 0x2 | |||
BPF_RET = 0x6 | |||
BPF_RSH = 0x70 | |||
@@ -470,6 +473,7 @@ const ( | |||
DM_DEV_WAIT = 0xc138fd08 | |||
DM_DIR = "mapper" | |||
DM_GET_TARGET_VERSION = 0xc138fd11 | |||
DM_IMA_MEASUREMENT_FLAG = 0x80000 | |||
DM_INACTIVE_PRESENT_FLAG = 0x40 | |||
DM_INTERNAL_SUSPEND_FLAG = 0x40000 | |||
DM_IOCTL = 0xfd | |||
@@ -714,6 +718,7 @@ const ( | |||
ETH_P_LOOPBACK = 0x9000 | |||
ETH_P_MACSEC = 0x88e5 | |||
ETH_P_MAP = 0xf9 | |||
ETH_P_MCTP = 0xfa | |||
ETH_P_MOBITEX = 0x15 | |||
ETH_P_MPLS_MC = 0x8848 | |||
ETH_P_MPLS_UC = 0x8847 | |||
@@ -749,6 +754,21 @@ const ( | |||
ETH_P_WCCP = 0x883e | |||
ETH_P_X25 = 0x805 | |||
ETH_P_XDSA = 0xf8 | |||
EV_ABS = 0x3 | |||
EV_CNT = 0x20 | |||
EV_FF = 0x15 | |||
EV_FF_STATUS = 0x17 | |||
EV_KEY = 0x1 | |||
EV_LED = 0x11 | |||
EV_MAX = 0x1f | |||
EV_MSC = 0x4 | |||
EV_PWR = 0x16 | |||
EV_REL = 0x2 | |||
EV_REP = 0x14 | |||
EV_SND = 0x12 | |||
EV_SW = 0x5 | |||
EV_SYN = 0x0 | |||
EV_VERSION = 0x10001 | |||
EXABYTE_ENABLE_NEST = 0xf0 | |||
EXT2_SUPER_MAGIC = 0xef53 | |||
EXT3_SUPER_MAGIC = 0xef53 | |||
@@ -787,9 +807,11 @@ const ( | |||
FAN_DELETE_SELF = 0x400 | |||
FAN_DENY = 0x2 | |||
FAN_ENABLE_AUDIT = 0x40 | |||
FAN_EPIDFD = -0x2 | |||
FAN_EVENT_INFO_TYPE_DFID = 0x3 | |||
FAN_EVENT_INFO_TYPE_DFID_NAME = 0x2 | |||
FAN_EVENT_INFO_TYPE_FID = 0x1 | |||
FAN_EVENT_INFO_TYPE_PIDFD = 0x4 | |||
FAN_EVENT_METADATA_LEN = 0x18 | |||
FAN_EVENT_ON_CHILD = 0x8000000 | |||
FAN_MARK_ADD = 0x1 | |||
@@ -809,6 +831,7 @@ const ( | |||
FAN_MOVE_SELF = 0x800 | |||
FAN_NOFD = -0x1 | |||
FAN_NONBLOCK = 0x2 | |||
FAN_NOPIDFD = -0x1 | |||
FAN_ONDIR = 0x40000000 | |||
FAN_OPEN = 0x20 | |||
FAN_OPEN_EXEC = 0x1000 | |||
@@ -819,6 +842,7 @@ const ( | |||
FAN_REPORT_DIR_FID = 0x400 | |||
FAN_REPORT_FID = 0x200 | |||
FAN_REPORT_NAME = 0x800 | |||
FAN_REPORT_PIDFD = 0x80 | |||
FAN_REPORT_TID = 0x100 | |||
FAN_UNLIMITED_MARKS = 0x20 | |||
FAN_UNLIMITED_QUEUE = 0x10 | |||
@@ -1331,6 +1355,20 @@ const ( | |||
KEY_SPEC_THREAD_KEYRING = -0x1 | |||
KEY_SPEC_USER_KEYRING = -0x4 | |||
KEY_SPEC_USER_SESSION_KEYRING = -0x5 | |||
LANDLOCK_ACCESS_FS_EXECUTE = 0x1 | |||
LANDLOCK_ACCESS_FS_MAKE_BLOCK = 0x800 | |||
LANDLOCK_ACCESS_FS_MAKE_CHAR = 0x40 | |||
LANDLOCK_ACCESS_FS_MAKE_DIR = 0x80 | |||
LANDLOCK_ACCESS_FS_MAKE_FIFO = 0x400 | |||
LANDLOCK_ACCESS_FS_MAKE_REG = 0x100 | |||
LANDLOCK_ACCESS_FS_MAKE_SOCK = 0x200 | |||
LANDLOCK_ACCESS_FS_MAKE_SYM = 0x1000 | |||
LANDLOCK_ACCESS_FS_READ_DIR = 0x8 | |||
LANDLOCK_ACCESS_FS_READ_FILE = 0x4 | |||
LANDLOCK_ACCESS_FS_REMOVE_DIR = 0x10 | |||
LANDLOCK_ACCESS_FS_REMOVE_FILE = 0x20 | |||
LANDLOCK_ACCESS_FS_WRITE_FILE = 0x2 | |||
LANDLOCK_CREATE_RULESET_VERSION = 0x1 | |||
LINUX_REBOOT_CMD_CAD_OFF = 0x0 | |||
LINUX_REBOOT_CMD_CAD_ON = 0x89abcdef | |||
LINUX_REBOOT_CMD_HALT = 0xcdef0123 | |||
@@ -1381,6 +1419,8 @@ const ( | |||
MADV_NOHUGEPAGE = 0xf | |||
MADV_NORMAL = 0x0 | |||
MADV_PAGEOUT = 0x15 | |||
MADV_POPULATE_READ = 0x16 | |||
MADV_POPULATE_WRITE = 0x17 | |||
MADV_RANDOM = 0x1 | |||
MADV_REMOVE = 0x9 | |||
MADV_SEQUENTIAL = 0x2 | |||
@@ -1436,6 +1476,18 @@ const ( | |||
MNT_FORCE = 0x1 | |||
MODULE_INIT_IGNORE_MODVERSIONS = 0x1 | |||
MODULE_INIT_IGNORE_VERMAGIC = 0x2 | |||
MOUNT_ATTR_IDMAP = 0x100000 | |||
MOUNT_ATTR_NOATIME = 0x10 | |||
MOUNT_ATTR_NODEV = 0x4 | |||
MOUNT_ATTR_NODIRATIME = 0x80 | |||
MOUNT_ATTR_NOEXEC = 0x8 | |||
MOUNT_ATTR_NOSUID = 0x2 | |||
MOUNT_ATTR_NOSYMFOLLOW = 0x200000 | |||
MOUNT_ATTR_RDONLY = 0x1 | |||
MOUNT_ATTR_RELATIME = 0x0 | |||
MOUNT_ATTR_SIZE_VER0 = 0x20 | |||
MOUNT_ATTR_STRICTATIME = 0x20 | |||
MOUNT_ATTR__ATIME = 0x70 | |||
MSDOS_SUPER_MAGIC = 0x4d44 | |||
MSG_BATCH = 0x40000 | |||
MSG_CMSG_CLOEXEC = 0x40000000 | |||
@@ -1635,11 +1687,12 @@ const ( | |||
NFNL_MSG_BATCH_END = 0x11 | |||
NFNL_NFA_NEST = 0x8000 | |||
NFNL_SUBSYS_ACCT = 0x7 | |||
NFNL_SUBSYS_COUNT = 0xc | |||
NFNL_SUBSYS_COUNT = 0xd | |||
NFNL_SUBSYS_CTHELPER = 0x9 | |||
NFNL_SUBSYS_CTNETLINK = 0x1 | |||
NFNL_SUBSYS_CTNETLINK_EXP = 0x2 | |||
NFNL_SUBSYS_CTNETLINK_TIMEOUT = 0x8 | |||
NFNL_SUBSYS_HOOK = 0xc | |||
NFNL_SUBSYS_IPSET = 0x6 | |||
NFNL_SUBSYS_NFTABLES = 0xa | |||
NFNL_SUBSYS_NFT_COMPAT = 0xb | |||
@@ -1929,6 +1982,12 @@ const ( | |||
PR_PAC_GET_ENABLED_KEYS = 0x3d | |||
PR_PAC_RESET_KEYS = 0x36 | |||
PR_PAC_SET_ENABLED_KEYS = 0x3c | |||
PR_SCHED_CORE = 0x3e | |||
PR_SCHED_CORE_CREATE = 0x1 | |||
PR_SCHED_CORE_GET = 0x0 | |||
PR_SCHED_CORE_MAX = 0x4 | |||
PR_SCHED_CORE_SHARE_FROM = 0x3 | |||
PR_SCHED_CORE_SHARE_TO = 0x2 | |||
PR_SET_CHILD_SUBREAPER = 0x24 | |||
PR_SET_DUMPABLE = 0x4 | |||
PR_SET_ENDIAN = 0x14 | |||
@@ -1972,6 +2031,7 @@ const ( | |||
PR_SPEC_ENABLE = 0x2 | |||
PR_SPEC_FORCE_DISABLE = 0x8 | |||
PR_SPEC_INDIRECT_BRANCH = 0x1 | |||
PR_SPEC_L1D_FLUSH = 0x2 | |||
PR_SPEC_NOT_AFFECTED = 0x0 | |||
PR_SPEC_PRCTL = 0x1 | |||
PR_SPEC_STORE_BYPASS = 0x0 | |||
@@ -2295,6 +2355,7 @@ const ( | |||
SECCOMP_MODE_DISABLED = 0x0 | |||
SECCOMP_MODE_FILTER = 0x2 | |||
SECCOMP_MODE_STRICT = 0x1 | |||
SECRETMEM_MAGIC = 0x5345434d | |||
SECURITYFS_MAGIC = 0x73636673 | |||
SEEK_CUR = 0x1 | |||
SEEK_DATA = 0x3 | |||
@@ -2406,12 +2467,15 @@ const ( | |||
SMART_WRITE_THRESHOLDS = 0xd7 | |||
SMB_SUPER_MAGIC = 0x517b | |||
SOCKFS_MAGIC = 0x534f434b | |||
SOCK_BUF_LOCK_MASK = 0x3 | |||
SOCK_DCCP = 0x6 | |||
SOCK_IOC_TYPE = 0x89 | |||
SOCK_PACKET = 0xa | |||
SOCK_RAW = 0x3 | |||
SOCK_RCVBUF_LOCK = 0x2 | |||
SOCK_RDM = 0x4 | |||
SOCK_SEQPACKET = 0x5 | |||
SOCK_SNDBUF_LOCK = 0x1 | |||
SOL_AAL = 0x109 | |||
SOL_ALG = 0x117 | |||
SOL_ATM = 0x108 |
@@ -5,7 +5,7 @@ | |||
// +build 386,linux | |||
// Code generated by cmd/cgo -godefs; DO NOT EDIT. | |||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include -m32 /build/_const.go | |||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include -m32 /build/unix/_const.go | |||
package unix | |||
@@ -293,6 +293,7 @@ const ( | |||
SO_BPF_EXTENSIONS = 0x30 | |||
SO_BROADCAST = 0x6 | |||
SO_BSDCOMPAT = 0xe | |||
SO_BUF_LOCK = 0x48 | |||
SO_BUSY_POLL = 0x2e | |||
SO_BUSY_POLL_BUDGET = 0x46 | |||
SO_CNX_ADVICE = 0x35 | |||
@@ -309,6 +310,7 @@ const ( | |||
SO_MARK = 0x24 | |||
SO_MAX_PACING_RATE = 0x2f | |||
SO_MEMINFO = 0x37 | |||
SO_NETNS_COOKIE = 0x47 | |||
SO_NOFCS = 0x2b | |||
SO_OOBINLINE = 0xa | |||
SO_PASSCRED = 0x10 |
@@ -5,7 +5,7 @@ | |||
// +build amd64,linux | |||
// Code generated by cmd/cgo -godefs; DO NOT EDIT. | |||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include -m64 /build/_const.go | |||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include -m64 /build/unix/_const.go | |||
package unix | |||
@@ -294,6 +294,7 @@ const ( | |||
SO_BPF_EXTENSIONS = 0x30 | |||
SO_BROADCAST = 0x6 | |||
SO_BSDCOMPAT = 0xe | |||
SO_BUF_LOCK = 0x48 | |||
SO_BUSY_POLL = 0x2e | |||
SO_BUSY_POLL_BUDGET = 0x46 | |||
SO_CNX_ADVICE = 0x35 | |||
@@ -310,6 +311,7 @@ const ( | |||
SO_MARK = 0x24 | |||
SO_MAX_PACING_RATE = 0x2f | |||
SO_MEMINFO = 0x37 | |||
SO_NETNS_COOKIE = 0x47 | |||
SO_NOFCS = 0x2b | |||
SO_OOBINLINE = 0xa | |||
SO_PASSCRED = 0x10 |
@@ -5,7 +5,7 @@ | |||
// +build arm,linux | |||
// Code generated by cmd/cgo -godefs; DO NOT EDIT. | |||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/_const.go | |||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/_const.go | |||
package unix | |||
@@ -300,6 +300,7 @@ const ( | |||
SO_BPF_EXTENSIONS = 0x30 | |||
SO_BROADCAST = 0x6 | |||
SO_BSDCOMPAT = 0xe | |||
SO_BUF_LOCK = 0x48 | |||
SO_BUSY_POLL = 0x2e | |||
SO_BUSY_POLL_BUDGET = 0x46 | |||
SO_CNX_ADVICE = 0x35 | |||
@@ -316,6 +317,7 @@ const ( | |||
SO_MARK = 0x24 | |||
SO_MAX_PACING_RATE = 0x2f | |||
SO_MEMINFO = 0x37 | |||
SO_NETNS_COOKIE = 0x47 | |||
SO_NOFCS = 0x2b | |||
SO_OOBINLINE = 0xa | |||
SO_PASSCRED = 0x10 |
@@ -5,7 +5,7 @@ | |||
// +build arm64,linux | |||
// Code generated by cmd/cgo -godefs; DO NOT EDIT. | |||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include -fsigned-char /build/_const.go | |||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include -fsigned-char /build/unix/_const.go | |||
package unix | |||
@@ -290,6 +290,7 @@ const ( | |||
SO_BPF_EXTENSIONS = 0x30 | |||
SO_BROADCAST = 0x6 | |||
SO_BSDCOMPAT = 0xe | |||
SO_BUF_LOCK = 0x48 | |||
SO_BUSY_POLL = 0x2e | |||
SO_BUSY_POLL_BUDGET = 0x46 | |||
SO_CNX_ADVICE = 0x35 | |||
@@ -306,6 +307,7 @@ const ( | |||
SO_MARK = 0x24 | |||
SO_MAX_PACING_RATE = 0x2f | |||
SO_MEMINFO = 0x37 | |||
SO_NETNS_COOKIE = 0x47 | |||
SO_NOFCS = 0x2b | |||
SO_OOBINLINE = 0xa | |||
SO_PASSCRED = 0x10 |
@@ -5,7 +5,7 @@ | |||
// +build mips,linux | |||
// Code generated by cmd/cgo -godefs; DO NOT EDIT. | |||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/_const.go | |||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/_const.go | |||
package unix | |||
@@ -293,6 +293,7 @@ const ( | |||
SO_BPF_EXTENSIONS = 0x30 | |||
SO_BROADCAST = 0x20 | |||
SO_BSDCOMPAT = 0xe | |||
SO_BUF_LOCK = 0x48 | |||
SO_BUSY_POLL = 0x2e | |||
SO_BUSY_POLL_BUDGET = 0x46 | |||
SO_CNX_ADVICE = 0x35 | |||
@@ -309,6 +310,7 @@ const ( | |||
SO_MARK = 0x24 | |||
SO_MAX_PACING_RATE = 0x2f | |||
SO_MEMINFO = 0x37 | |||
SO_NETNS_COOKIE = 0x47 | |||
SO_NOFCS = 0x2b | |||
SO_OOBINLINE = 0x100 | |||
SO_PASSCRED = 0x11 |
@@ -5,7 +5,7 @@ | |||
// +build mips64,linux | |||
// Code generated by cmd/cgo -godefs; DO NOT EDIT. | |||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/_const.go | |||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/_const.go | |||
package unix | |||
@@ -293,6 +293,7 @@ const ( | |||
SO_BPF_EXTENSIONS = 0x30 | |||
SO_BROADCAST = 0x20 | |||
SO_BSDCOMPAT = 0xe | |||
SO_BUF_LOCK = 0x48 | |||
SO_BUSY_POLL = 0x2e | |||
SO_BUSY_POLL_BUDGET = 0x46 | |||
SO_CNX_ADVICE = 0x35 | |||
@@ -309,6 +310,7 @@ const ( | |||
SO_MARK = 0x24 | |||
SO_MAX_PACING_RATE = 0x2f | |||
SO_MEMINFO = 0x37 | |||
SO_NETNS_COOKIE = 0x47 | |||
SO_NOFCS = 0x2b | |||
SO_OOBINLINE = 0x100 | |||
SO_PASSCRED = 0x11 |
@@ -5,7 +5,7 @@ | |||
// +build mips64le,linux | |||
// Code generated by cmd/cgo -godefs; DO NOT EDIT. | |||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/_const.go | |||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/_const.go | |||
package unix | |||
@@ -293,6 +293,7 @@ const ( | |||
SO_BPF_EXTENSIONS = 0x30 | |||
SO_BROADCAST = 0x20 | |||
SO_BSDCOMPAT = 0xe | |||
SO_BUF_LOCK = 0x48 | |||
SO_BUSY_POLL = 0x2e | |||
SO_BUSY_POLL_BUDGET = 0x46 | |||
SO_CNX_ADVICE = 0x35 | |||
@@ -309,6 +310,7 @@ const ( | |||
SO_MARK = 0x24 | |||
SO_MAX_PACING_RATE = 0x2f | |||
SO_MEMINFO = 0x37 | |||
SO_NETNS_COOKIE = 0x47 | |||
SO_NOFCS = 0x2b | |||
SO_OOBINLINE = 0x100 | |||
SO_PASSCRED = 0x11 |
@@ -5,7 +5,7 @@ | |||
// +build mipsle,linux | |||
// Code generated by cmd/cgo -godefs; DO NOT EDIT. | |||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/_const.go | |||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/_const.go | |||
package unix | |||
@@ -293,6 +293,7 @@ const ( | |||
SO_BPF_EXTENSIONS = 0x30 | |||
SO_BROADCAST = 0x20 | |||
SO_BSDCOMPAT = 0xe | |||
SO_BUF_LOCK = 0x48 | |||
SO_BUSY_POLL = 0x2e | |||
SO_BUSY_POLL_BUDGET = 0x46 | |||
SO_CNX_ADVICE = 0x35 | |||
@@ -309,6 +310,7 @@ const ( | |||
SO_MARK = 0x24 | |||
SO_MAX_PACING_RATE = 0x2f | |||
SO_MEMINFO = 0x37 | |||
SO_NETNS_COOKIE = 0x47 | |||
SO_NOFCS = 0x2b | |||
SO_OOBINLINE = 0x100 | |||
SO_PASSCRED = 0x11 |
@@ -5,7 +5,7 @@ | |||
// +build ppc,linux | |||
// Code generated by cmd/cgo -godefs; DO NOT EDIT. | |||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/_const.go | |||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/_const.go | |||
package unix | |||
@@ -348,6 +348,7 @@ const ( | |||
SO_BPF_EXTENSIONS = 0x30 | |||
SO_BROADCAST = 0x6 | |||
SO_BSDCOMPAT = 0xe | |||
SO_BUF_LOCK = 0x48 | |||
SO_BUSY_POLL = 0x2e | |||
SO_BUSY_POLL_BUDGET = 0x46 | |||
SO_CNX_ADVICE = 0x35 | |||
@@ -364,6 +365,7 @@ const ( | |||
SO_MARK = 0x24 | |||
SO_MAX_PACING_RATE = 0x2f | |||
SO_MEMINFO = 0x37 | |||
SO_NETNS_COOKIE = 0x47 | |||
SO_NOFCS = 0x2b | |||
SO_OOBINLINE = 0xa | |||
SO_PASSCRED = 0x14 |
@@ -5,7 +5,7 @@ | |||
// +build ppc64,linux | |||
// Code generated by cmd/cgo -godefs; DO NOT EDIT. | |||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/_const.go | |||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/_const.go | |||
package unix | |||
@@ -352,6 +352,7 @@ const ( | |||
SO_BPF_EXTENSIONS = 0x30 | |||
SO_BROADCAST = 0x6 | |||
SO_BSDCOMPAT = 0xe | |||
SO_BUF_LOCK = 0x48 | |||
SO_BUSY_POLL = 0x2e | |||
SO_BUSY_POLL_BUDGET = 0x46 | |||
SO_CNX_ADVICE = 0x35 | |||
@@ -368,6 +369,7 @@ const ( | |||
SO_MARK = 0x24 | |||
SO_MAX_PACING_RATE = 0x2f | |||
SO_MEMINFO = 0x37 | |||
SO_NETNS_COOKIE = 0x47 | |||
SO_NOFCS = 0x2b | |||
SO_OOBINLINE = 0xa | |||
SO_PASSCRED = 0x14 |
@@ -5,7 +5,7 @@ | |||
// +build ppc64le,linux | |||
// Code generated by cmd/cgo -godefs; DO NOT EDIT. | |||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/_const.go | |||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/_const.go | |||
package unix | |||
@@ -352,6 +352,7 @@ const ( | |||
SO_BPF_EXTENSIONS = 0x30 | |||
SO_BROADCAST = 0x6 | |||
SO_BSDCOMPAT = 0xe | |||
SO_BUF_LOCK = 0x48 | |||
SO_BUSY_POLL = 0x2e | |||
SO_BUSY_POLL_BUDGET = 0x46 | |||
SO_CNX_ADVICE = 0x35 | |||
@@ -368,6 +369,7 @@ const ( | |||
SO_MARK = 0x24 | |||
SO_MAX_PACING_RATE = 0x2f | |||
SO_MEMINFO = 0x37 | |||
SO_NETNS_COOKIE = 0x47 | |||
SO_NOFCS = 0x2b | |||
SO_OOBINLINE = 0xa | |||
SO_PASSCRED = 0x14 |
@@ -5,7 +5,7 @@ | |||
// +build riscv64,linux | |||
// Code generated by cmd/cgo -godefs; DO NOT EDIT. | |||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/_const.go | |||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/_const.go | |||
package unix | |||
@@ -281,6 +281,7 @@ const ( | |||
SO_BPF_EXTENSIONS = 0x30 | |||
SO_BROADCAST = 0x6 | |||
SO_BSDCOMPAT = 0xe | |||
SO_BUF_LOCK = 0x48 | |||
SO_BUSY_POLL = 0x2e | |||
SO_BUSY_POLL_BUDGET = 0x46 | |||
SO_CNX_ADVICE = 0x35 | |||
@@ -297,6 +298,7 @@ const ( | |||
SO_MARK = 0x24 | |||
SO_MAX_PACING_RATE = 0x2f | |||
SO_MEMINFO = 0x37 | |||
SO_NETNS_COOKIE = 0x47 | |||
SO_NOFCS = 0x2b | |||
SO_OOBINLINE = 0xa | |||
SO_PASSCRED = 0x10 |
@@ -5,7 +5,7 @@ | |||
// +build s390x,linux | |||
// Code generated by cmd/cgo -godefs; DO NOT EDIT. | |||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include -fsigned-char /build/_const.go | |||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include -fsigned-char /build/unix/_const.go | |||
package unix | |||
@@ -356,6 +356,7 @@ const ( | |||
SO_BPF_EXTENSIONS = 0x30 | |||
SO_BROADCAST = 0x6 | |||
SO_BSDCOMPAT = 0xe | |||
SO_BUF_LOCK = 0x48 | |||
SO_BUSY_POLL = 0x2e | |||
SO_BUSY_POLL_BUDGET = 0x46 | |||
SO_CNX_ADVICE = 0x35 | |||
@@ -372,6 +373,7 @@ const ( | |||
SO_MARK = 0x24 | |||
SO_MAX_PACING_RATE = 0x2f | |||
SO_MEMINFO = 0x37 | |||
SO_NETNS_COOKIE = 0x47 | |||
SO_NOFCS = 0x2b | |||
SO_OOBINLINE = 0xa | |||
SO_PASSCRED = 0x10 |
@@ -5,7 +5,7 @@ | |||
// +build sparc64,linux | |||
// Code generated by cmd/cgo -godefs; DO NOT EDIT. | |||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/_const.go | |||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/_const.go | |||
package unix | |||
@@ -347,6 +347,7 @@ const ( | |||
SO_BPF_EXTENSIONS = 0x32 | |||
SO_BROADCAST = 0x20 | |||
SO_BSDCOMPAT = 0x400 | |||
SO_BUF_LOCK = 0x51 | |||
SO_BUSY_POLL = 0x30 | |||
SO_BUSY_POLL_BUDGET = 0x49 | |||
SO_CNX_ADVICE = 0x37 | |||
@@ -363,6 +364,7 @@ const ( | |||
SO_MARK = 0x22 | |||
SO_MAX_PACING_RATE = 0x31 | |||
SO_MEMINFO = 0x39 | |||
SO_NETNS_COOKIE = 0x50 | |||
SO_NOFCS = 0x27 | |||
SO_OOBINLINE = 0x100 | |||
SO_PASSCRED = 0x2 |
@@ -17,6 +17,7 @@ int getdirent(int, uintptr_t, size_t); | |||
int wait4(int, uintptr_t, int, uintptr_t); | |||
int ioctl(int, int, uintptr_t); | |||
int fcntl(uintptr_t, int, uintptr_t); | |||
int fsync_range(int, int, long long, long long); | |||
int acct(uintptr_t); | |||
int chdir(uintptr_t); | |||
int chroot(uintptr_t); | |||
@@ -29,7 +30,6 @@ int fchmod(int, unsigned int); | |||
int fchmodat(int, uintptr_t, unsigned int, int); | |||
int fchownat(int, uintptr_t, int, int, int); | |||
int fdatasync(int); | |||
int fsync(int); | |||
int getpgid(int); | |||
int getpgrp(); | |||
int getpid(); | |||
@@ -255,6 +255,16 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) { | |||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT | |||
func fsyncRange(fd int, how int, start int64, length int64) (err error) { | |||
r0, er := C.fsync_range(C.int(fd), C.int(how), C.longlong(start), C.longlong(length)) | |||
if r0 == -1 && er != nil { | |||
err = er | |||
} | |||
return | |||
} | |||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT | |||
func Acct(path string) (err error) { | |||
_p0 := uintptr(unsafe.Pointer(C.CString(path))) | |||
r0, er := C.acct(C.uintptr_t(_p0)) | |||
@@ -379,16 +389,6 @@ func Fdatasync(fd int) (err error) { | |||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT | |||
func Fsync(fd int) (err error) { | |||
r0, er := C.fsync(C.int(fd)) | |||
if r0 == -1 && er != nil { | |||
err = er | |||
} | |||
return | |||
} | |||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT | |||
func Getpgid(pid int) (pgid int, err error) { | |||
r0, er := C.getpgid(C.int(pid)) | |||
pgid = int(r0) |
@@ -135,6 +135,16 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) { | |||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT | |||
func fsyncRange(fd int, how int, start int64, length int64) (err error) { | |||
_, e1 := callfsync_range(fd, how, start, length) | |||
if e1 != 0 { | |||
err = errnoErr(e1) | |||
} | |||
return | |||
} | |||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT | |||
func Acct(path string) (err error) { | |||
var _p0 *byte | |||
_p0, err = BytePtrFromString(path) | |||
@@ -283,16 +293,6 @@ func Fdatasync(fd int) (err error) { | |||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT | |||
func Fsync(fd int) (err error) { | |||
_, e1 := callfsync(fd) | |||
if e1 != 0 { | |||
err = errnoErr(e1) | |||
} | |||
return | |||
} | |||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT | |||
func Getpgid(pid int) (pgid int, err error) { | |||
r0, e1 := callgetpgid(pid) | |||
pgid = int(r0) |
@@ -18,6 +18,7 @@ import ( | |||
//go:cgo_import_dynamic libc_wait4 wait4 "libc.a/shr_64.o" | |||
//go:cgo_import_dynamic libc_ioctl ioctl "libc.a/shr_64.o" | |||
//go:cgo_import_dynamic libc_fcntl fcntl "libc.a/shr_64.o" | |||
//go:cgo_import_dynamic libc_fsync_range fsync_range "libc.a/shr_64.o" | |||
//go:cgo_import_dynamic libc_acct acct "libc.a/shr_64.o" | |||
//go:cgo_import_dynamic libc_chdir chdir "libc.a/shr_64.o" | |||
//go:cgo_import_dynamic libc_chroot chroot "libc.a/shr_64.o" | |||
@@ -30,7 +31,6 @@ import ( | |||
//go:cgo_import_dynamic libc_fchmodat fchmodat "libc.a/shr_64.o" | |||
//go:cgo_import_dynamic libc_fchownat fchownat "libc.a/shr_64.o" | |||
//go:cgo_import_dynamic libc_fdatasync fdatasync "libc.a/shr_64.o" | |||
//go:cgo_import_dynamic libc_fsync fsync "libc.a/shr_64.o" | |||
//go:cgo_import_dynamic libc_getpgid getpgid "libc.a/shr_64.o" | |||
//go:cgo_import_dynamic libc_getpgrp getpgrp "libc.a/shr_64.o" | |||
//go:cgo_import_dynamic libc_getpid getpid "libc.a/shr_64.o" | |||
@@ -136,6 +136,7 @@ import ( | |||
//go:linkname libc_wait4 libc_wait4 | |||
//go:linkname libc_ioctl libc_ioctl | |||
//go:linkname libc_fcntl libc_fcntl | |||
//go:linkname libc_fsync_range libc_fsync_range | |||
//go:linkname libc_acct libc_acct | |||
//go:linkname libc_chdir libc_chdir | |||
//go:linkname libc_chroot libc_chroot | |||
@@ -148,7 +149,6 @@ import ( | |||
//go:linkname libc_fchmodat libc_fchmodat | |||
//go:linkname libc_fchownat libc_fchownat | |||
//go:linkname libc_fdatasync libc_fdatasync | |||
//go:linkname libc_fsync libc_fsync | |||
//go:linkname libc_getpgid libc_getpgid | |||
//go:linkname libc_getpgrp libc_getpgrp | |||
//go:linkname libc_getpid libc_getpid | |||
@@ -257,6 +257,7 @@ var ( | |||
libc_wait4, | |||
libc_ioctl, | |||
libc_fcntl, | |||
libc_fsync_range, | |||
libc_acct, | |||
libc_chdir, | |||
libc_chroot, | |||
@@ -269,7 +270,6 @@ var ( | |||
libc_fchmodat, | |||
libc_fchownat, | |||
libc_fdatasync, | |||
libc_fsync, | |||
libc_getpgid, | |||
libc_getpgrp, | |||
libc_getpid, | |||
@@ -430,6 +430,13 @@ func callfcntl(fd uintptr, cmd int, arg uintptr) (r1 uintptr, e1 Errno) { | |||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT | |||
func callfsync_range(fd int, how int, start int64, length int64) (r1 uintptr, e1 Errno) { | |||
r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_fsync_range)), 4, uintptr(fd), uintptr(how), uintptr(start), uintptr(length), 0, 0) | |||
return | |||
} | |||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT | |||
func callacct(_p0 uintptr) (r1 uintptr, e1 Errno) { | |||
r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_acct)), 1, _p0, 0, 0, 0, 0, 0) | |||
return | |||
@@ -514,13 +521,6 @@ func callfdatasync(fd int) (r1 uintptr, e1 Errno) { | |||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT | |||
func callfsync(fd int) (r1 uintptr, e1 Errno) { | |||
r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_fsync)), 1, uintptr(fd), 0, 0, 0, 0, 0) | |||
return | |||
} | |||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT | |||
func callgetpgid(pid int) (r1 uintptr, e1 Errno) { | |||
r1, _, e1 = rawSyscall6(uintptr(unsafe.Pointer(&libc_getpgid)), 1, uintptr(pid), 0, 0, 0, 0, 0) | |||
return |
@@ -16,6 +16,7 @@ int getdirent(int, uintptr_t, size_t); | |||
int wait4(int, uintptr_t, int, uintptr_t); | |||
int ioctl(int, int, uintptr_t); | |||
int fcntl(uintptr_t, int, uintptr_t); | |||
int fsync_range(int, int, long long, long long); | |||
int acct(uintptr_t); | |||
int chdir(uintptr_t); | |||
int chroot(uintptr_t); | |||
@@ -28,7 +29,6 @@ int fchmod(int, unsigned int); | |||
int fchmodat(int, uintptr_t, unsigned int, int); | |||
int fchownat(int, uintptr_t, int, int, int); | |||
int fdatasync(int); | |||
int fsync(int); | |||
int getpgid(int); | |||
int getpgrp(); | |||
int getpid(); | |||
@@ -199,6 +199,14 @@ func callfcntl(fd uintptr, cmd int, arg uintptr) (r1 uintptr, e1 Errno) { | |||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT | |||
func callfsync_range(fd int, how int, start int64, length int64) (r1 uintptr, e1 Errno) { | |||
r1 = uintptr(C.fsync_range(C.int(fd), C.int(how), C.longlong(start), C.longlong(length))) | |||
e1 = syscall.GetErrno() | |||
return | |||
} | |||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT | |||
func callacct(_p0 uintptr) (r1 uintptr, e1 Errno) { | |||
r1 = uintptr(C.acct(C.uintptr_t(_p0))) | |||
e1 = syscall.GetErrno() | |||
@@ -295,14 +303,6 @@ func callfdatasync(fd int) (r1 uintptr, e1 Errno) { | |||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT | |||
func callfsync(fd int) (r1 uintptr, e1 Errno) { | |||
r1 = uintptr(C.fsync(C.int(fd))) | |||
e1 = syscall.GetErrno() | |||
return | |||
} | |||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT | |||
func callgetpgid(pid int) (r1 uintptr, e1 Errno) { | |||
r1 = uintptr(C.getpgid(C.int(pid))) | |||
e1 = syscall.GetErrno() |