From 32c9be59a2485ef44ac4b3accc2f102cf2eb5a39 Mon Sep 17 00:00:00 2001 From: "Joe Richey joerichey@google.com" Date: Tue, 22 Aug 2017 12:52:41 -0700 Subject: security: Moved cache dropping function --- security/cache.go | 41 +++++++++++++++++++++++++++++++++++++++++ security/privileges.go | 1 + 2 files changed, 42 insertions(+) create mode 100644 security/cache.go (limited to 'security') diff --git a/security/cache.go b/security/cache.go new file mode 100644 index 0000000..7002014 --- /dev/null +++ b/security/cache.go @@ -0,0 +1,41 @@ +/* + * cache.go - Handles cache clearing and management. + * + * Copyright 2017 Google Inc. + * Author: Joe Richey (joerichey@google.com) + * + * 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 security + +import ( + "log" + "os" +) + +// DropInodeCache instructs the kernel to clear the global cache of inodes and +// dentries. This has the effect of making encrypted directories whose keys +// are not present no longer accessible. Requires root privileges. +func DropInodeCache() error { + log.Print("dropping page caches") + // See: https://www.kernel.org/doc/Documentation/sysctl/vm.txt + file, err := os.OpenFile("/proc/sys/vm/drop_caches", os.O_WRONLY|os.O_SYNC, 0) + if err != nil { + return err + } + defer file.Close() + // "2" just clears the inodes and dentries + _, err = file.WriteString("2") + return err +} diff --git a/security/privileges.go b/security/privileges.go index f6e8098..aff41a7 100644 --- a/security/privileges.go +++ b/security/privileges.go @@ -18,6 +18,7 @@ */ // Package security manages: +// - Cache clearing (cache.go) // - Keyring Operations (keyring.go) // - Privilege manipulation (privileges.go) // - Maintaining the link between the root and user keyrings. -- cgit v1.3 From b15792b8d7c197d84970415fd2525c51aee3996c Mon Sep 17 00:00:00 2001 From: "Joe Richey joerichey@google.com" Date: Wed, 23 Aug 2017 12:29:10 -0700 Subject: Added some documentation and improved security API --- CONTRIBUTING.md | 10 ++++++++++ README.md | 4 ++-- pam/pam.go | 24 ++++++++++++++++++------ security/keyring.go | 12 ++++++++++-- 4 files changed, 40 insertions(+), 10 deletions(-) (limited to 'security') diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7272b10..6b7be43 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -15,6 +15,16 @@ You generally only need to submit a CLA once, so if you've already submitted one (even if it was for a different project), you probably don't need to do it again. +## Reporting an Issue + +Any bugs or problems found in fscrypt should be reported though the +[Github Issue Tracker](https://github.com/google/fscrypt/issues/new). When +reporting an issue, be sure to give as much information about the problem as +possible. If reporting an issue around the fscrypt command-line tool, post the +relevant output from fscrypt, running with the `--verbose` flag. For the +pam_fscrypt module, use the `debug` flag with the module and post the relevant +parts of the syslog (at ``). + ## Code reviews All submissions, including submissions by project members, require review. We diff --git a/README.md b/README.md index 4355239..cb1a1e3 100644 --- a/README.md +++ b/README.md @@ -545,8 +545,8 @@ file for more information about singing the CLA and submitting a pull request. ## Troubleshooting In general, if you are encountering issues with fscrypt, -[open an issue](https://github.com/google/fscrypt/issues/new). We will try our -best to help. +[open an issue](https://github.com/google/fscrypt/issues/new), following the +guidelines in `CONTRIBUTING.md`. We will try our best to help. #### I changed my login passphrase, now all my directories are inaccessible diff --git a/pam/pam.go b/pam/pam.go index 804171d..3049efb 100644 --- a/pam/pam.go +++ b/pam/pam.go @@ -32,12 +32,15 @@ import ( "errors" "fmt" "unsafe" + + "github.com/google/fscrypt/security" ) // Handle wraps the C pam_handle_t type. This is used from within modules. type Handle struct { handle *C.pam_handle_t status C.int + privs *security.Privileges } // NewHandle creates a Handle from a raw pointer. @@ -105,19 +108,28 @@ func (h *Handle) GetItem(i Item) (unsafe.Pointer, error) { return data, h.err() } -// GetIDs retrieves the UID and GID of the corresponding PAM_USER. -func (h *Handle) GetIDs() (uid int, gid int, err error) { +// DropThreadPrivileges sets the effective privileges to that of the PAM user +func (h *Handle) DropThreadPrivileges() error { var pamUsername *C.char + var err error + h.status = C.pam_get_user(h.handle, &pamUsername, nil) if err = h.err(); err != nil { - return 0, 0, err + return err } - pwnam := C.getpwnam(pamUsername) if pwnam == nil { - return 0, 0, fmt.Errorf("unknown user %q", C.GoString(pamUsername)) + return fmt.Errorf("unknown user %q", C.GoString(pamUsername)) } - return int(pwnam.pw_uid), int(pwnam.pw_gid), nil + + h.privs, err = security.DropThreadPrivileges(int(pwnam.pw_uid), int(pwnam.pw_gid)) + return err +} + +// RaiseThreadPrivileges restores the original privileges that were running the +// PAM module (this is usually root). +func (h *Handle) RaiseThreadPrivileges() error { + return security.RaiseThreadPrivileges(h.privs) } func (h *Handle) err() error { diff --git a/security/keyring.go b/security/keyring.go index f75b189..28225b0 100644 --- a/security/keyring.go +++ b/security/keyring.go @@ -151,11 +151,19 @@ func getUserKeyringID() (int, error) { func keyringLink(keyID int, keyringID int) error { _, err := unix.KeyctlInt(unix.KEYCTL_LINK, keyID, keyringID, 0, 0) log.Printf("KeyctlLink(%d, %d) = %v", keyID, keyringID, err) - return errors.Wrap(ErrKeyringLink, err.Error()) + + if err != nil { + return errors.Wrap(ErrKeyringLink, err.Error()) + } + return err } func keyringUnlink(keyID int, keyringID int) error { _, err := unix.KeyctlInt(unix.KEYCTL_UNLINK, keyID, keyringID, 0, 0) log.Printf("KeyctlUnlink(%d, %d) = %v", keyID, keyringID, err) - return errors.Wrap(ErrKeyringUnlink, err.Error()) + + if err != nil { + return errors.Wrap(ErrKeyringUnlink, err.Error()) + } + return err } -- cgit v1.3 From 7fbff9a4d531e33f3d7c7e0b9871c2e19a55bace Mon Sep 17 00:00:00 2001 From: Joseph Richey Date: Wed, 23 Aug 2017 23:46:54 -0700 Subject: security: fscrypt now possesses the user keyring --- README.md | 15 ++++++++------- security/keyring.go | 7 +++++++ 2 files changed, 15 insertions(+), 7 deletions(-) (limited to 'security') diff --git a/README.md b/README.md index cb1a1e3..342fe66 100644 --- a/README.md +++ b/README.md @@ -130,7 +130,7 @@ Once all the dependencies are installed, you can get the repository by running: go get -d github.com/google/fscrypt/... ``` and then you can run `make` in `$GOPATH/github.com/google/fscrypt` to build the -executable in that directory. Running `sudo make install` installs the binary to +executable and PAM moudle in that directory. Running `sudo make install` installs the binary to `/usr/local/bin`. See the `Makefile` for instructions on how to customize the build. This includes @@ -190,13 +190,14 @@ auth optional pam_fscrypt.so after `pam_unix.so` in `/etc/pam.d/common-password` or similar, and to add the line: ``` -session optional pam_fscrypt.so drop_caches +session optional pam_fscrypt.so drop_caches lock_policies ``` -after `pam_unix.so` in `/etc/pam.d/common-session` or similar. The `drop_caches` -option tells fscrypt to clear the filesystem caches on session closes if some -directories were unlocked. This ensures all unlocked data is inaccessible after -session close. All the types also support the `debug` option which prints -additional debug information to the syslog. +after `pam_unix.so` in `/etc/pam.d/common-session` or similar. The +`lock_policies` option locks the directories protected with the user's login +passphrase when the last session ends. The `drop_caches` option tells fscrypt to +clear the filesystem caches when the last session closes, ensuring all the +locked data is inaccessible. All the types also support the `debug` option which +prints additional debug information to the syslog. ## Note about stability diff --git a/security/keyring.go b/security/keyring.go index 28225b0..ef56364 100644 --- a/security/keyring.go +++ b/security/keyring.go @@ -141,6 +141,13 @@ func getUserKeyringID() (int, error) { } keyringID := int(parsedID) + // For some stupid reason, a thread does not automaticaly "possess" keys + // in the user keyring. So we link it into the process keyring so that + // we will not get "permission denied" when purging or modifying keys. + if err := keyringLink(keyringID, unix.KEY_SPEC_PROCESS_KEYRING); err != nil { + return 0, err + } + keyringIDCache[euid] = keyringID return keyringID, nil } -- cgit v1.3