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