Linux Kernel Crypto API : skcipher algorithm name not found by "crypto_alloc_skcipher" - c

I'm trying to make a Linux kernel driver using crypto API.
So first I have my own skcipher algorithm that I developed successfully registered on the crypto API and I can see it in the list of cryptos that is well registered.
.base = {
/* Name used by the framework to find who is implementing what. */
.cra_name = "cbc(aes)stackOverFlow",
/* Driver name. Can be used to request a specific implementation of an algorithm. */
.cra_driver_name = "stackOverFlow-cbc-aes",
/* Priority is used when implementation auto-selection takes place:
* if there are several implementers, the one with the highest priority is chosen.
* By convention: HW engine > ASM/arch-optimized > plain C
* */
.cra_priority = 300,
/* Driver module */
.cra_module = THIS_MODULE,
/* Size of the data blocks this algo operates on. */
.cra_blocksize = AES_BLOCK_SIZE,
.cra_flags = CRYPTO_ALG_INTERNAL | CRYPTO_ALG_TYPE_SKCIPHER,
/* Size of the context attached to an algorithm instance.
* This value informs the kernel crypto API about the memory size
* needed to be allocated for the transformation context.
*/
.cra_ctxsize = sizeof(struct crypto_aes_ctx),
/* Alignment mask for the input and output data buffer. */
.cra_alignmask = 15,
},
/* constructor/destructor methods called every time an alg instance is created/destroyed. */
.min_keysize = AES_MIN_KEY_SIZE,
.max_keysize = AES_MAX_KEY_SIZE,
.ivsize = AES_BLOCK_SIZE,
.init = test_skcipher_cra_init,
.exit = test_skcipher_cra_exit,
.setkey = test_aes_setkey,
.encrypt = test_cbc_aes_encrypt,
.decrypt = test_cbc_aes_decrypt,
};
And this is my init function module :
static int __init test_skcipher_cra_init(struct crypto_skcipher *tfm){
int ret;
ret = crypto_register_skcipher(&test_cbc_aes_alg);
if (ret < 0){
printk(KERN_ALERT "register failed %d", ret);
}
else{
printk(KERN_INFO "SUCCESS crypto_register\n");
}
return ret;
}
So to ensure that my driver works fine, I'm using the implementation user code (that I got from link) to encrypt some data : https://www.kernel.org/doc/html/v4.17/crypto/api-samples.html
But when I compile everything and move to see the kernel log messages I receive an error message "could not allocate skcipher handle" that comes from a part of the implementation code :
skcipher = crypto_alloc_skcipher("stackOverFlow-cbc-aes", 0, 0);
if (IS_ERR(skcipher)) {
pr_info("could not allocate skcipher handle\n");
return PTR_ERR(skcipher);
}
But in the crypto API, I can see the driver :
name : cbc(aes)stackOverFlow
driver : stackOverFlow-cbc-aes
module : kernel
priority : 300
refcnt : 1
selftest : passed
internal : yes
type : skcipher
async : no
blocksize : 16
min keysize : 16
max keysize : 32
ivsize : 16
chunksize : 16
walksize : 16
I really tried many times to modify the flag and other things in my algorithm but I don't understund it keeps showing me this message. So my question is why it gives me this error and my crypto driver is already registred on the crypto API ?
Notice that when I change the name to crypto_alloc_skcipher("cbc-aes-aesni", 0, 0) which is one of the already exist ones in the API, everything works fine.

I managed to resolve the problem, it was stupid mistake because of the Init algorithm function that I confused with Init function module.

Related

Cannot move camera using libuvc

I'm trying to control my camera using libuvc.
I tried this code I modified from the example:
#include <libuvc/libuvc.h>
#include <stdio.h>
#include <unistd.h>
int main() {
uvc_context_t *ctx;
uvc_device_t *dev;
uvc_device_handle_t *devh;
uvc_stream_ctrl_t ctrl;
uvc_error_t res;
/* Initialize a UVC service context. Libuvc will set up its own libusb
* context. Replace NULL with a libusb_context pointer to run libuvc
* from an existing libusb context. */
res = uvc_init(&ctx, NULL);
if (res < 0) {
uvc_perror(res, "uvc_init");
return res;
}
puts("UVC initialized");
/* Locates the first attached UVC device, stores in dev */
res = uvc_find_device(
ctx, &dev,
0, 0, NULL); /* filter devices: vendor_id, product_id, "serial_num" */
if (res < 0) {
uvc_perror(res, "uvc_find_device"); /* no devices found */
} else {
puts("Device found");
/* Try to open the device: requires exclusive access */
res = uvc_open(dev, &devh);
if (res < 0) {
uvc_perror(res, "uvc_open"); /* unable to open device */
} else {
puts("Device opened");
uvc_print_diag(devh, stderr);
//uvc_set_pantilt_abs(devh, 100, 100);
int result = uvc_set_pantilt_abs(devh, 5, 50);
printf("%d\n", result);
//sleep(5);
/* Release our handle on the device */
uvc_close(devh);
puts("Device closed");
}
/* Release the device descriptor */
uvc_unref_device(dev);
}
/* Close the UVC context. This closes and cleans up any existing device handles,
* and it closes the libusb context if one was not provided. */
uvc_exit(ctx);
puts("UVC exited");
return 0;
}
I tried both uvc_set_pantilt_abs and uvc_set_pantilt_rel and both are returning 0 so it means the action is successful. Except the camera does not move.
I'm sure the camera uses UVC because uvc_print_diag indicates
VideoControl:
bcdUVC: 0x0110
Am I doing something wrong? If not how can I troubleshoot it?
I found the answer a while ago but forgot to put it here.
I stumbled upon this project which controls a camera using a commandline tool with libuvc.
After playing a bit with it and compared it with my code I got what I did wrong. He was getting the pantilt data from the camera and then using it to send requests. It seems cameras need to receive a number which must be a multiple of the "step" provided by the camera as the movement unit.
Here's the part where he requests the pantilt information:
int32_t pan;
int32_t panStep;
int32_t panMin;
int32_t panMax;
int32_t tilt;
int32_t tiltStep;
int32_t tiltMin;
int32_t tiltMax;
// get current value
errorCode = uvc_get_pantilt_abs(devh, &pan, &tilt, UVC_GET_CUR);
handleError(errorCode, "Failed to read pan/tilt settings - possibly unsupported by this camera?\n");
// get steps
errorCode = uvc_get_pantilt_abs(devh, &panStep, &tiltStep, UVC_GET_RES);
handleError(errorCode, "Failed to read pan/tilt settings - possibly unsupported by this camera?\n");
// get min
errorCode = uvc_get_pantilt_abs(devh, &panMin, &tiltMin, UVC_GET_MIN);
handleError(errorCode, "Failed to read pan/tilt settings - possibly unsupported by this camera?\n");
// get max
errorCode = uvc_get_pantilt_abs(devh, &panMax, &tiltMax, UVC_GET_MAX);
handleError(errorCode, "Failed to read pan/tilt settings - possibly unsupported by this camera?\n");
Here's the full code

Can I call mknod from my kernel module?

As the title states I'm writing a kernel module and I want the character device that the module creates to show up automatically. can I use mknod and rm in my module_init and module_exit to create and remove the device?
EDIT: not sure if this is allowed but as an extension to the question, where can I find more information like this? most of my google searches lead to either very confusing for very old information (kernel 2.6 and older), whats the best place to learn how to write kernel modules?
No you can't use mknod and rm cli's from kernel space. These are bash commands. But other option exists to create and remove the device node file of your module from kernel space. In module init function you can use class_create() and then device_create() functions after doing registration for you device. After cdev_init() call you can use this two function for node file creation. Similarly you can use device_destroy() and class_destroy() functions in module_exit function to remove the node file.
Here is sample code that creates /dev/kmem in a char device init function:
int majorNum;
dev_t devNo; // Major and Minor device numbers combined into 32 bits
struct class *pClass; // class_create will set this
static int __init devkoInit(void) {
struct device *pDev;
// Register character device
majorNum = register_chrdev(0, "devko", &fileOps);
if (majorNum < 0) {
printk(KERN_ALERT "Could not register device: %d\n", majorNum);
return majorNum;
}
devNo = MKDEV(majorNum, 0); // Create a dev_t, 32 bit version of numbers
// Create /sys/class/kmem in preparation of creating /dev/kmem
pClass = class_create(THIS_MODULE, "kmem");
if (IS_ERR(pClass)) {
printk(KERN_WARNING "\ncan't create class");
unregister_chrdev_region(devNo, 1);
return -1;
}
// Create /dev/kmem for this char dev
if (IS_ERR(pDev = device_create(pClass, NULL, devNo, NULL, "kmem"))) {
printk(KERN_WARNING "devko.ko can't create device /dev/kmem\n");
class_destroy(pClass);
unregister_chrdev_region(devNo, 1);
return -1;
}
return 0;
} // end of devkoInit
static void __exit devkoExit(void) {
// Clean up after ourselves
device_destroy(pClass, devNo); // Remove the /dev/kmem
class_destroy(pClass); // Remove class /sys/class/kmem
unregister_chrdev(majorNum, DEVICE_NAME); // Unregister the device
} // end of devkoExit

WINAPI C - CreateFileMapping fails with error 8 - ERROR_NOT_ENOUGH_MEMORY

I'm working with file mappings on Windows but having some troubles with them.
First off, I have the necessity to partially map a file and setting the start and the end of it dynamically.
My code is the following:
long fiveMB = 5 * pow(2, 20);
for(int i=0;i<parts;i++){
long start = (i)*fiveMB;
long end = (i + 1)*fiveMB;
long realEnd = end;
if (roundedDim<realEnd)
realEnd = dim;
long chunkDim = realEnd - start;
LARGE_INTEGER fileMapStart.QuadPart = (start/granularity)*granularity;
LARGE_INTEGER mapViewSize.QuadPart = (start%granularity) + chunkDim;
LARGE_INTEGER fileMapSize.QuadPart = start + chunkDim;
long offset = start - fileMapStart.QuadPart;
HANDLE fileMappingH= CreateFileMapping(fileH, NULL, PAGE_READONLY, fileMapSize.HighPart, fileMapSize.LowPart, NULL);
if(fileMappingH == INVALID_HANDLE_VALUE || fileMappingH == NULL){
printf("Error mapping file: %d\n",GetLastError());
CloseHandle(fileH);
return 1;
}
char *mapView = (char *)MapViewOfFile(fileMappingH, FILE_MAP_READ, fileMapStart.HighPart, fileMapStart.LowPart, mapViewSize.QuadPart);
if ((LPVOID)mapView == NULL) {
printf("Error mapView: %d\n", GetLastError());
CloseHandle(fileMappingH);
CloseHandle(file);
return 1;
}
mapView += offset;
/* doing all the stuff */
UnmapViewOfFile((LPVOID)mapView);
CloseHandle(fileMappingH);
}
As far as I know, only MapViewOfFile requires the starting byte to be aligned with the system granularity, so I didn't bother to fix the maximum file mapping size for that.
I tried this code on a 1448 KB file (printing out dim I get 1482159 bytes) while calculating the available memory via GlobalMemoryStatusEx(&memstatus) and memstatus.ullAvailVirtual I get 2092208128 bytes but still stuck on having the CreateFileMapping call failed and with error code 8, ERROR_NOT_ENOUGH_MEMORY.
I also tried calling CreateFileMapping(fileH, NULL, PAGE_READONLY, 0, 0, NULL) to memory map the whole file, but instead there were problems on MapViewOfFile, error 5, ERROR_ACCESS_DENIED.
I don't understand what I'm doing wrong here, since I successfully did it with mmap on a Linux version of the same project.
Thanks anyone who may help.
EDITS:
c was a leftover, I actually meant i
added UnmapViewOfFile and CloseHandle calls
As far as I know, MapViewOfFile only requires the starting byte to be
aligned with the system granularity, so I didn't bother to fix the
maximum file mapping size for that.
this is root of error - really from MapViewOfFile
dwNumberOfBytesToMap [in]
The number of bytes of a file mapping to map to the view. All bytes
must be within the maximum size specified by CreateFileMapping. If
this parameter is 0 (zero), the mapping extends from the specified
offset to the end of the file mapping.
if we use 0 as MaximumSize in CreateFileMapping the maximum size of the file mapping object is equal to the current size of the file. and :
if an application specifies a size for the file mapping object that is
larger than the size of the actual named file on disk and if the
page protection allows write access (that is, the flProtect
parameter specifies PAGE_READWRITE or PAGE_EXECUTE_READWRITE),
then the file on disk is increased to match the specified size of the
file mapping object.
and about GetLastError and win32 errors at all. the errors in most case returned from kernel as NTSTATUS code. the win32 layer converts the specified NTSTATUS code to its equivalent system error code via RtlNtStatusToDosError. unfortunately this conversion not injective - the many different NTSTATUS code can convert to same win32 error and we lost sensitive info here.
so in some case much more better call RtlGetLastNtStatus() instead of GetlastError() - this give to as much more info about error.
CreateFileMapping call failed and with error code
ERROR_NOT_ENOUGH_MEMORY.
based on error ERROR_NOT_ENOUGH_MEMORY we can think that not enough memory in system (STATUS_NO_MEMORY). but also another status - STATUS_SECTION_TOO_BIG converted to the ERROR_NOT_ENOUGH_MEMORY. the CreateFileMapping is thin shell over ZwCreateSection the STATUS_SECTION_TOO_BIG returned when:
The value of MaximumSize is too big. This occurs when either
MaximumSize is greater than the system-defined maximum for sections, or if MaximumSize is greater than the specified file and the
section is not writable.
and this is exactly your case: you use PAGE_READONLY in call CreateFileMapping - so section is not writable and fileMapSize is greater than the specified file (size for the file mapping object that is larger than the size of the actual file on disk)
MapViewOfFile return ERROR_ACCESS_DENIED.
again GetLastError() plays here with us a cruel joke. the initial status is not STATUS_ACCESS_DENIED how we can wait, but STATUS_INVALID_VIEW_SIZE. this status also converted to ERROR_ACCESS_DENIED. the MapViewOfFile got it when not all bytes within the maximum size specified by CreateFileMapping
and call CreateFileMapping multiple time in loop - this is design error - need call this api only once, before loop. in loop only exist sense call MapViewOfFile. the test code can be:
void TestMap(PCWSTR lpFileName, ULONG dwChunkSize)
{
HANDLE hFile = CreateFileW(lpFileName, FILE_GENERIC_READ, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
FILE_STANDARD_INFO fsi;
if (GetFileInformationByHandleEx(hFile, FileStandardInfo, &fsi, sizeof(fsi)))
{
if (HANDLE hSection = CreateFileMappingW(hFile, 0, PAGE_READONLY, 0, 0, 0))
{
if (ULONG n = (ULONG)((fsi.EndOfFile.QuadPart + (dwChunkSize - 1)) / dwChunkSize))
{
LARGE_INTEGER ofs = {};
do
{
if (PVOID pv = MapViewOfFile(hSection, FILE_MAP_READ, ofs.HighPart, ofs.LowPart, --n ? dwChunkSize : 0))
{
UnmapViewOfFile(pv);
}
else
{
RtlGetLastNtStatus();
}
} while (ofs.QuadPart += dwChunkSize, n);
}
CloseHandle(hSection);
}
else
{
RtlGetLastNtStatus();
}
}
CloseHandle(hFile);
}
else
{
RtlGetLastNtStatus();
}
}

Using BASS_StreamCreateFile in WPF

BASS_StreamCreateFile(path,offset,length,BassFlags) always returns '0'. I am not understanding how to use this function. Need help on the usage of BassFlags.
PS : Using this with the help of WPF Sound Visualization Library.
Since 0 only informs you that there's an error, you should check what kind of error it is:
int BASS_ErrorGetCode();
This gives you the errorcode for the recent error.
Here's the list of possible error codes (= return values):
BASS_ERROR_INIT // BASS_Init has not been successfully called.
BASS_ERROR_NOTAVAIL // Only decoding channels (BASS_STREAM_DECODE) are allowed when using the "no sound" device. The BASS_STREAM_AUTOFREE // flag is also unavailable to decoding channels.
BASS_ERROR_ILLPARAM // The length must be specified when streaming from memory.
BASS_ERROR_FILEOPEN // The file could not be opened.
BASS_ERROR_FILEFORM // The file's format is not recognised/supported.
BASS_ERROR_CODEC // The file uses a codec that is not available/supported. This can apply to WAV and AIFF files, and also MP3 files when using the "MP3-free" BASS version.
BASS_ERROR_FORMAT // The sample format is not supported by the device/drivers. If the stream is more than stereo or the BASS_SAMPLE_FLOAT flag is used, it could be that they are not supported.
BASS_ERROR_SPEAKER // The specified SPEAKER flags are invalid. The device/drivers do not support them, they are attempting to assign a stereo stream to a mono speaker or 3D functionality is enabled.
BASS_ERROR_MEM // There is insufficient memory.
BASS_ERROR_NO3D // Could not initialize 3D support.
BASS_ERROR_UNKNOWN // Some other mystery problem!
(from bass.h)
Also make shure you have initialised BASS properly - BASS_Init() must get called before you create a stream:
BOOL BASS_Init(
int device, // The device to use... -1 = default device, 0 = no sound, 1 = first real output device
DWORD freq, // Output sample rate
DWORD flags, // A combination of flags
HWND win, // The application's main window... 0 = the current foreground window (use this for console applications)
GUID *clsid // Class identifier of the object to create, that will be used to initialize DirectSound... NULL = use default
);
Example:
int device = -1; // Default device
int freq = 44100; // Sample rate
BASS_Init(device, freq, 0, 0, NULL); // Init BASS

How do I create a "netlink" between kernel and userspace?

I want to use netlink to communicate between an application and kernel space. My Linux kernel version is 2.6.28, and the following is my wrong code:
nf_sock=netlink_kernel_create(NL_PROTO,0,nl_user_skb,THIS_MODULE);
The abbreviated error message is:
error: too few arguments to function 'netlink_kernel_create'
In the file <linux/netlink.h>, the function netlink_kernel_create() is defined as
extern struct sock *netlink_kernel_create(struct net *net,int unit,unsigned int groups,void (*input)(struct sk_buff *skb),struct mutex *cb_mutex,struct module *module)
I don't understand what to use for the first argument, net. Can someone explain what I should use here?
A struct net contains information about the network namespace, a set of network resources available to processes. Note that there could be multiple network namespaces (i.e. multiple instances of the networking stack), but most drivers use the init_net namespace.
Your call should probably look something like the following
nf_sock = netlink_kernel_create(&init_net,
NETLINK_USERSOCK,
0,
nl_rcv_func,
NULL,
THIS_MODULE);
where nl_rcv_func is a function taking struct sk_buff *skb as the only argument and processes the received netlink message.
You seem to have been following a guide such as this one, which (being from 2005) might well have been outpaced by the development of the kernel. It seems the internal API to create a netlink from the kernel side has changed.
Either check the Documentation/ folder in your local kernel tree for some (hopefully fresher) documentation, or read the code itself. You could also trawl the Linux Kernel mailing list archives for any mention of the changes that seem to have happened.
Here is the actual implemntation as of 2.6.29, if you'd rather puzzle it out backwards (and haven't already checked this in your own tree, of course).
Yes, struct net is indeed for net namespace, but it is not proper to always use init_net, you should register your own pernet_operations, like this:
static struct pernet_operations fib_net_ops = {
.init = fib_net_init,
.exit = fib_net_exit,
};
static int __net_init fib_net_init(struct net *net)
{
int error;
#ifdef CONFIG_IP_ROUTE_CLASSID
net->ipv4.fib_num_tclassid_users = 0;
#endif
error = ip_fib_net_init(net);
if (error < 0)
goto out;
error = nl_fib_lookup_init(net);
if (error < 0)
goto out_nlfl;
error = fib_proc_init(net);
if (error < 0)
goto out_proc;
out:
return error;
out_proc:
nl_fib_lookup_exit(net);
out_nlfl:
ip_fib_net_exit(net);
goto out;
}
static int __net_init nl_fib_lookup_init(struct net *net)
{
struct sock *sk;
struct netlink_kernel_cfg cfg = {
.input = nl_fib_input,
};
sk = netlink_kernel_create(net, NETLINK_FIB_LOOKUP, &cfg);
if (sk == NULL)
return -EAFNOSUPPORT;
net->ipv4.fibnl = sk;
return 0;
}
and finally:
register_pernet_subsys(&fib_net_ops);
I would suggest ioctl for kernel/user communication. The ioctl interface is standard and the chance of been updated between kernels is small.

Resources