Skip to content
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

Port to Darwin #95

Merged
merged 1 commit into from
Oct 18, 2023
Merged

Port to Darwin #95

merged 1 commit into from
Oct 18, 2023

Conversation

jaysoffian
Copy link

@jaysoffian jaysoffian commented Aug 31, 2023

Use raw syscalls to retrieve the command line under Darwin, since macOS
does not provide a /proc filesystem.

The code to do this is from https://github.com/elastic/go-sysinfo which
can be sanity checked against:

https://github.com/apple-oss-distributions/adv_cmds/blob/adv_cmds-205/ps/print.c#L115

I've verified with these changes that pam_sshca.so works as expected
under macOS 13 (Ventura) on an arm64 host.

Issues:

  1. The Linux pam.d/sudo configuration line:

    "auth   [success=done default=die]   pam_sshca.so"
    

    Does not work on Darwin. Instead use one of the following:

    "auth   requisite   /path/to/pam_sshca.so"
    

    Or:

    "auth   required   /path/to/pam_sshca.so"
    

    Neither is identical to [success=done default=die] whose
    semantics are impossible under Darwin. See the pam.conf man pages
    on Linux and macOS for details.

  2. The log/syslog module does not work under macOS >= 12 (Monterey).
    Log messages are silently dropped:

    log/syslog: local messages (syslog.New()) do not work on macOS Monterey/Ventura golang/go#59229

  3. The kern.procargs2 syscall returns incorrect data under macOS
    10.15 (Catalina) due to a bug in that OS version. The code won't
    panic under that OS version but it won't return a command line:

    providers/darwin - kern.procargs2 guard against runtime panic elastic/go-sysinfo#172

@jaysoffian jaysoffian force-pushed the port-to-darwin branch 3 times, most recently from 27f67aa to 3109d20 Compare August 31, 2023 18:01
Use raw syscalls to retrieve the command line under Darwin, since macOS
does not provide a `/proc` filesystem.

The code to do this is from https://github.com/elastic/go-sysinfo which
can be sanity checked against:

https://github.com/apple-oss-distributions/adv_cmds/blob/adv_cmds-205/ps/print.c#L115

I've verified with these changes that `pam_sshca.so` works as expected
under macOS 13 (Ventura) on an arm64 host.

Issues:

1. The Linux `pam.d/sudo` configuration line:

       "auth   [success=done default=die]   pam_sshca.so"

   Does not work on Darwin. Instead use one of the following:

       "auth   requisite   /path/to/pam_sshca.so"

   Or:

       "auth   required   /path/to/pam_sshca.so"

    Neither is identical to `[success=done default=die]` whose
    semantics are impossible under Darwin. See the `pam.conf` man pages
    on Linux and macOS for details.

2. The `log/syslog` module does not work under macOS >= 12 (Monterey).
   Log messages are silently dropped:

   golang/go#59229

3. The `kern.procargs2` syscall returns incorrect data under macOS
   10.15 (Catalina) due to a bug in that OS version. The code won't
   panic under that OS version but it won't return a command line:

   elastic/go-sysinfo#172

var unknownCommand = []byte("unknown command")

func getCmdLine() []byte {
Copy link
Contributor

Choose a reason for hiding this comment

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

Does os.Args not work to obtain the command line arguments because this is a shared object?

Choose a reason for hiding this comment

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

Yes. I believe the intention here was to log the actual command that was run under "sudo" when static keys were used.

Copy link
Author

Choose a reason for hiding this comment

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

@psasidhar is correct.

Copy link
Collaborator

@hkadakia hkadakia left a comment

Choose a reason for hiding this comment

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

needs some coding style change to follow the project standard. Can be done as a follow up PR.

@hkadakia hkadakia requested review from maditya and py4chen October 17, 2023 21:42
Copy link
Contributor

@maditya maditya left a comment

Choose a reason for hiding this comment

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

Can we add unit tests wherever possible?

// sysctl returns "invalid argument" for both "no such process"
// and "operation not permitted" errors.
msg.Printlf(msg.WARN, "No such process or operation not permitted: %w", err)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

can we log the error when it is not an "invalid argument" error?

// exe
lines := strings.Split(string(data), "\x00")
exe := lines[0]
lines = lines[1:]
Copy link
Contributor

Choose a reason for hiding this comment

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

can we do a length check for lines?

data = data[4:]

// exe
lines := strings.Split(string(data), "\x00")
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: since we need to return a byte slice, can we use bytes.Split and keep everything in a byte slice?

} else if len(cmd) == 0 {
cmd = []byte("empty command")
msg.Printlf(msg.WARN, "/proc/%d/cmdline is empty", os.Getpid())
}
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: can we do an early return here and after line 17 to keep things consistent?

Copy link
Author

Choose a reason for hiding this comment

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

Ditto.

cmd = cmd[:len(cmd)-1]
// Replace '\0' with ' '.
cmd = bytes.Replace(cmd, []byte{0}, []byte{' '}, -1)
cmd := getCmdLine()
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: can we pass os.Getpid() as a param to getCmdLine()?

)

func getCmdLine() []byte {
cmd, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/cmdline", os.Getpid()))
Copy link
Contributor

Choose a reason for hiding this comment

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

can we use https://pkg.go.dev/os#ReadFile instead?

Copy link
Author

Choose a reason for hiding this comment

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

This was copied from pam_sshca.go and I didn't want to change anything.

@maditya
Copy link
Contributor

maditya commented Oct 18, 2023

Let's address the comments in a follow-up PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants