1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specic language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef MEDIA_PROVIDER_JNI_NODE_INL_H_
18 #define MEDIA_PROVIDER_JNI_NODE_INL_H_
19 
20 #include <android-base/logging.h>
21 
22 #include <sys/types.h>
23 #include <atomic>
24 #include <cstdint>
25 #include <limits>
26 #include <list>
27 #include <memory>
28 #include <mutex>
29 #include <set>
30 #include <sstream>
31 #include <string>
32 #include <unordered_set>
33 #include <utility>
34 #include <vector>
35 
36 #include "libfuse_jni/ReaddirHelper.h"
37 #include "libfuse_jni/RedactionInfo.h"
38 
39 class NodeTest;
40 
41 namespace mediaprovider {
42 namespace fuse {
43 
44 struct handle {
handlehandle45     explicit handle(int fd, const RedactionInfo* ri, bool cached, bool passthrough, uid_t uid,
46                     uid_t transforms_uid)
47         : fd(fd),
48           ri(ri),
49           cached(cached),
50           passthrough(passthrough),
51           uid(uid),
52           transforms_uid(transforms_uid) {
53         CHECK(ri != nullptr);
54     }
55 
56     const int fd;
57     const std::unique_ptr<const RedactionInfo> ri;
58     const bool cached;
59     const bool passthrough;
60     const uid_t uid;
61     const uid_t transforms_uid;
62 
~handlehandle63     ~handle() { close(fd); }
64 };
65 
66 struct dirhandle {
dirhandledirhandle67     explicit dirhandle(DIR* dir) : d(dir), next_off(0) { CHECK(dir != nullptr); }
68 
69     DIR* const d;
70     off_t next_off;
71     // Fuse readdir() is called multiple times based on the size of the buffer and
72     // number of directory entries in the given directory. 'de' holds the list
73     // of directory entries for the directory handle and this list is available
74     // across subsequent readdir() calls for the same directory handle.
75     std::vector<std::shared_ptr<DirectoryEntry>> de;
76 
~dirhandledirhandle77     ~dirhandle() { closedir(d); }
78 };
79 
80 /** Represents file open result from MediaProvider */
81 struct FdAccessResult {
FdAccessResultFdAccessResult82     FdAccessResult(const std::string& file_path, const bool should_redact)
83         : file_path(file_path), should_redact(should_redact) {}
84 
85     const std::string file_path;
86     const bool should_redact;
87 };
88 
89 // Whether inode tracking is enabled or not. When enabled, we maintain a
90 // separate mapping from inode numbers to "live" nodes so we can detect when
91 // we receive a request to a node that has been deleted.
92 static constexpr bool kEnableInodeTracking = true;
93 
94 class node;
95 
96 // Tracks the set of active nodes associated with a FUSE instance so that we
97 // can assert that we only ever return an active node in response to a lookup.
98 class NodeTracker {
99   public:
NodeTracker(std::recursive_mutex * lock)100     explicit NodeTracker(std::recursive_mutex* lock) : lock_(lock) {}
101 
Exists(__u64 ino)102     bool Exists(__u64 ino) const {
103         if (kEnableInodeTracking) {
104             const node* node = reinterpret_cast<const class node*>(ino);
105             std::lock_guard<std::recursive_mutex> guard(*lock_);
106             return active_nodes_.find(node) != active_nodes_.end();
107         }
108     }
109 
CheckTracked(__u64 ino)110     void CheckTracked(__u64 ino) const {
111         if (kEnableInodeTracking) {
112             const node* node = reinterpret_cast<const class node*>(ino);
113             std::lock_guard<std::recursive_mutex> guard(*lock_);
114             CHECK(active_nodes_.find(node) != active_nodes_.end());
115         }
116     }
117 
NodeDeleted(const node * node)118     void NodeDeleted(const node* node) {
119         if (kEnableInodeTracking) {
120             std::lock_guard<std::recursive_mutex> guard(*lock_);
121             LOG(DEBUG) << "Node: " << reinterpret_cast<uintptr_t>(node) << " deleted.";
122 
123             CHECK(active_nodes_.find(node) != active_nodes_.end());
124             active_nodes_.erase(node);
125         }
126     }
127 
NodeCreated(const node * node)128     void NodeCreated(const node* node) {
129         if (kEnableInodeTracking) {
130             std::lock_guard<std::recursive_mutex> guard(*lock_);
131             LOG(DEBUG) << "Node: " << reinterpret_cast<uintptr_t>(node) << " created.";
132 
133             CHECK(active_nodes_.find(node) == active_nodes_.end());
134             active_nodes_.insert(node);
135         }
136     }
137 
138   private:
139     std::recursive_mutex* lock_;
140     std::unordered_set<const node*> active_nodes_;
141 };
142 
143 class node {
144   public:
145     // Creates a new node with the specified parent, name and lock.
Create(node * parent,const std::string & name,const std::string & io_path,const bool transforms_complete,const int transforms,const int transforms_reason,std::recursive_mutex * lock,ino_t ino,NodeTracker * tracker)146     static node* Create(node* parent, const std::string& name, const std::string& io_path,
147                         const bool transforms_complete, const int transforms,
148                         const int transforms_reason, std::recursive_mutex* lock, ino_t ino,
149                         NodeTracker* tracker) {
150         // Place the entire constructor under a critical section to make sure
151         // node creation, tracking (if enabled) and the addition to a parent are
152         // atomic.
153         std::lock_guard<std::recursive_mutex> guard(*lock);
154         return new node(parent, name, io_path, transforms_complete, transforms, transforms_reason,
155                         lock, ino, tracker);
156     }
157 
158     // Creates a new root node. Root nodes have no parents by definition
159     // and their "name" must signify an absolute path.
CreateRoot(const std::string & path,std::recursive_mutex * lock,ino_t ino,NodeTracker * tracker)160     static node* CreateRoot(const std::string& path, std::recursive_mutex* lock, ino_t ino,
161                             NodeTracker* tracker) {
162         std::lock_guard<std::recursive_mutex> guard(*lock);
163         node* root = new node(nullptr, path, path, true /* transforms_complete */,
164                               0 /* transforms */, 0 /* transforms_reason */, lock, ino, tracker);
165 
166         // The root always has one extra reference to avoid it being
167         // accidentally collected.
168         root->Acquire();
169         return root;
170     }
171 
172     // Maps an inode to its associated node.
FromInode(__u64 ino,const NodeTracker * tracker)173     static inline node* FromInode(__u64 ino, const NodeTracker* tracker) {
174         tracker->CheckTracked(ino);
175         return reinterpret_cast<node*>(static_cast<uintptr_t>(ino));
176     }
177 
178     // TODO(b/215235604)
FromInodeNoThrow(__u64 ino,const NodeTracker * tracker)179     static inline node* FromInodeNoThrow(__u64 ino, const NodeTracker* tracker) {
180         if (!tracker->Exists(ino)) return nullptr;
181         return reinterpret_cast<node*>(static_cast<uintptr_t>(ino));
182     }
183 
184     // Maps a node to its associated inode.
ToInode(node * node)185     static __u64 ToInode(node* node) {
186         return static_cast<__u64>(reinterpret_cast<uintptr_t>(node));
187     }
188 
189     // Releases a reference to a node. Returns true iff the refcount dropped to
190     // zero as a result of this call to Release, meaning that it's no longer
191     // safe to perform any operations on references to this node.
Release(uint32_t count)192     bool Release(uint32_t count) {
193         std::lock_guard<std::recursive_mutex> guard(*lock_);
194         if (refcount_ >= count) {
195             refcount_ -= count;
196             if (refcount_ == 0) {
197                 delete this;
198                 return true;
199             }
200         } else {
201             LOG(ERROR) << "Mismatched reference count: refcount_ = " << this->refcount_
202                        << " ,count = " << count;
203         }
204 
205         return false;
206     }
207 
208     // Builds the full path associated with this node, including all path segments
209     // associated with its descendants.
210     std::string BuildPath() const;
211 
212     // Builds the full PII safe path associated with this node, including all path segments
213     // associated with its descendants.
214     std::string BuildSafePath() const;
215 
216     // Looks up a direct descendant of this node by case-insensitive |name|. If |acquire| is true,
217     // also Acquire the node before returning a reference to it.
218     // |transforms| is an opaque flag that is used to distinguish multiple nodes sharing the same
219     // |name| but requiring different IO transformations as determined by the MediaProvider.
220     node* LookupChildByName(const std::string& name, bool acquire, const int transforms = 0) const {
221         return ForChild(name, [acquire, transforms](node* child) {
222             if (child->transforms_ == transforms) {
223                 if (acquire) {
224                     child->Acquire();
225                 }
226                 return true;
227             }
228             return false;
229         });
230     }
231 
232     // Marks this node children as deleted. They are still associated with their parent, and
233     // all open handles etc. to the deleted nodes are preserved until their refcount goes
234     // to zero.
SetDeletedForChild(const std::string & name)235     void SetDeletedForChild(const std::string& name) {
236         ForChild(name, [](node* child) {
237             child->SetDeleted();
238             return false;
239         });
240     }
241 
SetDeleted()242     void SetDeleted() {
243         std::lock_guard<std::recursive_mutex> guard(*lock_);
244         deleted_ = true;
245     }
246 
RenameChild(const std::string & old_name,const std::string & new_name,node * new_parent)247     void RenameChild(const std::string& old_name, const std::string& new_name, node* new_parent) {
248         ForChild(old_name, [=](node* child) {
249             child->Rename(new_name, new_parent);
250             return false;
251         });
252     }
253 
Rename(const std::string & name,node * new_parent)254     void Rename(const std::string& name, node* new_parent) {
255         std::lock_guard<std::recursive_mutex> guard(*lock_);
256 
257         if (new_parent != parent_) {
258             RemoveFromParent();
259             name_ = name;
260             AddToParent(new_parent);
261             return;
262         }
263 
264         // Changing name_ will change the expected position of this node in parent's set of
265         // children. Consider following scenario:
266         // 1. This node: "b"; parent's set: {"a", "b", "c"}
267         // 2. Rename("b", "d")
268         //
269         // After rename, parent's set should become: {"a", "b", "d"}, but if we simply change the
270         // name it will be {"a", "d", "b"}, which violates properties of the set.
271         //
272         // To make sure that parent's set is always valid, changing name is 3 steps procedure:
273         // 1. Remove this node from parent's set.
274         // 2  Change the name.
275         // 3. Add it back to the set.
276         // Rename of node without changing its parent. Still need to remove and re-add it to make
277         // sure lookup index is correct.
278         if (name_ != name) {
279             // If this is a root node, simply rename it.
280             if (parent_ == nullptr) {
281                 name_ = name;
282                 return;
283             }
284 
285             auto it = parent_->children_.find(this);
286             CHECK(it != parent_->children_.end());
287             parent_->children_.erase(it);
288 
289             name_ = name;
290 
291             parent_->children_.insert(this);
292         }
293     }
294 
GetName()295     const std::string& GetName() const {
296         std::lock_guard<std::recursive_mutex> guard(*lock_);
297         return name_;
298     }
299 
GetIoPath()300     const std::string& GetIoPath() const { return io_path_; }
301 
GetTransforms()302     int GetTransforms() const { return transforms_; }
303 
GetTransformsReason()304     int GetTransformsReason() const { return transforms_reason_; }
305 
IsTransformsComplete()306     bool IsTransformsComplete() const {
307         return transforms_complete_.load(std::memory_order_acquire);
308     }
309 
SetTransformsComplete(bool complete)310     void SetTransformsComplete(bool complete) {
311         transforms_complete_.store(complete, std::memory_order_release);
312     }
313 
GetParent()314     node* GetParent() const {
315         std::lock_guard<std::recursive_mutex> guard(*lock_);
316         return parent_;
317     }
318 
AddHandle(handle * h)319     inline void AddHandle(handle* h) {
320         std::lock_guard<std::recursive_mutex> guard(*lock_);
321         handles_.emplace_back(std::unique_ptr<handle>(h));
322     }
323 
DestroyHandle(handle * h)324     void DestroyHandle(handle* h) {
325         // A deadlock occurs between FuseDaemon lock and inode lock in the photo picker scenario.
326         // In order to address this deadlock, we release the FuseDaemon lock before closing the
327         // backing file.
328         std::unique_ptr<handle> temp;
329 
330         lock_->lock();
331 
332         auto comp = [h](const std::unique_ptr<handle>& ptr) { return ptr.get() == h; };
333         auto it = std::find_if(handles_.begin(), handles_.end(), comp);
334         CHECK(it != handles_.end());
335         temp = std::move(*it);
336         handles_.erase(it);
337 
338         lock_->unlock();
339     }
340 
HasCachedHandle()341     bool HasCachedHandle() const {
342         std::lock_guard<std::recursive_mutex> guard(*lock_);
343 
344         for (const auto& handle : handles_) {
345             if (handle->cached) {
346                 return true;
347             }
348         }
349         return false;
350     }
351 
CheckHandleForUid(const uid_t uid)352     std::unique_ptr<FdAccessResult> CheckHandleForUid(const uid_t uid) const {
353         std::lock_guard<std::recursive_mutex> guard(*lock_);
354 
355         bool found_handle = false;
356         bool redaction_not_needed = false;
357         for (const auto& handle : handles_) {
358             if (handle->uid == uid) {
359                 found_handle = true;
360                 redaction_not_needed |= !handle->ri->isRedactionNeeded();
361             }
362         }
363 
364         if (found_handle) {
365             return std::make_unique<FdAccessResult>(BuildPath(), !redaction_not_needed);
366         }
367 
368         return std::make_unique<FdAccessResult>(std::string(), false);
369     }
370 
SetName(std::string name)371     void SetName(std::string name) {
372         std::lock_guard<std::recursive_mutex> guard(*lock_);
373         name_ = std::move(name);
374     }
375 
HasRedactedCache()376     bool HasRedactedCache() const {
377         std::lock_guard<std::recursive_mutex> guard(*lock_);
378         return has_redacted_cache_;
379     }
380 
SetRedactedCache(bool state)381     void SetRedactedCache(bool state) {
382         std::lock_guard<std::recursive_mutex> guard(*lock_);
383         has_redacted_cache_ = state;
384     }
385 
AddDirHandle(dirhandle * d)386     inline void AddDirHandle(dirhandle* d) {
387         std::lock_guard<std::recursive_mutex> guard(*lock_);
388 
389         dirhandles_.emplace_back(std::unique_ptr<dirhandle>(d));
390     }
391 
DestroyDirHandle(dirhandle * d)392     void DestroyDirHandle(dirhandle* d) {
393         std::lock_guard<std::recursive_mutex> guard(*lock_);
394 
395         auto comp = [d](const std::unique_ptr<dirhandle>& ptr) { return ptr.get() == d; };
396         auto it = std::find_if(dirhandles_.begin(), dirhandles_.end(), comp);
397         CHECK(it != dirhandles_.end());
398         dirhandles_.erase(it);
399     }
400 
401     // Deletes the tree of nodes rooted at |tree|.
402     static void DeleteTree(node* tree);
403 
404     // Looks up an absolute path rooted at |root|, or nullptr if no such path
405     // through the hierarchy exists.
406     static const node* LookupAbsolutePath(const node* root, const std::string& absolute_path);
407 
408     // Looks up for the node with the given ino rooted at |root|, or nullptr if no such node exists.
409     static const node* LookupInode(const node* root, ino_t ino);
410 
GetBackingId()411     int GetBackingId() {
412         std::lock_guard<std::recursive_mutex> guard(*lock_);
413         return backing_id_;
414     }
415 
416     // A Node should only have one backing id.
SetBackingId(int new_id)417     bool SetBackingId(int new_id) {
418         std::lock_guard<std::recursive_mutex> guard(*lock_);
419         if (backing_id_) return false;
420         backing_id_ = new_id;
421         return true;
422     }
423 
424   private:
node(node * parent,const std::string & name,const std::string & io_path,const bool transforms_complete,const int transforms,const int transforms_reason,std::recursive_mutex * lock,ino_t ino,NodeTracker * tracker)425     node(node* parent, const std::string& name, const std::string& io_path,
426          const bool transforms_complete, const int transforms, const int transforms_reason,
427          std::recursive_mutex* lock, ino_t ino, NodeTracker* tracker)
428         : name_(name),
429           io_path_(io_path),
430           transforms_complete_(transforms_complete),
431           transforms_(transforms),
432           transforms_reason_(transforms_reason),
433           refcount_(0),
434           parent_(nullptr),
435           has_redacted_cache_(false),
436           deleted_(false),
437           lock_(lock),
438           ino_(ino),
439           backing_id_(0),
440           tracker_(tracker) {
441         tracker_->NodeCreated(this);
442         Acquire();
443         // This is a special case for the root node. All other nodes will have a
444         // non-null parent.
445         if (parent != nullptr) {
446             AddToParent(parent);
447         }
448     }
449 
450     // Acquires a reference to a node. This maps to the "lookup count" specified
451     // by the FUSE documentation and must only happen under the circumstances
452     // documented in libfuse/include/fuse_lowlevel.h.
Acquire()453     inline void Acquire() {
454         std::lock_guard<std::recursive_mutex> guard(*lock_);
455         refcount_++;
456     }
457 
458     // Adds this node to a specified parent.
AddToParent(node * parent)459     void AddToParent(node* parent) {
460         std::lock_guard<std::recursive_mutex> guard(*lock_);
461         // This method assumes this node is currently unparented.
462         CHECK(parent_ == nullptr);
463         // Check that the new parent isn't nullptr either.
464         CHECK(parent != nullptr);
465 
466         parent_ = parent;
467         parent_->children_.insert(this);
468 
469         // TODO(narayan, zezeozue): It's unclear why we need to call Acquire on the
470         // parent node when we're adding a child to it.
471         parent_->Acquire();
472     }
473 
474     // Removes this node from its current parent, and set its parent to nullptr.
RemoveFromParent()475     void RemoveFromParent() {
476         std::lock_guard<std::recursive_mutex> guard(*lock_);
477 
478         if (parent_ != nullptr) {
479             auto it = parent_->children_.find(this);
480             CHECK(it != parent_->children_.end());
481             parent_->children_.erase(it);
482 
483             parent_->Release(1);
484             parent_ = nullptr;
485         }
486     }
487 
488     // Finds *all* non-deleted nodes matching |name| and runs the function |callback| on each
489     // node until |callback| returns true.
490     // When |callback| returns true, the matched node is returned
ForChild(const std::string & name,const std::function<bool (node *)> & callback)491     node* ForChild(const std::string& name, const std::function<bool(node*)>& callback) const {
492         std::lock_guard<std::recursive_mutex> guard(*lock_);
493 
494         // lower_bound will give us the first child with strcasecmp(child->name, name) >=0.
495         // For more context see comment on the NodeCompare struct.
496         auto start = children_.lower_bound(std::make_pair(name, 0));
497         // upper_bound will give us the first child with strcasecmp(child->name, name) > 0
498         auto end =
499                 children_.upper_bound(std::make_pair(name, std::numeric_limits<uintptr_t>::max()));
500 
501         // Make a copy of the matches because calling callback might modify the list which will
502         // cause issues while iterating over them.
503         std::vector<node*> children(start, end);
504 
505         for (node* child : children) {
506             if (!child->deleted_ && callback(child)) {
507                 return child;
508             }
509         }
510 
511         return nullptr;
512     }
513 
514     // A custom heterogeneous comparator used for set of this node's children_ to speed up child
515     // node by name lookups.
516     //
517     // This comparator treats node* as pair (node->name_, node): two nodes* are first
518     // compared by their name using case-insenstive comparison function. If their names are equal,
519     // then pointers are compared as integers.
520     //
521     // See LookupChildByName function to see how this comparator is used.
522     //
523     // Note that it's important to first compare by name_, since it will make all nodes with same
524     // name (compared using strcasecmp) together, which allows LookupChildByName function to find
525     // range of the candidate nodes by issuing two binary searches.
526     struct NodeCompare {
527         using is_transparent = void;
528 
operatorNodeCompare529         bool operator()(const node* lhs, const node* rhs) const {
530             int cmp = strcasecmp(lhs->name_.c_str(), rhs->name_.c_str());
531             if (cmp != 0) {
532                 return cmp < 0;
533             }
534             return reinterpret_cast<uintptr_t>(lhs) < reinterpret_cast<uintptr_t>(rhs);
535         }
536 
operatorNodeCompare537         bool operator()(const node* lhs, const std::pair<std::string, uintptr_t>& rhs) const {
538             int cmp = strcasecmp(lhs->name_.c_str(), rhs.first.c_str());
539             if (cmp != 0) {
540                 return cmp < 0;
541             }
542             return reinterpret_cast<uintptr_t>(lhs) < rhs.second;
543         }
544 
operatorNodeCompare545         bool operator()(const std::pair<std::string, uintptr_t>& lhs, const node* rhs) const {
546             int cmp = strcasecmp(lhs.first.c_str(), rhs->name_.c_str());
547             if (cmp != 0) {
548                 return cmp < 0;
549             }
550             return lhs.second < reinterpret_cast<uintptr_t>(rhs);
551         }
552     };
553 
554     // A helper function to recursively construct the absolute path of a given node.
555     // If |safe| is true, builds a PII safe path instead
556     void BuildPathForNodeRecursive(bool safe, const node* node, std::stringstream* path) const;
557 
558     // The name of this node. Non-const because it can change during renames.
559     std::string name_;
560     // Filesystem path that will be used for IO (if it is non-empty) instead of node->BuildPath
561     const std::string io_path_;
562     // Whether any transforms required on |io_path_| are complete.
563     // If false, might need to call a node transform function with |transforms| below
564     std::atomic_bool transforms_complete_;
565     // Opaque flags that determines the 'required' transforms to perform on node
566     // before IO. These flags should not be interpreted in native but should be passed to the
567     // MediaProvider as part of a transform function and if successful, |transforms_complete_|
568     // should be set to true
569     const int transforms_;
570     // Opaque value indicating the reason why transforms are required.
571     // This value should not be interpreted in native but should be passed to the MediaProvider
572     // as part of a transform function
573     const int transforms_reason_;
574     // The reference count for this node. Guarded by |lock_|.
575     uint32_t refcount_;
576     // Set of children of this node. All of them contain a back reference
577     // to their parent. Guarded by |lock_|.
578     std::set<node*, NodeCompare> children_;
579     // Containing directory for this node. Guarded by |lock_|.
580     node* parent_;
581     // List of file handles associated with this node. Guarded by |lock_|.
582     std::vector<std::unique_ptr<handle>> handles_;
583     // List of directory handles associated with this node. Guarded by |lock_|.
584     std::vector<std::unique_ptr<dirhandle>> dirhandles_;
585     bool has_redacted_cache_;
586     bool deleted_;
587     std::recursive_mutex* lock_;
588     // Inode number of the file represented by this node.
589     const ino_t ino_;
590     // Backing identifier for upstream passthrough
591     int backing_id_;
592 
593     NodeTracker* const tracker_;
594 
~node()595     ~node() {
596         RemoveFromParent();
597 
598         handles_.clear();
599         dirhandles_.clear();
600 
601         tracker_->NodeDeleted(this);
602     }
603 
604     friend class ::NodeTest;
605 };
606 
607 }  // namespace fuse
608 }  // namespace mediaprovider
609 
610 #endif  // MEDIA_PROVIDER_JNI_MODE_INL_H_
611