I'm currently working on developing some driver. For now connection between kernel and system is done via simple text file created like this:
handle=CreateFile(TEXT("\\\\.\\" FILE_NAME),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
File is used for transfering data from kernel to system, kernel driver writes file and system app reads from it. My concern is safety of such solution, as for now anyone can simply go into this file, get all data in file, and what's even worse, modify it. Is it possible to make file not accesible for user, but still being accesible for system app?
UPDATE:
After doing some research I found a pattern how to do it for specific users:
ea[1].grfAccessPermissions = ACCESS_SYSTEM_SECURITY | READ_CONTROL | WRITE_DAC | GENERIC_ALL;
ea[1].grfAccessMode = DENY_ACCESS;
ea[1].grfInheritance = NO_INHERITANCE;
ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[1].Trustee.ptstrName = reinterpret_cast<char*>(&everyone_sid);
dwRes = SetEntriesInAclA(2, ea, NULL, &pNewDACL);
if (ERROR_SUCCESS != dwRes) {
printf("SetEntriesInAcl Error %u\n", dwRes);
//TODO: goto Cleanup;
}
PSECURITY_DESCRIPTOR pSD = NULL;
// Initialize a security descriptor.
pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR,
SECURITY_DESCRIPTOR_MIN_LENGTH);
if (NULL == pSD)
{
printf("error");
}
if (!InitializeSecurityDescriptor(pSD,
SECURITY_DESCRIPTOR_REVISION))
{
printf("error");
}
// Add the ACL to the security descriptor.
if (!SetSecurityDescriptorDacl(pSD,
TRUE, // bDaclPresent flag
pNewDACL,
FALSE)) // not a default DACL
{
printf("error");
}
SECURITY_ATTRIBUTES sa;
// Initialize a security attributes structure.
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = pSD;
sa.bInheritHandle = FALSE;
HANDLE hFile = CreateFileA(filename, GENERIC_ALL, 0, &sa, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
By this code I managed to make file not accesible for any user so It's great progress. However, I have no idea how to make it accesible for another project, for example:
int main()
{
std::cout << "Hello World!\n";
std::fstream testfile;
//basically in another project
testfile.open("created_file.txt", ios::out);
testfile.write("elo",3);
testfile.close();
}
I belive that maybe there is a way to get proccess SID and then give full access for it's SID, but question is how could I get process SID?
Related
I have two applications:
first one: running with SYSTEM Privileges started by a service and the
second one: running still as SYSTEM but with lower privileges (SE_GROUP_INTEGRITY = "S-1-16-4096")
I want both applications to communicate over sharedmemory. Both need to read and write.
In my first application i create the filemapping with specific SECURITY_ATTRIBUTES i learned from this post: How to share memory between services and user processes?
SECURITY_ATTRIBUTES attributes;
ZeroMemory(&attributes, sizeof(attributes));
attributes.nLength = sizeof(attributes);
ConvertStringSecurityDescriptorToSecurityDescriptor(
L"D:P(A;OICI;GA;;;SY)(A;OICI;GA;;;BA)(A;OICI;GWR;;;IU)",
SDDL_REVISION_1,
&attributes.lpSecurityDescriptor,
NULL);
HANDLE test = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 1024, "Global\\Test");
Everything works as expected, but if i then try to open the file mapping in my second application, it crashes with an access violation at OpenFileMapping.
HANDLE test = OpenFileMapping(FILE_ALL_ACCESS, FALSE, 1024, "Global\\Test");
if you want allow access to object for Low Integrity code you need add Low mandatory level (SDDL_ML_LOW) Integrity label (SDDL_MANDATORY_LABEL) to security descriptor. for example
"D:PNO_ACCESS_CONTROLS:(ML;;NW;;;LW)"
so in general code is next:
ULONG CreateSectionWithLowAccess(PHANDLE SectionHandle, ULONG dwMaximumSize, PCWSTR lpName)
{
SECURITY_ATTRIBUTES sa = { sizeof(sa) };
if (ConvertStringSecurityDescriptorToSecurityDescriptorW(L"D:PNO_ACCESS_CONTROLS:(ML;;NW;;;LW)",
SDDL_REVISION_1, &sa.lpSecurityDescriptor, NULL))
{
*SectionHandle = CreateFileMappingW(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, dwMaximumSize, lpName);
LocalFree(sa.lpSecurityDescriptor);
return *SectionHandle ? NOERROR : GetLastError();
}
return GetLastError();
}
I'm getting some strange results when checking if an SD Card is locked using the FILE_READ_ONLY_VOLUME file-system flag reported by GetVolumeInformation().
If the SD Card is locked, and the SD Card contains a volume with a file-system, then the flag is correctly set, however if there is no file-system, the flag is not set, even though Windows correctly reports the drive as read-only.
const wchar_t letter = "F";
DWORD filesystemFlags = 0;
TCHAR drivePath[kVolumePathShortLength];
sprintf_s(drivePath, "%c:\\", letter);
const HRESULT result = GetVolumeInformation(drivePath, NULL, 0, NULL, NULL, &filesystemFlags, NULL, 0);
if (SUCCEEDED(result)) {
if (filesystemFlags & FILE_READ_ONLY_VOLUME) {
printf("Drive is read-only\n");
} else {
printf("Drive is not read-only\n");
}
}
Since the code works fine if there is a file-system in the volume, I'm thinking there might be other way Disk Management checks if a volume is read-only or not, that works regardless of the file-system.
GetVolumeInformation applies to volumes, not disks. GetVolumeInformation also returns a BOOL, not a HRESULT so you cannot trust the output of your sample code!
You can try getting low-level disk information:
for (UINT d = 'A'; d <= 'Z'; ++d) // Real code should use GetLogicalDrives
{
WCHAR devbuf[20];
wsprintfW(devbuf, L"\\\\.\\%c:", d);
HANDLE hDev = CreateFileW(devbuf, 0, 7, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hDev == INVALID_HANDLE_VALUE) continue;
DWORD cb, gle;
BOOL succ = DeviceIoControl(hDev, IOCTL_DISK_IS_WRITABLE, NULL, 0, NULL, 0, &cb, NULL);
gle = GetLastError();
printf("%c: is %s (error %u)\n", d, succ ? "writable" : gle == ERROR_WRITE_PROTECT ? "read-only" : "unknown", succ ? 0 : gle);
CloseHandle(hDev);
}
This is what Windows file systems do according to this thread # OSR:
... the in-box file systems send IOCTL_DISK_IS_WRITEABLE to determine whether the disk is read-only or not.
You could also try IOCTL_DISK_GET_DISK_ATTRIBUTES but I would guess that flag is the same thing as IOCTL_DISK_IS_WRITABLE.
This thread claims that IOCTL_VOLUME_GET_GPT_ATTRIBUTES can be sent to all disk types but I don't see why this would be a better choice.
Using C, I'm trying to establish a pipe connection between a process and it's child process, while the child process has a lower mandatory(integrity) level (low, while the parent process is high).
I wrote the following program (it's a simplified version if it), but it fails with: ERROR_ACCESS_DENIED (0x5)
INT wmain(IN SIZE_T nArgc, IN PWSTR *pArgv)
{
SECURITY_ATTRIBUTES securityArrtibutes = { 0 };
HANDLE hPipeRead = NULL;
HANDLE hPipeWrite = NULL;
tSecurityArrtibutes.nLength = sizeof(tSecurityArrtibutes);
tSecurityArrtibutes.bInheritHandle = TRUE;
SetSeSecurityNamePrivilege();
CreatePipe(&hPipeRead, &hPipeWrite, &securityArrtibutes, 0);
ChangeMandatoryLabelHandle(hPipeRead);
}
VOID ChangeMandatoryLabelHandle(HANDLE hObject)
{
BOOL bRetval = FALSE;
DWORD dwError = 0;
PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
PACL ptSacl = NULL;
BOOL bSaclPresent = FALSE;
BOOL bSaclDefaulted = FALSE;
PWSTR pSDDL = NULL;
SDDL = L"S:(ML;;LW;;;NW)";
bRetval = ConvertStringSecurityDescriptorToSecurityDescriptorW(pSDDL, SDDL_REVISION_1, &pSecurityDescriptor, NULL);
if (FALSE == bRetval)
... // Handle failure
bRetval = GetSecurityDescriptorSacl(pSecurityDescriptor, &bSaclPresent, &ptSacl, &bSaclDefaulted);
if (FALSE == bRetval)
... // Handle failure
// getting ERROR_ACCESS_DENIED (0x5)
dwErr = SetSecurityInfo(hObject, SE_KERNEL_OBJECT, LABEL_SECURITY_INFORMATION, NULL, NULL, NULL, ptSacl);
if (ERROR_SUCCESS != dwErr)
... // Handle failure
... // Cleanup
}
I followed https://msdn.microsoft.com/en-us/library/windows/desktop/aa379588(v=vs.85).aspx and the remark that
To set the SACL of an object, the caller must have the SE_SECURITY_NAME privilege enabled. :
BOOL SetSeSecurityNamePrivilege()
{
HANDLE hToken;
TOKEN_PRIVILEGES tp;
LUID luid;
if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_IMPERSONATE, &hToken)
return FALSE
if (!LookupPrivilegeValue(NULL, SE_SECURITY_NAME, &luid))
return FALSE;
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
if (bEnablePrivilege)
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
else
tp.Privileges[0].Attributes = 0;
if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES)NULL, (PDWORD)NULL))
return FALSE;
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
return FALSE;
return TRUE;
}
note: I get the same result when I try to execute it with files, with CreateFile instead of CreatePipe.
In addition if I try to do that with files, and I replace SetSecurityInfo with SetNamedSecurityInfoW, and give it the full path of the file, it works great.
Does anyone have an idea how to make it work? Thanks!
A few notes before addressing the cause of your immediate problem.
First and foremost, you do not need to change the security descriptor at all, and doing so is unlikely to help you achieve your ultimate goal. The security descriptor is only checked when you attempt to open a handle to an object; if you already have a handle, the security descriptor has no effect. Since you are creating an unnamed pipe, you must be passing the handle, not the pipe name, to the child, so you do not need the ChangeMandatoryLabelHandle function at all.
Secondly, the SE_SECURITY_NAME privilege is not needed when setting LABEL_SECURITY_INFORMATION. The mandatory label is logically distinct from the rest of the SACL, and is treated as a special case.
Thirdly, your "S:(ML;;LW;;;NW)" is invalid.
I tried to use it in ConvertStringSecurityDescriptorToSecurityDescriptorW and got error 1336, The access control list (ACL) structure is invalid. Instead, use"D:NO_ACCESS_CONTROLS:(ML;;;;;LW)" or better still use the following code to create a security descriptor with a low label and no DACL:
ULONG cb = MAX_SID_SIZE;
PSID LowLabelSid = (PSID)alloca(MAX_SID_SIZE);
ULONG dwError = NOERROR;
if (CreateWellKnownSid(WinLowLabelSid, 0, LowLabelSid, &cb))
{
PACL Sacl = (PACL)alloca(cb += sizeof(ACL) + sizeof(ACE_HEADER) + sizeof(ACCESS_MASK));
if (InitializeAcl(Sacl, cb, ACL_REVISION) &&
AddMandatoryAce(Sacl, ACL_REVISION, 0, 0, LowLabelSid))
{
SECURITY_DESCRIPTOR sd;
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
SetSecurityDescriptorSacl(&sd, TRUE, Sacl, FALSE);
SECURITY_ATTRIBUTES sa = { sizeof(sa), &sd, TRUE };
// todo something here
}
else
{
dwError = GetLastError();
}
}
else
{
dwError = GetLastError();
}
But again, you need to understand that there is (almost) never any sense in creating a security descriptor for an unnamed object. The security descriptor is only checked when opening an object, and (in user mode) you cannot open an object that does not have a name.
(From kernel mode we can open an object by pointer using ObOpenObjectByPointer.)
(In older versions of Windows, CreatePipe actually created a pipe with a random name, but starting from Windows 7 the pipe really is unnamed, so it cannot be opened with CreateFile or any similar method.)
In any case, it is my opinion that using CreatePipe in this context was a bad choice. This function is not well designed and has too few parameters. There is no option to create a bidirectional pipe or to open the pipe in asynchronous mode. I think it is better to use CreateNamedPipeW and CreateFileW.
(Alternatively, from Windows 7 onwards, you can use ZwCreateNamedPipeFile and ZwOpenFile to create and open an unnamed pipe.)
The proximate problem with the code as posted is that SetSecurityInfo and SetKernelObjectSecurity return ERROR_ACCESS_DENIED when called with the handle returned by CreatePipe. This is because, as described in the documentation for LABEL_SECURITY_INFORMATION:
Right required to set: WRITE_OWNER
Since CreatePipe does not give you the option to select the access rights that the handles are opened with, you have no way of doing this. If you instead use CreateNamedPipe you can set WRITE_OWNER in dwOpenMode.
However, you should note that if you wish to create an object with a special security descriptor, it is preferable to provide that security descriptor when the object is created. There is no point in creating the object with a default security descriptor and then changing it; why do in two operations what you can do in one? In this case, the SECURITY_ATTRIBUTES structure you pass to CreatePipe or CreateNamedPipe can be used to specify the security descriptor, providing another way of addressing your immediate problem, although as previously mentioned this will not in fact be useful.
The only way I found to get a file size is to use the GetFileSizeEx() function. However, this function requires a HANDLE to the file, and if the file is already open for exclusive access I will not be able to get a HANDLE for it and hence I will not be able to get its size.
So is there a way to get a file size even if it is already open for exclusive access?
Edit, (see comments)
Using GetFileInformationByHandle
ULONGLONG filesize = 0;
HANDLE h = CreateFile(filename, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (h != INVALID_HANDLE_VALUE)
{
BY_HANDLE_FILE_INFORMATION info;
memset(&info, 0, sizeof(BY_HANDLE_FILE_INFORMATION));
if (GetFileInformationByHandle(h, &info))
{
ULARGE_INTEGER ul = { 0 };
ul.LowPart = info.nFileSizeLow;
ul.HighPart = info.nFileSizeHigh;
filesize = ul.QuadPart;
}
CloseHandle(h);
}
Another method, see GetFileAttributesEx
There is also FindFirstFile, but this can be inaccurate
From MSDN documentation for FindFirstFile
Note In rare cases or on a heavily loaded system, file attribute
information on NTFS file systems may not be current at the time this
function is called. To be assured of getting the current NTFS file
system file attributes, call the GetFileInformationByHandle function.
Using FindFirstFile
WIN32_FIND_DATA ffd;
HANDLE hfind = FindFirstFile(filename, &ffd);
if (hfind != INVALID_HANDLE_VALUE)
{
DWORD filesize = ffd.nFileSizeLow;
//for files larger than 4GB:
ULARGE_INTEGER ul;
ul.LowPart = ffd.nFileSizeLow;
ul.HighPart = ffd.nFileSizeHigh;
ULONGLONG llfilesize = ul.QuadPart;
FindClose(hfind);
}
I would like to know how can I set the permissions of a windows file?
Something like chmod(), instead it's a windows.
For example:
Create the file example.exe, and set its permissions in a way that only the owner
of this file can execute it.
I read that there's an ACL API for c somewhere, but I didn't quite get it.
It's a lot more work than chmod!
I have taken the liberty of creating the file AFTER creating the security descriptor - it is safer. If you do things the other way around (create the file first) then there is a short time when the required access is not set.
Try this:
#include <windows.h>
#include <AclAPI.h>
#include <Lmcons.h>
int main()
{
SECURITY_DESCRIPTOR sd;
EXPLICIT_ACCESS ea[1];
PACL pDacl;
SECURITY_ATTRIBUTES sa;
TCHAR UserBuffer[UNLEN+1];
DWORD ulen = UNLEN;
GetUserName(UserBuffer, &ulen);
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
BuildExplicitAccessWithName(&ea[0], UserBuffer, GENERIC_EXECUTE,
SET_ACCESS, NO_INHERITANCE);
SetEntriesInAcl(1, ea, NULL, &pDacl);
SetSecurityDescriptorDacl(&sd, TRUE, pDacl, FALSE);
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = FALSE;
sa.lpSecurityDescriptor = &sd;
CreateFileA("c:\\temp\\example.exe", GENERIC_EXECUTE, 0, &sa,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
return 0;
}