Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to disable virtual disk renaming? #1170

Open
stroev-ao opened this issue Sep 1, 2023 · 23 comments
Open

How to disable virtual disk renaming? #1170

stroev-ao opened this issue Sep 1, 2023 · 23 comments

Comments

@stroev-ao
Copy link

This does not interfere with the operation of the disk, but from a logical point of view, this should not be possible, since the disk name in my case is set remotely.

@Liryna
Copy link
Member

Liryna commented Sep 4, 2023

I haven't tried but I am pretty sure this is due to the default sddl (you can find the value in sys/dokan.h) allowing this.
You can set your custom value and deny the rename at mount time with the dokan option field VolumeSecurityDescriptor

@stroev-ao
Copy link
Author

I use the InitializeSecurityDescriptor and SetSecurityDescriptorDacl methods from advapi32.dll, get the SECURITY_DESCRIPTOR structure, convert its IntPtr to a byte array and set it to the VolumeSecurityDescriptor field. After that I get an exception when calling DokanBuilder.Build. Am I doing it right?
image
image
image

@Liryna
Copy link
Member

Liryna commented Sep 5, 2023

Sorry I haven't tried it myself from C# but there is indeed a Marshall allocation issue here

@stroev-ao
Copy link
Author

Can you create an c++ example please?

@LTRData
Copy link
Contributor

LTRData commented Sep 5, 2023

I use the InitializeSecurityDescriptor and SetSecurityDescriptorDacl methods from advapi32.dll, get the SECURITY_DESCRIPTOR structure, convert its IntPtr to a byte array and set it to the VolumeSecurityDescriptor field. After that I get an exception when calling DokanBuilder.Build. Am I doing it right?

I would strongly suggest that you use .NET model objects for this as far as possible.

        var sec = new FileSecurity();

        sec.AddAccessRule( ... );

        var bytes = sec.GetSecurityDescriptorBinaryForm();

        options.VolumeSecurityDescriptor = bytes;
        options.VolumeSecurityDescriptorLength = bytes.Length;

There could of course still be things that you need to call through P/Invoke depending on what you want to do. But in my experience, that is almost never needed.

Does this help in your case?

@stroev-ao
Copy link
Author

Thanks for the advice @LTRData! I tried to do it in .NET model objects but got the same exception. I also tried not setting a value in the VolumeSecurityDescriptorLength field - doesn't matter.
image

@LTRData
Copy link
Contributor

LTRData commented Sep 6, 2023

Could you share some details about the exception you get? What type of exception and if there are any more details in it.

@stroev-ao
Copy link
Author

Sure. Exception type is System.ArgumentException. Message: Type could not be marshaled because the length of an embedded array instance does not match the declared length in the layout. Stack trace:
at System.StubHelpers.MngdFixedArrayMarshaler.ConvertSpaceToNative(IntPtr pMarshalState, Object& pManagedHome, IntPtr pNativeHome)
--- End of stack trace from previous location ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at Interop.Ole32.CoTaskMemFree(IntPtr ptr)
at System.Runtime.InteropServices.Marshal.StructureToPtr(Object structure, IntPtr ptr, Boolean fDeleteOld)
at System.Runtime.InteropServices.Marshal.StructureToPtr[T](T structure, IntPtr ptr, Boolean fDeleteOld)
at DokanNet.NativeStructWrapper`1..ctor(T obj)
at DokanNet.NativeStructWrapper.Wrap[T](T obj)
at DokanNet.DokanInstance..ctor(ILogger logger, DOKAN_OPTIONS options, IDokanOperations operations)
at DokanNet.DokanInstanceBuilder.Build(IDokanOperations operations)
at MyClass (where DokanBuilder.Build is called).

What other information might help?

@LTRData
Copy link
Contributor

LTRData commented Sep 6, 2023

Ah okay I understand. I missed that part. You need to resize the array:
Array.Resize(ref bytes, 16384);

@stroev-ao
Copy link
Author

Ah okay I understand. I missed that part. You need to resize the array: Array.Resize(ref bytes, 16384);

Okay, one more exception. Type: DokanException. Message: Can't install the Dokan driver. Stack trace:
at DokanNet.DokanInstance..ctor(ILogger logger, DOKAN_OPTIONS options, IDokanOperations operations)
at DokanNet.DokanInstanceBuilder.Build(IDokanOperations operations)
at MyClass (where DokanBuilder.Build is called).

Am I doing it right?
image

@LTRData
Copy link
Contributor

LTRData commented Sep 6, 2023

Have you installed the Dokan setup package? Did you get any errors when you did that? What does the command sc query dokan2 at command line say?

@stroev-ao
Copy link
Author

Have you installed the Dokan setup package? Did you get any errors when you did that? What does the command sc query dokan2 at command line say?

Yes, the Dokan package installed without errors.
image
The command sc query dokan2 result:
image

@LTRData
Copy link
Contributor

LTRData commented Sep 6, 2023

Strange. Could it be some kind of version mismatch between the native dokan2.dll that gets loaded into your process and Dokan2 driver? I am unsure in this case. It looks like it should have worked.

@stroev-ao
Copy link
Author

Strange. Could it be some kind of version mismatch between the native dokan2.dll that gets loaded into your process and Dokan2 driver? I am unsure in this case. It looks like it should have worked.

You were right. The Dokan Library version was 2.0.6.1, the Dokan version from Nuget in my project is 2.0.5.1. I uninstalled Dokan Library 2.0.6.1 then installed Dokan Library 2.0.5.1, but the problem is still there.

@Liryna
Copy link
Member

Liryna commented Sep 7, 2023

If other C# sample work, it means your install is correct but the provided VolumeSecurity are incorrect and failed the mount.

@LTRData
Copy link
Contributor

LTRData commented Sep 7, 2023

Strange. Could it be some kind of version mismatch between the native dokan2.dll that gets loaded into your process and Dokan2 driver? I am unsure in this case. It looks like it should have worked.

You were right. The Dokan Library version was 2.0.6.1, the Dokan version from Nuget in my project is 2.0.5.1. I uninstalled Dokan Library 2.0.6.1 then installed Dokan Library 2.0.5.1, but the problem is still there.

I see now that this problem happens with that security descriptor if added to the native memfs C sample as well.

    PSECURITY_DESCRIPTOR sec_desc;
    ULONG sec_desc_length;
    BOOL rc = ConvertStringSecurityDescriptorToSecurityDescriptor(L"D:(D;;SD;;;WD)", SDDL_REVISION_1, &sec_desc, &sec_desc_length);
    memcpy(dokan_options.VolumeSecurityDescriptor, sec_desc, sec_desc_length);
    dokan_options.VolumeSecurityDescriptorLength = sec_desc_length;
    LocalFree(sec_desc);

I'll try to figure out what is going on here.

(Also, please do not post screenshots as pictures here, copy and paste your code instead so that it is easier for others to try out the same thing without the need to type your code manually and risk mistakes. Thank you!)

@LTRData
Copy link
Contributor

LTRData commented Sep 7, 2023

Okay, so the problem here is that the security descriptor does not allow anything which means that everything is disallowed, which causes dokan2.dll not to be able to open the volume using CreateFile. The security descriptor needs to allow something:

            var sec = new FileSecurity();
            sec.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.ReadAndExecute, AccessControlType.Allow));
            sec.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.Delete, AccessControlType.Deny));
            var bytes = sec.GetSecurityDescriptorBinaryForm();

But actually, you could skip denying delete actions because anything that is not explicitly allowed in this security descriptor will be denied automatically:

            var sec = new FileSecurity();
            sec.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.ReadAndExecute, AccessControlType.Allow));
            var bytes = sec.GetSecurityDescriptorBinaryForm();

@stroev-ao
Copy link
Author

Okay, so the problem here is that the security descriptor does not allow anything which means that everything is disallowed, which causes dokan2.dll not to be able to open the volume using CreateFile. The security descriptor needs to allow something:

            var sec = new FileSecurity();
            sec.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.ReadAndExecute, AccessControlType.Allow));
            sec.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.Delete, AccessControlType.Deny));
            var bytes = sec.GetSecurityDescriptorBinaryForm();

But actually, you could skip denying delete actions because anything that is not explicitly allowed in this security descriptor will be denied automatically:

            var sec = new FileSecurity();
            sec.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.ReadAndExecute, AccessControlType.Allow));
            var bytes = sec.GetSecurityDescriptorBinaryForm();

Great, it works! Thank you! But how to prevent drive renaming but allow all actions with all subdirectories and files? Because all security rights are inherited for all content I cannot rename or delete directories and create files. Ttried to add FileSystemRight.DeleteSubdirectoriesAndFiles. Also tried setting FullControl for all directories and files in the GetFileSecurity method. Another attempt is to use inheritance to all subdirectories and files when adding FileSystemRight.DeleteSubdirectoriesAndFiles. All attempts fail. Can you help me with this? I'm not strong with FileSystemRights yet.

@stroev-ao
Copy link
Author

I found that the FileSystemRights.WriteData right disables disk renaming when it's denied. But it also prevent files to being created. I tried this but to no avail:
fileSecurity.AddAccessRule(new FileSystemAccessRule(securityIdentifier, FileSystemRights.WriteData, InheritanceFlags.None, PropagationFlags.None, AccessControlType.Deny));

@LTRData
Copy link
Contributor

LTRData commented Sep 8, 2023

I think you should try to allow everything and then deny delete, but make sure that the denial does not propagate to anything else (i.e. "this object only"). But I am not really sure. This is a kind of generic question about disk volume permissions. There could be discussions about it in other places that could be useful to read through.

@Liryna
Copy link
Member

Liryna commented Oct 14, 2023

@stroev-ao Have you been able to resolve this issue ?

@stroev-ao
Copy link
Author

@stroev-ao Have you been able to resolve this issue ?

No, the problem is not solved. The advice above from @LTRData did not help.

@LTRData
Copy link
Contributor

LTRData commented Oct 15, 2023

@stroev-ao Have you been able to resolve this issue ?

No, the problem is not solved. The advice above from @LTRData did not help.

Like I said in my last comment, this is a more kind of general question not Dokan specific and you might want to search for hints about how to do it in other places. I would assume that you would need to create an ACL with some propagating allow permissions for all users and then some non-propagating deny permissions specifically denying deletion. The inheritance parts of it are most important in this specific case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants