Function Interposing on OSX Mavericks - osx-mavericks

I followed the directions exactly as they are on this site here
http://www.newosxbook.com/src.jl?tree=listings&file=4-5-interpose.c
Here is the code from that page
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <malloc/malloc.h> // for malloc_printf()
// Note: Compile with GCC, not cc (important)
//
//
// This is the expected interpose structure
typedef struct interpose_s { void *new_func;
void *orig_func; } interpose_t;
// Our prototypes - requires since we are putting them in
// the interposing_functions, below
void *my_malloc(int size); // matches real malloc()
void my_free (void *); // matches real free()
static const interpose_t interposing_functions[] \
__attribute__ ((section("__DATA, __interpose"))) = {
{ (void *)my_free, (void *)free },
{ (void *)my_malloc, (void *)malloc }
};
void *
my_malloc (int size) {
// In our function we have access to the real malloc() -
// and since we don’t want to mess with the heap ourselves,
// just call it
//
void *returned = malloc(size);
// call malloc_printf() because the real printf() calls malloc()
// // internally - and would end up calling us, recursing ad infinitum
malloc_printf ( "+ %p %d\n", returned, size); return (returned);
}
void
my_free (void *freed) {
// Free - just print the address, then call the real free()
malloc_printf ( "- %p\n", freed); free(freed);
}
#if 0
From output 4-11:
morpheus#Ergo(~)$ gcc -dynamiclib l.c -o libMTrace.dylib -Wall // compile to dylib
morpheus#Ergo(~)$ DYLD_INSERT_LIBRARIES=libMTrace.dylib ls // force insert into ls
ls(24346) malloc: + 0x100100020 88
ls(24346) malloc: + 0x100800000 4096
ls(24346) malloc: + 0x100801000 2160
ls(24346) malloc: - 0x100800000
ls(24346) malloc: + 0x100801a00 3312 ... // etc.
#endif
Is there something different about the latest version of OSX or the code written here? It did not seem to intercept anything.

add attribute((used)) before the interposing_functions definition, and it will work, as follow:
// Note: Compile with GCC, not cc (important)
//
//
// This is the expected interpose structure
typedef struct interpose_s { void *new_func;
void *orig_func; } interpose_t;
// Our prototypes - requires since we are putting them in
// the interposing_functions, below
void *my_malloc(int size); // matches real malloc()
void my_free (void *); // matches real free()
__attribute__((used)) static const interpose_t interposing_functions[] \
__attribute__ ((section("__DATA, __interpose"))) = {
{ (void *)my_free, (void *)free },
{ (void *)my_malloc, (void *)malloc }
};
void *
my_malloc (int size) {
....

It's not a feature of Mavericks, it's a feature of clang. If you use jtool , from the same website, you'll see the generated dylib has no _DATA._interpose, which is required for DYLD to work the interposition magic.
Incidentally, this question is best asked in that book's own forum. That's probably what it's there for.

Related

Freeing an already allocated memory by C.free(unsafe.Pointer) is crashing my program

I'm calling C APIs defined in another C library (main.dll) from my go code using cgo. The C API returns a ApiResponse pointer which populates error code and message. The memory for ApiResponsePtr is allocated by C API. After using this, when I call C.free to free the allocated memory, it crashes.
Crash log says : exit status 0xc0000374
Below is the working code, which can be used as it is.
Note I've used MSVC to create a main.dll from the main.c and main.h file. The same main.dll is linked in my go code.
main.go
package main
/*
#cgo CFLAGS: -g -Wall
#cgo CFLAGS: -I./
#cgo LDFLAGS: -L./ -lmain
#include <stdlib.h>
#include "main.h"
*/
import "C"
import (
"fmt"
"os"
"unsafe"
)
func main() {
var apiResponse *C.ApiResponse
var instanceID *C.char
property := C.CString(".\\properties")
defer C.free(unsafe.Pointer(property))
apiResponse = C.create_instance(property, &instanceID)
id := C.GoString(instanceID)
// I'm able to access data from apiResponse
stat := int32(apiResponse.status)
fmt.Println("status : ", stat)
fmt.Println("response : ", C.GoString(apiResponse.response))
fmt.Println("instanceID : ", id)
fmt.Println("Before call to free apiResponse")
// When I call free of the allocated memory, its crashing
C.free(unsafe.Pointer(apiResponse))
fmt.Println("After call to free apiResponse")
os.Exit(0)
}
main.c
#include <stdio.h>
#include <stdlib.h>
#include "main.h"
void GetInstaceID(char ** instanceID)
{
char * temp = NULL;
if(instanceID) {
temp = (char *) malloc(sizeof(char) * MAX_LEN_ID);
if(temp){
memset(temp, 0, MAX_LEN_ID);
strncpy(temp, "ABC-XYX-1234", MAX_LEN_ID-1);
}
*instanceID = temp;
}
}
ApiResponsePtr create_instance(char * property, char ** instanceID)
{
ApiResponsePtr ptr = NULL;
ptr = (ApiResponse *) calloc(1, sizeof(ApiResponse));
// Internally it allocates memory for instanceID and fill ID
GetInstaceID(instanceID);
// Do other stuff
// Fill ptr
ptr->status = 0;
ptr->response = (char *)malloc(MAX_STATUS_LEN * sizeof(char));
if(ptr->response) {
strncpy(ptr->response, "Success", MAX_STATUS_LEN-1); //hardcoding response as Success, actual would decide based on status
}
return ptr;
}
main.h
#ifndef MAIN_H_
#define MAIN_H_
#define MAX_LEN_ID 30
#define MAX_STATUS_LEN 64
//#define INSTANCE_ID "ABC-XYX-1234" // hard coding here, actual code would generate it
typedef struct api_response_t
{
int status; /*!< \details API status code */
char * response; /*!< \details API response message */
} ApiResponse, *ApiResponsePtr;
ApiResponsePtr create_instance(char * property, char ** instanceID);
#endif

Boost asio: including <arpa/inet.h> causes socket to always output 0 bytes

I'm trying to include <arpa/inet.h> in a low-level library so that I have access to hton* and ntoh* functions in the library. The low-level library gets called into by higher-level code running a Boost asio socket. I'm aware Boost asio contains the hton* and ntoh* functions, but i'd like to avoid linking all of Boost asio to the library since hton*/ntoh* are all I need.
However, if I simply include <arpa/inet.h> in the low-level library, 0 bytes always will be sent from the Boost asio socket. Confirmed by Wireshark.
Here's the class where i'd like to include <arpa/inet.h> but not Boost. If <arpa/inet.h> is included, 0 bytes will be sent.
#pragma pack(push, 1)
#include "PduHeader.h"
#include <arpa/inet.h>
class ClientInfoPdu
{
public:
ClientInfoPdu(const uint16_t _client_receiver_port)
{
set_client_receiver_port(_client_receiver_port);
}
PduHeader pdu_header{CLIENT_INFO_PDU, sizeof(client_receiver_port)};
inline void set_client_receiver_port(const uint16_t _client_receiver_port)
{
//client_receiver_port = htons(_client_receiver_port);
client_receiver_port = _client_receiver_port;
}
inline uint16_t get_client_receiver_port()
{
return client_receiver_port;
}
inline size_t get_total_size()
{
return sizeof(PduHeader) + pdu_header.get_pdu_payload_size();
}
private:
uint16_t client_receiver_port;
};
#pragma pack(pop)
Here's the higher level code that includes Boost and attempts to send the data via a socket. The printout indicates 5 bytes were sent, however 0 bytes were actually sent.
#include "ServerConnectionThread.h"
#include "config/ClientConfig.h"
#include "protocol_common/ClientInfoPdu.h"
#include <boost/asio.hpp>
#include <unistd.h>
using boost::asio::ip::udp;
void ServerConnectionThread::execute()
{
boost::asio::io_service io_service;
udp::endpoint remote_endpoint =
udp::endpoint(boost::asio::ip::address::from_string(SERVER_IP), SERVER_PORT);
udp::socket socket(io_service);
socket.open(udp::v4());
ClientInfoPdu client_info_pdu = ClientInfoPdu(RECEIVE_PORT);
while (true)
{
uint16_t total_size = client_info_pdu.get_total_size();
socket.send_to(boost::asio::buffer(&client_info_pdu, total_size), remote_endpoint);
printf("sent %u bytes\n", total_size);
usleep(1000000);
}
}
Again, simply removing "#include <arpa/inet.h>" will cause this code to function as expected and send 5 bytes per packet.
How is ClientInfoPdu defined? This looks like it is likely UB:
boost::asio::buffer(&client_info_pdu, total_size)
The thing is total size is sizeof(PduHeader) + pdu_header.get_pdu_payload_size() (so sizeof(PduHeader) + 2);
First problem is that you're mixing access modifiers, killing the POD/standard_layout properties of your types.
#include <type_traits>
static_assert(std::is_standard_layout_v<PduHeader> && std::is_trivial_v<PduHeader>);
static_assert(std::is_standard_layout_v<ClientInfoPdu> && std::is_trivial_v<ClientInfoPdu>);
This will fail to compile. Treating the types as POD (as you do) invokes
Undefined Behaviour.
This is likely the explanation for the fact that "it stops working" with some changes. It never worked: it might just accidentally have appeared to work, but it was undefined behaviour.
It's not easy to achieve POD-ness while still getting the convenience of the
constructors. In fact, I don't think that's possible. In short, if you want to
treat your structs as C-style POD types, make them... C-style POD types.
Another thing: a possible implementation of `PduHeader I
can see working for you looks a bit like so:
enum MsgId{CLIENT_INFO_PDU=0x123};
struct PduHeader {
MsgId id;
size_t payload_size;
size_t get_pdu_payload_size() const { return payload_size; }
};
Here, again you might have/need endianness conversions.
Suggestion
In short, if you want this to work, I'd say keep it simple.
Instead of creating non-POD types all over the place that are responsible for endianness conversion by adding getters/setters for each value, why not create a simple user-defined-type that does this always, and use them instead?
struct PduHeader {
Short id; // or e.g. uint8_t
Long payload_size;
};
struct ClientInfoPdu {
PduHeader pdu_header; // or inheritance, same effect
Short client_receiver_port;
};
Then just use it as a POD struct:
while (true) {
ClientInfoPdu client_info_pdu;
init_pdu(client_info_pdu);
auto n = socket.send_to(boost::asio::buffer(&client_info_pdu, sizeof(client_info_pdu)), remote_endpoint);
printf("sent %lu bytes\n", n);
std::this_thread::sleep_for(1s);
}
The function init_pdu can be implemented with overloads per submessage:
void init_pdu(ClientInfoPdu& msg) {
msg.pdu_header.id = CLIENT_INFO_PDU;
msg.pdu_header.payload_size = sizeof(msg);
}
There are variations on this where it can become a template or take a
PduHeder& (if your message inherits instead of aggregates). But the basic
principle is the same.
Endianness Conversion
Now you'll noticed I avoided using uint32_t/uint16_t directly (though uint8_t is fine because it doesn't need byte ordering). Instead, you could define Long and Short as simple POD wrappers around them:
struct Short {
operator uint16_t() const { return ntohs(value); }
Short& operator=(uint16_t v) { value = htons(v); return *this; }
private:
uint16_t value;
};
struct Long {
operator uint32_t() const { return ntohl(value); }
Long& operator=(uint32_t v) { value = htonl(v); return *this; }
private:
uint32_t value;
};
The assignment and conversions mean that you can use it as just another
int32_t/int16_t except that the necessary conversions are always done.
If you want to satnd on the shoulder of giants instead, you can use the better types from Boost Endian, which also has lots more advanced facilities
DEMO
Live On Coliru
#include <type_traits>
#include <cstdint>
#include <thread>
#include <arpa/inet.h>
using namespace std::chrono_literals;
#pragma pack(push, 1)
enum MsgId{CLIENT_INFO_PDU=0x123};
struct Short {
operator uint16_t() const { return ntohs(value); }
Short& operator=(uint16_t v) { value = htons(v); return *this; }
private:
uint16_t value;
};
struct Long {
operator uint32_t() const { return ntohl(value); }
Long& operator=(uint32_t v) { value = htonl(v); return *this; }
private:
uint32_t value;
};
static_assert(std::is_standard_layout_v<Short>);
static_assert(std::is_trivial_v<Short>);
static_assert(std::is_standard_layout_v<Long>);
static_assert(std::is_trivial_v<Long>);
struct PduHeader {
Short id; // or e.g. uint8_t
Long payload_size;
};
struct ClientInfoPdu {
PduHeader pdu_header; // or inheritance, same effect
Short client_receiver_port;
};
void init_pdu(ClientInfoPdu& msg) {
msg.pdu_header.id = CLIENT_INFO_PDU;
msg.pdu_header.payload_size = sizeof(msg);
}
static_assert(std::is_standard_layout_v<PduHeader> && std::is_trivial_v<PduHeader>);
static_assert(std::is_standard_layout_v<ClientInfoPdu> && std::is_trivial_v<ClientInfoPdu>);
#pragma pack(pop)
#include <boost/asio.hpp>
//#include <unistd.h>
using boost::asio::ip::udp;
#define SERVER_IP "127.0.0.1"
#define SERVER_PORT 6767
#define RECEIVE_PORT 6868
struct ServerConnectionThread {
void execute() {
boost::asio::io_service io_service;
udp::endpoint const remote_endpoint =
udp::endpoint(boost::asio::ip::address::from_string(SERVER_IP), SERVER_PORT);
udp::socket socket(io_service);
socket.open(udp::v4());
while (true) {
ClientInfoPdu client_info_pdu;
init_pdu(client_info_pdu);
auto n = socket.send_to(boost::asio::buffer(&client_info_pdu, sizeof(client_info_pdu)), remote_endpoint);
printf("sent %lu bytes\n", n);
std::this_thread::sleep_for(1s);
}
}
};
int main(){ }

sys v shared memory from kernel module to user space process

i am new in linux kernel module developpement and i am searching for sharing a memory segment from kernel module to user space process to escape latency of copying data.
i am using the sys v shared memory api, when i share memory between two process it's work fine, but i am not able to share memory between process and kernel module.
bellow is my code of the kernel module and the user space app
server side : module
#include <linux/module.h> // init_module, cleanup_module //
#include <linux/kernel.h> // KERN_INFO //
#include <linux/types.h> // uint64_t //
#include <linux/kthread.h> // kthread_run, kthread_stop //
#include <linux/delay.h> // msleep_interruptible //
#include <linux/syscalls.h> // sys_shmget //
#define BUFSIZE 100
#define SHMSZ BUFSIZE*sizeof(char)
key_t KEY = 5678;
static struct task_struct *shm_task = NULL;
static char *shm = NULL;
static int shmid;
static int run_thread( void *data )
{
char strAux[BUFSIZE];
shmid = sys_shmget(KEY, SHMSZ, IPC_CREAT | 0666);
if( shmid < 0 )
{
printk( KERN_INFO "SERVER : Unable to obtain shmid\n" );
return -1;
}
shm = sys_shmat(shmid, NULL, 0);
if( !shm )
{
printk( KERN_INFO "SERVER : Unable to attach to memory\n" );
return -1;
}
strncpy( strAux, "hello world from kernel module", BUFSIZE );
memcpy(shm, strAux, BUFSIZE);
return 0;
}
int init_module()
{
printk( KERN_INFO "SERVER : Initializing shm_server\n" );
shm_task = kthread_run( run_thread, NULL, "shm_server" );
return 0;
}
void cleanup_module()
{
int result;
printk( KERN_INFO "SERVER : Cleaning up shm_server\n" );
result = kthread_stop( shm_task );
if( result < 0 )
{
printk( KERN_INFO "SERVER : Unable to stop shm_task\n" );
}
result = sys_shmctl( shmid, IPC_RMID, NULL );
if( result < 0 )
{
printk( KERN_INFO
"SERVER : Unable to remove shared memory from system\n" );
}
}
MODULE_LICENSE( "GPL" );
MODULE_AUTHOR( " MBA" );
MODULE_DESCRIPTION( "Shared memory server" );
client side : process
#include <sys/ipc.h> // IPC_CREAT, ftok //
#include <sys/shm.h> // shmget, ... //
#include <sys/sem.h> // semget, semop //
#include <stdio.h> // printf //
#include <string.h> // strcpy //
#include <stdint.h> // uint64_t //
#define BUFSIZE 4096
key_t KEY = 5678;
int main(int argc, char *argv[]) {
int shmid, result;
char *shm = NULL;
shmid = shmget(KEY, BUFSIZE, 0666);
if (shmid == -1) {
perror("shmget");
exit(-1);
}
shm = shmat(shmid, NULL, 0);
if (!shm) {
perror("shmat");
exit(-1);
}
printf("%s\n", shm);
result = shmdt(shm);
if (result < 0) {
perror("shmdt");
exit(-1);
}
}
any suggestion or document can help.
System calls are not intended for being use by the kernel: they are for user programs only. Also, it is unlikely that is sys v memory sharing works for kernel threads.
Kernel and kernel modules have their own mechanism for interract with user
space. For sharing memory, your kernel module may implement character device and mmap method for it, which maps kernel's allocated memory to user. See example of such mmap implementation in Linux Device Drivers(3d edition), Chapter 15.

User space netlink socket receives empty messages from kernel space

Disclaimer - I have to admit that it's the 1'st time I'm using this kernel interface (socket).
I'm currently working on a design of a kernel module that is based on a netlink socket .
I'm using Ubuntu14.04 and linux kernel 4.
As a starter, I wanted to make sure that I can use the netlink socket in both directions.
I've written an application that does the following:
1) User send a message to kernel via the netlink socket.
2) Kernel, upon receiving the message – sends "ABCD" string message to a workqueue.
3) When the "ABCD" message is received by the workqueue, it calls a function (named - my_wq_function) which send it back to the user space via netlink socket.
4) In the user space I'm using a recvmsg function (blocking until a message is received) and displays the "ABCD" message.
My problem is that the return value from the recvmsg function is 20 (instead of 4), and the data itself (i.e. NLMSG_DATA) is empty.
During the debug I tried to change the message to "ABCD1234" and got a return value of 24 bytes, however the data is still empty.
I also verified that my entire path until the point of sending the "ABCD" from kernel to the socket is OK.
Not sure what I'm doing wrong here & will highly appreciate your help.
Thanks in advance, MotiC.
my code example can be found below:
User space code:
printf("netlink receiver thread started...\n");
nlh_rcv = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
while(true) //endless loop on netlink socket
{
memset(nlh_rcv, 0, NLMSG_SPACE(MAX_PAYLOAD));
iov_rcv.iov_base = (void *)nlh_rcv;
iov_rcv.iov_len = nlh_rcv->nlmsg_len;
msg_rcv.msg_name = (void *)&dest_addr;
msg_rcv.msg_namelen = sizeof(dest_addr);
msg_rcv.msg_iov = &iov;
msg_rcv.msg_iovlen = 1;
ret=recvmsg(sock_fd, &msg_rcv, 0);
printf("errno=%i bytes=%i message from kernel: %s\n",errno, ret, (char*)NLMSG_DATA(nlh_rcv));
uint8_t mymsg[100];
memcpy(mymsg, NLMSG_DATA(nlh_rcv), 100);
printf("message from kernel: %s\n",mymsg);
}
Kernel space code:
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/init.h> /* Needed for the macros */
#include <net/sock.h>
#include <linux/socket.h>
#include <linux/net.h>
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>
#include <linux/workqueue.h>
MODULE_LICENSE("GPL");
#include "rf_Kdriver_main.h"
//------ definitions ------------------------------------------------------------------------------------------------------------
#define NETLINK_USER 31
#define MAX_PAYLOAD 1024 /* maximum payload size*/
struct sock *nl_sk = NULL;
struct nlmsghdr *nlh;
struct nlmsghdr *nlh_out;
struct sk_buff *skb_out;
char buf_to_user[100];
int pid;
//------------------------------------------------------------------------------------------------------------------------------
struct workqueue_struct *my_wq;
typedef struct {
struct work_struct my_work;
uint8_t msg_to_pc[128];
uint8_t msg_len;
} my_work_t;
my_work_t *work, *work2;
//-----------------------------------------------------------------------------------------------------------------------------
static void my_wq_function( struct work_struct *work)
{
int res;
my_work_t *my_work = (my_work_t *)work;
skb_out = nlmsg_new(my_work->msg_len,0);
if (!skb_out)
{
printk("Failed to allocate new skb\n");
return;
}
nlh_out = nlmsg_put(skb_out, 0, 0, NLMSG_DONE,my_work->msg_len, 0);
NETLINK_CB(skb_out).dst_group = 0;
memcpy((char*)NLMSG_DATA(nlh_out), my_work->msg_to_pc , my_work->msg_len);
printk( "dequeue message to pc=%s len=%i\n", (char*)NLMSG_DATA(nlh_out), (int)strlen((char*)NLMSG_DATA(nlh_out)));
res = nlmsg_unicast(nl_sk, skb_out, pid);
if (res<0)
printk("Failed to send message from kernel to user\n");
kfree( (void *)work );
return;
}
//-----------------------------------------------------------------------------------------------------------------------------
int send_up_msg_to_workque(uint8_t msg_to_pc[], uint8_t msg_len)
{
int ret=0;
work = (my_work_t *)kmalloc(sizeof(my_work_t), GFP_KERNEL);
if (work) {
INIT_WORK( (struct work_struct *)work, my_wq_function );
memcpy(work->msg_to_pc, msg_to_pc, msg_len);
work->msg_len = msg_len;
ret = queue_work( my_wq, /*(struct work_struct *)RR*/work );
printk("kuku ret=%i msg=%s\n",ret,work->msg_to_pc);
}
return ret;
}
//------------------------------------------------------------------------------------------------------------------------------
static void netlink_recv_msg(struct sk_buff *skb)
{
char *msg = "ABCD1234";
printk(KERN_INFO "Entering: %s\n", __FUNCTION__);
nlh=(struct nlmsghdr*)skb->data;
printk(KERN_INFO "Netlink at kernel received msg payload: %s\n",(char*)NLMSG_DATA(nlh));
//rr
pid = nlh->nlmsg_pid;
send_up_msg_to_workque((uint8_t*) msg, strlen(msg));
}
//-------------------------------------------------------------------------------------------------------------------------------------
struct netlink_kernel_cfg cfg = {
.input = netlink_recv_msg,
};
static int __init rf_driver_start(void)
{
printk(KERN_INFO "Loading RF Driver module1...\n");
my_wq = create_workqueue("my_queue");
if (!my_wq)
{
printk("Failed to create work queue\n");
}
printk("Entering: %s\n",__FUNCTION__);
nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, &cfg);
if(!nl_sk)
{
printk(KERN_ALERT "Error creating socket.\n");
return -10;
}
return 0;
}
//--------------------------------------------------------------------------------------------------------------
static void __exit rf_driver_end(void)
{
netlink_kernel_release(nl_sk);
flush_workqueue(my_wq);
destroy_workqueue(my_wq);
printk(KERN_INFO "RF Driver exit...\n");
}
module_init(rf_driver_start);
module_exit(rf_driver_end);
Update,
I changed my user space function to:
char buf[100];
ret=recv(sock_fd, buf, 100, 0);
instead of:
ret=recvmsg(sock_fd, &msg_rcv, 0);
and it works...
does anyone have an idea regarding this strange behavior ?
Thanks.
Can you please paste complete userspace code.
I guess 'len' int this code is the issue:
memset(nlh_rcv, 0, NLMSG_SPACE(MAX_PAYLOAD));
iov_rcv.iov_len = nlh_rcv->nlmsg_len; << check to what value is it getting initialized.

How to create proc entry under /proc/driver?

I want to create a file under a /proc/driver directory. I would like to use a macro like proc_root_driver (or something else provided) rather than use "driver/MODULE_NAME" explicitly. I use create_proc_entry :
struct proc_dir_entry *simpleproc_fops_entry;
simpleproc_fops_entry = create_proc_entry(MODULE_NAME, 0400, NULL /* proc_root_dir */);
After googling, I found suggestion to use proc_root_driver, but when I use it, I get the error
proc_root_driver undeclared in this function
And also, proc_root_driver is not available in linux/proc_fs.h.
I have tried to declare structure like this:
struct proc_dir_entry proc_root;
struct proc_dir_entry *proc_root_driver = &proc_root;
The compilation errors gone, but the file didn't appear under /proc/driver or /proc. How can I make create an entry in /proc?
Looking at proc_fs.h, proc_root_driver is defined as :
extern struct proc_dir_entry *proc_root_driver;
so long as CONFIG_PROC_FS is enabled. If you have CONFIG_PROC_FS selected when you configure your kernel, you should be able to use it as you suggested yourself i.e. :
#include <linux/proc_fs.h>
struct proc_dir_entry * procfile
procfile = create_proc_entry("myprocfile", 0400, proc_root_driver);
If this does not work, check that you have CONFIG_PROC_FS set. To make sure, you can compile your source file with the -E option and check that the create_proc_entry call includes a non NULL parameter as the last parameter. If it is NULL, or the call is not there at all, then CONFIG_PROC_FS is not enabled.
/* proc entries for ayyaz */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/major.h>
#include <linux/fs.h>
#include <linux/err.h>
#include <linux/ioctl.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#ifdef CONFIG_PROC_FS
/*====================================================================*/
/* Support for /proc/ayyaz */
static struct proc_dir_entry *proc_ayyaz;
DEFINE_MUTEX(ayyaz_table_mutex);
/*====================================================================*/
/* Init code */
static int ayyaz_read_proc (char *page, char **start, off_t off, int count,
int *eof, void *data_unused)
{
int len, l, i;
off_t begin = 0;
mutex_lock(&ayyaz_table_mutex);
len = sprintf(page, "hello ayyaz here\n");
mutex_unlock(&ayyaz_table_mutex);
if (off >= len+begin)
return 0;
*start = page + (off-begin);
return ((count < begin+len-off) ? count : begin+len-off);
}
static int __init init_ayyaz(void)
{
if ((proc_ayyaz = create_proc_entry( "ayyaz_maps", 0, NULL )))
proc_ayyaz->read_proc = ayyaz_read_proc;
return 0;
}
static void __exit cleanup_ayyaz(void)
{
if (proc_ayyaz)
remove_proc_entry( "ayyaz", NULL);
}
module_init(init_ayyaz);
module_exit(cleanup_ayyaz);
#else
#error "Please add CONFIG_PROC_FS=y in your .config "
#endif /* CONFIG_PROC_FS */
MODULE_LICENSE("proprietary");
MODULE_AUTHOR("Md.Ayyaz A Mulla <md.ayyaz#gmail.com>");
MODULE_DESCRIPTION("proc files for ayyaz");
Compile this driver. If it compiles sucessfully, then you will see /proc/ayyaz.
#define PROC_ENTRY_NAME "driver/XX"
static struct proc_dir_entry *proc_XX;
static int XX_read_proc (char *page, char **start, off_t off, int count,
int *eof, void *data_unused)
{
return 0;
}
static int XX_write_proc (struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
return 0;
}
static int __init XX_add_driver(void)
{
if ((proc_flash = XX_entry(PROC_ENTRY_NAME, 0, NULL))) {
proc_XX->read_proc = XX_read_proc;
proc_XX->write_proc = XX_write_proc;
}
...
}
static void __exit XX_remove(void)
{
if (proc_flash)
remove_proc_entry(PROC_ENTRY_NAME, NULL);
return;
}
Then you can find the /proc/driver/XX entry.

Resources