View Full Version : Problemi con netlink
mentre cercavo di capire come usare connector ho trovato un articolo su netlink che mi sembrava molto chiaro.
ho provato a implementarlo per comunicare una piccola stringa in userspace, ma ci sono ENORMI problemi :D
al caricamento del modulo parte (tra le altre che però sono di certo corrette) questo:
static void create_socket(){
int err;
nl_sk = netlink_kernel_create(NETLINK_MINOX, 1, nl_data_ready, THIS_MODULE);
skb = skb_recv_datagram(nl_sk, 0, 0, &err);
nlh = (struct nlmsghdr *)skb->data;
pid = nlh->nlmsg_pid;
}
data ready viene direttamente dall'articolo, e sinceramente non capisco a che mi serva...
comuque è definita così:
static void nl_data_ready (struct sock *sk, int len)
{
wake_up_interruptible(sk->sk_sleep);
}
ogni qual volta venga creata una socket internet viene poi chiamata questa funzione:
static int negotiate_auth(u32 app_pid, int auth_type){
char buf[MAX_PAYLOAD];
int err;
snprintf(buf, MAX_PAYLOAD, "%d", app_pid/*, auth_type*/);
if(nlh != NULL && skb != NULL){
strcpy(NLMSG_DATA(nlh), buf);
NETLINK_CB(skb).pid = 0;
NETLINK_CB(skb).dst_pid = pid;
NETLINK_CB(skb).dst_group = 0;
netlink_unicast(nl_sk, skb, pid, MSG_DONTWAIT);
skb = skb_recv_datagram(nl_sk, 0, 0, &err);
if(skb != NULL){
nlh = (struct nlmsghdr *)skb->data;
if(strcmp(NLMSG_DATA(nlh), ACCESS_PERMITTED) == 0){
return 0;
}
}
}
return -EPERM;
}
le variabili che non vedete qua probabilmente sono dei define o delle variabili globali.
il problema è che quando un processo apre una socket viene rilevato, e viene inviato il pid copiato due volte di seguito.
nel frattempo il programma che apre la socket va in segmentation fault, e dmesg si lamenta di aver trovaoto un puntatore nullo...
io ho cercato, ma nel mio codice non ne trovo...
qualcuno con più esperienza di me a usare netlink mi può dare una mano?
grazie, ciao!
su che siete capaci... :cry:
ilsensine
19-06-2006, 14:45
Puoi postare del codice minimale compilabile per riprodurre il problema?
appena torno a casa metto tutto il codice.
comunque il resto e` abbastanza banale.
il codice che esegue durante l'errore non fa altro che controllare che la connessione sia af_inet, dopo di che restituisce la negotiate (passando come parametri current-->pid e un enum).
la funzione e` chiamata utilizzando il linux security framework (anche se mi sa che alcune cose di selinux mi verrebbero piu` comode che non lfs), aganciandosi alla chiamata di creazione di socket.
ciao!
mmmmmh... insospettito dalla doppia scritta del pid ho tolto la sprintf e sembra andare tutto...
non posso usare le funzioni standard nei moduli?
ora la ho sostituita con una memcopy di una struttura e sembra andare.
ah, ultima cosa...
quando lancio il modulo compare questa linea su dmesg...
assertion (!atomic_read(&sk->sk_rmem_alloc)) failed at net/netlink/af_netlink.c (145)
.....
quanto mi devo preoccupare?
:sofico:
ho trovato questa patch
http://www.uwsg.iu.edu/hypermail/linux/net/0503.3/0033.html
mi posso fidare?
grazie di nuovo :)
ciao!
ilsensine
20-06-2006, 15:02
mmmmmh... insospettito dalla doppia scritta del pid ho tolto la sprintf e sembra andare tutto...
non posso usare le funzioni standard nei moduli?
Assolutamente no; ma il kernel fornisce le implementazioni per le funzioni più comuni (tra cui sprintf). Sostituire con memcopy non è la soluzione, hai aggirato (o mascherato) il problema in qualche maniera.
ah, ultima cosa...
quando lancio il modulo compare questa linea su dmesg...
assertion (!atomic_read(&sk->sk_rmem_alloc)) failed at net/netlink/af_netlink.c (145)
.....
quanto mi devo preoccupare?
:sofico:
Non ho idea. Semplicemente _non_ deve capitare.
ho trovato questa patch
http://www.uwsg.iu.edu/hypermail/linux/net/0503.3/0033.html
mi posso fidare?
Dal seguito del thread, dovrebbe essere stata applicata.
ciao!
Dal seguito del thread, dovrebbe essere stata applicata.
si, sembrava anche a me...
ma non c'e`...
ho controllato sul 2.6.16.20, non risulta applicata :mbe:
Assolutamente no; ma il kernel fornisce le implementazioni per le funzioni più comuni (tra cui sprintf). Sostituire con memcopy non è la soluzione, hai aggirato (o mascherato) il problema in qualche maniera.
forte!
mmmmh... hai delle letture da consigliarmi?
mi sono letto quasi tutto linux kernel internal, ma non ne parla.
ciao
ilsensine
20-06-2006, 15:31
Allora forse non è più necessaria.
Comunque se fosse un problema così comune sarebbe noto; più facile che c'è qualche errore nel tuo codice.
velocita impressionante :eek:
vedro` di risolvere :cool:
e per la seconda domanda? :smack:
:sofico:
edit: ho trovato tal struct_copy che ho sostituito alla memcpy, ma se hai delle indicazioni la domanda rimane valida per avere un riferimento pper altri casi ;)
ilsensine
20-06-2006, 16:56
cat NA01_br0ken_module.c
cat: NA01_br0ken_module.c: No such file or directory
cat NA01_br0ken_module.c
cat: NA01_br0ken_module.c: No such file or directory
:mbe:
:eek:
mi sa che non ho capito :p
ilsensine
20-06-2006, 18:50
-ENOENT
'ndo stanno i sorgenti che ti ho chiesto?
mmmmh... già :sofico:
tolte tuuuuttte le chiamate di libreria sembra andare in modo abbastanza stabile.
l'ultimo problema lo avevo causato io da idiota.
controllavo tutte le creazioni di socket, comprese le netlink. quindi provava a controllarsi da solo, e si comportava in modo abbastanza casuale.
il link al download te lo ho messo qui apposta per te (sei commosso? :sofico: )
www.minox.altervista.org/download.html
gli occhi del grande ilsensine sul codice sono sempre i benvenuti, anche perchè non ho mai scritto roba del genere :eek:
ha bisogno del linux security framework compilato come modulo (altrimenti si arrabbia davvero tanto :cool: ) e credo di null'altro.
per sostituire la memcpy avevo trovato la struct_cpy, ma sembra che sia saltata allegramente per problemi di portabilità :mbe:
si consigliava di usare memcpy, e effettivamente non sembra dare problemi.
l'altra cosa che mi è rimasta da sistemare è che se il demone secca il modulo non sa più fare nulla (e questo è ok), ma nemmeno riaccettare un'altra connessione (e questo è un pò meno ok :D).
bho, comunque sia suppongo di poter trovare una soluzione.
il client invece è ancora incasinato.
ho la versione semi funzionante che si andava a cercare il processo partendo dagli idirizzi di connessione tutto in userspace (che però era lento lento, in quanto doveva controllare tutto a ogni pacchetto), e ora devo sistemarlo per farlo andare con netlink (e dovrebbe essere molto più veloce dato che deve controllare solo sull'apertura della socket).
metto qui la versione scritta a babbo con vari copia e incolla a caso per provare il modulo:
il file netlink incluso differisce dall'originale solo per questa riga:
#define NETLINK_MINOX 19
#include <stdio.h>
#include <linux/init.h>
#include <linux/un.h>
#include <sys/un.h>
#include <sys/socket.h>
#include "/usr/src/linux-2.6.16.20/include/linux/netlink.h"
#define MAX_PAYLOAD 1024
struct sockaddr_nl src_addr, dst_addr;
struct nlmsghdr *nlh = NULL;
struct msghdr msg;
struct iovec iov;
int sock_fd;
struct Query{
int app_pid;
int request;
};
int main()
{
int app_pid, auth_type;
sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_MINOX);
memset(&src_addr, 0, sizeof(src_addr));
src_addr.nl_family = AF_NETLINK;
src_addr.nl_pid = getpid();
src_addr.nl_groups = 0;
bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));
memset(&dst_addr, 0, sizeof(dst_addr));
dst_addr.nl_family = AF_NETLINK;
dst_addr.nl_pid = 0;
dst_addr.nl_groups = 0;
nlh = (struct nlhmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
nlh->nlmsg_pid = getpid();
nlh->nlmsg_flags = 0;
strcpy(NLMSG_DATA(nlh), "Register");
iov.iov_base = (void *)nlh;
iov.iov_len = nlh->nlmsg_len;
msg.msg_name = (void *)&dst_addr;
msg.msg_namelen = sizeof(dst_addr);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
sendmsg(sock_fd, &msg, 0);
while(1){
int perm = 1;
fprintf(stderr,"In Attesa...\n");
recvmsg(sock_fd, &msg, 0);
fprintf(stderr,"Comunicazione: pid: %d --- %d\n",
(*((struct Query*)((NLMSG_DATA(nlh))))).app_pid ,
(*((struct Query*)((NLMSG_DATA(nlh))))).request);
memcpy(NLMSG_DATA(nlh), &perm, sizeof(int));
iov.iov_base = (void *)nlh;
iov.iov_len = nlh->nlmsg_len;
msg.msg_name = (void *)&dst_addr;
msg.msg_namelen = sizeof(dst_addr);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
sendmsg(sock_fd, &msg, 0);
}
memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
recvmsg(sock_fd, &msg, 0);
printf("Received message payload: %d\n", NLMSG_DATA(nlh));
close(sock_fd);
return 0;
}
grazie, ciao!
ilsensine
21-06-2006, 09:50
C'è ben poco in quel sorgente; comunque...
nl_sk = netlink_kernel_create(NETLINK_MINOX, 1, nl_wait, THIS_MODULE);
skb = skb_recv_datagram(nl_sk, 0, 0, &err);
netlink_kernel_create non può mai fallire?
netlink_unicast(nl_sk, skb, pid, MSG_DONTWAIT);
Come sopra
skb = skb_recv_datagram(nl_sk, 0, 0, &err);
Non bello. Stai bloccando indefinitamente in attesa dei comodi del programma in userspace. Peggio ancora, trattandosi comunque di datagrammi (seppur locali), possono andare persi senza notifica in rare situazioni (ad es. in situazioni di forte pressione di memoria).
Poi, ho visto che nei sorgenti non è più presente questa chicca:
static int negotiate_auth(u32 app_pid, int auth_type){
char buf[MAX_PAYLOAD];
...
Già mi aveva insospettito, poi ho visto il #define MAX_PAYLOAD 1024 e stavo per premere il pulsante ban. Ho visto però che quell'array non è presente nel modulo che hai messo online.
l'altra cosa che mi è rimasta da sistemare è che se il demone secca il modulo non sa più fare nulla (e questo è ok), ma nemmeno riaccettare un'altra connessione (e questo è un pò meno ok ).
Per me stai sbagliando design.
Inizialmente falla semplice; visto che un programma per aprire una connessione netlink ha comunque bisogno dei privilegi di root, potresti inizialmente trascurare la forzatura di dover conoscere il pid del demone. Semplicemente, invia il messaggio netlink; se un demone c'è (netlink_has_listeners) riceverai risposta (metti sempre un timeout -- hint: poll); altrimenti fai una azione di default.
Ultima cosa -- ho paura che in release il modulo va marcato come "permanente". Non credo possa essere rimosso con sicurezza, una volta caricato.
C'è ben poco in quel sorgente; comunque...
gia`, e` questo che mi ha esaltato :D
e` semplicissimo rispetto agli infiniti giri che devi fare in userspace per risalire al pid che ha creato il pacchetto. senza contare che in questo modo devi controllare solo le creazioni delle socket :cool:
netlink_kernel_create non può mai fallire?
nel mio codice no!!! :sofico:
no, scherzo.
non doveva nemmeno essere pubblicato, semplicemente volevo vedere se era davvero cosi` semplice.
Poi, ho visto che nei sorgenti non è più presente questa chicca:
static int negotiate_auth(u32 app_pid, int auth_type){
char buf[MAX_PAYLOAD];
...
uno scherzone per vedere se eri attento :cool:
nono, era solo la cosa piu` veloce che mi era venuta in mente ;)
avevo appena cancellato tutta la parte di comunicazione precedente, e mi ero accorto che
non avevo copie i backup :eek:
volevo essere certo di non aver fatto una cavolata il piu` presto possibile
Per me stai sbagliando design.
Inizialmente falla semplice; visto che un programma per aprire una connessione netlink ha comunque bisogno dei privilegi di root, potresti inizialmente trascurare la forzatura di dover conoscere il pid del demone. Semplicemente, invia il messaggio netlink; se un demone c'è (netlink_has_listeners) riceverai risposta (metti sempre un timeout -- hint: poll); altrimenti fai una azione di default.
bella storia... non sapevo nemmeno che si potesse :sofico:
ti faccio la solita domanda...
dove trovo della documentazione su netlink?
ho cercato netlink samples e netlink howto su google, ma ho trovato solo un esempietto di unicast e multicast da cui ho tirato fuori questo...
grazie, ciao!
ilsensine
21-06-2006, 10:46
dove trovo della documentazione su netlink?
Nel solito libro scritto in c :cool:
ah, niente riassunto :Prrr:
come libro e` un po` esteso :p
sul serio non esiste nulla? :eek:
terribili sti programmatori :D
ilsensine
21-06-2006, 12:06
Non c'è grande interesse a scrivere documentazione per netlink; è una tecnica vecchia (quindi anche piena di esempi) e non accettata come utilizzo "general purpose", per il quale è stato sviluppato il connector.
ok, lo prendo come un consiglio di passare a connector :cool:
rinizio a leggere la documentazione allora.
intanto sono abituato a riscrivere tutto...
prima era in c e si appoggiava alla tua patch
poi e` rimasto in c, ma appoggiato a iptables
poi mi faceva schifo e lo ho riscritto in c++ (e ho buttato via un 5000 righe, o quantomeno le ho modificate pesantemente)
poi era lento a controllare tutto dato che calcolava gli md5 a ogni pacchetto e sono passato al modulo che comunicava con af_unix (e sono andate via migliai a di righe...)
poi mi sono preso degli insulti e sono passato a netlink...
e ora communicator?
perche` no :-D
tutta esperienza :cool:
ciaaaaao!
eh, che storiaccia...
non ho idea di come poter fare...
quano mi viene chiamata la callback come faccio a sapere che processo e` quello giusto, e sopratutto come rilasciarlo?
dovrei bloccare ogni processo e poi risvegliarlo quando ricevo la risposta.
supponendo che riesca bloccare e sbloccare il processo, come tengo in memoria una lista dei processi che aspettano l'autorizzazione?
e sopratutto, una volta che lo so sbloccare come faccio a passagli il ritorno giusto (0 o -eperm)?
mi sa che mi mancano delle basi...
ilsensine
27-06-2006, 15:35
Traduci: di quale callback parli? Di quella del connector? Delle hook di selinux?
Comunque in generale, se la tua callback sta in un path diretto che viene da una syscall, con get_current() ottieni il riferimento al task corrente.
ok, mi spiego meglio
il programma a crea una socket e viene eseguita la mia funzione.
la mia funzione manda un messaggio chiedendo che farsene di questa socket....
e ora se ho ben capito mi hai consigliato di gestire la ricezione utilizzando le callback di connector, quindi una funzione viene chiamata alla ricezione del messaggio.
ma a quale socket viene associato?
anche supponendo che un solo processo mi abbia chiesto una socket, come faccio a dirgli di proseguire accettando la creazione?
in questo momento il task non e` quello giusto, e comunque il punto del codice e` quello sbagliato, da qualche parte c'e` il mio processo fermo in attesa della creazione della sua socket.. e io sono da un'altra parte che sto gestendo la ricezione del messaggio
grazie, ciao!
poi, supponendo che io riesca a fare questo, mettiamo che due processi mi facciano una richiesta, a quanto ho capito nessuno mi assicura che l'ordine di risposta sia quello gusto...
quindi....
mi servirebbe una lista di richieste con i numeri di sequenza delle richieste, ma non so come si possano implementare in modo atomico. rischierei di avere problemi di coerenza sulla lista altrimenti, no?
ciao
ilsensine
27-06-2006, 16:41
Bè certo, devi mantenere una lista delle richieste. Puoi marcare ogni richiesta con un identificativo (può essere un contatore incrementale). In più, la richiesta deve contenere un oggetto di sincronizzazione su cui puoi "dormire" (ad es. un completion -- doh, spero che puoi "dormire" dentro agli hook altrimenti sono guai seri!):
/* Questa e' la struttura che invii al demone tramite il connector */
struct cnRequest
{
int request_id;
pid_t pid;
(ecc.)
};
/* Questa e' la struttura che mantieni in lista */
struct RequestDescriptor
{
struct list_head list;
struct completion complete;
int request_id; /* o l'intera cnRequest se preferisci */
}
Nella callback del connector, cerchi nella lista la richiesta con l'id corrispondente al messaggio del demone, rimuovi l'oggetto dalla lista e "completi" il completion, svegliando così il processo in attesa di autenticazione.
Ovviamente l'accesso alla lista deve essere protetto, credo che un veloce spinlock possa essere sufficiente.
ieri ho tirato fuori questa robbbbbba
www.minox.altervista.org/minoxmod.c
(link da copiare in una pagina nuova, altrimenti viene rifiutato da altervista)
prendendo spunto da cn_proc e dall'esempio fornito.
il problema è che non comunica una mazza in user space :D
dai log sembra effettivamente che crei le richieste, aspetti che scada il timeout (messo a 10 secondi per il momento) e scaduto questo le rifiuti. peccato che in mezzo dovrebbe collegarsi al demone....
gli indirizzi sono giusti, perchè senza il modulo la bind viene rifiutata, ma la send non sembra far nulla....
o magari il client è sbagliato....
questo viene da un semi copia - incolla da un esempio su lkm
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/netlink.h>
#include <linux/connector.h>
struct cnRequest{
int request_id;
pid_t app_pid;
int request;
};
struct cnResponse{
int requestId;
int response;
};
#define SEND_MESSAGE_LEN (NLMSG_LENGTH(sizeof(struct cn_msg) + sizeof(struct cnResponse)))
#define RECV_MESSAGE_LEN (NLMSG_LENGTH(sizeof(struct cn_msg) + sizeof(struct cnRequest)))
#define SEND_MESSAGE_SIZE (NLMSG_SPACE(SEND_MESSAGE_LEN))
#define RECV_MESSAGE_SIZE (NLMSG_SPACE(RECV_MESSAGE_LEN))
#define max(x,y) ((y)<(x)?(x):(y))
#define min(x,y) ((y)>(x)?(x):(y))
#define BUFF_SIZE (max(max(SEND_MESSAGE_SIZE, RECV_MESSAGE_SIZE), 1024))
#define MIN_RECV_SIZE (min(SEND_MESSAGE_SIZE, RECV_MESSAGE_SIZE))
int sk_nl;
char buff[BUFF_SIZE];
void handle_msg (struct cn_msg *cn_hdr)
{
struct cnResponse* req;
struct cnRequest *ev;
struct nlmsghdr *nl_hdr;
/* print the message */
ev = (struct cnRequest*)cn_hdr->data;
//fai qualcosa a caso...
fprintf(stderr,"pid %d\n", ev->app_pid);
nl_hdr = (struct nlmsghdr *)buff;
cn_hdr = (struct cn_msg *)NLMSG_DATA(nl_hdr);
req = (struct cnResponse*)&cn_hdr->data[0];
req->requestId = ev->request_id;
req->response = 0;
nl_hdr->nlmsg_len = SEND_MESSAGE_LEN;
nl_hdr->nlmsg_type = NLMSG_DONE;
nl_hdr->nlmsg_flags = 0;
nl_hdr->nlmsg_seq = 0;
nl_hdr->nlmsg_pid = getpid();
cn_hdr->id.idx = CN_IDX_MINOX;
cn_hdr->id.val = CN_VAL_MINOX;
cn_hdr->seq = 0;
cn_hdr->ack = 0;
cn_hdr->len = sizeof(struct cnResponse);
if (send(sk_nl, nl_hdr, nl_hdr->nlmsg_len, 0) != nl_hdr->nlmsg_len) {
printf("failed to send proc connector mcast ctl op!\n");
return;
}
printf("sent\n");
}
int main(int argc, char **argv)
{
int err;
struct sockaddr_nl my_nla, kern_nla, from_nla;
socklen_t from_nla_len;
int rc = -1;
struct cn_msg *cn_hdr;
// enum proc_cn_mcast_op *mcop_msg;
size_t recv_len = 0;
if (getuid() != 0) {
printf("Only root can start/stop the fork connector\n");
return 0;
}
sk_nl = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
if (sk_nl == -1) {
printf("socket sk_nl error");
return rc;
}
my_nla.nl_family = AF_NETLINK;
my_nla.nl_groups = CN_IDX_MINOX;
my_nla.nl_pid = getpid();
kern_nla.nl_family = AF_NETLINK;
kern_nla.nl_groups = CN_IDX_MINOX;
kern_nla.nl_pid = 1;
err = bind(sk_nl, (struct sockaddr *)&my_nla, sizeof(my_nla));
if (err == -1) {
printf("binding sk_nl error");
goto close_and_exit;
}
for(from_nla_len = sizeof(from_nla); ;from_nla_len = sizeof(from_nla)) {
memset(buff,0,BUFF_SIZE);
struct nlmsghdr *nlh = (struct nlmsghdr*)buff;
memcpy(&from_nla, &kern_nla, sizeof(from_nla));
recv_len = recvfrom(sk_nl, buff, BUFF_SIZE, 0,
(struct sockaddr*)&from_nla, &from_nla_len);
if (recv_len < 1)
continue;
while (NLMSG_OK(nlh, recv_len)) {
cn_hdr = NLMSG_DATA(nlh);
if (nlh->nlmsg_type == NLMSG_NOOP)
continue;
if ((nlh->nlmsg_type == NLMSG_ERROR) ||
(nlh->nlmsg_type == NLMSG_OVERRUN))
break;
handle_msg(cn_hdr);
if (nlh->nlmsg_type == NLMSG_DONE)
break;
nlh = NLMSG_NEXT(nlh, recv_len);
}
}
close_and_exit:
close(sk_nl);
exit(rc);
return 0;
}
se hai voglia di darmi un parere.... :vicini: :sofico:
ps: anche questa volta il modulo è scritto per vedere se funziona, non mi picchiare se vedi cose che non ti piacciono :p
ilsensine
07-07-2006, 15:39
se hai voglia di darmi un parere.... :vicini: :sofico:
<CENSORED>
Il programma userspace manca del NETLINK_ADD_MEMBERSHIP; il driver è una catastrofe.
Non ho selinux compilato e non posso testare il driver completo, ma di do un avvio.
Questo è un driver pseudofunzionante (emula le richiedte da un thread; tu le invocherai dagli hook di selinux):
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netlink.h>
#include <linux/init.h>
#include <net/sock.h>
#include <linux/un.h>
#include <linux/ip.h>
#include <linux/timer.h>
#include <linux/skbuff.h>
#include <linux/timer.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/connector.h>
#include <linux/kthread.h>
#include <linux/delay.h>
#define CN_MINOX_MSG_SIZE (sizeof(struct cn_msg) + sizeof(struct cnRequest))
#define CN_IDX_MINOX 3
#define CN_VAL_MINOX 1
struct cnRequest{
int request_id;
pid_t app_pid;
int request;
};
struct RequestDescriptor{
struct list_head dlist;
struct completion complete;
int requestId;
int response;
};
struct cnResponse{
int requestId;
int response;
};
static atomic_t requestId;
static struct cb_id cnId = { CN_IDX_MINOX, CN_VAL_MINOX };
static char cnName[] = "minoxmod";
static spinlock_t requests_lock;
static struct list_head requests;
static struct task_struct *ktask;
static void sendRequest(struct cnRequest *req)
{
struct cn_msg *msg;
__u8 buffer[CN_MINOX_MSG_SIZE];
msg = (struct cn_msg*)buffer;
msg->id = cnId;
msg->seq = req->request_id;
msg->ack = 0;
msg->len = sizeof(*req);
memcpy(msg->data, req, msg->len);
cn_netlink_send(msg, CN_IDX_MINOX, GFP_KERNEL);
}
static int make_request(int request_type){
struct cnRequest request;
struct RequestDescriptor rdesc;
request.app_pid = get_current()->pid;
request.request = request_type;
request.request_id = atomic_inc_return(&requestId);
rdesc.requestId = request.request_id;
rdesc.response = -ETIMEDOUT;
init_completion(&rdesc.complete);
spin_lock(&requests_lock);
list_add_tail(&rdesc.dlist, &requests);
spin_unlock(&requests_lock);
sendRequest(&request);
wait_for_completion_timeout(&rdesc.complete, msecs_to_jiffies(10000));
spin_lock(&requests_lock);
list_del(&rdesc.dlist);
spin_unlock(&requests_lock);
return rdesc.response;
}
static void evaluateResponse(void *data)
{
struct cn_msg *msg = data;
struct cnResponse *reply = (struct cnResponse *) msg->data;
int request_id;
struct RequestDescriptor *pos;
if (msg->len != sizeof(*reply))
return;
request_id = reply->requestId;
printk(KERN_DEBUG "Risposta ricevuta (id=%d res=%d)\n",
request_id, reply->response);
spin_lock(&requests_lock);
list_for_each_entry(pos, &requests, dlist) {
if (pos->requestId == request_id) {
pos->response = reply->response;
complete(&pos->complete);
break;
}
}
spin_unlock(&requests_lock);
}
static int test_thread(void *unused)
{
while (!kthread_should_stop()) {
int result = make_request(0);
printk(KERN_DEBUG "result=%d\n", result);
msleep(1000);
}
return 0;
}
static int __init testcn_init(void)
{
int err;
spin_lock_init(&requests_lock);
INIT_LIST_HEAD(&requests);
err = cn_add_callback(&cnId, cnName, evaluateResponse);
if (!err) {
ktask = kthread_create(test_thread, NULL, "test_thread");
if (IS_ERR(ktask)) {
cn_del_callback(&cnId);
err = PTR_ERR(ktask);
} else
wake_up_process(ktask);
}
return err;
}
static void __exit testcn_exit(void)
{
kthread_stop(ktask);
cn_del_callback(&cnId);
}
module_init(testcn_init);
module_exit(testcn_exit);
MODULE_LICENSE("GPL v2");
E' ancora da ripulire un pò (in particolare si può ridurre il consumo di stack che è un pò elevato).
Questo è il demone userspace che ho usato:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/netlink.h>
#include <linux/connector.h>
#define CN_IDX_MINOX 3
#define CN_VAL_MINOX 1
#ifndef SOL_NETLINK
#define SOL_NETLINK 270
#endif
struct cnRequest{
int request_id;
pid_t app_pid;
int request;
};
struct cnResponse{
int requestId;
int response;
};
static int open_connector()
{
int on;
struct sockaddr_nl my_nla;
int fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
if (fd<0) {
perror("socket");
return -1;
}
my_nla.nl_family = AF_NETLINK;
my_nla.nl_groups = CN_IDX_MINOX;
my_nla.nl_pid = getpid();
if (bind(fd, (struct sockaddr *)&my_nla, sizeof(my_nla))<0) {
perror("bind");
close(fd);
return -1;
}
on = my_nla.nl_groups;
setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &on, sizeof(on));
return fd;
}
static int make_response(struct cnRequest *req)
{
/* Calcola qui la risposta da inviare */
return req->request_id;
}
static void cn_reply(int fd, struct cnRequest *req)
{
struct {
struct nlmsghdr hdr;
struct cn_msg cnmsg;
struct cnResponse cresp;
} msg;
memset(&msg, 0, sizeof(msg));
msg.hdr.nlmsg_len = sizeof(msg);
msg.hdr.nlmsg_type = NLMSG_DONE;
msg.hdr.nlmsg_pid = getpid();
msg.cnmsg.id.idx = CN_IDX_MINOX;
msg.cnmsg.id.val = CN_VAL_MINOX;
msg.cnmsg.len = sizeof(msg.cresp);
msg.cresp.requestId = req->request_id;
msg.cresp.response = make_response(req);
send(fd, &msg, msg.hdr.nlmsg_len, MSG_NOSIGNAL);
}
static struct cnRequest *cn_read(int fd)
{
struct {
struct nlmsghdr hdr;
struct cn_msg cnmsg;
struct cnRequest creq;
} msg;
struct cnRequest *cret;
int rv = recv(fd, &msg, sizeof(msg), MSG_NOSIGNAL);
if (rv>=0 && rv!=sizeof(msg)) {
rv = -1;
errno = EINVAL;
}
if (rv<0) {
if (errno!=EINTR)
perror("recv");
return NULL;
}
cret = malloc(sizeof(*cret));
*cret = msg.creq;
return cret;
}
int main(int argc, char **argv)
{
int fd;
if (getuid() != 0) {
printf("Must be root.\n");
return 0;
}
fd = open_connector();
if (fd<0)
return -1;
while(1) {
struct cnRequest *req = cn_read(fd);
if (req!=NULL) {
fprintf(stderr, "request_id=%d\n", req->request_id);
cn_reply(fd, req);
free(req);
}
}
}
Non sono sicuro che il processo di bind sia 100% corretto, ma è un inizio.
ilsensine
17-07-2006, 17:50
Novità? Sei andato avanti?
si, un esame di basi di dati, due di sistemi operativi, il secondo di matematica computazionale, uno di geometria proiettiva, un progetto di interfacce utente e uno di inglese :D
no, a parte le idiozie (ah, tra parentesi... geometria mi ha suonato di brutto :cool: )...
ho applicato tutto al vecchio codice, ma permane (in forma decisamente minore) il problema di prima sulle prestazioni.
la navigazione con firefox porta la cpu al 50-60%, perchè questo burlone non fa altro che aprire nuove socket, e il programma non fa altro che ricontrollare l'md5 di tutte le librerie...
suppongo di dover allargare i controlli o quantomeno cambiare algoritmo di hash.
l'altra soluzione sarebbe reimplementarsi un sistema di controllo sulle modifiche sulle librerie che sono usate dai programmi che sono collegati (sempre tutte quelle belle funzioni di hook), ma questo mi ritoglie la possibilità di usare LSF (decisamente più diffuso dato che è in quasi tutti i kernel delle distribuzioni) per selinux...
comuqnue (se non è una cazzata) il mio moduletto riceverebbe anche le liste dei file da controllare (gli servono gli inode) e ci aggangia un hook sulle modifiche sopra.
in questo modo posso controllarli solo una volta, e poi posso segnarli come validi (fino a che qualcuno non mi dice che qualcuno ci ha scritto sopra).
comunque per i problemi espressi nelle prime due righe non ho più fatto nulla...
ho ancora esami fino a martedì prossimo :eek:
ciao ciao!
ilsensine
19-07-2006, 09:55
la navigazione con firefox porta la cpu al 50-60%, perchè questo burlone non fa altro che aprire nuove socket, e il programma non fa altro che ricontrollare l'md5 di tutte le librerie...
Usa una cache dei controlli, furbo.
Quando devi controllare un file, controlla se lo hai già verificato in precedenza. Il file nella tua cache non lo identificare con il come, ma con la coppia st_dev:st_ino restituita da stat. Se i campi st_mtime e st_ctime non sono variati, puoi con sicurezza utilizzare il risultato del controllo posto nella cache.
ilsensine
19-07-2006, 10:31
Se i campi st_mtime e st_ctime non sono variati...
Altra ideona qui: INOTIFY!
Altra ideona qui: INOTIFY!
questa si che mi è sembrata una figata...
sono appena tornato dalle vacanze e ho provato a mettercelo sopra...
va che è una bomba! :)
ora hanno smesso di funzionare ping e traceroute.... cmq il demone termina in modo controllato tramite un'eccezione (ora basta capire perchè viene sollevata :sofico: )
ma questo un altro giorno! oggi si festeggia perchè il consumo di cpu durante la navigazione è diventato irrisorio (non mi compare nemmeno su top :cool: )
sei stato prezioso come al solito!
ho preso la seconda idea perchè mi sembrava strana la prima... non si possono modificare quei campi?
ciao!
ilsensine
21-08-2006, 09:25
ho preso la seconda idea perchè mi sembrava strana la prima... non si possono modificare quei campi?
...?
non so...
su win quando ero ggggiovane mio cugggino mi aveva dato un coso che modificava le date di accesso e modifica dei file, almeno mi sembra.
supponevo che si potesse fare anche su linux, no?
bho, comunque inotify va che è una bomba, una volta che impara a parlare con il client pubblico la primissima versione.
la parte triste è che tolto qua e tolto là ormai è di 2000 righe :confused: a pensare quante inutilità ho scritto per poi sostituirle con librerie esistenti e quante righe ha sostituito il modulo del kernel che ne conta meno di 300 mi viene da piangere :cry: :sofico:
ciao!!!!
ps: il modulo del kernel lo hai praticamente scritto tutto te, ne ho modificato una parte infinitesimale... che ci scrivo?
ilsensine
21-08-2006, 11:39
ps: il modulo del kernel lo hai praticamente scritto tutto te, ne ho modificato una parte infinitesimale... che ci scrivo?
/*
* Copyright (c) 2006 Microsoft Corp.
* See EULA.txt for license details.
*/
ilsensine
21-08-2006, 11:49
non so...
su win quando ero ggggiovane mio cugggino mi aveva dato un coso che modificava le date di accesso e modifica dei file, almeno mi sembra.
Lo scopo era capire quando il file veniva modificato, ed era quindi necessario ricalcolare l'md5.
inotify risolve il problema in un modo diverso/migliore.
/*
* Copyright (c) 2006 Microsoft Corp.
* See EULA.txt for license details.
*/
no, dai! :D
a parte gli scherzi...
nella parte sul copyright che ci metto? -.-
niente?
qualcosa?
a te la scelta! :)
ilsensine
21-08-2006, 15:44
Mettici il tuo nome. Io ci avrei lavorato ancora un pò :D
vBulletin® v3.6.4, Copyright ©2000-2026, Jelsoft Enterprises Ltd.