Skip to content

Remove SMB file sharing for Windows #4879

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open

Remove SMB file sharing for Windows #4879

wants to merge 8 commits into from

Conversation

redbeam
Copy link
Contributor

@redbeam redbeam commented Aug 14, 2025

Fixes #4768

We are removing SMB file sharing support for Windows in favor of 9p. Some of the work has already been done by @anjannath, and it is included here (#4620).

Summary by CodeRabbit

  • New Features

    • Introduced 9P-based host directory sharing; home directory is now shared with the VM.
    • Shared directories are enabled by default across all platforms.
  • Refactor

    • Replaced SMB/CIFS sharing with 9P, removing the need for share credentials.
    • Simplified Windows installer by removing SMB share creation and related firewall steps.
  • Chores

    • Added a new dependency to support 9P file sharing.

cfergeau and others added 8 commits August 5, 2025 22:45
this will be moved to the 'crc setup' command as we should only enable
file sharing and create the smb share for home dir when users have set
the config option 'enable-shared-dirs' to 'true'

this should remove at least of the warnings reported by virustotal for
the MSI:
https://www.virustotal.com/gui/file/31b402dcc1da24265074a21a26018d6cde8eef0b63c77a18f89eb079b6556790
After the addition of 9p file sharing for Windows, we are removing
SMB file sharing support (#4768).
@redbeam redbeam self-assigned this Aug 14, 2025
@redbeam redbeam added the kind/task Workable task label Aug 14, 2025
@openshift-ci openshift-ci bot requested review from anjannath and evidolob August 14, 2025 15:05
Copy link

coderabbitai bot commented Aug 14, 2025

Walkthrough

Introduces 9P file sharing across platforms, replacing Windows-specific SMB handling. Adds a vendored 9P library, implements a 9P fileserver, updates daemon to start 9P shares, and switches VM shared-dir mounts to 9P. Removes SMB-related config, MSI custom actions, and password plumbing. Adds Plan 9 constants.

Changes

Cohort / File(s) Summary
Daemon 9P startup
cmd/crc/cmd/daemon.go
Adds 9P listener on gateway IP:Plan9Port; starts sharing host home via fs9p.StartShares; uses net.JoinHostPort.
Start config cleanup
cmd/crc/cmd/start.go
Removes Windows-only population of SharedDirUsername/SharedDirPassword.
Config/settings
pkg/crc/config/settings.go
Removes Windows-specific SMB validations/settings; unifies EnableSharedDirs (default true); drops SharedDirPassword.
Constants
pkg/crc/constants/constants.go
Adds Plan9Port (564) and Plan9Msize.
Machine: shared-dirs & drivers
pkg/crc/machine/start.go, pkg/crc/machine/driver.go, pkg/crc/machine/driver_windows.go, pkg/crc/machine/driver_linux.go, pkg/crc/machine/driver_darwin.go, pkg/crc/machine/libhvee/driver_windows.go
Removes SMB password update path; switches VM mount from CIFS to 9P; tags dirs as dirN; removes updateDriverStruct helpers.
Windows driver helpers
pkg/drivers/libhvee/libhvee_windows.go, pkg/drivers/libhvee/powershell_windows.go
Drops SMB share existence check and related PowerShell helpers.
Windows MSI template
packaging/windows/product.wxs.template
Removes all SMB share creation/removal and firewall UI/CustomActions.
9P fileserver
pkg/fileserver/fs9p/server.go, pkg/fileserver/fs9p/shares.go
Adds 9P server wrapper and StartShares to expose directories over 9P; stub for vsock shares.
Dependency addition
go.mod, vendor/modules.txt
Requires github.com/DeedleFake/p9 v0.6.12; updates vendor list.
Vendored 9P library
vendor/github.com/DeedleFake/p9/*, vendor/github.com/DeedleFake/p9/proto/*, vendor/github.com/DeedleFake/p9/internal/*
Adds full 9P protocol, client/server, filesystem bridge, OS-specific dir/QID handlers, and docs.
License/Docs (vendor)
vendor/github.com/DeedleFake/p9/LICENSE, vendor/github.com/DeedleFake/p9/README.md, vendor/github.com/DeedleFake/p9/doc.go
Adds MIT license and documentation for vendored 9P package.

Sequence Diagram(s)

sequenceDiagram
  actor User
  participant CRC as crc start
  participant VM as VM (guest)
  participant Daemon as crc daemon (host)
  participant FS as 9P Fileserver

  User->>CRC: run start
  CRC->>VM: configureSharedDirs (type=9p)
  Daemon->>FS: StartShares(home, Plan9Port)
  VM->>FS: Mount 9p to 192.168.127.1:564
  FS-->>VM: Expose host home dir
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Assessment against linked issues

Objective Addressed Explanation
Remove Windows SMB file sharing code and move to cross-platform alternative (#4768)

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
Add full vendored 9P protocol/client/server and FS bridge (vendor/github.com/DeedleFake/p9/*) Potentially beyond strict “remove Windows code” wording, but aligns with stated move to 9P cross-platform support; likely in scope.

Poem

I nibble cables, ears held high—
We swapped out SMB, waved goodbye.
Now 9P sings across the den,
From burrow host to guest again.
Hop, mount, share—so swift, so spry!
A carrot toast to Plan9’s sky. 🥕✨

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch remove_smb

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

openshift-ci bot commented Aug 14, 2025

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign praveenkumar for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 23

🧹 Nitpick comments (25)
vendor/github.com/DeedleFake/p9/addr_other.go (2)

11-16: Doc comment misleading for non-Unix build tag

This file is compiled on non-Linux/non-Darwin platforms, yet the comment explains Unix-like behavior. Clarify the comment to avoid confusion.

Apply this diff:

-// current namespace. On Unix-like systems, this is
-// /tmp/ns.$USER.$DISPLAY.
+// current namespace. On Unix-like systems, the path is typically
+// /tmp/ns.$USER.$DISPLAY, but for non-Unix platforms this implementation
+// uses os.TempDir() as the base.

1-1: Add modern build constraint for forward-compatibility

Consider adding the //go:build form alongside the legacy // +build for clarity and future-proofing. This mirrors Go's recommended syntax since 1.17.

Apply this diff:

+//go:build !linux && !darwin
 // +build !linux,!darwin
vendor/github.com/DeedleFake/p9/internal/debug/debug.go (2)

1-1: Add //go:build for consistency

Add the modern //go:build constraint alongside the legacy form.

Apply this diff:

+//go:build p9debug
 // +build p9debug

10-12: Optional: append newline to logs

Current logging will not append a newline, which can jumble outputs in stderr across multiple calls. If callers don't consistently include "\n", consider appending one here.

Apply this diff:

-func Log(str string, args ...interface{}) {
-	fmt.Fprintf(os.Stderr, str, args...)
-}
+func Log(str string, args ...interface{}) {
+	if len(args) == 0 && len(str) > 0 && str[len(str)-1] == '\n' {
+		fmt.Fprint(os.Stderr, str)
+		return
+	}
+	fmt.Fprintf(os.Stderr, str+"\n", args...)
+}
vendor/github.com/DeedleFake/p9/README.md (1)

1-52: Vendor docs violate markdownlint rules; exclude vendor from linting

markdownlint is flagging heading styles and hard tabs in vendored README. Vendor content should generally be excluded from linters to avoid false positives and churn.

Consider updating your markdownlint configuration to ignore vendor/:

Example .markdownlint-cli2.yaml at repo root:

  • ignores:
    • "vendor/**"

If you prefer to keep linting vendor content, we can convert headings to setext style and replace tabs with spaces in this file.

vendor/github.com/DeedleFake/p9/addr_unix.go (1)

1-1: Add //go:build for clarity

Add the modern build constraint along with the legacy tag.

Apply this diff:

+//go:build linux || darwin
 // +build linux darwin
vendor/github.com/DeedleFake/p9/proto/encoding.go (2)

82-84: Avoid encoding uintptr in a wire protocol

Including reflect.Uintptr introduces arch-dependent sizes. It's safer to reject uintptr or normalize it to a fixed width.

Apply this diff to drop uintptr support:

-	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uintptr:
+	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:

171-171: Prefer safe []byte->string conversion over unsafe.Pointer

The unsafe conversion ties the string lifetime to a transient []byte backing array and relies on runtime internals. For robustness, use string(buf). If performance is a concern, justify with benchmarks and limit to hot paths.

Apply this diff:

-		v.SetString(*(*string)(unsafe.Pointer(&buf)))
+		v.SetString(string(buf))
pkg/crc/constants/constants.go (1)

60-60: Validate msize across client implementations

Confirm that 1MiB msize works with the kernel 9p client(s) you target (Linux/macOS guests) and matches mount-time options. If necessary, consider making it configurable to ease tuning for performance/path MTU constraints.

vendor/github.com/DeedleFake/p9/dir_other.go (1)

1-1: Add go:build constraint for Go 1.17+ compatibility

The legacy // +build form is still supported, but pairing it with //go:build improves tooling compatibility.

Apply this diff:

+//go:build !linux && !darwin && !plan9 && !windows
 // +build !linux,!darwin,!plan9,!windows
vendor/github.com/DeedleFake/p9/encoding.go (1)

16-30: Graceful EOF handling is good; consider treating ErrUnexpectedEOF as end-of-stream too.

proto.Read may return io.ErrUnexpectedEOF on truncated directory streams. If your intent is “read until the stream ends,” it’s reasonable to treat both EOF and ErrUnexpectedEOF as a normal termination and return the accumulated entries.

Apply within this range:

-		err := proto.Read(r, &stat)
-		if err != nil {
-			if err == io.EOF {
-				err = nil
-			}
-			return entries, err
-		}
+		err := proto.Read(r, &stat)
+		if err != nil {
+			if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) {
+				return entries, nil
+			}
+			return entries, err
+		}

Additionally, add the import:

// add to imports
"errors"
vendor/github.com/DeedleFake/p9/internal/util/util.go (3)

8-13: Fix misleading comment about size semantics of N.

io.LimitedReader already uses int64, which is larger than uint32 on all architectures. The current comment suggests uint32 “allows larger sizes,” which is inaccurate. Recommend clarifying the rationale and the cap.

-// LimitedReader is a reimplementation of io.LimitedReader with two
-// main differences:
-//
-// * N is a uint32, allowing for larger sizes on 32-bit systems.
-// * A custom error can be returned if N becomes zero.
+// LimitedReader is similar to io.LimitedReader with two differences:
+//
+// * N is a uint32 (io.LimitedReader uses int64). This keeps the type small and
+//   consistent across architectures but caps the readable size at 4 GiB.
+// * A custom error can be returned when the limit is exhausted.

27-31: Use equality check for unsigned counter.

N is uint32; use N == 0 instead of N <= 0 for clarity.

-	if lr.N <= 0 {
+	if lr.N == 0 {
 		return 0, lr.err()
 	}

41-44: Align doc with implementation for Errorf.

The comment mentions “nil or io.EOF,” but the code only returns io.EOF directly. Either expand the implementation or narrow the comment. Suggest tightening the comment.

-// Errorf is a variant of fmt.Errorf that returns an error being
-// wrapped directly if it is one of a number of specific values, such
-// as nil or io.EOF.
+// Errorf is a variant of fmt.Errorf that returns io.EOF directly if it
+// appears among the arguments; otherwise it formats the error.
vendor/github.com/DeedleFake/p9/dir_plan9.go (2)

10-31: Populate QID fields in DirEntry when available.

When syscall.Dir is present, you can also fill DirEntry.Path and DirEntry.Version from sys.Qid to avoid an extra stat/QID lookup elsewhere.

 	return DirEntry{
 		FileMode:  ModeFromOS(fi.Mode()),
 		ATime:     time.Unix(int64(sys.Atime), 0),
 		MTime:     fi.ModTime(),
 		Length:    uint64(fi.Size()),
 		EntryName: fi.Name(),
 		UID:       sys.Uid,
 		GID:       sys.Gid,
 		MUID:      sys.Muid,
+		Path:      sys.Qid.Path,
+		Version:   sys.Qid.Vers,
 	}

39-42: Clarify error message to include the concrete type.

Improve diagnosability by naming the expected concrete type.

-		return QID{}, errors.New("failed to get QID: FileInfo was not Dir")
+		return QID{}, errors.New("failed to get QID: FileInfo.Sys() was not *syscall.Dir")
vendor/github.com/DeedleFake/p9/dir_linux.go (2)

52-55: Clarify error message to include the concrete type.

Improves diagnosability.

-	if sys == nil {
-		return QID{}, errors.New("failed to get QID: FileInfo was not Stat_t")
-	}
+	if sys == nil {
+		return QID{}, errors.New("failed to get QID: FileInfo.Sys() was not *syscall.Stat_t")
+	}

23-33: Optional: Fallback to numeric UID/GID when lookups fail.

LookupId/LookupGroupId can fail or be slow; consider falling back to numeric strings to retain information.

 	var uname string
 	uid, err := user.LookupId(strconv.FormatUint(uint64(sys.Uid), 10))
 	if err == nil {
 		uname = uid.Username
+	} else {
+		uname = strconv.FormatUint(uint64(sys.Uid), 10)
 	}
 
 	var gname string
 	gid, err := user.LookupGroupId(strconv.FormatUint(uint64(sys.Gid), 10))
 	if err == nil {
 		gname = gid.Name
+	} else {
+		gname = strconv.FormatUint(uint64(sys.Gid), 10)
 	}
vendor/github.com/DeedleFake/p9/proto/server.go (1)

80-93: Msizer handling: prevent double size negotiation warning spam

The setter.Do already guards the once-only behavior, but the outer check logs a warning even when the race resolves to first set wins. Consider moving the “already set” warning inside the Do block and only emit if setter wasn’t executed. Optional improvement.

vendor/github.com/DeedleFake/p9/proto/proto.go (1)

101-108: Dead branch on invalid type check.

Inside if t == nil { ... } the nested if err != nil { return ... } can never trigger; err wasn’t modified after the previous successful read. This is dead code and reduces clarity.

-	t := p.TypeFromID(msgType)
-	if t == nil {
-		if err != nil {
-			return nil, NoTag, err
-		}
-
-		return nil, NoTag, util.Errorf("receive: invalid message type: %v", msgType)
-	}
+	t := p.TypeFromID(msgType)
+	if t == nil {
+		return nil, NoTag, util.Errorf("receive: invalid message type: %v", msgType)
+	}
vendor/github.com/DeedleFake/p9/remote.go (2)

127-135: Variable shadowing obscures receiver; rename local for clarity.

file, err := file.walk(p) shadows the method receiver, reducing readability. Use a different name and avoid confusion.

-		file, err := file.walk(p)
+		next, err := file.walk(p)
 		if err != nil {
 			return err
 		}
 		// Close is not necessary. Remove is also a clunk.
 
-		return file.Remove("")
+		return next.Remove("")

323-331: Same shadowing issue in Stat(); rename local.

Avoid shadowing the receiver to keep code unambiguous.

-		file, err := file.walk(p)
+		next, err := file.walk(p)
 		if err != nil {
 			return DirEntry{}, err
 		}
-		defer file.Close()
+		defer next.Close()
 
-		return file.Stat("")
+		return next.Stat("")
vendor/github.com/DeedleFake/p9/fs.go (2)

179-186: Avoid unsafe string-to-byte conversion when hashing QID path.

Using unsafe to convert string to []byte is brittle and can break across Go versions. The allocation saved here is negligible compared to a SHA-256. Prefer a safe conversion.

-	sum := sha256.Sum256(*(*[]byte)(unsafe.Pointer(&p)))
+	sum := sha256.Sum256([]byte(p))
 	path := binary.LittleEndian.Uint64(sum[:])

Additionally remove the now-unused unsafe import from this file’s imports.
To support import cleanup, apply this change to the import block:

// Remove the "unsafe" import from the import list in this file.

446-527: Directory read handling is intentionally spec-relaxed; document client expectations.

The offset handling for directory reads is relaxed (offsets other than 0 are ignored). This is acceptable since the implementation returns the full entry list, but client-side code must not rely on precise offset semantics. Consider adding a short doc comment to the public-facing server wiring to set expectations.

vendor/github.com/DeedleFake/p9/stat.go (1)

135-153: Minor: unsafe-to-string conversion in String() is a trade-off.

Using unsafe to avoid allocation is fine in vendored perf-sensitive code, but note it ties to Go’s internal string representation. If we ever fork this lib, consider a safe string(buf) for maintainability.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these settings in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 3950d2d and 25ef0c7.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (43)
  • cmd/crc/cmd/daemon.go (4 hunks)
  • cmd/crc/cmd/start.go (0 hunks)
  • go.mod (1 hunks)
  • packaging/windows/product.wxs.template (0 hunks)
  • pkg/crc/config/settings.go (1 hunks)
  • pkg/crc/constants/constants.go (1 hunks)
  • pkg/crc/machine/driver.go (0 hunks)
  • pkg/crc/machine/driver_darwin.go (0 hunks)
  • pkg/crc/machine/driver_linux.go (0 hunks)
  • pkg/crc/machine/driver_windows.go (0 hunks)
  • pkg/crc/machine/libhvee/driver_windows.go (2 hunks)
  • pkg/crc/machine/start.go (2 hunks)
  • pkg/drivers/libhvee/libhvee_windows.go (0 hunks)
  • pkg/drivers/libhvee/powershell_windows.go (0 hunks)
  • pkg/fileserver/fs9p/server.go (1 hunks)
  • pkg/fileserver/fs9p/shares.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/LICENSE (1 hunks)
  • vendor/github.com/DeedleFake/p9/README.md (1 hunks)
  • vendor/github.com/DeedleFake/p9/addr.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/addr_other.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/addr_unix.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/client.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_darwin.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_linux.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_other.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_plan9.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_windows.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/doc.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/encoding.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/fs.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/internal/util/util.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/msg.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/p9.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/client.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/encoding.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/proto.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/server.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/remote.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/stat.go (1 hunks)
  • vendor/modules.txt (1 hunks)
💤 Files with no reviewable changes (8)
  • pkg/crc/machine/driver_darwin.go
  • pkg/crc/machine/driver_windows.go
  • cmd/crc/cmd/start.go
  • pkg/drivers/libhvee/libhvee_windows.go
  • pkg/drivers/libhvee/powershell_windows.go
  • pkg/crc/machine/driver_linux.go
  • pkg/crc/machine/driver.go
  • packaging/windows/product.wxs.template
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: redbeam
PR: crc-org/crc#4866
File: pkg/fileserver/fs9p/shares.go:0-0
Timestamp: 2025-08-06T09:48:10.441Z
Learning: The vsock implementation in pkg/fileserver/fs9p/shares.go was temporarily removed because 9pfs doesn't fully support it yet. It will be added back when 9pfs provides proper vsock support.
📚 Learning: 2025-08-06T09:48:10.441Z
Learnt from: redbeam
PR: crc-org/crc#4866
File: pkg/fileserver/fs9p/shares.go:0-0
Timestamp: 2025-08-06T09:48:10.441Z
Learning: The vsock implementation in pkg/fileserver/fs9p/shares.go was temporarily removed because 9pfs doesn't fully support it yet. It will be added back when 9pfs provides proper vsock support.

Applied to files:

  • vendor/github.com/DeedleFake/p9/README.md
  • cmd/crc/cmd/daemon.go
  • pkg/fileserver/fs9p/server.go
  • vendor/github.com/DeedleFake/p9/fs.go
  • pkg/fileserver/fs9p/shares.go
🧬 Code Graph Analysis (28)
vendor/github.com/DeedleFake/p9/dir_other.go (1)
vendor/github.com/DeedleFake/p9/stat.go (3)
  • DirEntry (255-267)
  • FileMode (23-23)
  • ModeFromOS (43-78)
vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1)
vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1)
  • Log (5-5)
vendor/github.com/DeedleFake/p9/encoding.go (2)
vendor/github.com/DeedleFake/p9/stat.go (2)
  • DirEntry (255-267)
  • Stat (156-168)
vendor/github.com/DeedleFake/p9/proto/encoding.go (2)
  • Read (34-38)
  • Write (25-31)
vendor/github.com/DeedleFake/p9/addr_unix.go (1)
vendor/github.com/DeedleFake/p9/addr_other.go (1)
  • NamespaceDir (17-29)
vendor/github.com/DeedleFake/p9/addr_other.go (1)
vendor/github.com/DeedleFake/p9/addr_unix.go (1)
  • NamespaceDir (17-29)
vendor/github.com/DeedleFake/p9/dir_plan9.go (3)
vendor/github.com/DeedleFake/p9/stat.go (4)
  • DirEntry (255-267)
  • FileMode (23-23)
  • ModeFromOS (43-78)
  • Stat (156-168)
vendor/github.com/DeedleFake/p9/dir.go (1)
  • Dir (16-16)
vendor/github.com/DeedleFake/p9/p9.go (2)
  • QID (42-46)
  • Version (10-10)
vendor/github.com/DeedleFake/p9/dir_darwin.go (3)
vendor/github.com/DeedleFake/p9/stat.go (3)
  • DirEntry (255-267)
  • FileMode (23-23)
  • ModeFromOS (43-78)
vendor/github.com/DeedleFake/p9/dir.go (1)
  • Dir (16-16)
vendor/github.com/DeedleFake/p9/p9.go (3)
  • QID (42-46)
  • QIDType (49-49)
  • Version (10-10)
vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1)
vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1)
  • Log (10-12)
vendor/github.com/DeedleFake/p9/dir_windows.go (1)
vendor/github.com/DeedleFake/p9/stat.go (3)
  • DirEntry (255-267)
  • FileMode (23-23)
  • ModeFromOS (43-78)
vendor/github.com/DeedleFake/p9/addr.go (2)
vendor/github.com/DeedleFake/p9/addr_other.go (1)
  • NamespaceDir (17-29)
vendor/github.com/DeedleFake/p9/addr_unix.go (1)
  • NamespaceDir (17-29)
vendor/github.com/DeedleFake/p9/client.go (5)
vendor/github.com/DeedleFake/p9/proto/client.go (3)
  • Client (18-31)
  • NewClient (35-56)
  • Dial (60-67)
vendor/github.com/DeedleFake/p9/msg.go (8)
  • Proto (75-77)
  • Tversion (79-82)
  • Tversion (84-84)
  • Rversion (86-89)
  • Tauth (95-99)
  • Rauth (101-103)
  • Tattach (105-110)
  • Rattach (112-114)
vendor/github.com/DeedleFake/p9/proto/proto.go (1)
  • Proto (38-41)
vendor/github.com/DeedleFake/p9/p9.go (3)
  • Version (10-10)
  • NoFID (18-18)
  • QID (42-46)
vendor/github.com/DeedleFake/p9/remote.go (1)
  • Remote (19-27)
pkg/crc/machine/libhvee/driver_windows.go (1)
vendor/github.com/crc-org/machine/libmachine/drivers/base.go (1)
  • SharedDir (27-35)
vendor/github.com/DeedleFake/p9/proto/encoding.go (1)
vendor/github.com/DeedleFake/p9/internal/util/util.go (1)
  • Errorf (44-52)
vendor/github.com/DeedleFake/p9/dir_linux.go (3)
vendor/github.com/DeedleFake/p9/stat.go (4)
  • DirEntry (255-267)
  • FileMode (23-23)
  • ModeFromOS (43-78)
  • Stat (156-168)
vendor/github.com/DeedleFake/p9/dir.go (1)
  • Dir (16-16)
vendor/github.com/DeedleFake/p9/p9.go (3)
  • QID (42-46)
  • QIDType (49-49)
  • Version (10-10)
cmd/crc/cmd/daemon.go (2)
pkg/crc/constants/constants.go (2)
  • Plan9Port (59-59)
  • GetHomeDir (164-170)
pkg/fileserver/fs9p/shares.go (2)
  • StartShares (25-56)
  • Mount9p (12-15)
vendor/github.com/DeedleFake/p9/remote.go (6)
vendor/github.com/DeedleFake/p9/client.go (1)
  • Client (22-26)
vendor/github.com/DeedleFake/p9/proto/client.go (1)
  • Client (18-31)
vendor/github.com/DeedleFake/p9/p9.go (4)
  • QID (42-46)
  • QIDType (49-49)
  • Version (10-10)
  • IOHeaderSize (70-70)
vendor/github.com/DeedleFake/p9/msg.go (14)
  • Twalk (133-137)
  • Rwalk (139-141)
  • Topen (143-146)
  • Ropen (148-151)
  • Tcreate (153-158)
  • Rcreate (160-163)
  • Tremove (192-194)
  • Tread (165-169)
  • Rread (171-173)
  • Twrite (175-179)
  • Rwrite (181-183)
  • Tclunk (185-187)
  • Tstat (199-201)
  • Rstat (203-205)
vendor/github.com/DeedleFake/p9/stat.go (3)
  • FileMode (23-23)
  • Stat (156-168)
  • DirEntry (255-267)
vendor/github.com/DeedleFake/p9/internal/util/util.go (1)
  • Errorf (44-52)
pkg/crc/config/settings.go (2)
pkg/crc/config/validations.go (1)
  • ValidateBool (19-25)
pkg/crc/config/callbacks.go (1)
  • SuccessfullyApplied (36-38)
pkg/crc/machine/start.go (1)
pkg/os/exec.go (1)
  • RunPrivileged (48-59)
pkg/fileserver/fs9p/server.go (3)
vendor/github.com/DeedleFake/p9/fs.go (2)
  • FileSystem (21-34)
  • FSConnHandler (162-167)
vendor/github.com/DeedleFake/p9/proto/server.go (1)
  • Serve (17-42)
pkg/crc/constants/constants.go (1)
  • Plan9Msize (60-60)
vendor/github.com/DeedleFake/p9/p9.go (1)
vendor/github.com/DeedleFake/p9/stat.go (1)
  • FileMode (23-23)
vendor/github.com/DeedleFake/p9/fs.go (8)
vendor/github.com/DeedleFake/p9/stat.go (4)
  • Stat (156-168)
  • DirEntry (255-267)
  • StatChanges (316-318)
  • FileMode (23-23)
vendor/github.com/DeedleFake/p9/p9.go (7)
  • QID (42-46)
  • QIDType (49-49)
  • IOHeaderSize (70-70)
  • Version (10-10)
  • QTAuth (58-58)
  • NoFID (18-18)
  • QTDir (54-54)
vendor/github.com/DeedleFake/p9/proto/server.go (3)
  • MessageHandler (135-139)
  • ConnHandler (112-114)
  • ConnHandlerFunc (125-125)
vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1)
  • Log (5-5)
vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1)
  • Log (10-12)
vendor/github.com/DeedleFake/p9/msg.go (2)
  • Tversion (79-82)
  • Tversion (84-84)
vendor/github.com/DeedleFake/p9/client.go (1)
  • ErrUnsupportedVersion (14-14)
vendor/github.com/DeedleFake/p9/encoding.go (1)
  • WriteDir (33-42)
vendor/github.com/DeedleFake/p9/stat.go (3)
vendor/github.com/DeedleFake/p9/p9.go (3)
  • QIDType (49-49)
  • QID (42-46)
  • Version (10-10)
vendor/github.com/DeedleFake/p9/proto/encoding.go (3)
  • Write (25-31)
  • Read (34-38)
  • Size (14-20)
vendor/github.com/DeedleFake/p9/internal/util/util.go (1)
  • LimitedReader (13-17)
vendor/github.com/DeedleFake/p9/proto/proto.go (3)
vendor/github.com/DeedleFake/p9/proto/encoding.go (3)
  • Read (34-38)
  • Write (25-31)
  • Size (14-20)
vendor/github.com/DeedleFake/p9/p9.go (1)
  • NoTag (15-15)
vendor/github.com/DeedleFake/p9/internal/util/util.go (2)
  • Errorf (44-52)
  • LimitedReader (13-17)
pkg/fileserver/fs9p/shares.go (1)
pkg/fileserver/fs9p/server.go (2)
  • Server (15-22)
  • New9pServer (26-62)
vendor/github.com/DeedleFake/p9/dir.go (3)
vendor/github.com/DeedleFake/p9/stat.go (4)
  • Stat (156-168)
  • DirEntry (255-267)
  • StatChanges (316-318)
  • FileMode (23-23)
vendor/github.com/DeedleFake/p9/fs.go (4)
  • File (100-119)
  • Attachment (44-74)
  • FileSystem (21-34)
  • QIDFS (89-91)
vendor/github.com/DeedleFake/p9/p9.go (7)
  • OWRITE (27-27)
  • ORDWR (28-28)
  • OEXEC (29-29)
  • OTRUNC (31-31)
  • OCEXEC (32-32)
  • ORCLOSE (33-33)
  • OREAD (26-26)
vendor/github.com/DeedleFake/p9/proto/server.go (2)
vendor/github.com/DeedleFake/p9/msg.go (1)
  • Proto (75-77)
vendor/github.com/DeedleFake/p9/proto/proto.go (1)
  • Proto (38-41)
vendor/github.com/DeedleFake/p9/proto/client.go (6)
vendor/github.com/DeedleFake/p9/msg.go (1)
  • Proto (75-77)
vendor/github.com/DeedleFake/p9/proto/proto.go (3)
  • Proto (38-41)
  • NoTag (27-27)
  • ErrClientClosed (22-22)
vendor/github.com/DeedleFake/p9/client.go (3)
  • NewClient (30-32)
  • Client (22-26)
  • Dial (36-43)
vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1)
  • Log (5-5)
vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1)
  • Log (10-12)
vendor/github.com/DeedleFake/p9/p9.go (1)
  • NoTag (15-15)
vendor/github.com/DeedleFake/p9/msg.go (6)
vendor/github.com/DeedleFake/p9/proto/proto.go (2)
  • NewProto (44-60)
  • Proto (38-41)
vendor/github.com/DeedleFake/p9/p9.go (2)
  • Version (10-10)
  • QID (42-46)
vendor/github.com/DeedleFake/p9/proto/client.go (1)
  • P9NoTag (221-223)
vendor/github.com/DeedleFake/p9/stat.go (3)
  • FileMode (23-23)
  • Stat (156-168)
  • ErrLargeStat (18-18)
vendor/github.com/DeedleFake/p9/proto/encoding.go (2)
  • Write (25-31)
  • Read (34-38)
vendor/github.com/DeedleFake/p9/internal/util/util.go (1)
  • LimitedReader (13-17)
🪛 markdownlint-cli2 (0.17.2)
vendor/github.com/DeedleFake/p9/README.md

12-12: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


17-17: Hard tabs
Column: 1

(MD010, no-hard-tabs)


21-21: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


26-26: Hard tabs
Column: 1

(MD010, no-hard-tabs)


32-32: Hard tabs
Column: 1

(MD010, no-hard-tabs)


37-37: Hard tabs
Column: 1

(MD010, no-hard-tabs)


43-43: Hard tabs
Column: 1

(MD010, no-hard-tabs)


49-49: Hard tabs
Column: 1

(MD010, no-hard-tabs)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Konflux kflux-prd-rh02 / crc-binary-on-pull-request
  • GitHub Check: build (macOS-14, 1.23)
  • GitHub Check: Run OKD bundle with crc (1.23)
  • GitHub Check: build (ubuntu-latest, 1.23)
  • GitHub Check: build (windows-2022, 1.23)
  • GitHub Check: build (macOS-13, 1.23)
🔇 Additional comments (26)
vendor/github.com/DeedleFake/p9/LICENSE (1)

1-21: MIT license file correctly included for vendored dependency.

License content and attribution look correct for github.com/DeedleFake/p9.

vendor/modules.txt (1)

13-18: Vendoring metadata for p9 v0.6.12 looks consistent.

Entries for root and subpackages are present and marked explicit.

vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1)

1-5: No-op debug build variant is fine.

Build tag and signature match the debug counterpart; safe to vendor as-is.

pkg/crc/machine/libhvee/driver_windows.go (2)

4-4: fmt import is justified by dynamic 9P tag generation.

No issues.


39-45: No change needed — Windows uses TCP 9p, vsock support is disabled and 9p server does not rely on "dir%d" tags

Short summary: I verified that drivers set Tag = fmt.Sprintf("dir%d", i) client-side, but the fs9p server exposes a directory per net.Listener (no tag mapping) and vsock shares are disabled. Windows path already uses TCP/9p, so the original tag/vsock concern is not applicable.

Files to note:

  • pkg/crc/machine/libhvee/driver_windows.go — sets Tag: fmt.Sprintf("dir%d", i) and Type: "9p"
  • pkg/fileserver/fs9p/shares.go — StartVsockShares returns nil (vsock support removed); StartShares uses New9pServer(listener, path)
  • pkg/fileserver/fs9p/server.go — New9pServer serves exposeDir on the provided net.Listener (no tag mapping)
  • cmd/crc/cmd/daemon.go — creates a TCP listener and calls fs9p.StartShares(...)
  • pkg/crc/machine/start.go — configureSharedDirs mounts "9p" via "9pfs 192.168.127.1" (TCP), not vsock

Conclusion: the original review suggestion to align 9p share tags and avoid vsock assumptions is incorrect for this codebase — Windows is already using the TCP/GVProxy 9p path and the server is listener-bound rather than tag-mapped.

Likely an incorrect or invalid review comment.

pkg/crc/machine/start.go (1)

209-211: LGTM: explanatory comment is accurate

The note about rpc.ServerError wrapping and the limitation of errors.Is() is correct and useful context here.

pkg/crc/config/settings.go (1)

87-88: Clarify EnableSharedDirs help text; do NOT enforce HostNetworkAccess

Short summary: I verified the implementation — the 9P server is started on the CRC virtual-network gateway and the guest mounts that gateway address, so the shared-dir feature is served via the CRC virtual network (not by mounting host /). Therefore the proposed validator that forces HostNetworkAccess=true for user networking is incorrect: HostNetworkAccess controls NAT to the host loopback and is not required for the 9P server the daemon creates.

Files to note:

  • pkg/crc/config/settings.go — AddSetting for EnableSharedDirs (update help text here)
  • cmd/crc/cmd/daemon.go — vn.Listen on configuration.GatewayIP and fs9p.StartShares (9P server is bound to the virtual-network gateway)
  • pkg/crc/machine/start.go — configureSharedDirs uses "9pfs 192.168.127.1" (guest mounts the gateway, mountpoint is not '/')
  • pkg/fileserver/fs9p/server.go & shares.go — New9pServer / StartShares bind to the provided listener
  • pkg/crc/constants/constants.go — Plan9Port = 564 (9P port)

Proposed help-text change (apply to pkg/crc/config/settings.go where EnableSharedDirs is registered):

-	cfg.AddSetting(EnableSharedDirs, true, ValidateBool, SuccessfullyApplied,
-		"Mounts host's home directory at '/' in the CRC VM (true/false, default: true)")
+	cfg.AddSetting(EnableSharedDirs, true, ValidateBool, SuccessfullyApplied,
+		"Expose the host's home directory to the CRC VM via 9P (true/false, default: true). The share is served via the CRC virtual-network gateway (e.g. 192.168.127.1) and mounted inside the VM via 9P (not mounted at '/')")

Validator guidance:

  • Do not add a validator that requires HostNetworkAccess=true for NetworkMode=user. Verified evidence: daemon binds the 9P server to the CRC virtual network gateway (cmd/crc/cmd/daemon.go -> vn.Listen on configuration.GatewayIP) and the VM mounts that gateway address (pkg/crc/machine/start.go uses "9pfs 192.168.127.1"). HostNetworkAccess is a separate toggle that maps a virtual host IP to the host loopback and is not necessary for the 9P share.

Likely an incorrect or invalid review comment.

vendor/github.com/DeedleFake/p9/doc.go (1)

1-63: LGTM: Clear, useful package-level docs

The overview and examples set the right expectations for both client and server APIs. No code changes; nothing else to flag.

vendor/github.com/DeedleFake/p9/proto/encoding.go (1)

147-159: No change required — reads are already capped with LimitedReader

proto.Receive reads the message size, enforces msize, then wraps the connection with util.LimitedReader (N = size, E = ErrLargeMessage) and uses that reader for subsequent decoding, so decoder.decode runs against a length-limited reader.

  • vendor/github.com/DeedleFake/p9/proto/proto.go: Receive(...) — reads size, checks msize, constructs lr := &util.LimitedReader{R: r, N: size, E: ErrLargeMessage} and calls Read(lr, ...)
  • vendor/github.com/DeedleFake/p9/internal/util/util.go: LimitedReader implementation that returns the configured error when the limit is reached
  • vendor/github.com/DeedleFake/p9/proto/encoding.go: decoder.decode handles slice lengths/allocations — safe when invoked via Receive
vendor/github.com/DeedleFake/p9/addr.go (1)

10-66: LGTM: ParseAddr covers common 9P forms and pseudo-port mapping

Solid handling of “$namespace”, Unix sockets, host:port (including 9p/9fs), and proto!addr[!port] forms. No functional issues spotted.

vendor/github.com/DeedleFake/p9/p9.go (2)

21-39: LGTM: Open mode/flag constants consistent with 9P semantics

The bit layout and the iota math are correct; no concerns.


41-66: LGTM: QID/QIDType and FileMode conversion look correct

QIDType->FileMode shift aligns with 9P’s mode top bits. No issues.

pkg/crc/constants/constants.go (1)

59-60: Plan 9 constants addition looks good

Using the standard 9P port (564) and a generous 1MiB msize is sensible for the initial integration.

cmd/crc/cmd/daemon.go (3)

27-27: Importing fs9p for 9P shares is appropriate

The new import aligns with the 9P home directory sharing introduced below.


181-185: Good: use net.JoinHostPort for listener address

This is safer (IPv6-aware) and avoids string formatting pitfalls.


197-211: Good: consistent JoinHostPort usage for network listener

Same benefits here; consistent and correct.

vendor/github.com/DeedleFake/p9/dir_other.go (1)

7-14: LGTM: sane fallback entry mapping

For non-listed OSes, mapping mode/mtime/size/name is correct and minimal.

vendor/github.com/DeedleFake/p9/dir_windows.go (1)

9-27: Windows DirEntry mapping looks correct

  • Safe type assertion on fi.Sys() and proper fallback when sys is nil.
  • Using Filetime.Nanoseconds() with time.Unix(0, ...) is the idiomatic conversion.
vendor/github.com/DeedleFake/p9/dir_darwin.go (1)

46-62: Darwin QID generation approach is sound

Using inode for Path and deriving QID type from mode mirrors Linux behavior and is appropriate. Error on missing Stat_t keeps semantics clear.

vendor/github.com/DeedleFake/p9/encoding.go (1)

33-42: LGTM: WriteDir is straightforward and correct.

Looped encode via proto.Write is clear and returns on first error as expected.

vendor/github.com/DeedleFake/p9/proto/client.go (2)

69-75: LGTM: clean shutdown path

Close() cancels the coordination goroutines and closes the underlying connection. This aligns with the reader/coord loop design.


176-208: Solid tagged/untagged messaging coordination

The Send/reader/coord interplay correctly handles both tagged messages and the special untagged case (P9NoTag), with backpressure and cancellation paths.

vendor/github.com/DeedleFake/p9/dir.go (1)

18-21: Consider hardening against traversal in path resolution

Dir.path simply joins the base with the provided p. If upstream always supplies normalized, component-wise paths (as expected by the 9P Walk semantics), this is fine. If not guaranteed, normalize and reject any attempt to escape the base (e.g., by resolving and verifying that the result has the base as a prefix).

Would you like me to add a safe-join helper that rejects absolute paths and any result escaping the base?

vendor/github.com/DeedleFake/p9/stat.go (1)

191-216: Stat encoding/decoding looks correct and spec-compliant.

The size-prefix and LimitedReader enforcement align with 9P stat encoding, and error propagation is sound.

vendor/github.com/DeedleFake/p9/msg.go (2)

207-233: Rstat length-prefixing matches Stat.P9Encode; decode bounds are correct.

The extra +2 accounts for Stat’s internal size field, and the LimitedReader bounds prevent overreads. This aligns with the 9P2000 spec.


44-72: Protocol registry is comprehensive and type-safe mapping looks good.

The reflect-based registry setup matches the declared message types and provides a solid base for dispatch.

Comment on lines +252 to +260
// 9p home directory sharing
listener9p, err := vn.Listen("tcp", net.JoinHostPort(configuration.GatewayIP, fmt.Sprintf("%d", constants.Plan9Port)))
if err != nil {
return err
}
if _, err := fs9p.StartShares([]fs9p.Mount9p{{Listener: listener9p, Path: constants.GetHomeDir()}}); err != nil {
return err
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

Don’t drop server handles; add graceful shutdown for 9P servers

You start 9P shares but discard the returned servers, so they can’t be stopped on shutdown. Capture them and defer Stop() to avoid leaking goroutines and to ensure clean teardown.

Apply this diff:

 // 9p home directory sharing
 listener9p, err := vn.Listen("tcp", net.JoinHostPort(configuration.GatewayIP, fmt.Sprintf("%d", constants.Plan9Port)))
 if err != nil {
   return err
 }
-if _, err := fs9p.StartShares([]fs9p.Mount9p{{Listener: listener9p, Path: constants.GetHomeDir()}}); err != nil {
-  return err
-}
+servers9p, err := fs9p.StartShares([]fs9p.Mount9p{{Listener: listener9p, Path: constants.GetHomeDir()}})
+if err != nil {
+  return err
+}
+defer func() {
+  for _, s := range servers9p {
+    if err := s.Stop(); err != nil {
+      logging.Errorf("Error stopping 9p server: %v", err)
+    }
+  }
+}()

Optional: If you want the daemon to exit on 9P server failure (not just log), consider plumbing fs9p server errors into errCh (requires fs9p.StartShares to accept a callback or return error channels).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// 9p home directory sharing
listener9p, err := vn.Listen("tcp", net.JoinHostPort(configuration.GatewayIP, fmt.Sprintf("%d", constants.Plan9Port)))
if err != nil {
return err
}
if _, err := fs9p.StartShares([]fs9p.Mount9p{{Listener: listener9p, Path: constants.GetHomeDir()}}); err != nil {
return err
}
// 9p home directory sharing
listener9p, err := vn.Listen("tcp", net.JoinHostPort(configuration.GatewayIP, fmt.Sprintf("%d", constants.Plan9Port)))
if err != nil {
return err
}
servers9p, err := fs9p.StartShares([]fs9p.Mount9p{{Listener: listener9p, Path: constants.GetHomeDir()}})
if err != nil {
return err
}
defer func() {
for _, s := range servers9p {
if err := s.Stop(); err != nil {
logging.Errorf("Error stopping 9p server: %v", err)
}
}
}()
🤖 Prompt for AI Agents
In cmd/crc/cmd/daemon.go around lines 252 to 260, the code starts 9P shares but
discards the returned server handles; capture the returned servers from
fs9p.StartShares into a variable, check the error as now, and immediately defer
a cleanup loop that calls Stop() (or Close()) on each returned server to ensure
graceful shutdown and avoid leaking goroutines; if there’s an existing errCh for
daemon components, optionally wire server errors into it (or modify StartShares
to accept a callback/return error channels) so 9P failures can cause daemon
shutdown instead of only logging.

@@ -4,6 +4,7 @@ go 1.23.0

require (
github.com/AlecAivazis/survey/v2 v2.3.7
github.com/DeedleFake/p9 v0.6.12
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Add p9 dependency: OK. Please double-check any lingering SMB/CIFS references.

The module addition aligns with the move to 9P. As a precaution for this PR’s objective (remove SMB on Windows), scan the tree for any remaining SMB/CIFS usage or password plumbing.

Run this script to verify no SMB/CIFS remnants remain and that 9p is wired on Windows:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Expect: no matches (outside vendor)
rg -n --hidden --glob '!vendor/**' -e '\bSMB\b' -e '\bsmb\b' -e '\bcifs\b' -e 'mount\.cifs' -e 'SharedDirPassword' -e 'SharedDirUsername' -e 'net use' -e 'MSI.*custom.*action'

# Expect: matches in Windows driver code
rg -n --glob '!vendor/**' -e 'Type:\s*"9p"' pkg/crc/machine

Length of output: 820


Add p9 dependency: OK — remove leftover SMB/CIFS credential plumbing

9p is wired on Windows, but the repo still contains SharedDir credential fields/uses; these need to be removed or refactored.

Files to fix:

  • pkg/crc/machine/start.go:317-318 — SharedDirPassword / SharedDirUsername passed through
  • pkg/crc/machine/types/types.go:37-38 — SharedDirPassword / SharedDirUsername fields
  • pkg/crc/machine/config/config.go:24-25 — SharedDirPassword / SharedDirUsername config fields
  • pkg/crc/config/settings.go:34 — SharedDirPassword setting (sensitive)
  • pkg/crc/machine/libhvee/driver_windows.go:44 — Type: "9p" (expected; confirms 9p is in use)

Action: remove or replace SMB/CIFS credential plumbing (structs, config, callers, and settings) or explicitly document why they must remain. Re-run the search after changes to confirm no SMB/CIFS remnants remain.

🤖 Prompt for AI Agents
In go.mod line 7 and across the codebase (specifically pkg/crc/machine/start.go
lines ~317-318, pkg/crc/machine/types/types.go lines ~37-38,
pkg/crc/machine/config/config.go lines ~24-25, pkg/crc/config/settings.go line
~34, and pkg/crc/machine/libhvee/driver_windows.go line ~44) there are leftover
SharedDirUsername/SharedDirPassword SMB/CIFS credential fields and plumbing that
are no longer needed because 9p is used; remove the SharedDirUsername and
SharedDirPassword fields from structs and config, delete or refactor any callers
that pass these credentials (e.g., remove arguments, calls, and validation
related to them), remove the sensitive setting from settings.go (or mark
deprecated with migration if you must preserve data), and update
driver_windows.go to rely on 9p-only configuration; after making these
removals/refactors, run a repository-wide search to ensure no remaining SMB/CIFS
credential references exist and update any comments/docs to reflect the removal
or provide a short note documenting why SMB fields were removed.

Comment on lines +39 to 45
for i, dir := range machineConfig.SharedDirs {
sharedDir := drivers.SharedDir{
Source: dir,
Target: convertToUnixPath(dir),
Tag: "crc-dir0", // smb share 'crc-dir0' is created in the msi
Type: "cifs",
Username: machineConfig.SharedDirUsername,
Source: dir,
Target: convertToUnixPath(dir),
Tag: fmt.Sprintf("dir%d", i),
Type: "9p",
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

9P migration: ensure tag/name symmetry with the 9P server and make tag generation deterministic.

  • The Tag "dir%d" must match the server’s share names (9P aname). If server-side naming diverges, mounts will fail. Recommend centralizing the tag format or deriving it from a shared helper/constant to avoid drift.
  • Consider sorting the list before assigning tags to keep mapping stable across runs/config reloads. Otherwise, reordering SharedDirs can change tags and surprise the guest mount logic.

Apply this refactor to stabilize ordering:

@@
-import (
-	"fmt"
+import (
+	"fmt"
+	"sort"
@@
 func configureShareDirs(machineConfig config.MachineConfig) []drivers.SharedDir {
 	var sharedDirs []drivers.SharedDir
-	for i, dir := range machineConfig.SharedDirs {
+	dirs := append([]string(nil), machineConfig.SharedDirs...)
+	sort.Strings(dirs)
+	for i, dir := range dirs {
 		sharedDir := drivers.SharedDir{
 			Source: dir,
 			Target: convertToUnixPath(dir),
 			Tag:    fmt.Sprintf("dir%d", i),
 			Type:   "9p",
 		}

Optionally, define a shared constant/func for the tag format (e.g., constants.Plan9ShareTagFmt = "dir%d") and use it both here and in the fileserver to prevent divergence. I can draft that change if you want.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for i, dir := range machineConfig.SharedDirs {
sharedDir := drivers.SharedDir{
Source: dir,
Target: convertToUnixPath(dir),
Tag: "crc-dir0", // smb share 'crc-dir0' is created in the msi
Type: "cifs",
Username: machineConfig.SharedDirUsername,
Source: dir,
Target: convertToUnixPath(dir),
Tag: fmt.Sprintf("dir%d", i),
Type: "9p",
}
import (
"fmt"
"sort"
)
func configureShareDirs(machineConfig config.MachineConfig) []drivers.SharedDir {
var sharedDirs []drivers.SharedDir
dirs := append([]string(nil), machineConfig.SharedDirs...)
sort.Strings(dirs)
for i, dir := range dirs {
sharedDir := drivers.SharedDir{
Source: dir,
Target: convertToUnixPath(dir),
Tag: fmt.Sprintf("dir%d", i),
Type: "9p",
}
sharedDirs = append(sharedDirs, sharedDir)
}
return sharedDirs
}
🤖 Prompt for AI Agents
In pkg/crc/machine/libhvee/driver_windows.go around lines 39 to 45, the current
Tag generation uses the unstable iteration index ("dir%d") which can diverge
from the 9P server's share names and be non-deterministic across runs; sort
machineConfig.SharedDirs (or a copy) deterministically (e.g., lexicographically
by Source) before assigning tags, and replace the inline "dir%d" format with a
shared constant or helper function (e.g., Plan9ShareTagFmt or
MakePlan9Tag(sourceOrIndex)) that the fileserver also uses so tag/aname symmetry
is guaranteed. Ensure you do not mutate the original slice unless intended (use
a sorted copy) and keep tag generation deterministic and centralized.

Comment on lines +244 to 251
case "9p":
// change owner to core user to allow mounting to it as a non-root user
if _, _, err := sshRunner.RunPrivileged("Changing owner of mount directory", "chown core:core", mount.Target); err != nil {
return err
}
if _, _, err := sshRunner.Run("9pfs 192.168.127.1", mount.Target); err != nil {
return err
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

9P mount: missing options, not privileged, and doesn’t use tag/aname

  • Mounting typically requires root; using sshRunner.Run (non-privileged) will likely fail.
  • The command lacks essential 9P options (trans=tcp, port, version, msize, cache).
  • The share/tag (aname) is not passed, so the server can't resolve which export to mount.
  • Using a non-standard “9pfs” helper is brittle; prefer explicit mount invocation.

Apply this diff to use a privileged, explicit 9P mount with tag and CRC constants:

 		case "9p":
-			// change owner to core user to allow mounting to it as a non-root user
-			if _, _, err := sshRunner.RunPrivileged("Changing owner of mount directory", "chown core:core", mount.Target); err != nil {
-				return err
-			}
-			if _, _, err := sshRunner.Run("9pfs 192.168.127.1", mount.Target); err != nil {
-				return err
-			}
+			// change owner to core user to allow non-root access after mounting
+			if _, _, err := sshRunner.RunPrivileged("Changing owner of mount directory", "chown core:core", mount.Target); err != nil {
+				return err
+			}
+			opts := fmt.Sprintf("trans=tcp,port=%d,msize=%d,cache=loose,version=9p2000.L,aname=%s", constants.Plan9Port, constants.Plan9Msize, mount.Tag)
+			if _, _, err := sshRunner.RunPrivileged(
+				fmt.Sprintf("Mounting %s (9p tag %s)", mount.Target, mount.Tag),
+				"mount", "-t", "9p", "-o", opts, "192.168.127.1", mount.Target,
+			); err != nil {
+				return err
+			}

Follow-ups to consider:

  • Idempotency: skip if already mounted (mountpoint -q). I can propose a patch if you want it built-in.
  • If SELinux confines containers, verify if additional labeling is needed for the 9p mount; 9p often doesn't support SELinux contexts like virtiofs does. We may need a chcon workaround or document the limitation.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
case "9p":
// change owner to core user to allow mounting to it as a non-root user
if _, _, err := sshRunner.RunPrivileged("Changing owner of mount directory", "chown core:core", mount.Target); err != nil {
return err
}
if _, _, err := sshRunner.Run("9pfs 192.168.127.1", mount.Target); err != nil {
return err
}
case "9p":
// change owner to core user to allow non-root access after mounting
if _, _, err := sshRunner.RunPrivileged("Changing owner of mount directory", "chown core:core", mount.Target); err != nil {
return err
}
opts := fmt.Sprintf("trans=tcp,port=%d,msize=%d,cache=loose,version=9p2000.L,aname=%s", constants.Plan9Port, constants.Plan9Msize, mount.Tag)
if _, _, err := sshRunner.RunPrivileged(
fmt.Sprintf("Mounting %s (9p tag %s)", mount.Target, mount.Tag),
"mount", "-t", "9p", "-o", opts, "192.168.127.1", mount.Target,
); err != nil {
return err
}

Comment on lines +39 to +46
errChan := make(chan error)

fs := p9.FileSystem(p9.Dir(exposeDir))

go func() {
errChan <- proto.Serve(listener, p9.Proto(), p9.FSConnHandler(fs, constants.Plan9Msize))
close(errChan)
}()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Prevent goroutine leaks and treat net.ErrClosed as a normal shutdown

  • The server goroutine writes exactly one error to ErrChan when proto.Serve returns (typically net.ErrClosed after Stop). If no one is receiving (WaitForError never called), the goroutine can block forever on the send. Also, WaitForError will surface net.ErrClosed as an error even on a clean Stop.
  • Make ErrChan buffered (size 1) and ignore net.ErrClosed in WaitForError.

Apply this diff:

@@
-	errChan := make(chan error)
+	errChan := make(chan error, 1)
@@
-func (s *Server) WaitForError() error {
-	err := <-s.ErrChan
-	return err
-}
+func (s *Server) WaitForError() error {
+	// If nobody is waiting, the server goroutine can still deliver its terminal error.
+	// Treat net.ErrClosed (listener closed due to Stop) as a clean shutdown.
+	if err, ok := <-s.ErrChan; ok {
+		if errors.Is(err, net.ErrClosed) {
+			return nil
+		}
+		return err
+	}
+	return nil
+}

Also add the import at the top:

@@
-import (
+import (
+	"errors"
 	"fmt"
 	"net"
 	"os"
 	"path/filepath"

Also applies to: 76-80

🤖 Prompt for AI Agents
In pkg/fileserver/fs9p/server.go around lines 39-46 (and similarly at 76-80),
the goroutine sending the Serve error can block if nobody receives and
WaitForError treats net.ErrClosed as an error; change errChan to a buffered
channel of size 1 to avoid goroutine leaks, update WaitForError to treat
net.ErrClosed as a normal shutdown (ignore it and return nil), and add the
necessary import for the net package at the top of the file so you can compare
errors against net.ErrClosed.

Comment on lines +85 to +94
if (msize > 0) && (size > msize) {
return nil, NoTag, util.Errorf("receive: %w", ErrLargeMessage)
}

lr := &util.LimitedReader{
R: r,
N: size,
E: ErrLargeMessage,
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

Off-by-4 framing bug: LimitedReader should bound to size-4 (size includes itself).

9P’s size field includes the 4 bytes of the size itself. After reading size, the remaining frame length is size-4. Using N: size allows reads to leak 4 bytes into the next frame on exact-boundary payloads. This breaks message framing and can cause hard-to-debug, nondeterministic errors.

Apply this diff to bound reads correctly and add a guard for undersized frames:

-	if (msize > 0) && (size > msize) {
+	if (msize > 0) && (size > msize) {
 		return nil, NoTag, util.Errorf("receive: %w", ErrLargeMessage)
 	}
 
-	lr := &util.LimitedReader{
-		R: r,
-		N: size,
-		E: ErrLargeMessage,
-	}
+	if size < 4 {
+		return nil, NoTag, util.Errorf("receive: invalid frame size: %d", size)
+	}
+	lr := &util.LimitedReader{
+		R: r,
+		N: size - 4,
+		E: ErrLargeMessage,
+	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (msize > 0) && (size > msize) {
return nil, NoTag, util.Errorf("receive: %w", ErrLargeMessage)
}
lr := &util.LimitedReader{
R: r,
N: size,
E: ErrLargeMessage,
}
if (msize > 0) && (size > msize) {
return nil, NoTag, util.Errorf("receive: %w", ErrLargeMessage)
}
if size < 4 {
return nil, NoTag, util.Errorf("receive: invalid frame size: %d", size)
}
lr := &util.LimitedReader{
R: r,
N: size - 4,
E: ErrLargeMessage,
}
🤖 Prompt for AI Agents
In vendor/github.com/DeedleFake/p9/proto/proto.go around lines 85 to 94, the
LimitedReader is currently bounded with N: size which is off-by-4 because the 9P
size field includes its own 4 bytes; change the reader bound to N: size-4 and
add a guard that returns an error if size < 4 (undersized frame) before
constructing the LimitedReader so we never allow negative/invalid bounds or leak
4 bytes into the next frame.

Comment on lines +3 to +9
import (
"io"
"log"
"net"
"sync"
)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Break on non-EOF read errors and don’t dispatch a handler on failed Receive

Currently, after a Receive error, the loop logs and then proceeds to call the handler with a garbage message/tag, which can panic or send invalid responses. Also, closed connections (e.g., net.ErrClosed) should terminate the loop, not busy-loop and spam logs.

Apply this diff:

@@
-import (
+import (
+	"errors"
 	"io"
 	"log"
 	"net"
 	"sync"
 )
@@
-		tmsg, tag, err := p.Receive(c, msize)
+		tmsg, tag, err := p.Receive(c, msize)
 		if err != nil {
-			if err == io.EOF {
-				return
-			}
-
-			log.Printf("Error reading message: %v", err)
+			// Terminate on EOF or closed connection.
+			if err == io.EOF || errors.Is(err, net.ErrClosed) {
+				return
+			}
+			// For other errors, log and continue to try receiving again.
+			log.Printf("Error reading message: %v", err)
+			continue
 		}
 
 		mode(func() {
 			rmsg := handler.HandleMessage(tmsg)

Also applies to: 71-79, 79-99

🤖 Prompt for AI Agents
In vendor/github.com/DeedleFake/p9/proto/server.go around lines 3-9, 71-79 and
79-99, the loop continues after a Receive error and calls the handler with
invalid data, and it busy-loops on closed connections; update the
receive-and-dispatch loop to: check the error returned by Receive and if err !=
nil then if errors.Is(err, io.EOF) or errors.Is(err, net.ErrClosed) break the
loop (cleanly close/return), otherwise log the error and break (do not call the
handler); only call the handler when Receive succeeds (no error) and ensure you
don’t use stale/garbage msg/tag after a failed Receive.

Comment on lines +37 to +43
w := []string{path.Clean(p)}
if w[0] != "/" {
w = strings.Split(w[0], "/")
}
if (len(w) == 1) && (w[0] == ".") {
w = nil
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

Absolute path handling in walk() sends invalid Wname (empty element or “/”).

path.Clean("/a/b") yields "/a/b"; the current code splits it into ["", "a", "b"] due to the leading slash, causing an empty name element in Twalk. For "/", it sends Wname = ["/"], which is also invalid. Twalk Wname must be path elements without empty strings or slashes.

-	w := []string{path.Clean(p)}
-	if w[0] != "/" {
-		w = strings.Split(w[0], "/")
-	}
-	if (len(w) == 1) && (w[0] == ".") {
-		w = nil
-	}
+	p = path.Clean(p)
+	var w []string
+	switch {
+	case p == "" || p == ".":
+		w = nil
+	default:
+		if strings.HasPrefix(p, "/") {
+			p = strings.TrimPrefix(p, "/")
+		}
+		if p == "" {
+			w = nil
+		} else {
+			w = strings.Split(p, "/")
+		}
+	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
w := []string{path.Clean(p)}
if w[0] != "/" {
w = strings.Split(w[0], "/")
}
if (len(w) == 1) && (w[0] == ".") {
w = nil
}
p = path.Clean(p)
var w []string
switch {
case p == "" || p == ".":
w = nil
default:
if strings.HasPrefix(p, "/") {
p = strings.TrimPrefix(p, "/")
}
if p == "" {
w = nil
} else {
w = strings.Split(p, "/")
}
}
🤖 Prompt for AI Agents
In vendor/github.com/DeedleFake/p9/remote.go around lines 37 to 43, the code
builds Wname incorrectly for absolute paths (leading "/" produces empty first
element and "/" alone yields invalid name); update the logic to Clean the path,
then split on "/" but remove any empty elements and any elements equal to "/" so
Wname contains only valid path components, and treat the root path (no
components) as nil/empty Wname for Twalk; ensure you handle both relative and
absolute inputs consistently by trimming a leading slash before splitting or by
filtering out empty tokens after Split.

Comment on lines +184 to +185
panic(util.Errorf("Invalid whence: %v", whence))
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

Don’t panic on invalid whence; return an error.

Library code should not panic for invalid input. Return the current position and a descriptive error instead.

-	panic(util.Errorf("Invalid whence: %v", whence))
+	return int64(file.pos), util.Errorf("invalid whence: %v", whence)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
panic(util.Errorf("Invalid whence: %v", whence))
}
return int64(file.pos), util.Errorf("invalid whence: %v", whence)
}
🤖 Prompt for AI Agents
In vendor/github.com/DeedleFake/p9/remote.go around lines 184-185, replace the
panic call for an invalid whence with returning the current position and an
error; specifically, remove panic(util.Errorf(...)) and instead return the
current offset/position variable (the value the function would report as the
current file position) along with util.Errorf("invalid whence: %v", whence) so
callers receive an error instead of the process aborting.

Comment on lines +198 to +201
func (file *Remote) maxBufSize() int {
return int(file.client.Msize() - IOHeaderSize)
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Guard against negative/invalid max buffer size.

If Msize() is misnegotiated or too small, int(file.client.Msize() - IOHeaderSize) can go negative, leading to slicing errors or infinite loops in chunked I/O. Return 0 in such cases.

-func (file *Remote) maxBufSize() int {
-	return int(file.client.Msize() - IOHeaderSize)
-}
+func (file *Remote) maxBufSize() int {
+	m := int(file.client.Msize())
+	if m <= IOHeaderSize {
+		return 0
+	}
+	return m - IOHeaderSize
+}

Please verify negotiated msize is always > IOHeaderSize on all supported backends.


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Searching for IOHeaderSize ==="
rg -n --hidden --no-ignore -S "IOHeaderSize" || true
echo

echo "=== Showing vendor/github.com/DeedleFake/p9/remote.go (first 300 lines) ==="
sed -n '1,300p' vendor/github.com/DeedleFake/p9/remote.go || true
echo

echo "=== Showing vendor/github.com/DeedleFake/p9/remote.go (around reported lines 180-220) ==="
sed -n '160,220p' vendor/github.com/DeedleFake/p9/remote.go || true
echo

echo "=== Searching for maxBufSize usages ==="
rg -n --hidden --no-ignore -S "maxBufSize" || true
echo

echo "=== Searching for Msize definitions/usages in vendor ==="
rg -n --hidden --no-ignore -S "Msize" vendor || true
echo

echo "=== Searching for type of client in repo (look for struct/interface fields named client) ==="
rg -n --hidden --no-ignore -S "client" || true
echo

echo "=== Grep for 'type Remote' to show its definition ==="
rg -n --hidden --no-ignore -S "type Remote" || true
sed -n '1,240p' vendor/github.com/DeedleFake/p9/remote.go | sed -n '1,120p' || true

Length of output: 273701


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== vendor/github.com/DeedleFake/p9/p9.go ==="
sed -n '1,240p' vendor/github.com/DeedleFake/p9/p9.go || true
echo

echo "=== vendor/github.com/DeedleFake/p9/proto/client.go ==="
sed -n '1,240p' vendor/github.com/DeedleFake/p9/proto/client.go || true
echo

echo "=== vendor/github.com/DeedleFake/p9/client.go ==="
sed -n '1,240p' vendor/github.com/DeedleFake/p9/client.go || true
echo

echo "=== vendor/github.com/DeedleFake/p9/fs.go (around msize logic) ==="
sed -n '1,320p' vendor/github.com/DeedleFake/p9/fs.go || true
echo

echo "=== Search for SetMsize or SetMsize usages ==="
rg -n --hidden --no-ignore -S "SetMsize|Set Msize|SetMsize" vendor/github.com/DeedleFake/p9 || true
echo

echo "=== Show vendor/github.com/DeedleFake/p9/proto/server.go (relevant Msize negotiation) ==="
sed -n '1,240p' vendor/github.com/DeedleFake/p9/proto/server.go || true

Length of output: 21739


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== List proto files ==="
ls -la vendor/github.com/DeedleFake/p9/proto || true
echo

echo "=== Show vendor/github.com/DeedleFake/p9/proto/proto.go ==="
sed -n '1,240p' vendor/github.com/DeedleFake/p9/proto/proto.go || true
echo

echo "=== Show vendor/github.com/DeedleFake/p9/proto/msg.go ==="
sed -n '1,300p' vendor/github.com/DeedleFake/p9/proto/msg.go || true
echo

echo "=== Search for Receive and Send implementations in proto ==="
rg -n --hidden --no-ignore -S "func .*Receive|func .*Send" vendor/github.com/DeedleFake/p9/proto || true

Length of output: 5465


Guard negotiated msize and avoid underflow / infinite-loop

Briefly: IOHeaderSize is 24 and Client.Msize() is a uint32. The current expression int(file.client.Msize() - IOHeaderSize) can underflow/wrap when the negotiated msize is <= IOHeaderSize. Returning 0 (as in the original suggestion) would cause an infinite loop in ReadAt/WriteAt (they do "start += size"). Fixes needed.

Files to update:

  • vendor/github.com/DeedleFake/p9/remote.go — maxBufSize()
  • vendor/github.com/DeedleFake/p9/client.go — Handshake() (validate negotiated msize)

Suggested changes (replace the previous diff — do NOT return 0; either validate at handshake or clamp to a safe positive chunk):

--- a/vendor/github.com/DeedleFake/p9/remote.go
+++ b/vendor/github.com/DeedleFake/p9/remote.go
@@
 func (file *Remote) maxBufSize() int {
-	return int(file.client.Msize() - IOHeaderSize)
+	m := file.client.Msize()
+	if m <= uint32(IOHeaderSize) {
+		// negotiated msize too small / invalid — avoid underflow or returning 0
+		// (returning 0 would make ReadAt/WriteAt loop forever).  Return 1
+		// so callers make forward progress; callers should still treat a
+		// tiny negotiated msize as an error (see Handshake validation below).
+		return 1
+	}
+	return int(m - uint32(IOHeaderSize))
 }

Optional but recommended: fail the handshake early so an invalid/too-small msize is rejected instead of working around it:

--- a/vendor/github.com/DeedleFake/p9/client.go
+++ b/vendor/github.com/DeedleFake/p9/client.go
@@
-import (
-	"errors"
-	"net"
-	"sync/atomic"
-
-	"github.com/DeedleFake/p9/proto"
-)
+import (
+	"errors"
+	"fmt"
+	"net"
+	"sync/atomic"
+
+	"github.com/DeedleFake/p9/proto"
+)
@@
 	version := rsp.(*Rversion)
 	if version.Version != Version {
 		return 0, ErrUnsupportedVersion
 	}
+
+	// Defensive: negotiated msize must be larger than the 9P IO header.
+	if version.Msize <= uint32(IOHeaderSize) {
+		return 0, fmt.Errorf("negotiated msize too small: %d", version.Msize)
+	}
 
 	c.SetMsize(version.Msize)
 
 	return version.Msize, nil
 }

Reasoning: underflow/wrap from unsigned arithmetic or int conversion can produce huge or negative values (on 32-bit), and returning 0 will break the chunking loops. Clamping to a safe positive value prevents infinite loops; failing the handshake is preferable so callers don't run with an unusable msize.

Please implement one or both of the above changes and verify that all supported server backends never negotiate Msize <= IOHeaderSize.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func (file *Remote) maxBufSize() int {
return int(file.client.Msize() - IOHeaderSize)
}
func (file *Remote) maxBufSize() int {
m := file.client.Msize()
if m <= uint32(IOHeaderSize) {
// negotiated msize too small / invalid — avoid underflow or returning 0
// (returning 0 would make ReadAt/WriteAt loop forever). Return 1
// so callers make forward progress; callers should still treat a
// tiny negotiated msize as an error (see Handshake validation below).
return 1
}
return int(m - uint32(IOHeaderSize))
}
🤖 Prompt for AI Agents
In vendor/github.com/DeedleFake/p9/remote.go around lines 198-201, avoid
unsigned underflow by not computing int(file.client.Msize() - IOHeaderSize)
directly; instead compute a safe positive chunk size (e.g. if
file.client.Msize() > IOHeaderSize return int(file.client.Msize() -
IOHeaderSize) else return a small positive minimum) or better yet validate
earlier. In vendor/github.com/DeedleFake/p9/client.go Handshake(), validate the
negotiated Msize immediately and return an error if Msize <= IOHeaderSize
(reject the handshake) so callers never run with an unusable msize; if you
choose to clamp in maxBufSize, ensure it never returns 0 and cannot trigger
infinite loops in ReadAt/WriteAt.

Copy link

openshift-ci bot commented Aug 14, 2025

@redbeam: The following tests failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/security 25ef0c7 link false /test security
ci/prow/integration-crc 25ef0c7 link true /test integration-crc
ci/prow/e2e-crc 25ef0c7 link true /test e2e-crc

Full PR test history. Your PR dashboard.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Copy link
Contributor

@cfergeau cfergeau left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only took a quick look, but it’s unexpected to see the 9p code being added in the first commits before being disabled, and then to have the smb code removal.
Regarding the 9p code, some of the comments of coderabbit.ai (including in the vendor’ed code) deserve a closer look.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/task Workable task
Projects
Status: Ready for review
Development

Successfully merging this pull request may close these issues.

Remove file sharing code completely from windows
3 participants