mirror of
https://github.com/Buriburizaem0n/nezha_domains.git
synced 2026-09-21 18:50:13 +00:00
fix(agentcompat): secure legacy file manager boundaries
Co-authored-by: naiba/CloudCode <hi+cloudcode@nai.ba>
This commit is contained in:
@@ -101,12 +101,14 @@ func (LegacyFM) Run(ctx context.Context, input LegacyFMInput) (result Result, ru
|
|||||||
payload := bytes.Repeat(payloadPattern, (1<<20+257)/len(payloadPattern)+1)
|
payload := bytes.Repeat(payloadPattern, (1<<20+257)/len(payloadPattern)+1)
|
||||||
payload = payload[:1<<20+257]
|
payload = payload[:1<<20+257]
|
||||||
sentinel := []byte("outside-fm-root-sentinel")
|
sentinel := []byte("outside-fm-root-sentinel")
|
||||||
sentinelPaths := []string{
|
workspaceRoot, err := os.OpenRoot(agentInstance.WorkspaceRoot())
|
||||||
filepath.Join(agentInstance.WorkspaceRoot(), "outside-fm-root-a.txt"),
|
if err != nil {
|
||||||
filepath.Join(agentInstance.WorkspaceRoot(), "outside-fm-root-b.txt"),
|
return finishLegacyFM(assertions, err)
|
||||||
}
|
}
|
||||||
for _, path := range sentinelPaths {
|
defer workspaceRoot.Close()
|
||||||
if err := os.WriteFile(path, sentinel, 0o600); err != nil {
|
sentinelNames := []string{"outside-fm-root-a.txt", "outside-fm-root-b.txt"}
|
||||||
|
for _, name := range sentinelNames {
|
||||||
|
if err := workspaceRoot.WriteFile(name, sentinel, 0o600); err != nil {
|
||||||
return finishLegacyFM(assertions, err)
|
return finishLegacyFM(assertions, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -252,7 +254,7 @@ func (LegacyFM) Run(ctx context.Context, input LegacyFMInput) (result Result, ru
|
|||||||
return finishLegacyFM(assertions, err)
|
return finishLegacyFM(assertions, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sentinelErr := verifyLegacyFMSentinels(sentinelPaths, sentinel)
|
sentinelErr := verifyLegacyFMSentinels(workspaceRoot, sentinelNames, sentinel)
|
||||||
assertions.Record("outside-root sentinels remain unchanged", sentinelErr == nil, errorText(sentinelErr))
|
assertions.Record("outside-root sentinels remain unchanged", sentinelErr == nil, errorText(sentinelErr))
|
||||||
if sentinelErr != nil {
|
if sentinelErr != nil {
|
||||||
return finishLegacyFM(assertions, sentinelErr)
|
return finishLegacyFM(assertions, sentinelErr)
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ type legacyFMUserForm struct {
|
|||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const legacyFMForeignUsername = "agentcompat-fm-foreign"
|
||||||
|
const legacyFMForeignPassword = "agentcompat-fm-password" // #nosec G101 -- Ephemeral localhost integration fixture, not a production credential.
|
||||||
|
|
||||||
type legacyFMFrameWriter interface {
|
type legacyFMFrameWriter interface {
|
||||||
WriteFrame(context.Context, client.Frame) error
|
WriteFrame(context.Context, client.Frame) error
|
||||||
}
|
}
|
||||||
@@ -116,13 +119,11 @@ func findLegacyFMServerID(ctx context.Context, dashboardInstance *dashboard.Dash
|
|||||||
}
|
}
|
||||||
|
|
||||||
func createForeignLegacyFMClient(ctx context.Context, dashboardInstance *dashboard.Dashboard) (*client.Client, func() error, error) {
|
func createForeignLegacyFMClient(ctx context.Context, dashboardInstance *dashboard.Dashboard) (*client.Client, func() error, error) {
|
||||||
const username = "agentcompat-fm-foreign"
|
|
||||||
const password = "agentcompat-fm-password"
|
|
||||||
admin := dashboardInstance.Clients().REST
|
admin := dashboardInstance.Clients().REST
|
||||||
userID, err := client.DoREST[legacyFMUserForm, uint64](ctx, admin, client.RESTRequest[legacyFMUserForm]{
|
userID, err := client.DoREST[legacyFMUserForm, uint64](ctx, admin, client.RESTRequest[legacyFMUserForm]{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
Path: "/api/v1/user",
|
Path: "/api/v1/user",
|
||||||
Body: &legacyFMUserForm{Role: 1, Username: username, Password: password},
|
Body: &legacyFMUserForm{Role: 1, Username: legacyFMForeignUsername, Password: legacyFMForeignPassword},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, func() error { return nil }, err
|
return nil, func() error { return nil }, err
|
||||||
@@ -137,7 +138,7 @@ func createForeignLegacyFMClient(ctx context.Context, dashboardInstance *dashboa
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, func() error { return nil }, errors.Join(err, cleanup())
|
return nil, func() error { return nil }, errors.Join(err, cleanup())
|
||||||
}
|
}
|
||||||
if _, err := loginClient.Login(ctx, client.LoginRequest{Username: username, Password: password}); err != nil {
|
if _, err := loginClient.Login(ctx, client.LoginRequest{Username: legacyFMForeignUsername, Password: legacyFMForeignPassword}); err != nil {
|
||||||
return nil, func() error { return nil }, errors.Join(err, cleanup())
|
return nil, func() error { return nil }, errors.Join(err, cleanup())
|
||||||
}
|
}
|
||||||
pat, err := client.DoREST[patRequest, patResponse](ctx, loginClient, client.RESTRequest[patRequest]{
|
pat, err := client.DoREST[patRequest, patResponse](ctx, loginClient, client.RESTRequest[patRequest]{
|
||||||
|
|||||||
@@ -133,9 +133,9 @@ func newLegacyFMRunID() (string, error) {
|
|||||||
return hex.EncodeToString(bytes), nil
|
return hex.EncodeToString(bytes), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyLegacyFMSentinels(sentinelPaths []string, sentinel []byte) error {
|
func verifyLegacyFMSentinels(root *os.Root, sentinelNames []string, sentinel []byte) error {
|
||||||
for _, path := range sentinelPaths {
|
for _, name := range sentinelNames {
|
||||||
content, err := os.ReadFile(path)
|
content, err := root.ReadFile(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user