diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp
index 6e043ecee5f9dbfaf8641d86aaa1657195f8bd74..af40c9e9310b5a9c435558a22247756fb77be6f3 100644
--- a/indra/newview/llmaterialeditor.cpp
+++ b/indra/newview/llmaterialeditor.cpp
@@ -293,8 +293,8 @@ bool LLSelectedTEGetMatData::apply(LLViewerObject* objectp, S32 te_index)
                 mTexEmissiveId = tex_emissive_id;
                 mTexNormalId = tex_normal_id;
                 mObjectTE = te_index;
-                mObjectId = objectp->getID();
                 mObject = objectp;
+                mObjectId = objectp->getID();
                 mFirst = false;
             }
             else
@@ -322,6 +322,7 @@ bool LLSelectedTEGetMatData::apply(LLViewerObject* objectp, S32 te_index)
             LLGLTFMaterial *mat = tep->getGLTFMaterial();
             LLLocalGLTFMaterial *local_mat = dynamic_cast<LLLocalGLTFMaterial*>(mat);
 
+            mObject = objectp;
             if (local_mat)
             {
                 mLocalMaterial = local_mat;
@@ -1297,38 +1298,39 @@ void LLMaterialEditor::createInventoryItem(const std::string &buffer, const std:
     // gen a new uuid for this asset
     LLTransactionID tid;
     tid.generate();     // timestamp-based randomization + uniquification
-    U32 next_owner_perm = LLFloaterPerms::getNextOwnerPerms("Materials");
+    LLPermissions final_perm;
+    {
+        final_perm.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null);
+
+        LLPermissions floater_perm;
+        floater_perm.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null);
+        floater_perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms("Materials"));
+        floater_perm.setMaskGroup(LLFloaterPerms::getGroupPerms("Materials"));
+        floater_perm.setMaskNext(LLFloaterPerms::getNextOwnerPerms("Materials"));
+
+        final_perm.accumulate(floater_perm);
+        final_perm.accumulate(owner_permissions);
+    }
+    // NOTE: create_inventory_item doesn't allow presetting some permissions.
+    // The rest will be fixed after the callback.
     LLUUID parent = gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_MATERIAL);
     const U8 subtype = NO_INV_SUBTYPE;  // TODO maybe use AT_SETTINGS and LLSettingsType::ST_MATERIAL ?
 
     create_inventory_item(gAgent.getID(), gAgent.getSessionID(), parent, tid, name, desc,
-        LLAssetType::AT_MATERIAL, LLInventoryType::IT_MATERIAL, subtype, next_owner_perm,
-        new LLBoostFuncInventoryCallback([output = buffer, owner_permissions](LLUUID const& inv_item_id)
+        LLAssetType::AT_MATERIAL, LLInventoryType::IT_MATERIAL, subtype, final_perm.getMaskNextOwner(),
+        new LLBoostFuncInventoryCallback([output = buffer, final_perm](LLUUID const& inv_item_id)
     {
         LLViewerInventoryItem* item = gInventory.getItem(inv_item_id);
         if (item)
         {
             // create_inventory_item doesn't allow presetting some permissions, fix it now
             LLPermissions perm = item->getPermissions();
-            if (perm.getMaskEveryone() != LLFloaterPerms::getEveryonePerms("Materials")
-                || perm.getMaskGroup() != LLFloaterPerms::getGroupPerms("Materials"))
-            {
-                LLPermissions floater_perm;
-                floater_perm.set(perm);
-                floater_perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms("Materials"));
-                floater_perm.setMaskGroup(LLFloaterPerms::getGroupPerms("Materials"));
-                perm.accumulate(floater_perm);
-                perm.accumulate(owner_permissions);
-                // TODO: Decide if these are needed
-                perm.setCreator(owner_permissions.getCreator());
-                perm.setLastOwner(owner_permissions.getLastOwner());
+            perm.accumulate(final_perm);
+            item->setPermissions(perm);
 
-                item->setPermissions(perm);
-
-                item->updateServer(FALSE);
-                gInventory.updateItem(item);
-                gInventory.notifyObservers();
-            }
+            item->updateServer(FALSE);
+            gInventory.updateItem(item);
+            gInventory.notifyObservers();
         }
 
         // from reference in LLSettingsVOBase::createInventoryItem()/updateInventoryItem()
@@ -1805,29 +1807,47 @@ void LLMaterialEditor::loadLive()
     }
 }
 
-// *NOTE: permissions_out ignores user preferences for new item creation
-// (LLFloaterPerms).  Those are applied later on in
+// *NOTE: permissions_out ignores user preferences for new item creation. See
+// LLFloaterPerms.  Preferences are applied later on in
 // LLMaterialEditor::createInventoryItem.
-bool can_save_objects_material(LLSelectedTEGetMatData& func, LLPermissions& permissions_out)
+bool can_use_objects_material(LLSelectedTEGetMatData& func, const std::vector<PermissionBit>& ops, LLPermissions& permissions_out)
 {
+    if (!LLMaterialEditor::capabilitiesAvailable())
+    {
+        return false;
+    }
+
     LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func, true /*first applicable*/);
     LLViewerObject* selected_object = func.mObject;
-    llassert(selected_object); // Note the function name
+    if (!selected_object)
+    {
+        // LLSelectedTEGetMatData can fail if there are no selected faces
+        // with materials, but we expect at least some object is selected.
+        llassert(LLSelectMgr::getInstance()->getSelection()->getFirstObject());
+        return false;
+    }
+    for (PermissionBit op : ops)
+    {
+        if (op == PERM_MODIFY && selected_object->isPermanentEnforced())
+        {
+            return false;
+        }
+    }
+
     const LLViewerInventoryItem* item = selected_object->getInventoryItemByAsset(func.mMaterialId);
 
     LLPermissions item_permissions;
-    const bool previous_item_owned = item && item->getPermissions().getLastOwner().notNull();
     if (item)
     {
         item_permissions.set(item->getPermissions());
-        if (!gAgent.allowOperation(PERM_MODIFY, item_permissions, GP_OBJECT_MANIPULATE))
-        {
-            return false;
-        }
-        if (!gAgent.allowOperation(PERM_COPY, item_permissions, GP_OBJECT_MANIPULATE))
+        for (PermissionBit op : ops)
         {
-            return false;
+            if (!gAgent.allowOperation(op, item_permissions, GP_OBJECT_MANIPULATE))
+            {
+                return false;
+            }
         }
+        // Update flags for new owner
         if (!item_permissions.setOwnerAndGroup(LLUUID::null, gAgent.getID(), LLUUID::null, true))
         {
             llassert(false);
@@ -1839,20 +1859,21 @@ bool can_save_objects_material(LLSelectedTEGetMatData& func, LLPermissions& perm
         item_permissions.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null);
     }
 
-    LLPermissions* object_permissions_p = LLSelectMgr::getInstance()->findObjectPermissions(selected_object);
+    // Use root object for permissions checking
+    LLViewerObject* root_object = selected_object->getRootEdit();
+    LLPermissions* object_permissions_p = LLSelectMgr::getInstance()->findObjectPermissions(root_object);
     LLPermissions object_permissions;
-    const bool previous_object_owned = object_permissions_p && object_permissions_p->getLastOwner().notNull();
     if (object_permissions_p)
     {
         object_permissions.set(*object_permissions_p);
-        if (!gAgent.allowOperation(PERM_MODIFY, object_permissions, GP_OBJECT_MANIPULATE))
+        for (PermissionBit op : ops)
         {
-            return false;
-        }
-        if (!gAgent.allowOperation(PERM_COPY, object_permissions, GP_OBJECT_MANIPULATE))
-        {
-            return false;
+            if (!gAgent.allowOperation(op, object_permissions, GP_OBJECT_MANIPULATE))
+            {
+                return false;
+            }
         }
+        // Update flags for new owner
         if (!object_permissions.setOwnerAndGroup(LLUUID::null, gAgent.getID(), LLUUID::null, true))
         {
             llassert(false);
@@ -1865,43 +1886,34 @@ bool can_save_objects_material(LLSelectedTEGetMatData& func, LLPermissions& perm
     }
 
     permissions_out.set(item_permissions);
+    // *NOTE: A close inspection of LLPermissions::accumulate shows that
+    // conflicting UUIDs will be unset. This is acceptable behavior for now.
+    // The server doesn't allow us to create an item while claiming someone
+    // else was the creator/previous owner.
     permissions_out.accumulate(object_permissions);
 
-    if (previous_item_owned != previous_object_owned)
-    {
-        // Likely ownership history conflict. Prefer the item history. Fall
-        // back to object history if no associated item.
-        if (previous_item_owned)
-        {
-            permissions_out.setCreator(item_permissions.getCreator());
-            permissions_out.setLastOwner(item_permissions.getLastOwner());
-        }
-        else if (previous_object_owned)
-        {
-            permissions_out.setCreator(object_permissions.getCreator());
-            permissions_out.setLastOwner(object_permissions.getLastOwner());
-        }
-    }
-
-    llassert(permissions_out.getOwner() == gAgent.getID());
-    llassert(permissions_out.getCreator().notNull());
-    llassert(permissions_out.getGroup().isNull());
-
     return true;
 }
 
+bool LLMaterialEditor::canModifyObjectsMaterial()
+{
+    LLSelectedTEGetMatData func(false);
+    LLPermissions permissions;
+    return can_use_objects_material(func, std::vector({PERM_MODIFY}), permissions);
+}
+
 bool LLMaterialEditor::canSaveObjectsMaterial()
 {
     LLSelectedTEGetMatData func(false);
     LLPermissions permissions;
-    return can_save_objects_material(func, permissions);
+    return can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), permissions);
 }
 
 void LLMaterialEditor::saveObjectsMaterialAs()
 {
     LLSelectedTEGetMatData func(false);
     LLPermissions permissions;
-    bool allowed = can_save_objects_material(func, permissions);
+    bool allowed = can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), permissions);
     if (!allowed)
     {
         LL_WARNS("MaterialEditor") << "Failed to save GLTF material from object" << LL_ENDL;
@@ -1986,7 +1998,6 @@ void LLMaterialEditor::saveMaterialAs(const LLGLTFMaterial* render_material, con
     LLSD args;
     args["DESC"] = LLTrans::getString("New Material");
 
-    // At this point, last owner, etc should be set. LLFloaterPerms will be honored later on
     if (local_material)
     {
         LLPermissions local_permissions;
diff --git a/indra/newview/llmaterialeditor.h b/indra/newview/llmaterialeditor.h
index 5ee42f65f4ba42ec009b76202a58ad2b2e007c6e..54e59fcdf85f52c9eacff7faaa54b589268a9028 100644
--- a/indra/newview/llmaterialeditor.h
+++ b/indra/newview/llmaterialeditor.h
@@ -112,6 +112,7 @@ class LLMaterialEditor : public LLPreview, public LLVOInventoryListener
     static void updateLive(const LLUUID &object_id, S32 te);
     static void loadLive();
 
+    static bool canModifyObjectsMaterial();
     static bool canSaveObjectsMaterial();
     static void saveObjectsMaterialAs();
     static void onSaveObjectsMaterialAsMsgCallback(const LLSD& notification, const LLSD& response, const LLPermissions& permissions);
diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp
index b9daf19284fc1e79af89e2082bbec471b18db262..90271b75b2285eb5db83211a631cd63bb1b7860c 100644
--- a/indra/newview/llpanelface.cpp
+++ b/indra/newview/llpanelface.cpp
@@ -51,6 +51,7 @@
 #include "llinventorymodelbackgroundfetch.h"
 #include "llfloatermediasettings.h"
 #include "llfloaterreg.h"
+#include "llfloatertools.h"
 #include "lllineeditor.h"
 #include "llmaterialmgr.h"
 #include "llmaterialeditor.h"
@@ -77,6 +78,7 @@
 #include "llviewerregion.h"
 #include "llviewerstats.h"
 #include "llvovolume.h"
+#include "llvoinventorylistener.h"
 #include "lluictrlfactory.h"
 #include "llpluginclassmedia.h"
 #include "llviewertexturelist.h"// Update sel manager as to which channel we're editing so it can reflect the correct overlay UI
@@ -1834,13 +1836,48 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 	}
 }
 
+// One-off listener that updates the build floater UI when the prim inventory updates
+class PBRPickerItemListener : public LLVOInventoryListener
+{
+protected:
+    LLViewerObject* mObjectp;
+public:
+
+    PBRPickerItemListener(LLViewerObject* object)
+    : mObjectp(object)
+    {
+        registerVOInventoryListener(mObjectp, nullptr);
+    }
+
+    const LLViewerObject* const getObject() { return mObjectp; }
+
+    void inventoryChanged(LLViewerObject* object,
+        LLInventoryObject::object_list_t* inventory,
+        S32 serial_num,
+        void* user_data) override
+    {
+        if (gFloaterTools)
+        {
+            gFloaterTools->dirty();
+        }
+        removeVOInventoryListener();
+    }
+
+    ~PBRPickerItemListener()
+    {
+        removeVOInventoryListener();
+    }
+};
+
 void LLPanelFace::updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material, bool& has_faces_without_pbr, bool force_set_values)
 {
     has_pbr_material = false;
 
-    const bool editable = objectp->permModify() && !objectp->isPermanentEnforced();
     bool has_pbr_capabilities = LLMaterialEditor::capabilitiesAvailable();
     bool identical_pbr = true;
+    const bool settable = has_pbr_capabilities && objectp->permModify() && !objectp->isPermanentEnforced();
+    const bool editable = LLMaterialEditor::canModifyObjectsMaterial();
+    const bool saveable = LLMaterialEditor::canSaveObjectsMaterial();
 
     // pbr material
     LLTextureCtrl* pbr_ctrl = findChild<LLTextureCtrl>("pbr_control");
@@ -1850,13 +1887,23 @@ void LLPanelFace::updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material,
         LLSelectedTE::getPbrMaterialId(pbr_id, identical_pbr, has_pbr_material, has_faces_without_pbr);
 
         pbr_ctrl->setTentative(identical_pbr ? FALSE : TRUE);
-        pbr_ctrl->setEnabled(editable && has_pbr_capabilities);
+        pbr_ctrl->setEnabled(settable);
         pbr_ctrl->setImageAssetID(pbr_id);
     }
 
-    getChildView("pbr_from_inventory")->setEnabled(editable && has_pbr_capabilities);
-    getChildView("edit_selected_pbr")->setEnabled(editable && has_pbr_material && !has_faces_without_pbr && has_pbr_capabilities);
-    getChildView("save_selected_pbr")->setEnabled(LLMaterialEditor::canSaveObjectsMaterial() && identical_pbr);
+    const bool inventory_pending = objectp->isInventoryPending();
+    getChildView("pbr_from_inventory")->setEnabled(settable);
+    getChildView("edit_selected_pbr")->setEnabled(editable && !inventory_pending && !has_faces_without_pbr);
+    getChildView("save_selected_pbr")->setEnabled(saveable && !inventory_pending && identical_pbr);
+    // TODO: Vet inventory updates and memory management
+    if (inventory_pending && (!mInventoryListener || mInventoryListener->getObject() != objectp))
+    {
+        mInventoryListener = std::make_unique<PBRPickerItemListener>(objectp);
+    }
+    else
+    {
+        mInventoryListener = nullptr;
+    }
 
     const bool show_pbr = mComboMatMedia->getCurrentIndex() == MATMEDIA_PBR && mComboMatMedia->getEnabled();
     if (show_pbr)
diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h
index e2d9f65e58c8ef0b0adbf9e98d2a0937233cf55d..d737665ad04119839b886411a29255ee526d47cb 100644
--- a/indra/newview/llpanelface.h
+++ b/indra/newview/llpanelface.h
@@ -35,6 +35,8 @@
 #include "lltextureentry.h"
 #include "llselectmgr.h"
 
+#include <memory>
+
 class LLButton;
 class LLCheckBoxCtrl;
 class LLColorSwatchCtrl;
@@ -51,6 +53,8 @@ class LLMaterialID;
 class LLMediaCtrl;
 class LLMenuButton;
 
+class PBRPickerItemListener;
+
 // Represents an edit for use in replicating the op across one or more materials in the selection set.
 //
 // The apply function optionally performs the edit which it implements
@@ -503,6 +507,8 @@ class LLPanelFace : public LLPanel
 
     static Selection sMaterialOverrideSelection;
 
+    std::unique_ptr<PBRPickerItemListener> mInventoryListener;
+
 public:
 	#if defined(DEF_GET_MAT_STATE)
 		#undef DEF_GET_MAT_STATE