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 
411   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)412     node(node* parent, const std::string& name, const std::string& io_path,
413          const bool transforms_complete, const int transforms, const int transforms_reason,
414          std::recursive_mutex* lock, ino_t ino, NodeTracker* tracker)
415         : name_(name),
416           io_path_(io_path),
417           transforms_complete_(transforms_complete),
418           transforms_(transforms),
419           transforms_reason_(transforms_reason),
420           refcount_(0),
421           parent_(nullptr),
422           has_redacted_cache_(false),
423           deleted_(false),
424           lock_(lock),
425           ino_(ino),
426           tracker_(tracker) {
427         tracker_->NodeCreated(this);
428         Acquire();
429         // This is a special case for the root node. All other nodes will have a
430         // non-null parent.
431         if (parent != nullptr) {
432             AddToParent(parent);
433         }
434     }
435 
436     // Acquires a reference to a node. This maps to the "lookup count" specified
437     // by the FUSE documentation and must only happen under the circumstances
438     // documented in libfuse/include/fuse_lowlevel.h.
Acquire()439     inline void Acquire() {
440         std::lock_guard<std::recursive_mutex> guard(*lock_);
441         refcount_++;
442     }
443 
444     // Adds this node to a specified parent.
AddToParent(node * parent)445     void AddToParent(node* parent) {
446         std::lock_guard<std::recursive_mutex> guard(*lock_);
447         // This method assumes this node is currently unparented.
448         CHECK(parent_ == nullptr);
449         // Check that the new parent isn't nullptr either.
450         CHECK(parent != nullptr);
451 
452         parent_ = parent;
453         parent_->children_.insert(this);
454 
455         // TODO(narayan, zezeozue): It's unclear why we need to call Acquire on the
456         // parent node when we're adding a child to it.
457         parent_->Acquire();
458     }
459 
460     // Removes this node from its current parent, and set its parent to nullptr.
RemoveFromParent()461     void RemoveFromParent() {
462         std::lock_guard<std::recursive_mutex> guard(*lock_);
463 
464         if (parent_ != nullptr) {
465             auto it = parent_->children_.find(this);
466             CHECK(it != parent_->children_.end());
467             parent_->children_.erase(it);
468 
469             parent_->Release(1);
470             parent_ = nullptr;
471         }
472     }
473 
474     // Finds *all* non-deleted nodes matching |name| and runs the function |callback| on each
475     // node until |callback| returns true.
476     // When |callback| returns true, the matched node is returned
ForChild(const std::string & name,const std::function<bool (node *)> & callback)477     node* ForChild(const std::string& name, const std::function<bool(node*)>& callback) const {
478         std::lock_guard<std::recursive_mutex> guard(*lock_);
479 
480         // lower_bound will give us the first child with strcasecmp(child->name, name) >=0.
481         // For more context see comment on the NodeCompare struct.
482         auto start = children_.lower_bound(std::make_pair(name, 0));
483         // upper_bound will give us the first child with strcasecmp(child->name, name) > 0
484         auto end =
485                 children_.upper_bound(std::make_pair(name, std::numeric_limits<uintptr_t>::max()));
486 
487         // Make a copy of the matches because calling callback might modify the list which will
488         // cause issues while iterating over them.
489         std::vector<node*> children(start, end);
490 
491         for (node* child : children) {
492             if (!child->deleted_ && callback(child)) {
493                 return child;
494             }
495         }
496 
497         return nullptr;
498     }
499 
500     // A custom heterogeneous comparator used for set of this node's children_ to speed up child
501     // node by name lookups.
502     //
503     // This comparator treats node* as pair (node->name_, node): two nodes* are first
504     // compared by their name using case-insenstive comparison function. If their names are equal,
505     // then pointers are compared as integers.
506     //
507     // See LookupChildByName function to see how this comparator is used.
508     //
509     // Note that it's important to first compare by name_, since it will make all nodes with same
510     // name (compared using strcasecmp) together, which allows LookupChildByName function to find
511     // range of the candidate nodes by issuing two binary searches.
512     struct NodeCompare {
513         using is_transparent = void;
514 
operatorNodeCompare515         bool operator()(const node* lhs, const node* rhs) const {
516             int cmp = strcasecmp(lhs->name_.c_str(), rhs->name_.c_str());
517             if (cmp != 0) {
518                 return cmp < 0;
519             }
520             return reinterpret_cast<uintptr_t>(lhs) < reinterpret_cast<uintptr_t>(rhs);
521         }
522 
operatorNodeCompare523         bool operator()(const node* lhs, const std::pair<std::string, uintptr_t>& rhs) const {
524             int cmp = strcasecmp(lhs->name_.c_str(), rhs.first.c_str());
525             if (cmp != 0) {
526                 return cmp < 0;
527             }
528             return reinterpret_cast<uintptr_t>(lhs) < rhs.second;
529         }
530 
operatorNodeCompare531         bool operator()(const std::pair<std::string, uintptr_t>& lhs, const node* rhs) const {
532             int cmp = strcasecmp(lhs.first.c_str(), rhs->name_.c_str());
533             if (cmp != 0) {
534                 return cmp < 0;
535             }
536             return lhs.second < reinterpret_cast<uintptr_t>(rhs);
537         }
538     };
539 
540     // A helper function to recursively construct the absolute path of a given node.
541     // If |safe| is true, builds a PII safe path instead
542     void BuildPathForNodeRecursive(bool safe, const node* node, std::stringstream* path) const;
543 
544     // The name of this node. Non-const because it can change during renames.
545     std::string name_;
546     // Filesystem path that will be used for IO (if it is non-empty) instead of node->BuildPath
547     const std::string io_path_;
548     // Whether any transforms required on |io_path_| are complete.
549     // If false, might need to call a node transform function with |transforms| below
550     std::atomic_bool transforms_complete_;
551     // Opaque flags that determines the 'required' transforms to perform on node
552     // before IO. These flags should not be interpreted in native but should be passed to the
553     // MediaProvider as part of a transform function and if successful, |transforms_complete_|
554     // should be set to true
555     const int transforms_;
556     // Opaque value indicating the reason why transforms are required.
557     // This value should not be interpreted in native but should be passed to the MediaProvider
558     // as part of a transform function
559     const int transforms_reason_;
560     // The reference count for this node. Guarded by |lock_|.
561     uint32_t refcount_;
562     // Set of children of this node. All of them contain a back reference
563     // to their parent. Guarded by |lock_|.
564     std::set<node*, NodeCompare> children_;
565     // Containing directory for this node. Guarded by |lock_|.
566     node* parent_;
567     // List of file handles associated with this node. Guarded by |lock_|.
568     std::vector<std::unique_ptr<handle>> handles_;
569     // List of directory handles associated with this node. Guarded by |lock_|.
570     std::vector<std::unique_ptr<dirhandle>> dirhandles_;
571     bool has_redacted_cache_;
572     bool deleted_;
573     std::recursive_mutex* lock_;
574     // Inode number of the file represented by this node.
575     const ino_t ino_;
576 
577     NodeTracker* const tracker_;
578 
~node()579     ~node() {
580         RemoveFromParent();
581 
582         handles_.clear();
583         dirhandles_.clear();
584 
585         tracker_->NodeDeleted(this);
586     }
587 
588     friend class ::NodeTest;
589 };
590 
591 }  // namespace fuse
592 }  // namespace mediaprovider
593 
594 #endif  // MEDIA_PROVIDER_JNI_MODE_INL_H_
595