PBR individual material UUIDs accessible via llGetPrimitiveParams on non-full permission objects
tracked
Raven Seraph
If a PBR material is set by editing the object & manually selecting a texture per slot, OR set via PRIM_GLTF_BASE_COLOR or other GLTF Overrides, anyone can read the UUID using llGetPrimitiveParams even if they do not have full permissions on the object. This severely limits ones ability to utilize the GLTF features w/o needing an entire material set. It becomes a security risk if you want to customize an individual material via script without changing all other materials.
EDIT - If you "edit PBR material" on a non-full perm object & open any of the textures as if you were going to change them (it obviously does not exist in your inventory), and simply hit "OK", you can then read that textures UUID from llGetPrimitiveParams as well.
Log In
Kristy Aurelia
Okay, so I've been doing some testing... and Material Permissions are just chaotic nonsense...
Part 1
So first of all, it seems that scripts can always read UUIDs of Material Override textures, it doesn't matter if the texture used for the override is in the inventory or not. It just works.
Render Material itself works as expected. Giving NULL_KEY if object is not full perm.
Now I've asked this during the SUG meeting and was told the following:
[2024/07/09 12:13:41] Brad Linden: the PBR texture UUID permissions should follow existing patterns for how plain texture UUIDs work in LSL.
While this makes sense it presents problems for scripts that want to change colour or alpha and preserve the texture, as in cases when there is an override, that would be lost. Currently due to UUID being present this scenario works as expected.
Part 2 - A
https://wiki.secondlife.com/wiki/GLTF_Overrides states that:
"When a no-mod glTF material is applied to a prim face, its glTF overrides cannot be modified, with the exception of texture transforms."
Which to me sounds like an arbitrary restriction to begin with, since normally overrides have no read-write interaction with each other anyway and it seems silly to enforce partial no-mod restriction on an otherwise mod item, but I digress...
If you apply a copy, no-mod, transfer material to an object of your own creation, you get locked out of editing the overrides, by hand and by scripts.
However if you transfer that object to someone else, they can Save the material from the edit floater to their inventory, and they receive a full perm version of the material, they can then delete existing no-mod material that was put into the object's inventory and reapply the full-perm version of it to the object... or just send you back the full-perm version of the material.
Part 2 - B
If you create your own material, and set it as no-mod then apply it to an object, then give that object to someone as copy, mod, no-trans. They can change the overrides on the object just fine. So the whole "no-mod" material blocks overrides case does not apply here.
Which makes it extra stupid, since if you do want to enforce the material rules, you need to transfer that material to someone else, or have them make it in the first place, and then give it to you for use in this object.
But then you run into Part 2 - A, where they person down the chain can reset the permissions anyway.
Part 0
And now we also to circle back to the original issue where if you apply material to an object and give it to someone as copy, mod, no-trans they can edit the material as if it was an override, just press the 'ok' button on the texture picker without changing anything, and seemingly the Render Material properties get copied into the Override, which due to Part 1, are completely exposed.
My proposal on how it should work
In my opinion the best solution would be:
- Keep overrides as completely editable, with exposed UUIDs and all that. By keeping them exposed, this allows scripts to do get - edit - set sequence on the object without losing any properties. This would also pick up any overrides a person modding the item they've bought has applied.
- Get rid of the whole if Render Material is no mod, you can't edit the overrides part. It just seems confusing and pointless and leads to even more confusing partial-mod items, this would make shopping for mod items impossible, since if the item is mod, and material is not, is the mod item reallymod?
- Change it so if the Render Material is no mod applied to the object is no-mod OR the object is not full-permission OR the Render Material is not part of item's inventory - the save material button should be disabled. If the material object is in the inventory, or the material is mod, you should be able to resave it + overrides as new material, but keep the no-trans permission, if the inventory object had it or if the object the material is applied to had it. This way people can modify the items they've bought, but they can't transfer those modifications to others if the original creator of the item did not allow transferring.
- Fix the override editing causing Render Material details to leak out.
Gael Streeter
I totally agree with Raven! For me this is a HUGE PROBLEM. This makes the use of PBR extremely complex for creators, especially in HUD/Appliers that allow configuring the different settings of the material.
Maestro Linden
tracked
Maestro Linden
Hi Raven, thanks for the report. Reading these parameters should behave the same as llGetTexture() and similar functions, which follows the following logic:
If the texture is in the prim's inventory, the return value is the inventory name, otherwise the returned value is the texture UUID.
While object permissions does not affect llGetTexture() behavior, one can hide the texture UUIDs from any scripts by placing the textures applied to object faces in prim inventory - that way, scripts will just see "metal grate" or similar, rather than the asset UUID. Furthermore, to prevent any snooping, if the texture is removed from prim inventory, it is automatically removed from any prim faces.
In server 2024-06-03.9357471418, I see that PRIM_RENDER_MATERIAL behaves as expected (like llGetTexture() et al.), but can confirm that PRIM_GLTF_BASE_COLOR always returns a UUID rather than the name of the texture in prim inventory.
My repro is:
- Rez a sphere
- Drag a material from agent inventory onto the sphere
- Add the material to prim inventory
- Edit the material on the prim, and set some texture in agent inventory as a base color override
- Add the same texture to prim inventory
- Add the script below to the object, and touch it
- Remove the texture from prim inventory - note if the object's appearance changes
- Remove the material from prim inventory - note if the object's appearance changes
Expected results:
- In (6), the script should print the prim inventory names of both the material and the base color texture.
- In (7), the base color override should be stripped from the prim face
- In (8), the material should be removed from the prim face
Actual results:
- In (6), PRIM_MATERIAL is behaving correctly but PRIM_GLTF_BASE_COLOR exposes the asset UUID:
PRIM_GLTF_BASE_COLOR = ["bca29a42-c2f3-bf92-c614-ed91654c7bf7","<1.000000, 1.000000, 0.000000>","<0.000000, 0.000000, 0.000000>",0.000000,"","","","",""]
PRIM_RENDER_MATERIAL = ["duck with material (Material_0)"]
- In (7), the base color is not removed from the prim face
- In (8), the material is removed from the prim face (as expected)
I haven't tried the other PRIM_GLTF_ parameters that contain a texture reference, but I expect they have the same issue as PRIM_GLTF_BASE_COLOR.
default
{
touch_start(integer total_number)
{
llSay(0, "PRIM_GLTF_BASE_COLOR = " + llList2Json(JSON_ARRAY, llGetPrimitiveParams([PRIM_GLTF_BASE_COLOR, 0])));
llSay(0, "PRIM_RENDER_MATERIAL = " + llList2Json(JSON_ARRAY, llGetPrimitiveParams([PRIM_RENDER_MATERIAL, 0])));
}
}
Raven Seraph
Maestro Linden Thank you for responding. llGetTexture should return NULL_KEY if the object is not full permission. (it appears to correctly do so on live grid.) PRIM_GLTF_ parameters never return NULL_KEY, instead they return blank, or the UUID. Currently I am able to retrieve UUIDs of any object I've received with PBR materials so long as it is modify. This only seems to work if I first Edit PBR Material -> Open the Base Color Texture picker as if I wanted to apply something else, and just hit OK. Now if I attempt to read PRIM_GLTF_BASE_COLOR it will expose the UUID of a texture that is not mine/ does not exist in the inventory of the object
Kristy Aurelia
Maestro Linden
While object permissions does not affect llGetTexture() behavior
That is wrong, object permissions very much do affect the behaviour. The wiki says:
NULL_KEY is returned when the owner does not have full permissions to the object and the texture is not in the prim's inventory.
And this has been for a long time, you can get any copy+mod no-trans item, and make a script to dump all texture UUIDs of all faces, and all of them will return null.
The wiki also indicates that this was the behaviour since 2005.
Kristy Aurelia
Maestro Linden I've just realised, your repro is flawed. You get the UUID because the sphere you rezzed in Step 1 is full perm
to you
, since you've created it.Here's a proper repro:
- Have person 1 make a object and apply materials as overrides.
- Have that person give you the object as Copy + Mod + No-Transfer
- Put this script in the object:
default
{
touch_start(integer total_number)
{
integer numPrims = llGetNumberOfPrims();
integer linkIdx = 1;
if (numPrims == 1)
{
linkIdx = 0;
numPrims = 0;
}
list faceTextures = [];
list faceMaterials = [];
while (linkIdx <= numPrims)
{
integer numFaces = llGetLinkNumberOfSides(linkIdx);
integer faceIdx = 0;
while (faceIdx < numFaces)
{
list faceBase = llGetLinkPrimitiveParams(linkIdx, [PRIM_GLTF_BASE_COLOR, faceIdx]);
list faceMat = llGetLinkPrimitiveParams(linkIdx, [PRIM_RENDER_MATERIAL, faceIdx]);
faceTextures += llList2String(faceBase, 0);
faceMaterials += llList2String(faceMat, 0);
++faceIdx;
}
++linkIdx;
}
llOwnerSay("Textures: " + llList2CSV(faceTextures));
llOwnerSay("materials: " + llList2CSV(faceMaterials));
}
}
- Touch the object. You'll get Textures: , , , , ,for as many as there are faces with materials.
- Select a single face, 'Edit Selected' PBR Material, open the texture picker for Base Color and just pressing [OK] without making changes.
- Touch the object again: You'll get Textures: cd730b0b-XXXX, 3b2edf69-XXXX, 04bf90d1-XXXXfor each face you've edited in step 5. I've redacted the full UUIDs here, but they're very much visible on a PBR enabled item I have bought.
This is all done without me having any material objects myself, nor there being any inside the object.
Tested on SIM 2024-04-13.8669470296 and Using Alchemy Beta 7.1.7.2486 as well as Firestorm Beta 7.1.8.74246