Codebase list fscrypt / 0fcb660
filesystem: libblkid -> search /dev/disk/by-uuid Joe Richey 6 years ago
5 changed file(s) with 80 addition(s) and 93 deletion(s). Raw diff Collapse all Expand all
99 - sourceline: 'deb http://en.archive.ubuntu.com/ubuntu/ artful main universe'
1010 packages:
1111 - libargon2-0-dev
12 - libblkid-dev
1312 - libpam0g-dev
1413 - e2fsprogs
1514 - protobuf-compiler
5858 # builds the C code with high optimizations, and C warnings fail.
5959 # LDFLAGS
6060 # Change the flags passed to the C linker. Empty by default.
61 # For example:
62 # make fscrypt "LDFLAGS = -static -luuid -ldl -laudit -lpthread"
63 # will build a static binary.
61 # For example (on my system with additional dev packages):
62 # make fscrypt "LDFLAGS = -static -ldl -laudit -lcap-ng"
63 # will build a static fscrypt binary.
6464 # GO_FLAGS
6565 # Change the flags passed to "go build". Empty by default.
6666 # For example:
178178 sudo mkdir -p $(MOUNT)
179179 sudo mount -o rw,loop $(IMAGE) $(MOUNT)
180180 sudo chmod +777 $(MOUNT)
181 # Add UUID to BLKID cache
182 sudo blkid $$(df $(MOUNT) --output=source | grep /dev/)
183181
184182 test-teardown:
185183 sudo umount $(MOUNT)
118118 >>>>> make
119119 >>>>> sudo make install
120120 ```
121 * Headers for `libblkid` and `libpam`. These can be installed with the
122 appropriate package manager.
123 - `sudo apt-get install libblkid-dev libpam0g-dev`
124 - `sudo yum install libblkid-devel pam-devel`
125 - `pam` and `util-liux` packages for Arch
121 * Headers for `libpam`. Install them with the appropriate package manager.
122 - `sudo apt-get install libpam0g-dev`
123 - `sudo yum install pam-devel`
124 - `pam` package for Arch (part of the `base` group)
126125
127126 Once all the dependencies are installed, you can get the repository by running:
128127 ```shell
148147 * Kernel support for filesystem encryption (this will depend on your kernel
149148 configuration and specific filesystem)
150149 * `libargon2.so` (see the above installation instructions for Argon2)
151 * `libblkid.so` and `libpam.so`. These libraries are almost certainly already
152 on your system.
150 * `libpam.so` (almost certainly already on your system)
153151
154152 The dynamic libraries are not needed if you built a static executable.
155153
8383 // There is also the ability to reference another filesystem's metadata. This is
8484 // used when a Policy on filesystem A is protected with Protector on filesystem
8585 // B. In this scenario, we store a "link file" in the protectors directory whose
86 // contents look like "UUID=3a6d9a76-47f0-4f13-81bf-3332fbe984fb". These
87 // contents can be anything parsable by libblkid (i.e. anything that could be in
88 // the Device column of /etc/fstab).
86 // contents look like "UUID=3a6d9a76-47f0-4f13-81bf-3332fbe984fb".
8987 type Mount struct {
9088 Path string
9189 Filesystem string
2020
2121 package filesystem
2222
23 import (
24 "io/ioutil"
25 "os"
26 )
27
2328 /*
24 #cgo LDFLAGS: -lblkid
25 #include <blkid/blkid.h> // blkid functions
26 #include <stdlib.h> // free()
2729 #include <mntent.h> // setmntent, getmntent, endmntent
2830
2931 // The file containing mountpoints info and how we should read it
3032 const char* mountpoints_filename = "/proc/mounts";
3133 const char* read_mode = "r";
32
33 // Helper function for freeing strings
34 void string_free(char* str) { free(str); }
35
36 // Helper function to lookup tokens
3734 */
3835 import "C"
3936
5249 // These maps hold data about the state of the system's mountpoints.
5350 mountsByPath map[string]*Mount
5451 mountsByDevice map[string][]*Mount
55 // Cache for information about the devices
56 cache C.blkid_cache
5752 // Used to make the mount functions thread safe
5853 mountMutex sync.Mutex
5954 // True if the maps have been successfully initialized.
6055 mountsInitialized bool
56 // Supported tokens for filesystem links
57 uuidToken = "UUID"
58 // Location to perform UUID lookup
59 uuidDirectory = "/dev/disk/by-uuid"
6160 )
6261
6362 // getMountInfo populates the Mount mappings by parsing the filesystem
7978 C.GoString(C.mountpoints_filename))
8079 }
8180 defer C.endmntent(fileHandle)
82
83 // Load the device information from the default blkid cache
84 if cache != nil {
85 C.blkid_put_cache(cache)
86 }
87 if C.blkid_get_cache(&cache, nil) != 0 {
88 return errors.Wrap(ErrGlobalMountInfo, "could not read blkid cache")
89 }
9081
9182 for {
9283 entry := C.getmntent(fileHandle)
213204 }
214205
215206 // getMountsFromLink returns the Mount objects which match the provided link.
216 // This link can be an unparsed tag (e.g. <token>=<value>) or path (e.g.
217 // /dev/dm-0). The matching rules are determined by libblkid. These are the same
218 // matching rules for things like UUID=3a6d9a76-47f0-4f13-81bf-3332fbe984fb in
219 // "/etc/fstab". Note that this can match multiple Mounts. An error is returned
220 // if the link is invalid or we cannot load the required mount data. If a
221 // filesystem has been updated since the last call to one of the mount
222 // functions, run UpdateMountInfo to see the change.
207 // This link if formatted as a tag (e.g. <token>=<value>) similar to how they
208 // apprear in "/etc/fstab". Currently, only "UUID" tokens are supported. Note
209 // that this can match multiple Mounts (due to the existance of bind mounts). An
210 // error is returned if the link is invalid or we cannot load the required mount
211 // data. If a filesystem has been updated since the last call to one of the
212 // mount functions, run UpdateMountInfo to see the change.
223213 func getMountsFromLink(link string) ([]*Mount, error) {
224 // Use blkid_evaluate_spec to get the device name.
225 cLink := C.CString(link)
226 defer C.string_free(cLink)
227
228 cDeviceName := C.blkid_evaluate_spec(cLink, &cache)
229 defer C.string_free(cDeviceName)
230 deviceName := C.GoString(cDeviceName)
231
232 log.Printf("blkid_evaluate_spec(%q, <cache>) = %q", link, deviceName)
233
234 if deviceName == "" {
235 return nil, errors.Wrapf(ErrFollowLink, "link %q is invalid", link)
236 }
237 deviceName, err := cannonicalizePath(deviceName)
238 if err != nil {
239 return nil, err
240 }
241
214 // Parse the link
215 linkComponents := strings.Split(link, "=")
216 if len(linkComponents) != 2 {
217 return nil, errors.Wrapf(ErrFollowLink, "link %q format in invalid", link)
218 }
219 token := linkComponents[0]
220 value := linkComponents[1]
221 if token != uuidToken {
222 return nil, errors.Wrapf(ErrFollowLink, "token type %q not supported", token)
223 }
224
225 // See if UUID points to an existing device
226 searchPath := filepath.Join(uuidDirectory, value)
227 if filepath.Base(searchPath) != value {
228 return nil, errors.Wrapf(ErrFollowLink, "value %q is not a UUID", value)
229 }
230 devicePath, err := cannonicalizePath(searchPath)
231 if err != nil {
232 return nil, errors.Wrapf(ErrFollowLink, "no device with UUID %q", value)
233 }
234
235 // Lookup mountpoints for device in global store
242236 mountMutex.Lock()
243237 defer mountMutex.Unlock()
244238 if err := getMountInfo(); err != nil {
245239 return nil, err
246240 }
247
248 if mnts, ok := mountsByDevice[deviceName]; ok {
249 return mnts, nil
250 }
251
252 return nil, errors.Wrapf(ErrFollowLink, "device %q is invalid", deviceName)
241 mnts, ok := mountsByDevice[devicePath]
242 if !ok {
243 return nil, errors.Wrapf(ErrFollowLink, "no mounts for device %q", devicePath)
244 }
245 return mnts, nil
253246 }
254247
255248 // makeLink returns a link of the form <token>=<value> where value is the tag
256 // value for the Mount's device according to libblkid. An error is returned if
257 // the device/token pair has no value.
249 // value for the Mount's device. Currently, only "UUID" tokens are supported. An
250 // error is returned if the mount has no device, or no UUID.
258251 func makeLink(mnt *Mount, token string) (string, error) {
259 // The blkid cache may not always hold the canonical device path. To
260 // solve this we first use blkid_evaluate_spec to find the right entry
261 // in the cache. Then that name is used to get the token value.
262 cDevice := C.CString(mnt.Device)
263 defer C.string_free(cDevice)
264
265 cDeviceEntry := C.blkid_evaluate_spec(cDevice, &cache)
266 defer C.string_free(cDeviceEntry)
267 deviceEntry := C.GoString(cDeviceEntry)
268
269 log.Printf("blkid_evaluate_spec(%q, <cache>) = %q", mnt.Device, deviceEntry)
270
271 cToken := C.CString(token)
272 defer C.string_free(cToken)
273
274 cValue := C.blkid_get_tag_value(cache, cToken, cDeviceEntry)
275 defer C.string_free(cValue)
276 value := C.GoString(cValue)
277
278 log.Printf("blkid_get_tag_value(<cache>, %s, %s) = %s", token, deviceEntry, value)
279
280 if value == "" {
281 return "", errors.Wrapf(ErrMakeLink, "no %s", token)
282 }
283 return fmt.Sprintf("%s=%s", token, C.GoString(cValue)), nil
284 }
252 if token != uuidToken {
253 return "", errors.Wrapf(ErrMakeLink, "token type %q not supported", token)
254 }
255 if mnt.Device == "" {
256 return "", errors.Wrapf(ErrMakeLink, "no device for mount %q", mnt.Path)
257 }
258
259 dirContents, err := ioutil.ReadDir(uuidDirectory)
260 if err != nil {
261 return "", errors.Wrap(ErrMakeLink, err.Error())
262 }
263 for _, fileInfo := range dirContents {
264 if fileInfo.Mode()&os.ModeSymlink == 0 {
265 continue // Only interested in UUID symlinks
266 }
267 uuid := fileInfo.Name()
268 devicePath, err := cannonicalizePath(filepath.Join(uuidDirectory, uuid))
269 if err != nil {
270 log.Print(err)
271 continue
272 }
273 if mnt.Device == devicePath {
274 return fmt.Sprintf("%s=%s", uuidToken, uuid), nil
275 }
276 }
277 return "", errors.Wrapf(ErrMakeLink, "device %q has no UUID", mnt.Device)
278 }